环境:
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版代码参阅)
#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
实现流程:
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);
}
//人脸检测函数
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 );
}
下来就是编译程序,流程请参阅参考文献【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中文网站——人脸检测 实例