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(){}