Pendahuluan
Jika ingin membangun robot humanoid yang handal, maka penguasaan computer vision sangat penting. Arah dari penguasan teknologi ini ialah membuat robot yang mirip manusia yang dapat diterapkan sebagai robot pelayan (servant robot). Computer vision berguna mengolah input images, umumnya melalui camera pada robot.
Mengenal Computer Vision Pada Robot
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.
Pemrograman Dasar OpenCV
Anda membutuhkan editor dan kompiler Visual Studio .Net 2005 untuk mengedit dan kompilasi program OpenCV. Anda terlebih dahulu harus mengkonfigurasi Visual C++ .Net tersebut dimana file library dan sourcenya harus disertakan (lihat tutorialnya di internet). Beberapa file library juga harus ditambahkan pada input linker di Visual C++.
Gambar 8.1 Konfigurasi File Library
Sebagai contoh, buatlah program Win32 console application untuk menampilkan sebuah gambar di Windows, berikut contohnya :
Demo.cpp:
// Demo Program menampilkan gambar imut
// By Mr. Widodo 2010
#include "stdafx.h"
#include "conio.h"
#include <cv.h>
#include <highgui.h>
int main(int argc, char** argv)
{
IplImage* img =cvLoadImage(argv[1]);
cvNamedWindow ("Contoh_DISPLAY_GAMBAR",CV_WINDOW_AUTOSIZE);
cvShowImage("Contoh_DISPLAY_GAMBAR",img);
cvWaitKey(0);
cvReleaseImage(&img);
cvDestroyWindow("Contoh_DISPLAY_GAMBAR");
}
Program di atas akan meload file .jpg yang kita berikan menggukan cvLodImage(), lalu ditampilkan menggunakan cvNamedWindow(). Setelah dikompilasi, eksekusi file .exe yang tercipta atau jalankan dengan perintah:
Demo fira.JPG
Maka akan tampil gambar berikut :
Gambar 8.2 Hasil program menampilkan image cute
Berikut contoh memodifikasi/memroses gambar :
Gambar.cpp:
#include "stdafx.h"
#include <cv.h>
#include <highgui.h>
#include <math.h>
int main( int argc, char** argv ) {
CvPoint center;
double scale=-3;
IplImage* image = argc==2 ? cvLoadImage(argv[1]) : 0;
if(!image) return -1;
center = cvPoint(image->width/2,image->height/2);
for(int i=0;i<image->height;i++)
for(int j=0;j<image->width;j++) {
double dx=(double)(j-center.x)/center.x;
double dy=(double)(i-center.y)/center.y;
double weight=exp((dx*dx+dy*dy)*scale);
uchar* ptr =&CV_IMAGE_ELEM(image,uchar,i,j*3);
ptr[0] = cvRound(ptr[0]*weight);
ptr[1] = cvRound(ptr[1]*weight);
ptr[2] = cvRound(ptr[2]*weight); }
cvSaveImage("copy.png", image );
cvNamedWindow( "test", 1 );
cvShowImage( "test", image );
cvWaitKey();
return 0;
}
Jalankan program dengan perintah berikut :
Gambar fira.JPG
Hasilnya seperti gambar berikut :
Gambar 8.2 Hasil program
Jika Anda ingin mendeteksi webcam dan mengambil image dari webcam tersebut, gunakan demo kode berikut ini, dimana fungsi yang umum digunakan ialah :
pCapture = cvCaptureFromCAM( CV_CAP_ANY );
WebcamCapture.cpp:
// Demo koneksi ke webcam dan simpan frame
#include "stdafx.h"
#include "stdio.h"
#include "string.h"
#include "cv.h"
#include "highgui.h"
int main(int argc, char ** argv)
{
CvCapture * pCapture = 0;
IplImage * pVideoFrame = 0;
int i;
char filename[50];
// Inisialisasi video capture
pCapture = cvCaptureFromCAM( CV_CAP_ANY );
if( !pCapture )
{
fprintf(stderr, "Gagal inisialisasi webcam\n");
return -1;
}
// Ambil 3 frame video
for(i=0; i<3; i++)
{
pVideoFrame = cvQueryFrame( pCapture );
if( !pVideoFrame )
{
fprintf(stderr, "failed to get a video frame\n");
}
// tulis ke file
sprintf(filename, "VideoFrame%d.jpg", i+1);
if( !cvSaveImage(filename, pVideoFrame) )
{
fprintf(stderr, "failed to write image file %s\n", filename);
}
}
// Terminasi video capture
cvReleaseCapture( &pCapture );
return 0;
}
Pengenalan Wajah
Haar Cascade Classifier
OpenCV ialah open source library computer vision, yang memudahkan pemrograman deteksi wajah, face tracking, face recognition, kalman filtering dn berbagai metode artificial intelligent.
OpenCV menggunakan sebuah tipe face detector yang dsebut 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.
Konsep Pendeteksian Wajah
OpenCV face detector menggunakan metode Paul Viola dan Michael Jones, silahkan baca detail paper mereka di CD Program. Metode mengkombinasikan :
· Fitur rectangular sederhana yang disebut fitur Haar
· Integral imag untuk deteksi fitur yang cepat
· Metode machine learning AdaBoost.
· Sebuah pengklasifikasi cascade untkmengkombinasikan banyak fitur secara efisien.
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.
Implementasi Deteksi Wajah:
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);
Untuk memasukkan image ke display, panggil fungsi cvShowImage() dengan nama yang telah dibuat pada window dan nama image yang ingin ditampilkan.
Berikut ini kodel lengkapnya :
DetectFace.cpp:
// Hak Cipta cognotics.com
...
// *********************************************
#define OPENCV_ROOT "C:/Program Files/OpenCV"
// *********************************************
void displayDetections(IplImage * pInpImg, CvSeq * pFaceRectSeq);
int main(int argc, char** argv)
{
// variables
IplImage * pInpImg = 0;
CvHaarClassifierCascade * pCascade = 0; // face detector
CvMemStorage * pStorage = 0; // memory for detector to use
CvSeq * pFaceRectSeq; // memory-access interface
// pengecekan
if(argc < 2)
{
printf("Missing name of image file!\n"
"Usage: %s <imagefilename>\n", argv[0]);
exit(-1);
}
// initializations
pInpImg = (argc > 1) ? cvLoadImage(argv[1], CV_LOAD_IMAGE_COLOR) : 0;
pStorage = cvCreateMemStorage(0);
pCascade = (CvHaarClassifierCascade *)cvLoad
((OPENCV_ROOT"/data/haarcascades/haarcascade_frontalface_default.xml"),
0, 0, 0 );
// validate that everything initialized properly
if( !pInpImg || !pStorage || !pCascade )
{
printf("Initialization failed: %s\n",
(!pInpImg)? "can't load image file" :
(!pCascade)? "can't load haar-cascade -- "
"make sure path is correct" :
"unable to allocate memory for data storage", argv[1]);
exit(-1);
}
// detect faces in image
pFaceRectSeq = cvHaarDetectObjects
(pInpImg, pCascade, pStorage,
1.1, // increase search scale by 10% each pass
3, // merge groups of three detections
CV_HAAR_DO_CANNY_PRUNING, // skip regions unlikely to contain a face
cvSize(40,40)); // smallest size face to detect = 40x40
// tampilkn wajah yang terdeteksi
displayDetections(pInpImg, pFaceRectSeq);
// clean up and release resources
cvReleaseImage(&pInpImg);
if(pCascade) cvReleaseHaarClassifierCascade(&pCascade);
if(pStorage) cvReleaseMemStorage(&pStorage);
return 0;
}
void displayDetections(IplImage * pInpImg, CvSeq * pFaceRectSeq)
{
const char * DISPLAY_WINDOW = "Haar Window";
int i;
// create a window to display detected faces
cvNamedWindow(DISPLAY_WINDOW, CV_WINDOW_AUTOSIZE);
// draw a rectangular outline around each detection
for(i=0;i<(pFaceRectSeq? pFaceRectSeq->total:0); i++ )
{
CvRect* r = (CvRect*)cvGetSeqElem(pFaceRectSeq, i);
CvPoint pt1 = { r->x, r->y };
CvPoint pt2 = { r->x + r->width, r->y + r->height };
cvRectangle(pInpImg, pt1, pt2, CV_RGB(0,255,0), 3, 4, 0);
}
// tampilkan
cvShowImage(DISPLAY_WINDOW, pInpImg);
cvWaitKey(0);
cvDestroyWindow(DISPLAY_WINDOW);
}
Gambar 8.3 Wajah cantik yang terdeteksi
Tracking Wajah
OpenCV face tracker menggunakan algoritma CamShift. Camfsit terdiri dari beberapa langkah :
1. Membuat histogram warna untuk merepresentasikan wajah
Camshift merepresentasikan wajah yang ditrack sebagai histogram nilai warna. Ketinggian tiap bar berwarna diindikasikan berapa banyak pixel pada daerah image memiliki “hue” Hue ialah satu dari 3 nilai yang menjelaskan warna pixel pada HSV (Hue, Saturation, Value)
2. Menghitung probabilitas wajah untuk tiap pixel pada frame video yang diterima.
3. Menggeser lokasi dari persegi wajah pada tiap frame video
4. Camshift menggeser estimasinya dari lokasi wajah, membuat tepat terpusat pada area dengan konsentrasi tinggi dari pixel terang pada image face probability. Ia akan mencari lokasi baru tersebut dengan memulai pada lokasi sebelumnya dan menghitung pusat gravitasi dari nilai face-probability dalam sebuah kotak. Lalu menggeser kotak hingga kotaknya melewati pusat gravitasi. Dilakukan beberapa kali ke pusat kotak. Fungsi cvCamShift() mengimplementasikan langkah untuk menggeser ke lokasi baru. Proses shifting kotak untuk menghubungi dengan pusat gravitasi berdasarkan algoritma “Mean Shift” oleh Dorin Comaniciue.
5. Menghitung ukuran dan sudut.
Metode continuosly adaptive digunakan , bukan hanya “Mean Shift” karena ia juga menyesuaikan ukuran dan sudut dari kotak rectangle tiap kali shifting, dengan cara skala dan orientasi yang terbaik pada pixel face-probability di dalam lokasi kotak.
Berikut ini contoh kodenya:
FaceTrack.cpp
// Demo Tracking wajah
// Hak Cipta Cognotics.com
#include "cv.h"
#include "highgui.h"
#include <stdio.h>
#include "capture.h"
...
const char * DISPLAY_WINDOW = "DisplayWindow";
#define OPENCV_ROOT "C:/Program Files/OpenCV"
//// Global variables
IplImage * pVideoFrameCopy = 0;
//// Definisi fungsi
int initAll();
void exitProgram(int code);
void captureVideoFrame();
void main( int argc, char** argv )
{
CvRect * pFaceRect = 0;
if( !initAll() ) exitProgram(-1);
// Capture and display video frames until a face
// is detected
while( 1 )
{
// mencari wajah pada next frame
captureVideoFrame();
pFaceRect = detectFace(pVideoFrameCopy);
// Tampilkan image
cvShowImage( DISPLAY_WINDOW, pVideoFrameCopy );
if( (char)27==cvWaitKey(1) ) exitProgram(0);
// exit loop when a face is detected
if(pFaceRect) break;
}
// initialize tracking
startTracking(pVideoFrameCopy, pFaceRect);
// Track the detected face using CamShift
while( 1 )
{
CvBox2D faceBox;
CvPoint facePoint;
// ambil next frame video
captureVideoFrame();
// track wajah pada video frame
faceBox = track(pVideoFrameCopy);
// Bentuk elips
cvEllipseBox(pVideoFrameCopy, faceBox,
CV_RGB(50,255,0), 2, CV_AA, 0 );
cvShowImage( DISPLAY_WINDOW, pVideoFrameCopy );
if( (char)27==cvWaitKey(1) ) break;
}
exitProgram(0);
}
int initAll()
{
if( !initCapture() ) return 0;
if( !initFaceDet(OPENCV_ROOT
"/data/haarcascades/haarcascade_frontalface_default.xml"))
return 0;
// Buat jendela display
cvNamedWindow( DISPLAY_WINDOW, 1 );
// Initialize tracker
captureVideoFrame();
if( !createTracker(pVideoFrameCopy) ) return 0;
// Set parameter Camshift
setVmin(60);
setSmin(50);
return 1;
}
void exitProgram(int code)
{
// Release resources
cvDestroyWindow( DISPLAY_WINDOW );
cvReleaseImage( &pVideoFrameCopy );
// Release resources
closeCapture();
closeFaceDet();
releaseTracker();
exit(code);
}
void captureVideoFrame()
{
printf ("Data : %d\n");
// Capture the next frame
IplImage * pVideoFrame = nextVideoFrame();
if( !pVideoFrame ) exitProgram(-1);
// Copy it to the display image, inverting it if needed
if( !pVideoFrameCopy )
pVideoFrameCopy = cvCreateImage( cvGetSize(pVideoFrame), 8, 3 );
cvCopy( pVideoFrame, pVideoFrameCopy, 0 );
pVideoFrameCopy->origin = pVideoFrame->origin;
if( 1 == pVideoFrameCopy->origin ) // 1 means the image is inverted
{
cvFlip( pVideoFrameCopy, 0, 0 );
pVideoFrameCopy->origin = 0;
}
}
Gambar 8.6 Hasil deteksi dan tracking wajah Mr. Widodo
Latihan:
1. Untuk mahir computer vision pada robot, tidak ada cara lain selain Anda mengerjakan tugas yang penulis berikan. Buatlah program Robot Line Follower yang mengikuti wajah orang di depannya.
2. Buatlah program edge detection menggunakan OpenCV
3. Buatlah program Threshold dan ROI menggunakan OpenCV.
4. Jelaskan cara kerja Haar Cascade Classifier.
5. Buatlah program dan file library XML untuk deteksi obyek buatan Anda, misalnya deteksi gelas dan gunting. Anda harus membuat file positif berupa file gambar yang ingin dideteksi minimal 12 gambar dengan berbagai pose dan file negatif berisi gambar yang bukan ingin dideteksi. Lalu lakukan pembuatan file vector, dengan contoh perintah :
createsamples.exe -info positiveSample/info.txt -vec data/vector.vec -num 18 -w 20 -h 20
Kemudian melakukan training dengan perintah :
haartraining.exe -data data/cascade -vec data/vector.vec -bg negativeSample/infofile.txt -npos 12 -nneg 2 -mem 1000 -mode ALL -w 20 -h 20 –nonsym
Lalu membuat file XML dengan perintah :
haarconv.exe data output.xml 20 20
Gambar 8.7 Hasil deteksi dan tracking obyek buatan XML
Robot Pelayan Humanoid
Pendahuluan
Robot pelayan ialah robot yang mampu melayani manusia, dalam hal ini ialah robot pelayan pada rumah makan /cafe. Berbekal materi sebelumnya dan kerja keras Anda, robot yang dipaparkan di sini harus Anda buat hingga sukses jika ingin benar benar mewujudkan robot humanoid yang mirip manusia.
Rancangan Robot Pelayan
Arsitektur Robot Pelayan
Perkembangan pesat teknologi robot telah menuntut hadirnya robot cerdas yang mampu melengkapi dan membantu pekerjaan manusia. Salah satu harapan dari perkembangan teknologi robot ialah hadirnya robot pelayan di sekitar kita. Robot tipe ini tentunya harus mampu berinterasi sosial dengan manusia, antara lain dapat mengenal wajah, suara dan berbicara. Di Indonesia sendiri dapat dikatakan belum ada robot pelayan yang benar-benar telah diterapkan pada dunia komersial, oleh karena itu penulis tertarik untuk memotivasi pembaca agar membuat robot ini.
Robot yang harus Anda buat berbasiskan 2 buah mikrokontroler Basic Stamp dan AVR Atmega8535 untuk mengendalikan webcam serta aktuator. Perangkat yang digunakan secara detail ialah :
· 2 Buah mikrokontroler Basic Stamp
· 1 buah mikrokontroler AVR
· Modul Text to speech dari Parallax
· SG6 Arm Robot 5 DOF Crustcrawler
· 2 buah servo continuous parallax
· 2 buah Webcam standar
· Sensor jarak PING
· Motor dan roda robot serta komponen pendukung
Berikut ini rancangannya, intinya robot mendeteksi wajah seseorang menggunakan webcam, robot menerima input order dari switch manual atau speech recognition. Setelah itu robot dapat memberikan order orang tersebut menggunakan arm robot dengan berjalan menggunakan kaki atau roda. Berikut arsitektur robot penulis bernama Srikandi.
Gambar 9.1 Arsitektur robot pelayan Srikandi (servant robot, hak cipta penulis)
Gambar 9.2 Tampak depan robot pelayan Srikandi
Gambar 9.3 Tampak samping robot pelayan Srikandi
Perangkat Lunak Robot Pelayan
Untuk mengendalikan Basic Stamp, digunakan bahasa PBASIC, untuk mengendalikan Webcam dan Image processing di PC digunakan OpenCV, sedangkan mengendalikan AVR digunakan CodeVision C AVR. Untuk antarmuka antara PC dengan pengguna (User Interface) digunakan Visual C# .Net. Agar robot dapat berbicara, digunakan kit Text to speech dari Parallax, contoh robot berbicara sudah dibahas penulis pada buku sebelumnya yaitu 10 Proyek Robot Spektakuler terbitan Elex Media Komputindo.
Face Recognition
Konsep Dasar
Untuk membuat robot pelayan dari arsitektur di atas, pertama Anda harus membuat program Face recognition yang akan mengenal wajah pemesan dan object recognition untuk mengenal gelas atau bukan. Object recognition dapat dibuat dengan membuat file library XML. Face recognition di sini menggunakan eigenspace dan PCA, suatu teknik yang umum dikenal jika pemula ingin belajar pengenalan dan identifikasi wajah. Penulis mengharapkan Anda membaca paper asli dari penemu teknik ini di CD Program. Penulis juga mengharapkan Anda mempelajari Machine Learning. Program dimulai dengan training dimana program akan melakukan proses pembelajaran, lalu pengetesan images dimana akan dilakukan proses pengenalan wajah. Buatlah proyek baru dan beri nama FaceEigen sebagai berikut:
FaceEigen.cpp:
// Program demo Face recognition berbasis Eigenspace
// Hak Cipta Cognotics.com
#include "stdafx.h"
#include <stdio.h>
#include <string.h>
#include "cv.h"
#include "cvaux.h"
#include "highgui.h"
//// Global variables
IplImage ** faceImgArr = 0; // array of face images
CvMat * personNumTruthMat = 0; // array of person numbers
int nTrainFaces = 0; // the number of training images
int nEigens = 0; // the number of eigenvalues
IplImage * pAvgTrainImg = 0; // the average image
IplImage ** eigenVectArr = 0; // eigenvectors
CvMat * eigenValMat = 0; // eigenvalues
CvMat * projectedTrainFaceMat = 0; // projected training faces
//// Function prototypes
void learn();
void recognize();
void doPCA();
void storeTrainingData();
int loadTrainingData(CvMat ** pTrainPersonNumMat);
int findNearestNeighbor(float * projectedTestFace);
int loadFaceImgArray(char * filename);
void printUsage();
void main( int argc, char** argv )
{
if( !strcmp(argv[1], "train") )
{
learn();
}
if( !strcmp(argv[1], "test") )
{
recognize();
}
}
void learn()
{
int i, offset;
// load training data
nTrainFaces = loadFaceImgArray("train.txt");
if( nTrainFaces < 2 )
{
fprintf(stderr,
"Need 2 or more training faces\n"
"Input file contains only %d\n", nTrainFaces);
return;
}
// do PCA on the training faces
doPCA();
// project the training images onto the PCA subspace
projectedTrainFaceMat = cvCreateMat( nTrainFaces, nEigens, CV_32FC1 );
offset = projectedTrainFaceMat->step / sizeof(float);
for(i=0; i<nTrainFaces; i++)
{
//int offset = i * nEigens;
cvEigenDecomposite(
faceImgArr[i],
nEigens,
eigenVectArr,
0, 0,
pAvgTrainImg,
//projectedTrainFaceMat->data.fl + i*nEigens);
projectedTrainFaceMat->data.fl + i*offset);
}
// store the recognition data as an xml file
storeTrainingData();
}
void recognize()
{
int i, nTestFaces = 0; // the number of test images
CvMat * trainPersonNumMat = 0; // the person numbers during training
float * projectedTestFace = 0;
// load test images and ground truth for person number
nTestFaces = loadFaceImgArray("test.txt");
//printf("%d test faces loaded\n", nTestFaces);
// load the saved training data
if( !loadTrainingData( &trainPersonNumMat ) ) return;
// project the test images onto the PCA subspace
projectedTestFace = (float *)cvAlloc( nEigens*sizeof(float) );
for(i=0; i<nTestFaces; i++)
{
int iNearest, nearest, truth;
// project the test image onto the PCA subspace
cvEigenDecomposite(
faceImgArr[i],
nEigens,
eigenVectArr,
0, 0,
pAvgTrainImg,
projectedTestFace);
iNearest = findNearestNeighbor(projectedTestFace);
truth = personNumTruthMat->data.i[i];
nearest = trainPersonNumMat->data.i[iNearest];
printf("Wajah ini mirip dengan = %d, Truth = %d\n", nearest, truth);
}
}
int loadTrainingData(CvMat ** pTrainPersonNumMat)
{
CvFileStorage * fileStorage;
int i;
// create a file-storage interface
fileStorage = cvOpenFileStorage( "facedata.xml", 0, CV_STORAGE_READ );
if( !fileStorage )
{
fprintf(stderr, "Can't open facedata.xml\n");
return 0;
}
nEigens = cvReadIntByName(fileStorage, 0, "nEigens", 0);
nTrainFaces = cvReadIntByName(fileStorage, 0, "nTrainFaces", 0);
*pTrainPersonNumMat = (CvMat *)cvReadByName(fileStorage, 0, "trainPersonNumMat", 0);
eigenValMat = (CvMat *)cvReadByName(fileStorage, 0, "eigenValMat", 0);
projectedTrainFaceMat = (CvMat *)cvReadByName(fileStorage, 0, "projectedTrainFaceMat", 0);
pAvgTrainImg = (IplImage *)cvReadByName(fileStorage, 0, "avgTrainImg", 0);
eigenVectArr = (IplImage **)cvAlloc(nTrainFaces*sizeof(IplImage *));
for(i=0; i<nEigens; i++)
{
char varname[200];
sprintf( varname, "eigenVect_%d", i );
eigenVectArr[i] = (IplImage *)cvReadByName(fileStorage, 0, varname, 0);
}
// release the file-storage interface
cvReleaseFileStorage( &fileStorage );
return 1;
}
void storeTrainingData()
{
CvFileStorage * fileStorage;
int i;
// create a file-storage interface
fileStorage = cvOpenFileStorage( "facedata.xml", 0, CV_STORAGE_WRITE );
// store all the data
cvWriteInt( fileStorage, "nEigens", nEigens );
cvWriteInt( fileStorage, "nTrainFaces", nTrainFaces );
cvWrite(fileStorage, "trainPersonNumMat", personNumTruthMat, cvAttrList(0,0));
cvWrite(fileStorage, "eigenValMat", eigenValMat, cvAttrList(0,0));
cvWrite(fileStorage, "projectedTrainFaceMat", projectedTrainFaceMat, cvAttrList(0,0));
cvWrite(fileStorage, "avgTrainImg", pAvgTrainImg, cvAttrList(0,0));
for(i=0; i<nEigens; i++)
{
char varname[200];
sprintf( varname, "eigenVect_%d", i );
cvWrite(fileStorage, varname, eigenVectArr[i], cvAttrList(0,0));
}
// release the file-storage interface
cvReleaseFileStorage( &fileStorage );
}
int findNearestNeighbor(float * projectedTestFace)
{
//double leastDistSq = 1e12;
double leastDistSq = DBL_MAX;
int i, iTrain, iNearest = 0;
for(iTrain=0; iTrain<nTrainFaces; iTrain++)
{
double distSq=0;
for(i=0; i<nEigens; i++)
{
float d_i =
projectedTestFace[i] -
projectedTrainFaceMat->data.fl[iTrain*nEigens + i];
distSq += d_i*d_i; // Euclidean
}
if(distSq < leastDistSq)
{
leastDistSq = distSq;
iNearest = iTrain;
}
}
return iNearest;
}
void doPCA()
{
int i;
CvTermCriteria calcLimit;
CvSize faceImgSize;
// set the number of eigenvalues to use
nEigens = nTrainFaces-1;
// allocate the eigenvector images
faceImgSize.width = faceImgArr[0]->width;
faceImgSize.height = faceImgArr[0]->height;
eigenVectArr = (IplImage**)cvAlloc(sizeof(IplImage*) * nEigens);
for(i=0; i<nEigens; i++)
eigenVectArr[i] = cvCreateImage(faceImgSize, IPL_DEPTH_32F, 1);
// allocate the eigenvalue array
eigenValMat = cvCreateMat( 1, nEigens, CV_32FC1 );
// allocate the averaged image
pAvgTrainImg = cvCreateImage(faceImgSize, IPL_DEPTH_32F, 1);
// set the PCA termination criterion
calcLimit = cvTermCriteria( CV_TERMCRIT_ITER, nEigens, 1);
// compute average image, eigenvalues, and eigenvectors
cvCalcEigenObjects(
nTrainFaces,
(void*)faceImgArr,
(void*)eigenVectArr,
CV_EIGOBJ_NO_CALLBACK,
0,
0,
&calcLimit,
pAvgTrainImg,
eigenValMat->data.fl);
cvNormalize(eigenValMat, eigenValMat, 1, 0, CV_L1, 0);
}
int loadFaceImgArray(char * filename)
{
FILE * imgListFile = 0;
char imgFilename[512];
int iFace, nFaces=0;
// open the input file
if( !(imgListFile = fopen(filename, "r")) )
{
fprintf(stderr, "Can\'t open file %s\n", filename);
return 0;
}
// count the number of faces
while( fgets(imgFilename, 512, imgListFile) ) ++nFaces;
rewind(imgListFile);
// allocate the face-image array and person number matrix
faceImgArr = (IplImage **)cvAlloc( nFaces*sizeof(IplImage *) );
personNumTruthMat = cvCreateMat( 1, nFaces, CV_32SC1 );
// store the face images in an array
for(iFace=0; iFace<nFaces; iFace++)
{
// read person number and name of image file
fscanf(imgListFile,
"%d %s", personNumTruthMat->data.i+iFace, imgFilename);
// load the face image
faceImgArr[iFace] = cvLoadImage(imgFilename, CV_LOAD_IMAGE_GRAYSCALE);
if( !faceImgArr[iFace] )
{
fprintf(stderr, "Can\'t load image from %s\n", imgFilename);
return 0;
}
}
fclose(imgListFile);
return nFaces;
}
void printUsage()
{
printf("Usage: eigenface <command>\n",
" Valid commands are\n"
" train\n"
" test\n");
}
Siapkan basis data file gambar berekstension .pgm dengan aneka posisi wajah. Berikan data percobaan untuk training.txt , misalnya:
1 s1/1.pgm
2 s2/1.pgm
3 s3/1.pgm
4 s1/2.pgm
5 s2/2.pgm
6 s3/2.pgm
Berikan data percobaan untuk test.txt:
1 s1/1.pgm
2 s1/2.pgm
3 s2/1.pgm
Jika program ini dijalankan dengan melakukan training terlebih dahulu, lalu test, maka akan terlihat bahwa gambar 1, gambar 2 dan 3 sesuai dengan basis data 1, 4 dan 2.
Gambar 9.4 Hasil face recognition
Jika program diatas telah berhasil dikembangkan, maka langkah berikutnya ialah membuat program object recognition. Setelah itu membuat lengan robot yang dapat mengambil dan menerima gelas. Untuk mengendalikan servo pada lengan robot, paling mudah menggunakan Parallax Servo Controller, yang dapat memperoleh posisi servo.
Gambar 9.5 Hubungan Parallax Servo Controller
Berikut demo mencari versi kit dari Parallax Servo Controller, dimana output mikrokontroler berupa data serial dihubungkan ke pin 15..
Ver.bsp:
' {$STAMP BS2p}
' {$PBASIC 2.5}
Sdat PIN 15
baud CON 1021
buff VAR Byte(3)
findPSC:
DEBUG "Mencari PSC", CR
SEROUT Sdat, baud + $8000, ["!SCVER?",CR]
SERIN Sdat, baud, 500, findPSC, [STR buff\3]
DEBUG "PSC ver:", buff(0), buff(1), buff(2), CR
STOP
Jika lengan robot Anda telah sukses bergerak sesuai program demo, terakhir ialah Anda harus kembangkan dan integrasikn program yang mengenal wajah dan menyimpn informasi wajah tersebut beserta namanya. Setelah robot mengenal dan mengingat pesanan dari pelanggan tersebut, gelas yang berisi minuman pemesan harus diberikan oleh robot dengan berjalan menggunakan roda. Robot juga harus berkomunikasi secara efektif menggunakan modul text to speech yang telah dipasang. Selamat Mencoba J.