Physical Address
304 North Cardinal St.
Dorchester Center, MA 02124
Physical Address
304 North Cardinal St.
Dorchester Center, MA 02124

Pada kesempatan kali ini saya akan memberikan penjelasan mengenai eksperimen saya dengan flutter yakni memadukan Flutter dengan Machine Learning Firebase. Sebelumnya saya mencoba bereksperimen menggunakan Android Native menggunakan Kotlin, namun pada akhirnya alangkah lebih bagus apabila diterapkan di Flutter Dart juga. Eksperimen kali ini adalah mengembangkan aplikasi Flutter Optical Character Recognize (OCR) menggunakan Text Recognize Machine Learning Firebase, aplikasi ini akan memindai hasil dari jepretan kamera lalu diekstrak teks dari gambar sehingga hasil akhir berupa teks yang ditampilkan di Textview.

Flutter sendiri merupakan Google Software Development Kit untuk mengembangkan aplikasi mobile Android dan iOS. Sedangkan Firebase (Milik Google juga) sendiri menawarkan layanan backend khusus mobile. Ada banyak sekali produk atau layanan yang ditawarkan oleh Firebase khususnya yang kita akan kembangkan kali ini yakni Machine Learning (ML) Kit. ML kit ini juga merupakan SDK yang menghadirkan machine learning untuk aplikasi android dan iOS yang andal, tentunya mudah digunakan bagi para praktisi yang sebelumnya tidak ada latar belakang machine learning sekalipun. Nah, semua penjabaran diatas jelas dipergunakan untuk pembuatan mobile development, Google benar-benar fokus untuk memberikan pengalaman development yang menyenangkan alias nggak usah mikirin kerepotan backend machine learning.
Show me your code
Hmm . . jangan dulu, quote diatas harusnya ditunda, kita harus mempersiapkan segala hal yang perlu dipergunakan misal SDK dan setting environtment. Nah sebelum memulai, Anda diharuskan sudah memiliki Flutter SDK yang sudah ter-install, Editor seperti Visual Code atau Android Studio dengan plugin Dart/Flutter.





Sepertinya kita akan langsung menulis kode atau kopas kode dibawah ini, hehe akan saya coba terangkan beberapa bagian khususnya pada Machine Learning kit Flutter. Perlu teman-teman perhatikan bahwa kode yang saya tampilkan dibawah hanya berupa potongan kode saja, untuk lebih lengkapnya Anda bisa fork atau clone project saya di github diakhir tulisan.
import 'package:flutter/material.dart'; import 'dart:async'; import 'dart:io'; import 'package:firebase_ml_vision/firebase_ml_vision.dart'; import 'package:flutter/material.dart'; import 'package:image_picker/image_picker.dart'; import 'detector_painter.dart';
Petikan baris kode berikut digunakan untuk mengimport kelas dari luar. Bagian utama jelas seperti Flutter material digunakan untuk mengimplementasi widget material, kemudian async digunakan untuk proses asynchrounous, IO digunakan untuk fungsi input/output seperti parsing json dll. Jangan lupa untuk memasukkan image picker dan firebase ml vision. Sedangkan kelas dart terakhir adalah kelas kustomasi untuk membuat kotak karakter dari text recognize yang dibaca oleh machine learning.
Future<void> _getImage() async {
setState(() {
_imageFile = null;
_imageSize = null;
});
final File imageFile =
await ImagePicker.pickImage(source: ImageSource.camera);
if (imageFile != null) {
_getImageSize(imageFile);
_scanImage(imageFile);
}
setState(() {
_imageFile = imageFile;
});
}
Fungsi _getImage() diatas digunakan untuk mengambil file image hasil dari kamera. setState diawal menginisiasi bahwa variabel imageFile dan imageSize adalah null, kemudian setelah diproses secara asynchrounouse yakni yang tercantum istilah await didepannya baru pengecekan, apakah hasil proses tersebut kosong atau tidak apabila tidak maka fungsi _getImagesize() dan _scanImage() dijalankan dengan isian parameter imageFile
SetState digunakan lagi untuk mengupdate nilai _imageFile yang sebelumnya null. Future adalah kembalian pada fungsi _getImage() digunakan untuk proses return yang bersifat asynchronous atau menjalankan operasi asynchronous. Bila menjalankan operasi asynchronous async dan await akan kita gunakan. Kenapa harus Async? karena proses pengambilan image membutuhkan komputasi yang lebih atau ada proses yang membutuhkan waktu tunggu seperti mengambil respon dari API internet. Hal tersebut tidak tepat dilakukan pada main thread apabila tidak menggunakan proses Async, maka berakibat aplikasi menjadi Freezee.
Future<void> _getImageSize(File fileImage) async {
final Completer<Size> completer = new Completer<Size>();
final Image image = new Image.file(fileImage);
image.image
.resolve(const ImageConfiguration())
.addListener((ImageInfo info, bool _) {
completer.complete(
Size(info.image.width.toDouble(), info.image.height.toDouble()));
});
final Size sizeImage = await completer.future;
setState(() {
_imageSize = sizeImage;
});
}
Fungsi selanjutnya adalah fungsi _getImageSize() yang memiliki parameter berupa file image. fungsi ini digunakan untuk membuat object Size image untuk selanjutnya diolah kembali oleh kelas detector_painter.dart. Secara sederhana fungsi ini memetakan Size kotak teks yang dibaca oleh machine learning Firebase sehingga nanti ada garis kotak yang melingkupi teks.
Completer diatas adalah cara untuk membuat objek Future secara async nantinya Completer bertugas untuk memberikan pesan error dan mengeluarkan hasil prosesnya. SetState bertugas untuk mengupdate data _imageSize yang sebelumnya null dengan data Size hasil proses pengolahan image.
Future<String> textScaned(List<TextBlock> listString) async {
StringBuffer buffer = new StringBuffer();
listString.forEach((item) {
buffer.write(item.text);
});
setState(() {
text = buffer.toString();
});
}
textScanned() berfungsi sebagai penyedia teks yang ingin diolah, parameter fungsi tersebut adalah listString yakni list yang berisi objek TextBlock. TextBlock adalah salah satu API Firebase atau mesin OCR untuk membaca satu blok teks. Proses diatas me-looping listString yang kemudian di gabungkan menjadi satu kesatuan teks String menggunakan StringBuffer. setText kemudian mengupdate variabel text dengan hasil teks yang sudah disatukan.
Future<void> _scanImage(File imageFile) async {
setState(() {
_scanResult = null;
});
final FirebaseVisionImage visionImage =
FirebaseVisionImage.fromFile(imageFile);
final FirebaseVisionDetector textDetector =
FirebaseVision.instance.textDetector();
final List<TextBlock> result =
await textDetector.detectInImage(visionImage) ?? <dynamic>[];
textScaned(result);
setState(() {
_scanResult = result;
_visibility = false;
});
}
Selanjutnya fungsi _scanImage(), fungsi ini yang memuat kelas-kelas API Firebase dari library firebase_ml_vision yang kita import tadi. Baiklah kita coba dedah satu persatu, variabel visionImage digunakan untuk memperoleh objek FirebaseVisionImage berdasarkan file image. Sementara untuk membuat teks detektor atau pendeteksi teks kita harus menginisiasi FirebaseVision.instance.textDetector() terlebih dahulu kemudian memanggil detectImage().
Jangan lupa untuk mengisi parameter tersebut dengan visionImage dari file image. operator double question adalah operator untuk mengecek apakah null atau tidak apabila null maka aplikasi akan membuat objek list baru dengan tipe data dynamic. Nah proses tersebut menghasilkan List Text Block. Untuk memperoleh String dari proses tersebut kita menggunakan fungsi yang telah kita rancang tadi yakni fungsi textScaned(). SetState akan mengupdate data _scanResult dengan result dan _visibility dengan false. Variabel _visibility digunakan untuk menghilangkan FAB saat gambar telah selesai di ekstrak menjadi teks.
CustomPaint _buildResult(Size imageSize, List<dynamic> result) {
CustomPainter painter;
painter = new TextDetectorPainter(imageSize, result);
return new CustomPaint(painter: painter);
}
Fungsi diatas bertugas untuk membuat kotak teks yang akan ditampilkan diatas gambar yang kita ambil melalui kamera, kotak teks tersebut melingkupi teks yang ada pada gambar. CustomPaint merupakan kelas dari Flutter untuk menggambar, lalu fungsi TextDetectorPainter() adalah fungsi kustomasi untuk menggambar kotak yang melingkupi teks. Hasil akhirnya nanti berupa CustomPaint Widget yang akan kita terapkan pada User Interface (UI).
Widget _buildImage() {
return new Container(
child: SingleChildScrollView(
child: new ConstrainedBox(
constraints: new BoxConstraints(),
child: new Column(
children: <Widget>[
new Container(
constraints: BoxConstraints.expand(height: 700.0),
decoration: new BoxDecoration(
image: new DecorationImage(
image: Image.file(_imageFile).image, fit: BoxFit.fill)),
child: _imageSize == null || _scanResult == null
? const Center(
child: Text('Loading scan Image',
style:
TextStyle(color: Colors.green, fontSize: 30.0)),
)
: _buildResult(_imageSize, _scanResult)),
new Container(
padding: const EdgeInsets.all(10.0),
child: new Text(text, textAlign: TextAlign.center),
),
],
),
)),
);
}
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: const Text("ML Kit Flutter"),
),
body: _imageFile == null
? const Center(
child: Text("No image Selected"),
)
: _buildImage(),
floatingActionButton: new Opacity(
opacity: _visibility ? 1.0 : 0.0,
child: new FloatingActionButton(
onPressed: _getImage,
tooltip: "picking image",
child: const Icon(Icons.add_a_photo),
),
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
);
}
Sehabis kita berkutat pada logika tibalah kita untuk membuat User Interface. Fungsi diatas digunakan untuk menampilkan image hasil sebelum diolah dan setelah diolah dibawah gambar terdapat Textview sebagai penampil hasil ekstrak gambar menjadi teks. UI diatas menggunakan Scroll layout sehingga apabila gambar terlalu besar kita masih bisa menggulung layar sampai bawah untuk melihat hasil teks yang ditampilkan.
Silakan Anda jalankan dengan perintah flutter run pada terminal. Perlu diperhatikan bahwa Firebase membutuhkan beberapa komponen untuk menunjang layanan, khususnya ML kit. Sebelum kita menjalankan, Firebase akan mendownload komponen dari Google service. Pastikan koneksi Anda lancar, apabila Anda menjalankan proses TextRecognize sebelum proses download selesai Anda maka ekstrak teks dari gambar tidak dapat dilakukan atau tidak ada hasilnya. Namun jika masih belum bisa atau hasil ekstrak masih belum tampil, coba Anda cek logcat pada terminal, kesalahan atau error apa yang sedang terjadi. Kemungkinan Anda harus meng-clear cache dari data Google service supaya komponen tersebut memiliki cukup ruang dari hasil download komponen. Proses download komponen hanya berlangsung sekali saja dalam satu perangkat sehingga ketika Anda sudah mendownload Anda dapat menjalankan aplikasi tersebut secara luring.
project lengkap saya bisa teman-teman peroleh di Github ini
Sekian dari saya kurang lebihnya mohon maaf. Apabila ada pertanyaan silakan isi kolom komentar dan mari kita berdiskusi. π