OpenCV是一個基於(開源)發行的跨平臺計算機視覺庫,能夠運行在Linux、Windows和Mac OS操做系統上。它輕量級並且高效——由一系列 C 函數和少許 C++ 類構成,同時提供了Python、Ruby、MATLAB等語言的接口,實現了圖像處理和計算機視覺方面的不少通用算法。php
pcDuino是一款兼容Arduino接口的mini pc,A8架構1Ghz的CPU,計算能力不俗,用來跑OpenCV剛恰好。這裏就用他們實現一個能夠跟隨人臉移動的攝像頭。
在優酷裏面有一個視頻: OpenCV+pcDuino人臉跟蹤
硬件清單
一、pcDuino一塊;
二、傳感器擴展板一塊;
三、攝像頭雲臺一個;
四、攝像頭一個. html
1、編譯安裝OpenCV:
一、先安裝各類依賴庫,根據你的環境不一樣,可能出現缺失,全都補上,以求OpenCV一次編譯經過(由於編譯過程耗時將近3小時)
sudo apt-get install build-essential libgtk2.0-dev libavcodec-dev libavformat-dev libjpeg62-dev libtiff4-dev cmake libswscale-dev libjasper-dev linux
二、下載解壓OpenCV包,用cmake工具生成編譯所需的信息,第四句說明編譯成release版本,安裝目錄是/usr/local git
cd ~/opencv
mkdir release
cd release
cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local .. 算法
三、開始編譯
make
make install ubuntu
關於OpenCV的安裝你們能夠參照官方文檔:http://docs.opencv.org/doc/tutorials/introduction/linux_install/linux_install.html#linux-installation架構
2、編譯安裝c_enviroment:函數
一、c_enviroment是Pcduino控制硬件I/O的庫,從開頭軟件環境處給的連接下載c_enviroment的zip包,解壓編譯
cd c_enviroment
make
編譯完後,咱們能夠進入output/test目錄,測試一下點亮led的sample 工具
3、編譯安裝Qt: oop
爲了方便開發,我這裏用了Qt creator做爲IDE
一、安裝Qt creator
sudo apt-get install qtcreator
如今已經能夠在programing裏運行Qt creator了,可是這時候它還不能用,還須要安裝Qt library
二、安裝Qt library
經過開頭軟件環境中的連接下載嵌入式版Qt library:Qt libraries 4.8.5 for embedded Linux
具體安裝過程你們能夠參照這個帖子,這裏就不贅述了:
http://www.pcduino.org/forum.php?mod=viewthread&tid=21&highlight=%E5%9C%A8pcduino%E5%AE%89%E8%A3%85Qt
通過漫長的編譯安裝,Qt終於完成,至此環境算是搭好一大半了。
新建一個名爲face_tracking_camera的C++項目,編輯face_tracking_camera.pro文件,加入OpenCV和 c_enviroment的源文件、頭文件和類庫路徑,我這裏OpenCV安裝在/usr/local/,c_enviroment安裝在/home /ubuntu/c_enviroment/
expand source
到這裏,環境就所有搭好了。
代碼 #include <opencv2/opencv.hpp> #include <Arduino.h> #include <wiring_private.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <assert.h> #include <math.h> #include <float.h> #include <limits.h> #include <time.h> #include <ctype.h> #include <sys/time.h> #include <signal.h> //用於人臉識別的分類器特徵庫文件路徑 constchar* cascade_name =」/usr/local/share/OpenCV/haarcascades/haarcascade_frontalface_alt.xml」; //定義了X軸(橫向擺動),Y軸(縱向擺動)舵機的中心點 staticintcenterlevelX = 110; staticintcenterlevelY = 60; //定義了舵機的頻率 constintfrequncy = 260; //用一個整數存儲目前舵機擺動方向 staticintturningRight = 1; //函數的簽名列表 voiddetect_and_draw( IplImage* image ); voidstart_pulse(intpwm_id,intfreq,intvalue); voidsigroutine(intdunno); voidreset(); longgetCurrentTime(); longstartTime; longendTime; //led指示燈pin腳 intpin_led = 3; //爲OpenCV申請一塊用於計算的內存 staticCvMemStorage* storage = 0; //聲明一個haar分類器 staticCvHaarClassifierCascade* cascade = 0; voidsetup(){ //定義指示燈針腳爲輸出 pinMode(pin_led,OUTPUT); //復位雲臺舵機 reset(); //監聽中斷信號 signal(SIGINT,sigroutine); //創建一個名爲result的窗口 cvNamedWindow(「result」, 1 ); //打開攝像頭 CvCapture* capture = cvCaptureFromCAM(-1); //聲明兩個opencv圖像類型 IplImage *img; IplImage *newImg; //加載分類器 cascade = (CvHaarClassifierCascade*)cvLoad( cascade_name, 0, 0, 0 ); //檢查分類器加載異常 if( !cascade ){ fprintf( stderr,」ERROR: Could not load classifier cascade\n」); } //定位內存塊 storage = cvCreateMemStorage(0); while(1) { //因爲pcduino的計算能力有限,爲了保證幀率,把從攝像頭採集來的畫面縮小1/2 newImg = cvQueryFrame( capture ); if( !newImg )break; img = cvCreateImage(cvSize(newImg->width/2, newImg->height/2), newImg->depth, newImg->nChannels); cvResize(newImg, img); //翻轉圖像 cvFlip(img, img, 1); //調用識別和繪製圖像的函數 detect_and_draw(img); //釋放圖像使用的內存 cvReleaseImage(&img); //監聽esc鍵 intc = cvWaitKey(33); if( c == 27 )break; } //釋放攝像頭 cvReleaseCapture( &capture ); //銷燬窗口 cvDestroyWindow(「result」); } voiddetect_and_draw( IplImage* img ){ startTime = getCurrentTime(); //清空使用過的內存空間 cvClearMemStorage( storage ); intscale = 1; inti; //聲明一箇中心點存儲識別出來的人臉位置 CvPoint ptcenter; //人臉識別 if( cascade ){ //逐幀檢測人臉 CvSeq* faces = cvHaarDetectObjects( img, cascade, storage, 1.1, 2, CV_HAAR_DO_CANNY_PRUNING, cvSize(80, 80)); //若是檢測到多張臉,遍歷取出 for( i = 0; i < (faces ? faces->total : 0); i++ ){ //建立人臉矩形 CvRect* r = (CvRect*)cvGetSeqElem( faces, i ); //換算出人臉矩形的中心點 ptcenter.x = (r->x+(r->width/2))*scale; ptcenter.y = (r->y+(r->height/2))*scale; //繪製一個圓形標識出人臉的位置 cvCircle(img, ptcenter, (r->width+r->height)/4, CV_RGB(255,0,0), 3, 8, 0 ); } } //顯示圖像 cvShowImage(「result」, img ); //計算幀率 endTime = getCurrentTime(); longtime= endTime-startTime; intframerate = 1000/time; //檢查中心點是否爲空 if(ptcenter.x && ptcenter.y){ //std::cout<<」center_point:(「<<ptcenter.x<<」,」<<ptcenter.y<<」)\tframe_rate:」<<framerate<<」\n」<<std::endl; //std::cout<<」x:」<<(ptcenter.x-img->width/2)<<」\ty:」<<(ptcenter.y-img->height/2)<<std::endl; //向led指示燈引腳輸出低電平,熄滅指示燈 digitalWrite(pin_led,LOW); //驅動攝像頭移動到人臉中心位置 centerlevelX += (ptcenter.x-img->width/2)/110*2; if(centerlevelX <= 170 && centerlevelX >= 50)start_pulse(6,frequncy,centerlevelX); centerlevelY -= (ptcenter.y-img->height/2)/70; if(centerlevelY <= 90 && centerlevelY >= 45)start_pulse(5,frequncy,centerlevelY); //顯示修正的X和Y軸幅度和幀率 std::cout<<」X:」<<centerlevelX<<」\tY:」<<centerlevelY<<」\tFrameRate:」<<framerate<<std::endl; }else{ printf(「no face is detected in the image\n」); //指示燈亮起 digitalWrite(pin_led,HIGH); //若是沒有檢測到人臉則左右搖擺攝像頭 if(centerlevelX <= 170 && turningRight == 1){ start_pulse(6,frequncy,centerlevelX+=2); if(centerlevelX > 170)turningRight = 0; //std::cout<<centerlevelX<<std::endl; } if(centerlevelX >= 50 && turningRight == 0){ start_pulse(6,frequncy,centerlevelX-=2); if(centerlevelX < 50)turningRight =1; //std::cout<<centerlevelX<<std::endl; } } //防止攝像頭下移過分 if(centerlevelY < 45) centerlevelY = 45; } //復位函數,調整舵機X、Y軸到中心位置 voidreset(){ delay(50); start_pulse(5,frequncy,60); start_pulse(6,frequncy,110); delay(50); } longgetCurrentTime(){ structtimeval tv; gettimeofday(&tv,NULL); longtime= tv.tv_sec * 1000 + tv.tv_usec / 1000; returntime; } //舵機驅動函數 voidstart_pulse(intpwm_id,intfreq,intvalue){ intstep = 0; step = pwmfreq_set(pwm_id, freq); //printf(「PWM%d set freq %d and valid duty cycle range [0, %d]\n」, pwm_id, freq, step); if(step > 0){ //printf(「PWM%d test with duty cycle %d\n」, pwm_id, value); analogWrite(pwm_id, value); delay(50); } } //signal回調函數,監聽中斷信號,作一些狀態復位工做 voidsigroutine(intdunno) { switch(dunno) { case2: printf(「Get a signal – SIGINT \n」); reset(); analogWrite(6,0); analogWrite(5,0); digitalWrite(pin_led,LOW); exit(0); break; } } voidloop(){}