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.
Dapatkan materi lengkap bab ini pada buku :
Membuat Robot Humanoid
Karangan : Widodo Budiharto & Paulus Andi Nalwan
Terbitan Elex Media Komputindo Agustus 2009.
Tidak ada komentar:
Posting Komentar