TQ210开发板人脸检测代码优化(2)

通过上一次的优化:见[2014.5.27]TQ210开发板人脸检测代码优化(1)_vimer-hz的博客-CSDN博客

注意每次paintEvent()的时间:

主要花费时间在Qimage图像转换为Iplimage图像的这个函数。这里注意一点,当时在Ubuntu上测试时主要的花费时间在getframe上,大约有20ms左右,而qimage—iplimage这个函数耗时只有8ms左右,跑到TQ210开发板后就不一样了,应该是和电路结构和浮点运算能力有关,TQ210取一帧的时间只有0.02ms,而qimage—iplimage这个函数消耗大约有65ms,所以这次优化的目的是避开这个转换函数。

Qimage图像之所以要转换为Iplimag图像是因为后面压缩图像用的函数如cvresize,cvrectangle等等需要的是Iplimage函数,优化思路是摄像头取来的帧是Qimage图像,就在QT直接显示出来,然后每5帧选1帧进行Qimage转换为Iplimage图像并进行人脸检测,还需要注意的是画人脸检测方框不能再用cvrecttangle函数,要用Qpainter直接在取回来的帧图像上画矩形框,再在QT上显示出来。

优化后的测试时间如下:

这样一来,平均每帧时间=(39 + 40 + 51 +42 + 143)/5 = 63ms,相当于每秒15.8帧,这看起来比较流畅了,但是矩形框就不是“即时”的,人脸移动不是高速移动的物体,勉强可以。

具体代码解释如下:

#include "widget.h"
#include "ui_widget.h"
#include <QtGui>
 
#ifndef PROPERTY
#define PROPERTY
 
#define image_width 320      //图片显示宽度
#define image_height 240          //图片显示高度
#define image_Format QImage::Format_RGB888       //图片显示格式
#define cameraDevice"/dev/video3"           //摄像头设备
#define haarXML "./data/haarcascade_frontalface_alt2.xml"      //人脸正脸模型级联分类器文件 
#define haarXML_profile"./data/haarcascade_profileface.xml"       //人脸侧脸模型级联分类器文件
#define imgSizeScaleSmall 0.5                //图像放缩比例
#define imgSizeScaleBig 3    //图像放缩比例
 
#endif //PROPERTY
 
long frame_count = 0;                 //统计第几帧
#define N 4
 
Widget::Widget(QWidget *parent) :
   QWidget(parent),
   ui(new Ui::Widget)
{
   ui->setupUi(this);
 
   imgBuf = (unsigned char *)malloc(image_width * image_height* 3 *sizeof(char));
   frame = new QImage(imgBuf,image_width,image_height,image_Format);                
   m_camera = new VideoDevice(tr(cameraDevice));                                   
   connect(m_camera, SIGNAL(display_error(QString)),this,SLOT(display_error(QString)));
   camReturn = m_camera->open_device();                                             
    {
       QMessageBox::warning(this,tr("error"),tr("open /dev/dsperror"),QMessageBox::Yes);
       m_camera->close_device();
    }
 
   camReturn = m_camera->init_device();                                               
   if(-1==camReturn)
    {
       QMessageBox::warning(this,tr("error"),tr("initfailed"),QMessageBox::Yes);
       m_camera->close_device();
    }
 
   camReturn = m_camera->start_capturing();                                            
   if(-1==camReturn)
    {
       QMessageBox::warning(this,tr("error"),tr("start capturefailed"),QMessageBox::Yes);
       m_camera->close_device();
    }
 
   if(-1==camReturn)
    {
       QMessageBox::warning(this,tr("error"),tr("get framefailed"),QMessageBox::Yes);
       m_camera->stop_capturing();
    }
 
   cascadeFile = haarXML;
   cascade = (CvHaarClassifierCascade *) cvLoad(cascadeFile.toUtf8());
 
   cascadeFile_profile = haarXML_profile;
   cascade_profile = (CvHaarClassifierCascade *)cvLoad(cascadeFile_profile.toUtf8());
      
   storage = cvCreateMemStorage(0);
}
 
Widget::~Widget()
{
   delete ui;
}
 
void Widget::changeEvent(QEvent *e)
{
   QWidget::changeEvent(e);
   switch (e->type())
    {
   case QEvent::LanguageChange:
       ui->retranslateUi(this);
       break;
   default:
       break;
    }
}
 
void Widget::paintEvent(QPaintEvent *)
{
   frame_count++;
   double t_0 = (double)cvGetTickCount();
 
   uchar * pImgBuf;
   unsigned int len;
   camReturn = m_camera->get_frame((void **)&pImgBuf,&len);
 
   double t_1 = (double)cvGetTickCount()-t_0;                                                       //t_get_frame        
   printf( "run t_get_frame = %gms\n",t_1/((double)cvGetTickFrequency()*1000.) );
   
   convert_yuv_to_rgb_buffer(pImgBuf,imgBuf,image_width,image_height);
   frame->loadFromData((uchar *)imgBuf,image_width * image_height * 3 *sizeof(char));
   
   static CvScalar colors[] =
    {
       {{0,0,255}},
       {{0,255,0}},
   };
   static CvSeq* face1=NULL;                                                          //记录正脸检测矩形序列           
   static CvSeq* face2=NULL;                                                          //记录侧脸检测矩形序列
   static IplImage* dst1=NULL;                                                         //
   double scale = 2.0;                                                               
 
   if(frame_count % N == 1)                                                                //N帧只Qimage转换Iplimage1帧,人脸检测1帧
   {
          
           IplImage* src = QImageToIplImage(frame);
           if (!src)
           {
              printf("imgerror!");
              return;
           }
  
           double t_4 =(double)cvGetTickCount()-t_0;                                         //t_qimage_iplimage
           printf( "run t_qimage_iplimage =%gms\n", t_4/((double)cvGetTickFrequency()*1000.) );
 
       //压缩图像
           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);
       dst1 = dst;
           cvResize(src,dst, CV_INTER_LINEAR);
 
       //RGB转为灰度图
       IplImage*gray = cvCreateImage( cvSize(dst->width,dst->height), 8, 1 );              
           IplImage* small_img = cvCreateImage(cvSize( cvRound (dst->width/scale),         
                cvRound(dst->height/scale)), 8, 1 );
           cvCvtColor( dst, gray, CV_BGR2GRAY );
           cvResize( gray, small_img,CV_INTER_LINEAR );
           cvEqualizeHist( small_img, small_img );
           cvClearMemStorage( storage );
 
       double t = (double)cvGetTickCount();                                                                       
       CvSeq* faces = cvHaarDetectObjects( small_img, cascade, storage,
                        1.3,1, 0, cvSize(40,40) );
       face1 = faces;                                                                       //记录正脸检测序列
       t = (double)cvGetTickCount() - t;
       printf( "detection t_face_frontal = %gms\n",t/((double)cvGetTickFrequency()*1000.) );        //t_face_frontal
       
      double t_profile =(double)cvGetTickCount();                                            
      CvSeq* faces_profile = cvHaarDetectObjects(small_img, cascade_profile, storage,
                        1.3,2, 0, cvSize(40,40) );
       face2 = faces_profile;                                                                   //记录侧脸检测序列
       t_profile = (double)cvGetTickCount() - t_profile;
       printf( "detection t_face_profile = %gms\n", t_profile/((double)cvGetTickFrequency()*1000.) );  //t_face_profile
 
           cvReleaseImage(&src);
       cvReleaseImage( &gray );
       cvReleaseImage( &small_img );
   }
/*  
   for( int i = 0; i < (face1 ? face1->total : 0); i++ )
        {
           CvRect* r = (CvRect*)cvGetSeqElem( face1, 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(dst1, rectP1, rectP2, colors[0], 3, 8, 0);
       }
  for( int i = 0; i < (face2 ? face2->total : 0); i++ )
       {
           CvRect* r_pro = (CvRect*)cvGetSeqElem( face2, i );
           CvPoint rectP1, rectP2;
           rectP1.x = cvRound(r_pro->x * (scale));
           rectP1.y = cvRound(r_pro->y * (scale));
           rectP2.x = cvRound((r_pro->x + r_pro->width) * (scale));
           rectP2.y = cvRound((r_pro->y + r_pro->height) * (scale));
           cvRectangle(dst1, rectP1, rectP2, colors[1], 3, 8, 0);
       }
*/   
  double t_5 = (double)cvGetTickCount()-t_0;
  printf( "run t_detect_draw = %gms\n",t_5/((double)cvGetTickFrequency()*1000.) );                    //t_detect_draw
  
       long x1,x2;
           QImage frame_dst =(*frame).scaled(image_width*1*1.5,image_height*1*1.5);                    //放大图像后显示Qiamge图像
       //每帧图像不再用原来的cvRectangle花矩形,而采用QPainter直接画矩形
       for( int i = 0; i < (face1 ? face1->total : 0); i++ )
       {
           CvRect* r = (CvRect*)cvGetSeqElem( face1, 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));
 
            x1 = rectP1.x;
            x2 = rectP2.x;
 
           printf( "x1_frontal = %ld \n", x1);
           printf( "x2_frontal = %ld \n", x2);
 
           QPainter paint(&frame_dst);
           paint.setPen(QPen(Qt::red,14,Qt::SolidLine));                           //QPainter红色矩形框
 
           if(x1>=0 && x1<=20)                                                    //以下根据横坐标调整矩形框大小
           paint.drawRect(rectP1.x*2.8,rectP1.y*2,rectP2.x*2.7,rectP2.y*2.7);
 
           if(x1>20 && x1<=40)
           paint.drawRect(rectP1.x*2.8,rectP1.y*2,rectP2.x*2.2,rectP2.y*2.7);
 
            if(x1>40 && x1<=60)
           paint.drawRect(rectP1.x*2.8,rectP1.y*2,rectP2.x*1.9,rectP2.y*2.7);
 
           if(x1>60 && x1<=80)
           paint.drawRect(rectP1.x*2.8,rectP1.y*2,rectP2.x*1.7,rectP2.y*2.7);
 
           if(x1>80)
           paint.drawRect(rectP1.x*2.8,rectP1.y*2,rectP2.x*1.5,rectP2.y*2.7);
 
           paint.end();
       }
       
     for( int i = 0; i < (face2 ?face2->total : 0); i++ )
       {
           CvRect* r_pro = (CvRect*)cvGetSeqElem( face2, i );
           CvPoint rectP1, rectP2;
           rectP1.x = cvRound(r_pro->x * (scale));
           rectP1.y = cvRound(r_pro->y * (scale));
           rectP2.x = cvRound((r_pro->x + r_pro->width) * (scale));
           rectP2.y = cvRound((r_pro->y + r_pro->height) * (scale));
  
            x1 = rectP1.x;
 
           printf( "x1_profile = %ld \n", x1);
 
           QPainter paint(&frame_dst);
           paint.setPen(QPen(Qt::green,14,Qt::SolidLine));
 
           if(x1>=0 && x1<=20)
           paint.drawRect(rectP1.x*2.8,rectP1.y*2,rectP2.x*2.6,rectP2.y*2.7);
 
           if(x1>20 && x1<=40)
           paint.drawRect(rectP1.x*2.8,rectP1.y*2,rectP2.x*2.2,rectP2.y*2.7);
 
           if(x1>40 && x1<=60)
           paint.drawRect(rectP1.x*2.8,rectP1.y*2,rectP2.x*2,rectP2.y*2.7);
 
           if(x1>60 && x1<=80)
           paint.drawRect(rectP1.x*2.9,rectP1.y*2,rectP2.x*1.8,rectP2.y*2.7);
 
           //if(x1>80)
           //paint.drawRect(rectP1.x*2.8,rectP1.y*2,rectP2.x*1.5,rectP2.y*2.7);
 
           paint.end();
       }
 
           ui->m_imgLabel->setPixmap(QPixmap::fromImage(frame_dst));                                   //显示
 
   camReturn = m_camera->unget_frame();
   double t_7 = (double)cvGetTickCount()-t_0;
   printf( "run t_all = %gms\n\n",t_7/((double)cvGetTickFrequency()*1000.) );                       //t_all
}
 
void Widget::display_error(QString err)
{
   QMessageBox::warning(this,tr("error"), err,QMessageBox::Yes);
}
 
intWidget::convert_yuv_to_rgb_buffer(unsigned char *yuv, unsigned char *rgb,unsigned int width, unsigned int height)
{
 unsigned int in, out = 0;
 unsigned int pixel_16;
 unsigned char pixel_24[3];
 unsigned int pixel32;
 inty0, u, y1, v;
 for(in = 0; in < width * height * 2; in +=4) {
 pixel_16 =
  yuv[in + 3] << 24 |
  yuv[in + 2] << 16 |
  yuv[in + 1] <<  8 |
  yuv[in + 0];
  y0= (pixel_16 & 0x000000ff);
 u  = (pixel_16 & 0x0000ff00)>>  8;
  y1= (pixel_16 & 0x00ff0000) >> 16;
 v  = (pixel_16 & 0xff000000)>> 24;
 pixel32 = convert_yuv_to_rgb_pixel(y0, u, v);
 pixel_24[0] = (pixel32 & 0x000000ff);
 pixel_24[1] = (pixel32 & 0x0000ff00) >> 8;
 pixel_24[2] = (pixel32 & 0x00ff0000) >> 16;
 rgb[out++] = pixel_24[0];
 rgb[out++] = pixel_24[1];
 rgb[out++] = pixel_24[2];
 pixel32 = convert_yuv_to_rgb_pixel(y1, u, v);
 pixel_24[0] = (pixel32 & 0x000000ff);
 pixel_24[1] = (pixel32 & 0x0000ff00) >> 8;
 pixel_24[2] = (pixel32 & 0x00ff0000) >> 16;
 rgb[out++] = pixel_24[0];
 rgb[out++] = pixel_24[1];
 rgb[out++] = pixel_24[2];
 }
 return 0;
}
 
int Widget::convert_yuv_to_rgb_pixel(int y,int u, int v)
{
 unsigned int pixel32 = 0;
 unsigned char *pixel = (unsigned char*)&pixel32;
 intr, g, b;
 r =y + (1.370705 * (v-128));
 g =y - (0.698001 * (v-128)) - (0.337633 * (u-128));
 b =y + (1.732446 * (u-128));
 if(r> 255) r = 255;
 if(g> 255) g = 255;
 if(b> 255) b = 255;
 if(r< 0) r = 0;
 if(g< 0) g = 0;
 if(b< 0) b = 0;
 pixel[0] = r * 220 / 256;
 pixel[1] = g * 220 / 256;
 pixel[2] = b * 220 / 256;
 return pixel32;
}
 
 
 
IplImage* Widget::QImageToIplImage(constQImage * qImage)
{
   int width = qImage->width();
    intheight = qImage->height();
   CvSize Size;
   Size.height = height;
   Size.width = width;
   IplImage *IplImageBuffer = cvCreateImage(Size, IPL_DEPTH_8U, 3);
   
   for (int y = 0; y < (int)(height); y++)
    {
       for (int x = 0; x < (int)(width); x++)
       {
              QRgb rgb = qImage->pixel(x, y);
               cvSet2D(IplImageBuffer, y, x,CV_RGB(qRed(rgb), qGreen(rgb), qBlue(rgb)));
       }
    }
   return IplImageBuffer;
}

代码下载:http://download.csdn.net/detail/u012906122/7408591

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值