• 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个重叠的图像,很是郁闷!

     

    初步设计如下界面:

     

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

  • 相关阅读:
    KindEditor-编辑器配置参数属性
    泛型作为返回类型的写法
    ObservableCollection<T> 类
    常遇到的问题
    实现跨浏览器html5表单验证
    mysql 密码重置
    Web用户的身份验证及WebApi权限验证流程的设计和实现
    Discuz3.2 新用户插入数据库SQL
    3. 深入研究 UCenter API 之 加密与解密(转载)
    window.open实现模式窗口
  • 原文地址:https://www.cnblogs.com/preorder69/p/3026974.html
Copyright © 2020-2023  润新知