Handwriting number recognizer with Flutter and Tensorflow (part III)

Source: Deep Learning on Medium

As usual, amazing to have you back!

In this third article, we are going to build the finger painting widget for our application. Hope you are ready for painting some serious stuff at the end of the tutorial 😉

Drawing on the screen

Let’s start checking what Flutter has available for us for painting in the screen. If we dig a little bit, we will find references to CustomPaint, CustomPainter and Canvas. If you are interested, bellow are the links to the Flutter documentation of this classes, but right above it I’m highlighting as best as possible the main differences.

I’m going to keep the long story short in here and resume it in a few bullet points:

  • CustomPaint is a widget that provides us with a Canvas under the hood.
  • CustomPaint uses a CustomPainter to run paint commands on the Canvas.
  • We cannot easily access the Canvas value of a CustomPainter outside its methods.
  • CustomPainter can be subclassed and we could override some of its methods , but it is difficult to replace the Canvas there.
  • A Canvas cannot be used as a Widget by itself.
  • A Canvas has a method to export an image of its content.
Real time images from one of our readers

I know, it may be a bit too much to process. Let’s see what we actually need:

We want a something that allow us to paint in a rectangle in the screen and allow us to export it as an image, so we can feed that image to our model.

Well… it does seem that neither Canvas nor CustomPaint can help us by themselves… 😭 I guess we will have to use both of them!

For the moment, let’s just worry to have a widget where we can use our finger to paint, so let’s bring CustomPaint onto our app. This is going to bring a little bit of code into our app, so let’s go step by step.

CustomPaint

First of all, replace our SizedBox by the following code:

CustomPaint(
size: Size(kCanvasSize, kCanvasSize),
painter: DrawingPainter(
offsetPoints: points,
),
),

CustomPaint is already included in material.dart, so we don’t need to import anything else. You will notice that there are a couple of undefined things there: kCanvasSize, DrawingPainter and points. Let’s get them next.

Points

Points is simply a property declaration in our class and it is going to host a list of points. Just place it under our _RecognizerScreen definition as follows:

class _RecognizerScreen extends State<RecognizerScreen> {
List<Offset> points = List();

...
}

kCanvasSize

Anything that starts by k is going to be a constant within our app, and that means we need to create a file to hold our contants, so create a constants.dart file and add the canvas size to it:

const double kCanvasSize = 200.0;

Then you will need to import our constants file to our recognizer screen as follows:

import 'package:handwritten_number_recognizer/constants.dart';

DrawingPainter

The drawing painter is going to be our custom subclass for CustomPainter. CustomPainter is used by CustomPaint to execute drawing commands in the canvas.

Our intention will be to pass a list of points to our CustomPainter and those will be the drawing commands we want it to execute. I will explain later how we are going to obtain that list of points.

So let’s create a new file called drawing_painter.dart and copy this code in there:

import 'package:flutter/material.dart';
import 'package:handwritten_number_recognizer/constants.dart';
final Paint drawingPaint = Paint()
..strokeCap = StrokeCap.square
..isAntiAlias = kIsAntiAlias
..color = kBlackBrushColor
..strokeWidth = kStrokeWidth;
class DrawingPainter extends CustomPainter {
DrawingPainter({this.offsetPoints});
List<Offset> offsetPoints;
@override
void paint(Canvas canvas, Size size) {
for (int i = 0; i < offsetPoints.length - 1; i++) {
if (offsetPoints[i] != null && offsetPoints[i + 1] != null) {
canvas.drawLine(offsetPoints[i], offsetPoints[i + 1], drawingPaint);
}
}
}
@override
bool shouldRepaint(DrawingPainter oldDelegate) => true;
}

You will also notice there is a Paint class at the top of the page, that is, as its name indicates, the paint we are going to use for painting in the canvas; and its values are defined in our constants file. Just add the following there:

const double kStrokeWidth = 12.0;
const Color kBlackBrushColor = Colors.black;
const bool kIsAntiAlias = true;

You have to import flutter/material.dart to been able to use Colors within that file.

Ok, let’s take a break and try running the app.