Computer Vision untuk Robot

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

// www.toko-robot.com    www.toko-elektronika.com

 

#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

// www.toko-elektronika.com 2010

#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.