环境:
Ubuntu10.04
arm linux OS: 3.0.1
arm上 qt-4.7.1
g++ / gcc 4.4.3
arm-linux-g++ / arm-linux-gcc 4.3.2
QTCreator:
(建议先参考我的另外一篇博文《Opencv-2.0.0的ARM移植和使用(Ubuntu10.04 / OK6410开发板 / linux3.01)》【1】
特别标注:
有些网站转载我的文章不标明出处,并且转载不到位,没有把相应的链接一块转过去,比如说下载链接或相关文献的链接等,导致一些网友阅读和使用出现障碍和知识的不连续,所以在此特别标注:我的这篇文章发表在CSDN博客上,可以到CSDN博客来阅读。
实现过程:
1、先了解opencv在ARM上的移植和使用,请参阅文章后面的参考文献【1】;
2、在已经实现了opencv结合QT在ARM上的使用之后,事情就简单很多了,剩下的事情就是实现人脸检测算法的问题了,主要算法可以借鉴opencv安装包里面的samples文件夹里提供的facedetect应用程序来实现;
还是那个简单思路,从熟悉的东西入手,先在Ubuntu上实现,再移植ARM上。
3、在Ubuntu使用QTCreator实现的流程我就不讲了,具体情况请下载PC版源代码来琢磨吧。下来主要列表一些ARM上的实现流程,其实跟ubuntu上的实现流程是一样一样的,主要就是编译环境方式不同而已。先表一下Ubuntu上的实现效果吧。(为了表征真实性,贡献出本人的销魂照,特此警告:保护好你的电脑屏幕,不要上面铺满了喷泄物之后才来问候上苍的爹娘!本人不负任何责任)
4、下来就好好聊聊ARM上的实现吧。
先来看看主要代码:(具体代码和实现请下载ARM版代码参阅)
<span xmlns="http://www.w3.org/1999/xhtml" style="">#ifndef PROPERTY #define PROPERTY #define image_width 320 //图片显示宽度 #define image_height 240 //图片显示高度 #define image_Format QImage::Format_RGB888 //图片显示格式 #define cameraDevice "/dev/video2" //摄像头设备 #define haarXML "./data/haarcascade_frontalface_alt2.xml" //人脸模型级联分类器文件 #define imgSizeScaleSmall 0.5 //图像放缩比例 #define imgSizeScaleBig 2 //图像放缩比例 #endif //PROPERTY</span>
实现流程:
<span xmlns="http://www.w3.org/1999/xhtml" style=""><span xmlns="http://www.w3.org/1999/xhtml" style=""><span xmlns="http://www.w3.org/1999/xhtml" style=""><span xmlns="http://www.w3.org/1999/xhtml" style="">void Widget::paintEvent(QPaintEvent *) { uchar * pImgBuf; unsigned int len; camReturn = m_camera->get_frame((void **)&pImgBuf,&len); convert_yuv_to_rgb_buffer(pImgBuf,imgBuf,image_width,image_height/*QWidget::width(),QWidget::height()*/); frame->loadFromData((uchar *)imgBuf,/*len*/image_width * image_height * 3 * sizeof(char)); //QImage转IplImage IplImage* src = QImageToIplImage(frame); if (!src) { printf("img error!"); return; } //压缩图像大小,提升人脸检测的速度 double sizeScale = imgSizeScaleSmall; CvSize img_cvsize; img_cvsize.width = src->width * sizeScale; img_cvsize.height = src->height * sizeScale; IplImage* dst = cvCreateImage(img_cvsize, src->depth, src->nChannels); cvResize(src, dst, CV_INTER_LINEAR); detect_and_draw(dst); //实现人脸检测 // cvSaveImage("jason.jpg", img); //此函数highgui.h里的众多函数在ARM上都不可用 //恢复原图像大小,但图像分辨率有所下降,图像较原始图像模糊 //(亦可用原始图像直接显示,但ARM处理资源有限,不建议耗费太多资源,除此之外暂时还没想到更好的处理方式) sizeScale = imgSizeScaleBig; img_cvsize.width = dst->width * sizeScale; img_cvsize.height = dst->height * sizeScale; IplImage* img = cvCreateImage(img_cvsize, dst->depth, dst->nChannels); cvResize(dst, img, CV_INTER_LINEAR); QImage qimage = QImage((uchar *)img->imageData, img->width,img->height, image_Format); //IplImage为BGR格式,QImage为RGB格式,所以要交换B和R通道显示才正常 //可以用OpenCV的cvConcertImage函数交换,也可以用QImage的rgbSwapped函数交换; qimage = qimage.rgbSwapped(); ui->m_imgLabel->setPixmap(QPixmap::fromImage(qimage)); camReturn = m_camera->unget_frame(); cvReleaseImage(&img); //释放图片内存 cvReleaseImage(&src); }</span></span></span></span>
<span style="font-size:14px;">//人脸检测函数 void Widget::detect_and_draw(IplImage *img) { static CvScalar colors[] = { {{0,0,255}}, {{0,128,255}}, {{0,255,255}}, {{0,255,0}}, {{255,128,0}}, {{255,255,0}}, {{255,0,0}}, {{255,0,255}} }; double scale = 2.0; //此变量关系到人脸检测的范围精度 IplImage* gray = cvCreateImage( cvSize(img->width,img->height), 8, 1 ); IplImage* small_img = cvCreateImage( cvSize( cvRound (img->width/scale), cvRound (img->height/scale)), 8, 1 ); int i; cvCvtColor( img, gray, CV_BGR2GRAY ); cvResize( gray, small_img, CV_INTER_LINEAR ); cvEqualizeHist( small_img, small_img ); cvClearMemStorage( storage ); if( cascade ) { double t = (double)cvGetTickCount(); CvSeq* faces = cvHaarDetectObjects( small_img, cascade, storage, 1.2, 2, 0, cvSize(30, 30) ); t = (double)cvGetTickCount() - t; printf( "detection time = %gms\n", t/((double)cvGetTickFrequency()*1000.) ); for( i = 0; i < (faces ? faces->total : 0); i++ ) { CvRect* r = (CvRect*)cvGetSeqElem( faces, i ); CvPoint rectP1, rectP2; rectP1.x = cvRound(r->x * scale); rectP1.y = cvRound(r->y * scale); rectP2.x = cvRound((r->x + r->width) * scale); rectP2.y = cvRound((r->y + r->height) * scale); cvRectangle(img, rectP1, rectP2, colors[i%8], 3, 8, 0); } m_FaceCount = faces->total; } cvReleaseImage( &gray ); cvReleaseImage( &small_img ); }</span>
下来就是编译程序,流程请参阅参考文献【1】,程序移植之后的效果如下:
(不好意思,别吐,还是我的销魂照)
这里想主要说一下这块OK6410B的ARM开发板的处理速度问题,它的主频在0.5GHZ,由于能力有限,不懂得怎样实现硬加速或者软加速,导致图像处理速递非常的低效,在没经过后期处理之前,在face detection阶段,detection time每一帧约为600ms,也就是整个流程下来要将近1秒的时间。摄像头在PC上的处理速度约为每秒30帧左右,这样看起来实时性比较高,ARM上速度却下降了30倍左右,这是没法接受的。综合考虑了自己的需求,在检测精度许可的范围内,只能尽可能地压缩图像,加快图像的处理速度,本工程为较原来长宽尺度的0.5倍大小,空间缩小为原来的6分之1左右,经过测试,处理速度确实有了明显提高,降至100ms左右。如下图所示:(虽然看起来还是有些不流畅,但已经有所改进,后面有时间再研究其他加速方式)
涉及其他方面的知识,请参阅我之前的相关博文。
这里得注意一个问题,就是摄像头的名称,我的ubuntu上的名称为:/dev/video0,在ARM上为:/dev/video2;注意修改此处的代码
注:
对于编译时出现的缺少或者不能打开opencv相应的文件或库,原因是你的Makefile里面的环境路径配置有问题,不要把我的工程直接不做修改就拿来编译,会出问题的(工程中我编译出来的最终程序也许可以使用),因为我安装的opencv路径可能和你的不一样,具体修改方式请打开Makefile文件,参照原来的内容进行修改,或者生成自己的Makefile文件亦可。
附录:
源码下载:1、PC版人脸检测源程序
2、ARM版人脸检测源程序
参考文献:
【1】Opencv-2.0.0的ARM移植和使用(Ubuntu10.04 / OK6410开发板 / linux3.01)
【2】Opencv中文网站——人脸检测 实例