Kalau dalam Fisika, gerak diartikan sebagai
perpindahan benda dari satu titik ke titik lainnya. Nah, kalau dalam pengolahan
citra tentunya kita tidak bisa mengatakan titik-titik warnanya berpindah tempat
bukan? Yang terjadi adalah warna yang hampir sama ditampilkan oleh
piksel-piksel yang bersebelahan secara bergantian. Kalau dilihat dengan mata,
kita mudah sekali membedakan benda bergerak dan benda diam. Namun, bagaimana
caranya komputer dapat mengenal gerak?
Nah, dalam tutorial kali ini kita akan belajar
membuat sebuah sensor gerak sederhana menggunakan webcam. Metode yang kita
gunakan adalah background subtraction Gaussian Mixture Model (GMM). Kalau
di OpenCV metode ini dikenal dengan fungsi BackgroundSubtractorMOG2(). Selain
yang MOG2 kita juga bisa gunakan yang MOG saja. Bedanya yang MOG2 katanya lebih
cepat dan akurat. Oh iya, MOG itu singkatan dari Mixture of Gaussian.
Kalau mau tahu teorinya yang lebih lengkap cari aja GMM di internet.
Pertama, buat project baru dari template OpenCV,
beri nama projectnya “sonsorgerak”. Seperti biasa buat tombol “Mulai” dan
“Berhenti” serta sebuah PictureBox. Biar lebih menarik, tambahkan pula
ProgressBar. Setelah itu, klik 2 kali tombol “Mulai” dan juga tombol “Berhenti”
lalu masukkan kode berwarna merah berikut:
int tutup;
private: System::Void
button1_Click(System::Object^ sender,
System::EventArgs^ e) {
VideoCapture webcam;
webcam.open(0);
Mat asli,mask;
tutup=0;
Ptr<BackgroundSubtractor> MOG2;
MOG2 = new BackgroundSubtractorMOG2();
float alfa=0.1;
cv::Scalar mean, stdev;
namedWindow("tes",0);
namedWindow("asli",0);
while(tutup==0)
{
webcam>>asli;
MOG2->operator()(asli, mask, alfa);
imshow("tes",mask);
meanStdDev(mask,mean,stdev);
double stddev=*stdev.val/1.2;
if(stddev<100)
progressBar1->Value=stddev;
else progressBar1->Value=100;
cvtColor(mask,mask,CV_GRAY2BGR);
MatIterator_<Vec3b> it, end;
for( it = mask.begin<Vec3b>(), end =
mask.end<Vec3b>(); it != end; ++it)
{
if((*it)[2]>0)
{
(*it)[0]=0;
(*it)[2]=0;
}
}
addWeighted(asli,1,mask,0.9,0.0,asli);
imshow("asli",asli);
Mat img1 = asli;
System::Drawing::Graphics^ graphics1 =
pictureBox1->CreateGraphics();
System::IntPtr ptr1(img1.ptr());
System::Drawing::Bitmap^ b1 = gcnew
System::Drawing::Bitmap(img1.cols,
img1.rows, img1.step,
System::Drawing::Imaging::PixelFormat::Format24bppRgb, ptr1);
System::Drawing::RectangleF rect1(0, 0,
pictureBox1->Width, pictureBox1->Height);
graphics1->DrawImage(b1, rect1);
waitKey(1);
}
}
private: System::Void
button2_Click(System::Object^ sender,
System::EventArgs^ e) {
tutup=1;
destroyAllWindows();
}
Lalu, jangan lupa menambah event FormClosing (baca
tutorial 3 atau 4) dan masukkan kode:
tutup=1;
Bagaimana hasilnya? Kalau sukses maka kita akan
melihat ProgressBar yang berubah-ubah nilainya saat ada yang bergerak di depan
webcam. Semakin banyak gerakan yang terjadi maka nilai pada ProgressBar juga
akan semakin besar. Nah, bagaimana sistematika penjelasannya?
Dalam tutorial ini kita menggunakan fungsi MOG2. Pada
fungsi ini nilai piksel gambar terbaru (foreground, FG) akan dikurangkan dengan
nilai piksel gambar acuan (background, BG). BG bisa dibuat statis atau dinamis,
misalnya BG adalah gambar pertama saja, gabungan 10 gambar sebelum FG, atau
gambar tepat sebelum FG. Banyaknya gambar yang dijadikan BG ditentukan dengan
variabel alfa. Perhitungannya adalah:
log 0,9 / log (1-alfa) = n frame
Jadi misalkan kita menggunakan alfa 0,001 maka BG terdiri dari campuran
105 gambar sebelum FG. Kalau misalkan webcam bekerja maksimal (30 fps) maka waktunya
kira-kira 3,5 detik. Artinya jika kamu diam di depan webcam selama 3,5 detik
maka program tidak lagi menganggap kamu sebagai benda asing/bergerak. Namun,
jika kamera bekerja minimal (6 fps) maka dibutuhkan waktu + 7,5 detik.
Oh iya, biasanya prosesor saya cuma bisa 22 fps jika tidak menggunakan CUDA.
Gambar hasil BG subtraction (disebut mask)
kemudian dicari nilai standar deviasinya (SD) dengan fungsi meanStdDev(). Jika
ukuran gambar dari webcam adalah 640x480 piksel maka nilai SD ini memiliki
nilai maksimal sekitar 127,5. Nilai maksimal ini tercapai jika gambar mask
memiliki piksel putih dan hitam berjumlah sama. Nilai SD ini sebanding dengan
banyaknya piksel putih. Simpelnya semakin besar gerakan yang terjadi, maka
ProgressBar akan semakin penuh. Nilai SD ini bisa diakses dari variabel stdev
atau stddev (stddev=stdev/1,2).
Selanjutnya gambar mask dikonversi dari
GRAY ke BGR dengan fungsi cvtColor() dan diambil hanya warna hijaunya sebagai
indikator piksel-piksel yang menunjukkan pergerakan. Jika ingin menggunakan
warna lain kita bisa mengubah kode:
(*it)[0]=0;
(*it)[2]=0;
Kode [0] adalah komponen warna merah, [1] hijau,
dan [2] merah. sedangkan nilai setelah tanda “=” adalah intensitas warna-warna
tersebut dengan nilai maksimal 255. Misalkan kita ingin menggunakan warna
oranye maka kita ganti kodenya dengan:
(*it)[0]=0;
(*it)[1]=150;
(*it)[2]=255;
Nah, selanjutnya gambar mask tersebut
dibaurkan dengan gambar asli sehingga tercipta kesan warna hijau/oranye pada
piksel yang mendeteksi gerakan. Penggabungan kedua gambar ini dilakukan dengan
fungsi addWeighted(), di mana intensitas kedua gambar dapat diatur. Pada tutorial
ini intensitas gambar mask diatur pada 0,9.
Ingat bahwa tutorial ini sifatnya masih simpel.
Untuk aplikasi nyatanya kita bisa menggunakannya untuk menghitung barang/orang
yang melewati webcam, sistem parkir, webcam keamanan, atau juga mengukur
periode bandul. Sedikit bocoran, kita bisa menggunakan prinsip kontur (baca
tutorial 4) untuk melakukannya. Nah, selamat ngoding...
kenapa tutorialnya nggak dilanjutin lagi mas? Padahal blognya bagus..
ReplyDeletepermisi gan, saya kebetulan sedang mencari referensi untuk membuat program mendeteksi gerak menggunakan opencv dan kemudian ketemu dengan thread agan. tetapi saat saya coba codingnya, kenapa error ya gan? karena saya belum paham betul soal opencv, makanya saya hanya mensalin semua coding yang agan tulis di sini dan saya paste ke visualstudionya. kira-kira kenapa ya gan? barangkali bisa membantu. terimakasih.
ReplyDeleteBagus banget penjelasan nya om...
ReplyDeleteizin baca artikel selanjutnya
thanks
Permisi kak, penjelasan mengenai standar deviasinya saya kurang paham. Untuk rumusnya bagaimana ya? Terima kasih kak.
ReplyDelete