移植opencv到pcDuino

 

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(){} 
相關文章
相關標籤/搜索