Computer Vision untuk Robot

Shulthon Hanif Majid On Monday, August 1, 2011

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.

Comments
0 Comments

{ 0 comment... read them below or add one }