[MUSIC PLAYING]
MATT SULLIVAN: Hello there.
I'm Matt from the Flutter Devrel team.
In this video, we're going to be checking out
Flutter's ML vision plug-in.
If you've ever wanted to experiment with face detection,
recognize some text, or work out whether a photo has been taken
down the beach or at the top of a mountain,
then this is the plug-in for you.
All this ML goodness is powered by Firebase's ML kit, which
provides machine learning models for a variety of use cases.
Text recognition, face detection, bar code scanning,
image labeling, landmark recognition, and some custom
model inference.
To check out ML Kit in action we're
going to implement face detection
in a Flutter app using the device's camera or gallery.
Let's get started by installing a couple of plugins
that our app's going to need by adding them
to our pubspec.yaml.
We're going to need some way of taking or selecting images.
So let's add an image picker.
And of course, we're going to need Flutter's ML vision
plug-in.
We also need to set up a Firebase project, which we've
covered in a previous video.
Click on the link in the description below
to learn more from Andrew on Firebase setup goodness.
Right.
Now that configuration is out of the way,
on to building our face detection app.
First things first.
We're going to need our basic app structure.
Let's begin by creating a basic scaffold with a floating action
button.
We're using a stateful widget, as we're
going to need to track the selected image
and any faces detected.
We'll add state as we work through the code.
We've got three tasks to perform to get our app detecting faces.
Firstly, we need to select an image that we'd
like to search for faces.
Secondly, we need to load in that image for processing.
And thirdly, we need to search that image
for faces using ML Kit.
On to the first task.
Image selection couldn't be easier in Flutter.
This single line of code using Image Picker
will launch either the device's native gallery or the camera
app, depending on which source you provide--
camera or gallery.
A file reference is returned asynchronously.
Next, we load the selected image.
The Firebase vision image class from the vision
plug-in loads and stores an image in a format suitable
for feature detection.
That's another line of code.
We're at task number three, and we're
ready to detect some faces.
We need an instance of the Firebase vision class
that's initialized with a face detector.
Other detectors are available for a variety
of detecting situations.
We can provide the face detector with optional parameters
to control things like accuracy and whether we
should look for landmark features such as eyes, ears,
and noses.
Finally, we pass the image to our detector,
which asynchronously returns a list of any
faces that it finds.
The face object contains a bunch of interesting info.
But the data we're most interested in
is the bounding boxes surrounding
each face, whose coordinates are relative to the true size
of the image.
And finally, let's wrap our code up in a function
that we can drop into our stateful widget.
Great.
Now we've got image selection, loading, and processing.
Not bad for four lines of code, all thanks
to the power of plugins.
Let's wire everything together in our app.
First, let's add our image file and list of detected
faces into our state class.
Now that we have a newly minted function,
we can add that and wire it up to the floating action button.
We need to make sure that we mark the state as Updated
once face detection completes.
We can add a call to set state in our function
and update our state variables.
Now while all this looks great on the face of it,
there's a subtle issue here.
Let's take a look at our face detection function again.
Note we're waiting twice for async functions to complete.
And when they complete, there is no guarantee
that the face page widget will still be active or mounted.
The user could have navigated away from the page,
or left the app altogether.
As soon as dispose is called, any ongoing background work
is wasted processing and battery.
We should check the widget's mounted state
after each AsyncTask finishes.
But here we'll use a more simple solution
and just check whether the widget is mounted
before setting the state.
Now, with that out of the way, let's
wrap this up and display both the image
and our detected faces.
We'll start by replacing the placeholder container
with a new widget--
image and faces.
We'll pass the image file path and list
of faces to our new widget.
Let's put the image and list in a column
and use flexible widgets to determine
the proportion they take up.
We'll give 2/3 of the screen space to the image.
Then we load the image using image.file, and ensure that it
covers the available space.
And let's ensure that the space the image is given fully
covers 2/3 of the screen.
Now let's give the faces list the bottom 1/3
and use a list view to display the faces,
mapping the faces to a new widget that displays each one.
Our new widget will simply show the coordinates
of the face's bounding box.
So there you have it.
Image selection and face detection in a few lines
of code.
To see how to modify an image in Flutter
and highlight all those detected faces in the image
itself, please check out the companion video
on custom painters.
More information in the links below.
And please come visit us at flutter.al.
SPEAKER 1: That was pretty delightful.
If you like that, we have lots more of stuff
where that came from.
And particularly, you should check out the Flutter channel
and subscribe.
Subscribe.
Do it.
[MUSIC PLAYING]