7.3. Halo BlazeFace

BlazeFace adalah jaringan saraf deteksi wajah dari koleksi MediaPipe Google. Satu panggilan inferensi menghasilkan persegi panjang kotak pembatas di sekitar setiap wajah yang terdeteksi beserta enam titik kunci wajah -- mata kanan, mata kiri, hidung, mulut, telinga kanan, telinga kiri. Setiap OpenMV Cam yang dikirimkan dengan dukungan jaringan saraf menyertakan model blazeface_front_128.tflite pada flash, sehingga menjalankan detektor wajah end-to-end hanya membutuhkan beberapa baris Python.

7.3.1. Skrip lengkap

import csi
import ml
from ml.postprocessing.mediapipe import BlazeFace

csi0 = csi.CSI()
csi0.reset()
csi0.pixformat(csi.RGB565)
csi0.framesize(csi.VGA)
csi0.window((400, 400))

model = ml.Model("/rom/blazeface_front_128.tflite",
                 postprocess=BlazeFace(threshold=0.4))

while True:
    img = csi0.snapshot()
    for (x, y, w, h), score, keypoints in model.predict([img]):
        img.draw_rectangle((x, y, w, h), color=(0, 255, 0))
        ml.utils.draw_keypoints(img, keypoints, color=(255, 0, 0))

Itulah seluruh detektor wajah. Tidak ada yang lain; skrip menangkap bingkai, menyerahkannya ke model, menelusuri daftar deteksi yang dikembalikan, dan menggambar kotak pembatas serta enam titik kunci setiap wajah kembali ke dalam bingkai. Pratinjau IDE menampilkan kotak dan titik kunci secara real time.

7.3.2. Apa yang dilakukan setiap baris

Tiga baris pertama mengimpor modul yang dibutuhkan skrip. csi adalah antarmuka sensor kamera; ml adalah modul pembelajaran mesin yang dibahas dalam bab ini; BlazeFace adalah pasca-prosesor yang mengubah tensor keluaran mentah BlazeFace menjadi daftar kotak pembatas dan titik kunci yang diiterasi oleh skrip.

Lima baris berikutnya mengonfigurasi sensor. Kamera direset ke kondisi awal yang diketahui, diatur ke warna RGB565, diatur ke resolusi VGA, lalu di-window menjadi persegi 400-kali-400. Window ini penting: BlazeFace dilatih pada crop persegi, dan memberikannya masukan persegi menyelaraskan rasio aspek yang diharapkan jaringan dengan apa yang terlihat dalam bingkai yang diambil.

Baris pemuatan model membuka file model:

model = ml.Model("/rom/blazeface_front_128.tflite",
                 postprocess=BlazeFace(threshold=0.4))

ml.Model membaca file pada jalur yang diberikan -- /rom/ adalah filesystem yang berada di flash yang dibahas nanti -- dan mengembalikan objek model yang akan digunakan skrip untuk inferensi. Kata kunci postprocess= mendaftarkan pasca-prosesor BlazeFace; tanpanya, predict akan mengembalikan tensor keluaran mentah jaringan dan aplikasi harus mendekodenya secara manual. Dengan pasca-prosesor, predict mengembalikan hasil yang sudah didekode secara langsung. Argumen threshold=0.4 pada pasca-prosesor menetapkan kepercayaan minimum yang harus dilaporkan jaringan sebelum deteksi disimpan; nilai yang lebih rendah menangkap wajah yang lebih samar dengan risiko lebih banyak false positive.

Empat baris yang tersisa adalah loop utama. Setiap iterasi menangkap satu bingkai dan menanyakan model tentang apa yang dilihatnya:

img = csi0.snapshot()
for (x, y, w, h), score, keypoints in model.predict([img]):
    img.draw_rectangle((x, y, w, h), color=(0, 255, 0))
    ml.utils.draw_keypoints(img, keypoints, color=(255, 0, 0))

predict() mengambil daftar masukan (di sini, satu citra yang diambil) dan mengembalikan daftar tuple deteksi. Setiap tuple berisi persegi panjang kotak pembatas (x, y, w, h), score kepercayaan antara nol dan satu, serta ndarray berukuran (6, 2) yang berisi koordinat titik kunci -- mata kanan, mata kiri, hidung, mulut, telinga kanan, dan telinga kiri secara berurutan. Panggilan gambar menggunakan draw_rectangle() -- primitif yang sama yang digunakan setiap detektor klasik di bab citra -- untuk menggarisbawahi wajah. ml.utils.draw_keypoints() adalah helper kecil dari utilitas ml yang menandai setiap titik kunci dengan tanda silang di posisi (x, y)-nya.

7.3.3. Apa yang tidak dikatakan skrip

Skrip ini terdiri dari tujuh baris inferensi yang dapat dijalankan setelah impor dan pengaturan sensor, tetapi banyak sekali aritmatika yang terjadi di dalam tujuh baris tersebut. Bingkai RGB565 berukuran 400-kali-400 yang diambil menjadi tensor 8-bit terkuantisasi berukuran 128-kali-128 sebelum mencapai jaringan; jaringan menjalankan ratusan operasi terhadap puluhan ribu bobot; tensor skor kepercayaan dan offset kotak yang dihasilkan menjadi daftar berperingkat kotak pembatas yang tidak saling tumpang tindih dengan titik kunci terlampir sebelum predict mengembalikan hasil. Setiap transformasi tersebut adalah sesuatu yang dapat dikendalikan oleh aplikasi jika diperlukan, dan beberapa di antaranya harus disetel untuk model non-default.

Empat subbagian berikutnya mengurai transformasi-transformasi tersebut secara terbuka. Secara berurutan:

  • Modul ml -- apa yang diekspos ml.Model setelah model dimuat, dan di mana file model sebenarnya berada pada kamera.

  • Pipeline inferensi -- empat tahap setiap panggilan predict().

  • Engine inferensi -- jalur CPU dan NPU yang menjalankan aritmatika jaringan.

  • Mendekode keluaran -- pasca-prosesor yang mengubah tensor keluaran mentah menjadi deteksi yang diiterasi oleh skrip ini.

Pada akhir bab ini, pembaca dapat menulis skrip yang setara untuk model yang tidak dikirimkan bersama kamera, mendekode tensor yang pasca-prosessornya belum ada, dan memahami mengapa model tertentu berjalan pada 30 FPS di satu kamera dan 3 FPS di kamera lain.