Bab 13 Computer Vision
Tujuan Instruksional Umum : 1.
Mahasiswa mampu menjelaskan peranan dan konsep pemrograman Computer Vision
Tujuan Instruksional Khusus : 1. 2. 3. 4. 5.
Mahasiswa mampu menjelaskan fungsi dari Computer Vision Mahasiswa dapat menyebutkan beberapa penerapan dari Computer Vision Menjelaskan fungsi dari program OpenCV Mahasiswa dapat menjelaskan penelitian di bidang Computer Vision Mahasiswa dapat menginstal program OpenCV dan membuat program loading image.
13.1 Pendahuluan Pada masa ini, perhatian difokuskan pada kemampuan komputer dalam mengerjakan sesuatu yang dapat dilakukan oleh manusia. Dalam hal ini, komputer tersebut dapat meniru kemampuan kecerdasan dan perilaku manusia. Salah satu cabang dari Kecerdasan buatan ialah Computer Vision. Menurut Forsyth dan Ponece, Computer Vision adalah: Extracting descriptions of the world from pictures or sequences of pictures
Computer vision merupakan teknologi paling penting di masa yang akan datang dalam pengembangan robot yang interaktif. Computer Vision merupakan bidang pengetahuan yang berfokus pada bidang sistem kecerdasan buatan dan berhubungan dengan akuisisi dan pemrosesan images. Contoh penerapan computer vision pada dunia riset dan industri ialah :
Pengontrolan proses industri
Pendeteksi nomor plat kendaraan
3D model building (photogrammetry)
Robot Vision, Humanoid Robot dan Robot Soccer.
Surveillance (monitor penyusup, analisa trafik jalan tol dan lainnya)
Modeling obyek atau lingkungan
Interaksi manusia dan robot (Human Robot Interaction) Gambar di bawah menampilkan relasi antara computer vision dengan bidang riset lainnya :
Gambar 13.1 Hubungan Computer vision dengan bidang lainnya Pada penerapannya, computer vision dan machine visionmenerapkan digital image processing untuk menerapkan algoritma komputer untuk pemrosesan image pada image digital. Menurut Forsyth dan Ponce, Computer Vision adalah mengekstrak deskripsi dunia dari gambar atau urutan gambar. Computer vision secara umum merupakan area yang menyertakan metode metode untuk mengambil, pemroses menganalisa dan memahami image untuk menghasilkan informasi numeric atau simbolik. Image processing merupakan proses mengubah image 2D menggunakan metode Edge detection, fourier transform atau enhancement untuk memperoleh output image 2D yang diinginkan (misalnya smoothing gambar).
Gambar 13.2 Proses Image processing
Penerapan terkini misalnya pada system Robot Vision, dimana robot dapat melihat menggunakan kamera dan unit pendukung berupa sensor dan controller berkecepatan tinggi. Output yang umum dari Machine Vision ialah keputusan pass/fail. Penerapan terkini misalnya pada system industry HP dan Robot Vision, dimana robot dapat melihat menggunakan kamera dan unit pendukung berupa sensor dan controller berkecepatan tinggi.
Gambar 13.3 Proses inspeksi Machine Vision pada Industri
13.2 Program OpenCV OpenCV ialah program open source berbasiskan C++ yang saat ini banyak digunakan sebagai program computer vision, salah satu penerapannya ialah pada robotika. Dengan OpenCV, Anda dapat membuat interaksi antara manusia dan robot (Human Robot Interaction. Misalnya, wajah dari manusia dideteksioleh camera/webcam, lalu diproses oleh komputer, untuk kemudian diproses oleh robot untuk melakukan aksi tertentu, misalnya mengikuti/mengenal wajah orang tersebut. Kesemuanya itu membutuhkan OpenCV sebagai program utama antara webcam dan pengolahnya yaitu komputer. Silahkan kunjungi situs opencv.org untuk download atau mengetahui berita terbaru tentang software ini. Program OpenCV 2.4.11 merupakan edisi terbaru yang harus Anda gunakan pada buku ini.
Pemrograman Dasar OpenCV Anda membutuhkan editor dan kompiler Visual C++ 2013/ Visual Studio 2013 Express Edition untuk mengedit dan kompilasi program OpenCV. Anda terlebih dahulu harus mengkonfigurasi Visual C++ .Net tersebut dimana file library dan sourcenya harus disertakan. Beberapa file library juga harus ditambahkan pada input linker di Visual C++. 1.
Jalankan program dan install pada suatu direktori, misalnya f:/OpenCV246 atau f:/OpenCV246 jika menggunakan versi OpenCV 2.4.6.
Gambar 13.4 Proses instalasi pada satu direktori
2. Tambahkan path ke Path Variable: f:\OpenCV246\opencv\build\x86\vc10\bin f:\OpenCV246\opencv\build\common\tbb\ia32\vc10
3.
Lalu, buat proyek baru untuk OpenCV menggunakan Visual C++ 2013, dengan memilih create a new Win32 console Application. Klik kanan Project dan pilh properties
Gambar 13.5 Memilih properties
Pada bagian kiri, pilih C/C++ lalu edit Additional Include Directories dengan menambahkan : f:\OpenCV246\opencv\build\include\opencv f:\OpenCV246\opencv\build\include 4. PIlih linker dan tambahkan direktori ke Additional Library Directories: f:\OpenCV246\opencv\build\x86\vc10\lib
Gambar 13.6 Menambahkan Additional library Directories
5.
Buka Linker dan pilih input, tambahkan Additional Dependencies berikut:
opencv_core246d.lib opencv_imgproc246d.lib opencv_highgui246d.lib opencv_ml246d.lib opencv_video246d.lib opencv_features2d246d.lib opencv_calib3d246d.lib opencv_objdetect246d.lib opencv_contrib246d.lib opencv_legacy246d.lib opencv_flann246d.lib
Gambar 13.7 Menambahkan dependencies
Jika sudah selesai, sebagai contoh buatlah program Win32 console application untuk menampilkan sebuah gambar di Windows, berikut contohnya:
Displayimage.cpp: // Menampilkan Image menggunakan cvLoadImage //Dibuat oleh Widodo Budiharto #include "stdafx.h" #include
#include #include int _tmain(int argc, _TCHAR* argv[]) { // meload image IplImage *img = cvLoadImage("f:\handsome.jpg"); cvNamedWindow("OpenCV",1); cvShowImage("OpenCV",img); //tunggu sembarang input dari user untuk exit cvWaitKey(0); cvDestroyWindow("OpenCV "); cvReleaseImage(&img); return 0; } Pada program di atas, dibutuhkan library seperti cv.h, sxcore.h dan highgui.h agar fungsi dikenal oleh compiler. Hasil dari program di atas ialah :
Gambar 13.8 Hasil program menampilkan image Jika Anda menginginkan pemrograman dengan style 2.x C++, berikut contohnya menggunakan cv::Mat. Cv::Mat muncul di OpenCV versi terkini yang secara mendasar ialah sebuah class dengan 2 bagian data, yaitu
header matrik (berisi informasi ukuran matrik, metode yang digunakan untuk menyimpan) dan sebuah pointer ke matrik berisi nilai pixel, berikut contohnya: cv::Mat A, C; // membuat bagian header A = imread(argv[1], CV_LOAD_IMAGE_COLOR); // alokasi matrik cv::Mat B(A); // menggunakan kopi constructor C = A; // operator assignment
Pada program di atas, kita meload image menggunakan fungsi imread(). Berikut contoh program untuk loading image berbasis C++: DisplayImage2.cpp: #include "stdafx.h" // Program demo C++ untuk display image. #include <stdlib.h> #include #include #include int _tmain(int argc, _TCHAR* argv[]) { cv::Mat img = cv::imread("f:\handsome.jpg"); cv::imshow("OpenCV",img); //tunggu sembarang input dari user untuk exit cv::waitKey(); return EXIT_SUCCESS; }
13.3 Digital Image Processing Sebuah image ialah sebuah array, atau matrik dari piksel persegi yang disusun dalam format kolom dan baris. Pada image greyscale (8bit), tiap elemen gambar memiliki intesitas antara 0-255, sedangkan image true color terdiri dari 24 bit( 8x8x8 =16 juta warna) seperti gambar di bawah :
(a)
(b)
Gambar 13.9 Image greyscale 8 bit (a), dan image true color yang tersusun dari 3 greyscale image berwarna merah, hijau dan biru yang dapat berisi hingga 16 juta warna berbeda (b).
Image standar dikenal sebagai image RGB (terdiri dari komponen Merah, Hijau dan biru) dan memiliki sistem warna 24 bit yang masing masing terdiri dari 8 bit. Representasi warna bertipe integer bervariasi dari 0255, sedangkan untuk tipe float berkisar antara 0-1. Nilai warna tersebut disimpan pada matrik 3 dimensi yang dilambangkan dalam Intensitas I (X,Y, channel). Nilai warna RGB dapat dinormalisasi menggunakan persamaan : �
�
=
�
�+�+�
�
�
=
�
�+�+�
�
�
=
Sedangkan proses grascale menggunakan persamaan ���� =
�
�+�+�
�+�+� �
(13.1)
(13.2)
Kadang citra yang kita miliki perlu kita olah untuk tujuan tertentu yang dikenal dengan istilah Pengolahan Citra, misalnya proses penjumlahan nilai RGB pada images. Awal mula pemrosesan image digital dimulai pada sekitar tahun 1960an pada Jet Propulsion Laboratory, Massachusetts Institute of Technology, Bell Laboratories, University of Maryland, untuk aplikasi satelit, medical imaging dan character recognition.
Pemrosesan image
digital memungkinkan penggunaan algoritma komplek untuk pemrosesan image sehingga menghasilkan performa sistem yang robust dan berbiaya murah. Klasifikasi merupakan metode yang sangat penting dalam image processing. Pemrosesan image digital umumnya digunakan pada proses :
Classification
Feature extraction
Pattern recognition
Multi-scale signal analysis Beberapa teknik yang digunakan pada pemrosesan image digital antara lain :
Pixelization
Linear filtering
Erosi dan dilasi
Principal components analysis
Independent component analysis
Hidden Markov models
Anisotropic diffusion
Partial differential equations
Robotika saat ini membutuhkan metode computer vision untuk membuat service robot [6]. Sebagai percobaan, untuk mengenal RGB, buatlah sebuah proyek baru dan beri nama RGB, lalu buat program di bawah ini :
RGB.cpp: //Program penjumlahan RGB #include "stdafx.h" #include <stdio.h> #include #include void sum_rgb( IplImage* src, IplImage* dst ) { // Allocate individual image planes. IplImage* r = cvCreateImage(cvGetSize(src),IPL_DEPTH_8U,1 ); IplImage* g = cvCreateImage(cvGetSize(src),IPL_DEPTH_8U,1 ); IplImage* b = cvCreateImage(cvGetSize(src),IPL_DEPTH_8U,1 ); // Temporary storage. IplImage* s = cvCreateImage(cvGetSize(src),IPL_DEPTH_8U,1 ); // Split image cvSplit( src, r, g, b, NULL ); // Add equally weighted rgb values. cvAddWeighted( r, 1./3., g, 1./3., 0.0, s ); cvAddWeighted( s, 2./3., b, 1./3., 0.0, s ); // Truncate nilai diatas 100. cvThreshold( s, dst, 150, 100, CV_THRESH_TRUNC ); cvReleaseImage( &r ); cvReleaseImage( &g ); cvReleaseImage( &b ); cvReleaseImage( &s ); } int main(int argc, char** argv) { // Buat jendela cvNamedWindow( argv[1], 1 ); // Load the image from the given file name. IplImage* src = cvLoadImage( argv[1] ); IplImage* dst = cvCreateImage( cvGetSize(src), src->depth, 1); sum_rgb( src, dst); // Tampilkan jendela cvShowImage( argv[1], dst ); // Idle until the user hits the "Esc" key. while( 1 ) { if( (cvWaitKey( 10 )&0x7f) == 27 ) break; } // Bersihkan jendela dan memori cvDestroyWindow( argv[1] ); cvReleaseImage( &src ); cvReleaseImage( &dst );
}
Hasil program di atas berupa gambar yang nilai RGB-nya telah berubah seperti gambar di bawah :
Gambar 13.10 Hasil penjumlahan RGB
Pada pengolahan citra dasar, biasanya edge detection, threshold dan countour sangat dibutuhkan, berikut contohnya :
Countour.cpp: //Program membuat countour dan variasi threshold #include #include IplImage* image = 0; int thresh = 100; void on_trackbar(int) { IplImage* gray = cvCreateImage( cvGetSize(image), 8, 1 ); CvMemStorage* storage = cvCreateMemStorage(0); CvSeq* contours = 0; cvCvtColor( image, gray, CV_BGR2GRAY ); cvThreshold( gray, gray, thresh, 255, CV_THRESH_BINARY ); cvFindContours( gray, storage, &contours ); cvZero( gray ); if( contours ) cvDrawContours( gray, contours, cvScalarAll(255), cvScalarAll(255), 100 ); cvShowImage( "Contours", gray );cvReleaseImage( &gray ); cvReleaseMemStorage( &storage ); } int main( int argc, char** argv ) { IplImage* image; if( argc != 2 || !(image = cvLoadImage(argv[1])) )
return -1; cvNamedWindow( "Contours", 1 ); cvCreateTrackbar( "Threshold", "Contours", &thresh, 255, on_trackbar ); on_trackbar(0); cvWaitKey(); return 0; }
Gambar 13.11 Program countour pada Lena.jpg
3.1 Penggunaan Kamera Kamera sangat penting pada dunia machine vision[1]. Secara umum, struktur umum dari penggunaan machine vision pada dunia industri atau riset dapat digambarkan pada gambar 13.12 berikut :
Gambar 13.12 Struktur umum dari Machine vision
Fungsi untuk menampilkan image menggunakan kamera pada OpenCV ialah [3]:
pCapture =cvCaptureFromCAM (CV_CAP_ANY);
atau cvCapture* cvCreateCameraCapture(int index);// index merupakan urutan // kamera yang ada.
Jika ingin mengatur lebar dan tinggi frame, gunakan kode berikut :
capture = cvCaptureFromCAM(CV_CAP_ANY); // Capture dari webcam cvSetCaptureProperty( capture, CV_CAP_PROP_FRAME_WIDTH, 640); cvSetCaptureProperty( capture, CV_CAP_PROP_FRAME_HEIGHT, 480);
Sebagai contoh, jika Anda ingin mendeteksi webcam dan mengambil streaming video dari webcam tersebut, gunakan demo kode berikut ini:
Kamera.cpp: //Menampilkan image menggunakan Webcam #include "stdafx.h" #include "cv.h" #include "highgui.h" int main( int argc, char** argv ) { cvNamedWindow( "Camera", CV_WINDOW_AUTOSIZE ); CvCapture* capture; if (argc==1) { capture = cvCreateCameraCapture( 0 ); //kamera pertama } else { capture = cvCreateFileCapture( argv[1] ); } assert( capture != NULL );
IplImage* frame; while(1) { frame = cvQueryFrame( capture ); if( !frame ) break; cvShowImage( "Camera", frame ); char c = cvWaitKey(10); if( c == 27 ) break; } cvReleaseCapture( &capture ); cvDestroyWindow( "Camera" ); }
Gambar 13.13 Hasil penggunaan webcam dengan deteksi wajah Jika menggunakan versi terbaru, berikut kodenya: using namespace cv; int main(int, char) VideoCapture cap(0); // open the default camera if(!cap.isOpened()) // check if we succeeded return -1; Mat edges;
namedWindow("edges",1); for(;;) Mat frame; cap >> frame; // get a new frame from camera cvtColor(frame, edges, CV_BGR2GRAY); GaussianBlur(edges, edges, Size(7,7), 1.5, 1.5); Canny(edges, edges, 0, 30, 3); imshow("edges", edges);
if(waitKey(30) >= 0) break; // the camera will be deinitialized automatically in VideoCapture destructor return 0;
13.2 Konsep Image Filtering Sebuah mask ialah sebuah matrik kecil dimana nilainya disebut weights. Linear filtering adalah filtering dimana nilai dari tiap piksel output merupakan sebuah kombinasi linear dari nilai piksel pada input. Linear filtering dilakukan melalui operasi convolution. Sebuah filter ialah sebuah fungsi yang mengambil nilai input signal dan menghasilkan output yang sesuai dengan persamaan yang ada pada fungsi tersebut. A. Blurring Image Blurring sebuah image ialah langkah untuk mengurangi ukuran image tanpa mengubah tampilan gambar terlalu banyak, menggunakan matrik kernel. Blurring dapat dilakukan dengan mengganti tiap pixel image dengan beberapa nilai rata-rata di sekitarnya. Kernel Gaussian umum digunakan pada proses ini demgam nilai:
1 4 6 4 1
4 16 24 16 4
6 24 36 24 6
4 16 24 16 4
Blurring.cpp: //Program blurring image #include "opencv2/highgui/highgui.hpp" #include "opencv2/imgproc/imgproc.hpp" #include #include <stdio.h> using namespace cv; using namespace std;
1 4 6 4 1
Mat image, image_blurred; int slider=5; float sigma=0.3 *((slider -1) *0.5-1)+0.8; void on_trackbar(int, void*) { int k_size=max(1,slider); k_size=k_size%2==0?k_size+1:k_size; setTrackbarPos("Kernel size", "Bluerred image",k_size); sigma=0.3*((k_size -1) *0.5-1) +0.8; GaussianBlur(image,image_blurred, Size(k_size,k_size),sigma); imshow ("Blurred image", image_blurred); } int main() { image=imread ("lena.jpg"); namedWindow ("Original image"); namedWindow ("Blurred image"); imshow ("Original image", image); sigma=0.3*((slider-1) *0.5-1)+0.8; GaussianBlur (image,image_blurred,Size(slider,slider),sigma); imshow ("Blurred image", image_blurred); createTrackbar("Kernel size", "Blurred image", &slider, 21, on_trackbar); while (char(waitKey(1) !='q')) {} return 0; }
Gambar 13.14 Hasil blurring sebuah image
b. Dilasi dan Erosi Erosi dan dilasi merupakan 2 operasi morfologis pada image.
ErosiDilasi.cpp: #include #include
#include "opencv2/highgui/highgui.hpp" #include "opencv2/imgproc/imgproc.hpp" #include #include <stdio.h> using namespace cv; using namespace std; Mat image, image_processed; int choice_slider=0, size_slider=5;//0=erosi, 1=dilasi void proses(){ Mat st_elem=getStructuringElement(MORPH_RECT, Size(size_slider, size_slider)); if (choice_slider==0) { erode(image, image_processed, st_elem); } else { dilate(image,image_processed, st_elem); } imshow("Processed image", image_processed); } void on_choice_slider(int, void*) { proses(); } void on_size_slider(int, void*) { int size=max(1,size_slider) ; size=size%2==0 ? size+1:size; setTrackbarPos("Kernel size", "Processed image", size); proses(); } int main() { image=imread("gambar.png"); namedWindow("Original image"); namedWindow("Processed image"); imshow("Original image", image); Mat st_elem=getStructuringElement(MORPH_RECT, Size(size_slider, size_slider)); erode(image, image_processed, st_elem); imshow("Processed image", image_processed); createTrackbar("Erode/Dilate", "Processed image", &choice_slider, 1, on_choice_slider); createTrackbar("Kernel Size", "Processed image", &size_slider, 21, on_size_slider); while (char(waitKey(1) !='q')) {} return 0; }
Hasil dari program di atas ditunjukkan oleh gambar di bawah ini:
Gambar 13.15 Hasil erosi dilasi
3.3 Canny Edge Detector Edge atau tepi ialah titik-titik di image dimana gradient dari image tersebut cukup tinggi. Gradient image dihitung menggunakan gradient pada arah X dan Y dan dikombinasikan dengan teorema phythagoras. Arah X dan Y dihitung dengan konvolusi image dengan kernel berikut
-3
0
3
-10
0
10
-3
0
3 ( untuk arah X)
-3
-10
-3
0
0
0
3
10
3 (untuk arah Y)
dan
Dengan nilai gradient G=sqrt(Gx2 + Gy2) dan sudut gradient Θ=arctan(Gy/Gx)
Berikut contoh kode canny edge detector:
Canny.cpp: //Canny Edge Detector #include "opencv2/imgproc/imgproc.hpp" #include "opencv2/highgui/highgui.hpp" #include <stdlib.h> #include <stdio.h> using namespace cv; /// Global variables Mat src, src_gray; Mat dst, detected_edges; int edgeThresh = 1; int lowThreshold; int const max_lowThreshold = 100; int ratio = 3; int kernel_size = 3; char* window_name = "Canny Edge Detector"; void CannyThreshold(int, void*){ /// Reduce noise with a kernel 3x3 blur( src_gray, detected_edges, Size(3,3) ); /// Canny detector Canny( detected_edges, detected_edges, lowThreshold, lowThreshold*ratio, kernel_size ); /// Using Canny's output as a mask, we display our result dst = Scalar::all(0); src.copyTo( dst, detected_edges); imshow( window_name, dst ); } int main( int argc, char** argv ){ /// Load an image src = imread("lena.jpg" ); if( !src.data ) { return -1; } /// Create a matrix of the same type and size as src (for dst) dst.create( src.size(), src.type() ); /// Convert the image to grayscale cvtColor( src, src_gray, CV_BGR2GRAY ); /// Create a window namedWindow( window_name, CV_WINDOW_AUTOSIZE );
/// Create a Trackbar for user to enter threshold createTrackbar( "Min Threshold:", window_name, &lowThreshold, max_lowThreshold, CannyThreshold ); /// Show the image CannyThreshold(0, 0); /// Wait until user exit program by pressing a key waitKey(0); return 0; }
Gambar 13.16 Hasil Canny Edge Detector
13.4 Implementasi: Color-Based Object Detector Untuk membuat color-based object detector, dapat menggunakan fungsi inRange di openCv sebagai berikut : inRange(frame, Scalar (low_b, low_g,low_r), Sclar (high_b, high_g,high_r), frame thresholded);
colorbased.cpp: //Color-Based Object Detector #include "opencv2/highgui/highgui.hpp" #include "opencv2/imgproc/imgproc.hpp" #include #include <stdio.h>
using namespace cv; using namespace std;
Mat frame, frame_thresholded; int rgb_slider=0,low_slider=30, high_slider=100; int low_r=30,low_g=30,low_b=30, high_r=100, high_g=100, high_b=100;
void on_rgb_trackbar(int, void*) { switch (rgb_slider) { case 0: setTrackbarPos("Low threshold", "Segmentation", low_r); setTrackbarPos("High threshold", "Segmentation", high_r); break; case 1: setTrackbarPos("Low threshold", "Segmentation", low_g); setTrackbarPos("High threshold", "Segmentation", high_g); break; case 2: setTrackbarPos ("Low threshold", "Segmentation", low_b); setTrackbarPos("High threshold", "Segmentation", high_b); break; } } void on_low_thresh_trackbar(int,void*) { switch (rgb_slider) { case 0: low_r=min (high_slider -1, low_slider); setTrackbarPos("Low threshold", "Segmentation", low_r); break; case 1: low_g=min(high_slider-1, low_slider); setTrackbarPos("Low threshold", "Segmentation", low_g); break; case 2: low_b=min (high_slider-1, low_slider);
setTrackbarPos("Low threshold", "Segmentation", low_b); break; } } void on_high_thresh_trackbar(int,void*) { switch (rgb_slider) { case 0: high_r=max(low_slider+1, high_slider); setTrackbarPos("High threshold", "Segmentation", high_r); break; case 1: high_g=max(low_slider+1, high_slider); setTrackbarPos("High threshold", "Segmentation", high_g); break; case 2: high_b=max(low_slider+1, high_slider); setTrackbarPos("High threshold", "Segmentation", high_b); break; } }
int main() { //capture video VideoCapture cap(0); //cek apakah dapat diakses
if (!cap.isOpened()) { cout<<"Tidak dapat membuka"<<endl; return -1; } namedWindow("Video"); namedWindow("Segmentation");
createTrackbar("0. R\n1. G\n2. B","Segmentation", &rgb_slider, 2, on_rgb_trackbar); createTrackbar ("Low threshold","Segmentation", &low_slider, 255, on_low_thresh_trackbar); createTrackbar("High threshold","Segmentation", &high_slider, 255,on_high_thresh_trackbar);
while(char(waitKey(1)) !='q' && cap.isOpened()) { cap>>frame; if (frame.empty()) { cout<<"Video over"<<endl; break; } inRange(frame,Scalar(low_b,low_g,low_r),Scalar(high_b,high_g,high_r),frame_thresholded); imshow("Video", frame); imshow("Segmentation",frame_thresholded); } return 0; }
Gambar 13.17 Hasil streaming object detecter yang masih terlihat adanya noise
13.5 Morphological Opening dan Closing Operasi Opening diperoleh dengan proses erosi pada image diikuti dengan dilasi dengan hasil penghapusan daerah putih yang kecil pada image. Penerapannya misalnya pada smoothing image untuk deteksi obyek yang akan diambil oleh lengan robot berbasis vision[4]. Operasi
Closing diperoleh dengan dilasi image diikuti dengan proses erosi yang berakibat pada efek sebaliknya. Kedua operasi ini berfungsi utuk menghapus oise dari image.
Fungsi
morphologyEX() dapat digunakan utuk melakukan operasi morphological seperti opening dan closing pada image. Berikut contohnya : inRange(frame,Scalar(low_b,low_g,low_r),Scalar(high_b,high_g,high_r),frame_thresholded);
//Operasi Opening dan Closing Mat str_el=getStructuringElement(MORPH_RECT, Size(3,3)); morphologyEx(frame_thresholded, frame_thresholded,MORPH_OPEN, str_el); morphologyEx(frame_thresholded, frame_thresholded,MORPH_CLOSE, str_el); imshow("Video", frame); imshow("Segmentation",frame_thresholded);
Gambar 13.18 Hasil streaming object detector yang sudah bersih dari noise karena operasi opening dan closing
Untuk menyimpan file, gunakan fungsi imwrite() berikut : cv::Mat red_image; cv::inRange(image, cv::Scalar(40, 0, 180), cv::Scalar(135, 110, 255), red_image); //cv::imwrite("out1.png", red_image);
13.6 Deteksi dan Pengenalan Wajah
Haar Cascade Classifier OpenCV menggunakan sebuah tipe face detector yang disebut Haar Cascade classifier. Gambar menunjukkan face detector berhasil bekerja pada sebuah gambar. Jika ada sebuah image (bias dari file /live video), face detector menguji tiap lokasi image dan mengklasifikasinya sebagai “wajah” atau “bukan wajah”. Klasifikasi dimisalkan sebuah skala fix untuk wajah, misal 50x50 pixel. Jika wajah pada image lebih besar atau lebih kecil dari pixel tersebut, classifier terus menerus jalan beberapa kali, untuk mencari wajah pada gambar tersebut. Classifier menggunakan data yang disimpan pada file XML untuk memutuskan bagaimana mengklasifikasi tiap lokasi image. OpenCV menggunakan 4 data XML untuk deteksi wajah depan, dan 1 untuk wajah profile. Termasuk juga 3 file XML bukan wajah: 1 untuk deteksi full body, 1 untuk upper body, dan 1 untuk lower body. Anda harus memberitahukan classifier dimana menemukan file data yang akan anda gunakan. Salah satunya bernama haarcascade_frontalface_default.xml. Pada OpenCV, terletak pada : Program_Files/OpenCV/data/haarcasades/haarcascade_frontalface_default.xml.
Fitur yang digunakan Viola dan Jones menggunakan bentuk gelombang Haar. Bentuk gelombang Haar ialah sebuah gelombang kotak.
Pada 2 dimensi, gelombang kotak ialah
pasangan persegi yang bersebelahan, 1 terang dan 1 gelap. Haar ditentukan oleh pengurangan pixel rata-rata daerah gelap dari pixel rata-rata daerah terang. Jika perbedeaan diatas threshold (diset selama learning), fitur tersebut dikatakan ada.Kata cascade pada classfier berarti total classifier terdiri dari classifier yang lebih simple yang diaplikasikan secara subsekuen ke ROI .
Gambar 13.19 Feature yang diusulkan Viola dan Jones
Implementasi Deteksi Wajah pada Haar Classifier sebagai berikut: 1. Variable CvHaarClassifierCascade * pCascade menyimpan data dari file XML. Untuk meload data XML ke pCascade, Anda dapat menggunakan fungsi cvLoad(). cvLoad ialah fungsi umum untuk meload data dari file yang membutuhkan hingga 3 parameter input. JIka anda membuat kode pada C, set parameter sisanya menjadi 0, jika menggunakan C++ hilangkan parameter yang tidak digunakan. 2. Sebelum mendeteksi wajah pada images, Anda membutuhkan objek
CvMemStorage.
Detector akan mendaftar wajah yang terdeteki ke buffer. Yang harus anda kerjakan ialah membuatnya pStorage=CvCreateMemStorage(0); dan mereleasenya ketika telah selesai. cvReleaseMemStorage(&pStorage);
3. Anda akan sering meload data dari file, tentu ada kemungkinan salah path, sebaiknya berikan pengecekan untuk memastikan file diload dengan benar.
if(!pInpImg || {
!pStorage
|| !pCascade)
printf (“Inisialisasi gagal \n”); } exit (-1); }
4. Untuk menjalankan detector, panggil objek cvHaarDetect. Fungsi ini membutuhkan 7 parameter, 3 pertama ialah pointer image, XML data dan memory buffer, sisanya diset pada default C++. pFaceRectSeq =cvHaarDetectObjects (pInpImg, pCascade, pStorage,1.1, //tingkatkan skala pencarian dengan 10% tiap passing 3, //drop group yang kurang dari 3 deteksi CV_HAAR_DO_CANNY_PRUNNING //skip region yang tidak berisi //wajah cvSize(0,)); //gunakan XML default untuk skala pencarian //terkecil.
5. Untuk membuat display Window gunakan cvNamedWindow seperti berikut: cvNamedWindow (“Haar Window”, CV_WINDOW_AUTOSIZE);
6. Untuk memasukkan image ke display, panggil fungsi cvShowImage() dengan nama yang telah dibuat pada window dan nama image yang ingin ditampilkan.
Jika ingin mendeteksi wajah termasuk mata menggunakan webcam, gunakan contoh program di bawah ini :
FaceandEyeDetection.cpp: //Face and eyes detection using Haar Cascade Classifier // Copyright Dr. Widodo Budiharto 2015 #include "opencv2/objdetect/objdetect.hpp" #include "opencv2/highgui/highgui.hpp" #include "opencv2/imgproc/imgproc.hpp"
#include using namespace std; using namespace cv; void detectAndDisplay( Mat frame ); /** Variabel global */ String face_cascade_name = "lbpcascade_frontalface.xml"; String eyes_cascade_name = "haarcascade_eye_tree_eyeglasses.xml"; CascadeClassifier face_cascade; CascadeClassifier eyes_cascade; string window_name = "Face detection";
int main( int argc, const char** argv ) { CvCapture* capture; Mat frame;
//-- 1. Load the cascade if( !face_cascade.load( face_cascade_name ) ){ printf("--(!)Error loading face\n"); return -1; }; if( !eyes_cascade.load( eyes_cascade_name ) ){ printf("--(!)Error loading eye\n"); return -1; };
//-- 2. Read the video stream capture = cvCaptureFromCAM(0); if( capture ) { while( true ) { frame = cvQueryFrame( capture );
//-- 3. Apply the classifier to the frame if( !frame.empty() ) { detectAndDisplay( frame ); } else { printf(" --(!) No captured frame -- Break!"); break; }
int c = waitKey(10);
if( (char)c == 'c' ) { break; }
} } return 0; }
void detectAndDisplay( Mat frame ) { std::vector faces; Mat frame_gray;
cvtColor( frame, frame_gray, CV_BGR2GRAY ); equalizeHist( frame_gray, frame_gray );
//-- Detect faces face_cascade.detectMultiScale( frame_gray, faces, 1.1, 2, 0, Size(80, 80) );
for( int i = 0; i < faces.size(); i++ ) { Mat faceROI = frame_gray( faces[i] ); std::vector eyes;
//-- deteksi mata eyes_cascade.detectMultiScale( faceROI, eyes, 1.1, 2, 0 |CV_HAAR_SCALE_IMAGE, Size(30, 30) ); if( eyes.size() == 2) { //gambar wajah Point center( faces[i].x + faces[i].width*0.5, faces[i].y + faces[i].height*0.5 ); ellipse( frame, center, Size( faces[i].width*0.5, faces[i].height*0.5), 0, 0, 360, Scalar( 255, 0, 0 ), 2, 8, 0 );
for( int j = 0; j < eyes.size(); j++ ) { //-- Draw the eyes Point center( faces[i].x + eyes[j].x + eyes[j].width*0.5, faces[i].y + eyes[j].y + eyes[j].height*0.5 ); int radius = cvRound( (eyes[j].width + eyes[j].height)*0.25 );
circle( frame, center, radius, Scalar( 255, 0, 255 ), 3, 8, 0 ); } }
} //-- Show the result imshow( window_name, frame ); } Hasilnya akan tampil seperti gambar di bawah ini:
Gambar 13.21 Wajah dan mata gadis yang terdeteksi
Menampilkan hasil wajah yang terdeteksi pada kamera webcam dengan garis circle dan kotak sering dibutuhkan, karena dapat digunakan untuk mengukur jarak antara kamera dan obyek sebagai pengganti sensor jarak ultrasonik, kode berikut dapat digunakan : cvCircle( img, center, radius, color, 3, 8, 0 ); cvRectangle( img,cvPoint( r->x, r->y ),cvPoint( r->x + r->width, r->y + r->height ),CV_RGB( 0, 255, 0 ), 1, 8, 0 );
DeteksidenganRectangle.cpp:
// Face Detection using Rectangle // By Dr. Widodo Budiharto 2014 // HP: 08569887384 #include "stdafx.h" #include "opencv2/objdetect/objdetect.hpp" #include "opencv2/highgui/highgui.hpp" #include "opencv2/imgproc/imgproc.hpp" #include #include "cv.h" #include "highgui.h" #include #include #ifdef _EiC #define WIN32 #endif using namespace std; using namespace cv; void detectAndDraw( Mat& img, CascadeClassifier& cascade, CascadeClassifier& nestedCascade, double scale); String cascadeName ="haarcascade_frontalface_alt.xml"; int main( int argc, const char** argv ){ CvCapture* capture = 0; Mat frame, frameCopy, image; const String scaleOpt = "--scale="; size_t scaleOptLen = scaleOpt.length(); const String cascadeOpt = "--cascade="; size_t cascadeOptLen = cascadeOpt.length(); String inputName; CascadeClassifier cascade, nestedCascade; double scale = 1; if( !cascade.load( cascadeName ) ) { cerr << "ERROR: Could not load classifier cascade" << endl; cerr << "Usage: facedetect [--cascade=\"\"]\n" " [--nested-cascade[=\"nested_cascade_path\"]]\n" " [--scale[=\n" " [filename|camera_index]\n" ; return -1; }
capture = cvCaptureFromCAM(0); cvNamedWindow( "Face Detection with Rectangle", 1 ); if( capture ) { for(;;)
{ IplImage* iplImg = cvQueryFrame( capture ); frame = iplImg; if( frame.empty() ) break; if( iplImg->origin == IPL_ORIGIN_TL ) frame.copyTo( frameCopy ); else flip( frame, frameCopy, 0 ); detectAndDraw( frameCopy, cascade, nestedCascade, scale ); if( waitKey( 10 ) >= 0 ) goto _cleanup_; } waitKey(0); _cleanup_: cvReleaseCapture( &capture ); } cvDestroyWindow("result"); return 0; } void detectAndDraw( Mat& img, CascadeClassifier& cascade, CascadeClassifier& nestedCascade,double scale){ int i = 0; double t = 0; vector faces; const static Scalar colors[] = { CV_RGB(100,0,255), CV_RGB(0,100,255), CV_RGB(0,255,255), CV_RGB(0,255,0), CV_RGB(255,128,0), CV_RGB(255,255,0), CV_RGB(255,0,0), CV_RGB(255,0,255)} ; Mat gray, smallImg( cvRound (img.rows/scale), cvRound(img.cols/scale), CV_8UC1 ); cvtColor( img, gray, CV_BGR2GRAY ); resize( gray, smallImg, smallImg.size(), 0, 0, INTER_LINEAR ); equalizeHist( smallImg, smallImg ); t = (double)cvGetTickCount(); cascade.detectMultiScale( smallImg, faces, 1.1, 2, 0 //|CV_HAAR_FIND_BIGGEST_OBJECT //|CV_HAAR_DO_ROUGH_SEARCH |CV_HAAR_SCALE_IMAGE , Size(30, 30) ); t = (double)cvGetTickCount() - t; printf( "detection time = %g ms\n", t/((double)cvGetTickFrequency()*1000.) );
for( vector::const_iterator r = faces.begin(); r != faces.end(); r++, i++ ) { Mat smallImgROI; vector nestedObjects; Point center; Scalar color = colors[i%8]; int radius; center.x = cvRound((r->x + r->width*0.5)*scale); center.y = cvRound((r->y + r->height*0.5)*scale); radius = cvRound((r->width + r->height)*0.25*scale); circle( img, center, radius, color, 3, 8, 0 ); cv::rectangle( img,cvPoint( r->x, r->y ),cvPoint( r->x + r->width, r->y + r->height ), CV_RGB( 255, 0, 0 ), 1, 8, 0 ); } cv::imshow( "Face Detection with Rectangle", img ); }
Gambar 13.22 Wajah yang terdeteksi menggunakan rectangle
Deteksi fitur wajah seperti mata, hidung dan mulut sangat penting untuk robot vision. Robot harus mampu mengenal ekspresi(marha, sedih, senang dll) dan fitur lainnya yang ada pada wajah di depan robot. Contoh berikut menampilkan deteksi wajah, mata dan hidung menggunakan library :
haarcascade_frontalface_alt2.xml
haarcascade_mcs_eyepair_big.xml
haarcascad_mcs_nose.xml
haarcascade_mcs_mouth.xml
haarcascade_smile.xml
Aplikasi dari sistem ini sangat luas, mulai dari deteksi kantuk pada pengemudi, facial emotion recognition serta kendali robot vision. Untuk 3D Head pose estimation, riset terkini pada pengenalan wajah berfokus pada Active Appearance Model (AAM) dan Active Shape Model (ASM) yang sangat berguna untuk memelajari variasi shape[5]. Active appearance model merupakan model parameterisasi dari kombinasi tekstur dan bentuk untuk digunakan pada algoritma pencarian yang efisien.
Gambar 13.23 Active Appearance Model (AAM)
Kode AAM yang dapat dikembangkan sebagai berikut : int main() { VideoCapture cap(0); if (!cap.isOpened()) return -1; AAM aam= loadPreviouslyTrainedAAM(); HeadModel headModel=load3DHeadModel(); Mapping mapping=mapAAMLandmarsToHeadModel(); Pose2D pose=detectFacePosition(); while(1) { Mat frame; cap>>frame;
Pose2D new2DPose =performAAMSearch(pose, aam); Pose3D new3DPose=applyPOSIT(new2DPose, headModel, mapping); if (waitKey(30) >=0) break; } return 0; }
Latihan : 1. Buatlah program untuk menyimpan hasil streaming kamera yang sudah dismoothing ke dalam file .avi. 2. Buatlah program online training faces menggunakan PCA dan LDA serta LBP yang mampu menyimpan informasi wajah pelanggan dan orderan minuman pelanggan tersebut yang tersimpan pada file .xml sebagai berikut 3. Jelaskan cara kerja Haar Cascade Classifier. 4. Buat program yang dapat mengukur jarak obyek menggunakan kamera stereo
Referensi: 1.
Forsyth, D., Ponce, J. (2012). Computer Vision: A Modern Approach. 2nd ed. Prentice Hall. ISBN: 978-0-27376414-4
2.
Stuart Russel and Peter Norvig, (2011), Artificial Intelligence, A Modern Approach, Pearson Publisher.
3.
Opencv.org
4.
Widodo Budiharto, Bayu Kanigoro, Viska Noviantri, Ball Distance Estimation and Tracking System of Humanoid Soccer Robot, Lecturer Notes on Information Technology, Springer Publisher, 2014.
5.
Widodo Budiharto, Modern Robotics with OpenCV(2014), SPG Publisher.
6.
Widodo Budiharto, Design of Tracked Robot with Remote Control for Surveillance, IEEE International conference on Advanced Mechatronics and Systems, Kumamoto Japan, pp.342-346, 10-12 August, 2014.