Zedboardwebcam设计问题篇(五)opencv处理帧数据,函数代码实现

有过之前的那次碰壁之后,不敢在费时间编译OpenCV了,不过还是一直关注这个问题,openhw论坛中也有人遇到这个问题了,有的人解决了,不过我的情况还是比他的复杂。

这里我把他的贴出来,算是一个方法把。不过我还是继续往下走了,因为摄像头已经打开了。他的博客:http://www.openhw.org/wicoboy/blog/13-04/293302_71692.html

我今天的主题时opencv处理图像,以及QT界面设计。

根据之前做过的例子,主要在paintEvent中进行图像的显示。现在我的思路时将QImage转为OpenCV能够处理的Mat/IplImage/Array的形式,利用OpenCV库进行图像的处理。

void Widget::paintEvent(QPaintEvent *)
{
    rs = vd->get_frame((void **)&p,&len);
    //IplImage* img = NULL;
    //IplImage* cannyImg = NULL;
    //CvArr* Cvframe;
    convert_yuv_to_rgb_buffer(p,pp,640,480);
    frame->loadFromData((uchar *)pp,/*len*/640 * 480 * 3 * sizeof(char));
    ui->label->setPixmap(QPixmap::fromImage(*frame,Qt::AutoColor));
    //Mat cvframe=qimage2mat(*frame);
    //cannyImg = cvCreateImage( cvGetSize( cvframe ), IPL_DEPTH_8U, 1 );
    //cvConvertImage(cvframe,cannyImg,0);
    //Mat mtx(cvframe);
    //Canny(cvframe,cvframe, 50, 150, 3);
    //IplImage* cvframe=mtx;
    //*frame=mat2qimage(cvframe);
    ui->label_2->setPixmap(QPixmap::fromImage(*frame,Qt::AutoColor));
    ui->label_3->setPixmap(QPixmap::fromImage(*frame,Qt::AutoColor));
    ui->label_4->setPixmap(QPixmap::fromImage(*frame,Qt::AutoColor));
    rs = vd->unget_frame();

}

要进行图像转换,必须要了解QImage,IplImage,Mat,Arrary的图像结构和要素吧。

Qt提供了4个图像处理的类:QImage,QPixmap,QBitmap和QPicture;QImage优化了I/O操作,可直接存取操纵像素,QImage支持单色,8位,32位和Alpha混合格式。

使用QImage构造函数,load函数,loadFromData几种方法。loadFromData((uchar *)pp,/*len*/640 * 480 * 3 * sizeof(char));

关于Mat数据格式我看了这篇博客,写的到位:http://blog.csdn.net/yang_xian521/article/details/7107786

Mat的矩阵结构其实在书里面也写的很清楚了,

    <span style="font-size: medium;">typedef struct CvMat  
    {  
        int type;  
        int step;  
      
        /* for internal use only */  
        int* refcount;  
        int hdr_refcount;  
      
        union  
        {  
            uchar* ptr;  
            short* s;  
            int* i;  
            float* fl;  
            double* db;  
        } data;  
      
    #ifdef __cplusplus  
        union  
        {  
            int rows;  
            int height;  
        };  
      
        union  
        {  
            int cols;  
            int width;  
        };  
    #else  
        int rows;  
        int cols;  
    #endif  
      
    }  
    CvMat;</span>  

主要分为两部分了,一个矩阵头,一个数据data;操作方法在上面的博客中讲的非常好。

关于IplImage:

在类型关系上,我们可以说IplImage类型继承自CvMat类型,当然还包括其他的变量将之解析成图像数据。

    <span style="font-size: medium;">typedef struct _IplImage  
    {  
        int  nSize;             /* sizeof(IplImage) */  
        int  ID;                /* version (=0)*/  
        int  nChannels;         /* Most of OpenCV functions support 1,2,3 or 4 channels */  
        int  alphaChannel;      /* Ignored by OpenCV */  
        int  depth;             /* Pixel depth in bits: IPL_DEPTH_8U, IPL_DEPTH_8S, IPL_DEPTH_16S, 
                                   IPL_DEPTH_32S, IPL_DEPTH_32F and IPL_DEPTH_64F are supported.  */  
        char colorModel[4];     /* Ignored by OpenCV */  
        char channelSeq[4];     /* ditto */  
        int  dataOrder;         /* 0 - interleaved color channels, 1 - separate color channels. 
                                   cvCreateImage can only create interleaved images */  
        int  origin;            /* 0 - top-left origin, 
                                   1 - bottom-left origin (Windows bitmaps style).  */  
        int  align;             /* Alignment of image rows (4 or 8). 
                                   OpenCV ignores it and uses widthStep instead.    */  
        int  width;             /* Image width in pixels.                           */  
        int  height;            /* Image height in pixels.                          */  
        struct _IplROI *roi;    /* Image ROI. If NULL, the whole image is selected. */  
        struct _IplImage *maskROI;      /* Must be NULL. */  
        void  *imageId;                 /* "           " */  
        struct _IplTileInfo *tileInfo;  /* "           " */  
        int  imageSize;         /* Image data size in bytes 
                                   (==image->height*image->widthStep 
                                   in case of interleaved data)*/  
        char *imageData;        /* Pointer to aligned image data.         */  
        int  widthStep;         /* Size of aligned image row in bytes.    */  
        int  BorderMode[4];     /* Ignored by OpenCV.                     */  
        int  BorderConst[4];    /* Ditto.                                 */  
        char *imageDataOrigin;  /* Pointer to very origin of image data 
                                   (not necessarily aligned) - 
                                   needed for correct deallocation */  
    }  
    IplImage;</span>  

下面就是要进行QImage和OpenCV图像格式的转换,以及OpenCV和QImage图像格式的转换,图像格式清楚了,转换也就方便了。刚开始我用了下面两个函数:

/*QImage *Widget::IplImageToQImage(const IplImage *img)//change IplImage to QImage
{
    QImage *image;
 //   cvCvtColor(img,img,CV_BGR2RGB);
    //Mat mtx(img);
    //cv::cvtColor(mtx,mtx,CV_BGR2RGB);
    uchar *imgData=(uchar *)img->imageData;
    image=new QImage(imgData,img->width,img->height,QImage::Format_RGB888);
    return image;
}*/

/*IplImage *Widget::QImageToIplImage(const QImage * qImage)//change QImage to IplImage
{
    int width = qImage->width();
    int height = qImage->height();
    CvSize Size;
    Size.height = height;
    Size.width = width;
    IplImage *IplImageBuffer = cvCreateImage(Size, IPL_DEPTH_8U, 3);
    for (int y = 0; y < height; ++y)
    {
        for (int x = 0; x < width; ++x)
        {
            QRgb rgb = qImage->pixel(x, y);
            cvSet2D(IplImageBuffer, y, x, CV_RGB(qRed(rgb), qGreen(rgb), qBlue(rgb)));
        }
    }
    return IplImageBuffer;
}*/

但是,IplImage的图像格式好多函数用不了,比如我用了cvtColor,Canny,发现一直是这样的错误:

: 错误:invalid initialization of reference of type 'cv::InputArray {aka const cv::_InputArray&}' from expression of type 'const IplImage* {aka const _IplImage*}'

一顿搜,发现这个错误是类型问题,才知道跟OpenCV版本有关系啊,

旧版本的OpenCV中的C结构体有 CvMat 和 CvMatND,目前我用的是 2.3.1版,里面的文档指出 CvMat 和 CvMatND 弃用了,在C++封装中用 Mat 代替,另外旧版还有一个 IplImage,同样用 Mat 代替;

然后发现我用的两个函数原型时这样的:

//! applies Canny edge detector and produces the edge map.
CV_EXPORTS_W void Canny( InputArray image, OutputArray edges,
                         double threshold1, double threshold2,
                         int apertureSize=3, bool L2gradient=false );
//! converts image from one color space to another
CV_EXPORTS_W void cvtColor( InputArray src, OutputArray dst, int code, int dstCn=0 );

InputArray和IplImage显然不是同一种数据图像格式,而且强制转换在程序执行时出现了:segmentation fault;

所以我采用QImage和Mat相互转换来进行图像处理;

QImage Widget::mat2qimage(const Mat& mat)
{
      Mat rgb;
      cvtColor(mat, rgb, CV_BGR2RGB);
      return QImage((const unsigned char*)(rgb.data), rgb.cols, rgb.rows, QImage::Format_RGB888);
}
Mat Widget::qimage2mat(const QImage& qimage)
{
      cv::Mat mat = cv::Mat(qimage.height(), qimage.width(), CV_8UC4, (uchar*)qimage.bits(), qimage.bytesPerLine());
      cv::Mat mat2 = cv::Mat(mat.rows, mat.cols, CV_8UC3 );
      int from_to[] = { 0,0, 1,1, 2,2 };
      cv::mixChannels( &mat, 1, &mat2, 1, from_to, 3 );
      return mat2;
}

编译很顺利通过了,但是在Zed板子上执行出错了:

OpenCV Error: Assertion failed (scn == 3 || scn == 4) in cvtColor, file /home/j4
terminate called after throwing an instance of 'cv::Exception'                  
  what():  /home/jiong/opencv-2.4.5/modules/imgproc/src/color.cpp:3414: error: r                                                                             
Aborted

看到错误实在cvtColor这里出现的,那就又有可能时cvtColor的参数不对了,回去再看这两个图像的格式。

其实,格式转换无非就是找到格式间参数的对应关系:

             QImage               Mat

数据指针  uchar* bits()       uchar* data

宽度        int width()          int cols

高度        int height()         int rows

步长      int bytesPerLine()   cols * elemeSize()

格式      Format_Indexed8      8UC1, GRAY,灰度图

            Format_RGB888        8UC3, BGR, 需要通过mixChannels进行顺序调换

            Format_ARGB32        8UC4, BGRA,需要通过mixChannels进行顺序调换

         以此类推,只要保证通道数以及排列顺序一致即可。

发现Canny(cvframe,cvframe, 50, 150, 3);这一句输入输出都是单通道的,所以对于输出的图像进行修改cv::cvtColor(cvframe, cvframe, CV_GRAY2RGB);

果然错误消失了,出现图像了,可惜边缘检测后出现了4个重叠的图像,很是郁闷!

 

初步设计如下界面:

 

 今天先到这里了,又要去看论文了!

原文地址:https://www.cnblogs.com/preorder69/p/3026974.html