现在的位置: 首页 > 操作系统 > 正文

Opencv实现ARM上的人脸检测(ubuntu10.04 / QT / OK6410开发板)

2017年06月16日 操作系统 ⁄ 共 4666字 ⁄ 字号 评论关闭

环境:

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中文网站——人脸检测 实例

抱歉!评论已关闭.