天天看点

openCV图片显示到Qt控件QLabel

初入坑openCV,记录学习收获,如有错误还望指正。

关于Qt中配置openCV不再累述,在编程之前要加入外部库,首先在.pro中加入

INCLUDEPATH += $$PWD/../../Java/OpenCV3/install/include
DEPENDPATH += $$PWD/../../Java/OpenCV3/install/include

unix|win32: LIBS += -L$$PWD/../../Java/OpenCV3/install/x86/mingw/lib/ -llibopencv_core320.dll

unix|win32: LIBS += -L$$PWD/../../Java/OpenCV3/install/x86/mingw/lib/ -llibopencv_highgui320.dll

unix|win32: LIBS += -L$$PWD/../../Java/OpenCV3/install/x86/mingw/lib/ -llibopencv_imgproc320.dll
unix|win32: LIBS += -L$$PWD/../../Java/OpenCV3/install/x86/mingw/lib/ -llibopencv_imgcodecs320.dll
           

注意具体的地址要依照储存位置而定。

依照惯例先贴代码

mattoimage.h

#ifndef MATTOIMAGE_H
#define MATTOIMAGE_H

#include <QMainWindow>
#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgcodecs/imgcodecs.hpp"

namespace Ui {
class matToImage;
}

using namespace cv;

class matToImage : public QMainWindow
{
    Q_OBJECT

public:
    explicit matToImage(QWidget *parent = );
    ~matToImage();

private:
    Ui::matToImage *ui;
};

#endif // MATTOIMAGE_H
           

有两点需要注意需要加入命名空间CV,注意加入openCV2所需的头文件。

mattoimage.cpp

#include <QImage>
#include <QPixmap>
#include "mattoimage.h"
#include "ui_mattoimage.h"

matToImage::matToImage(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::matToImage)
{
    ui->setupUi(this);
    Mat img = imread("D:\\QTproject\\matToImage\\pic\\timg.jpg");
    int width=img.cols;
    int height=img.rows;
    int i,j;
    QImage *Image = new QImage(width,height,QImage::Format_RGB888);
    for(i=;i<height;i++)
    {
        unsigned char *ptr = img.ptr<unsigned char>(i);
        //unsigned char *ptr = img.ptr<unsigned char>(i)[0];
        for(j=;j<width*;j+=)
        {
            Image->bits()[(Image->bytesPerLine()*i)+(j+)] =  ptr[j+];
            Image->bits()[(Image->bytesPerLine()*i)+(j+)] =  ptr[j+];
            Image->bits()[(Image->bytesPerLine()*i)+(j)] = ptr[j];
        }
    }

    ui->imageLabel->setPixmap(QPixmap::fromImage(*Image).scaled(ui->imageLabel->size()));

}

matToImage::~matToImage()
{
    delete ui;
}
           

这次需要显示的图片

openCV图片显示到Qt控件QLabel

24位3通道彩图,需要从文件读取为Mat类型的图片,后转化为QImage类型显示到QLabel中。

注意Mat图有行和列,即cv::Mat中有公有成员变量cols和rows,注意,这里的cols就是图像的宽度width,rows就是图像的高度height。此处用int型保存下来。

声明一个QImage用于接收Mat类型,

openCV图片显示到Qt控件QLabel
QImage *Image = new QImage(width,height,QImage::Format_RGB888);
           

确定了宽和高以及类型为24位RGB图片。双重循环将Mat矩阵的像素信息一一赋值给QImage。

注意这里先行后列的循环顺序,我们意想中的点阵储存是有行有列的二维形式,其实在计算机内存中,是将其以一维的形式,4的整倍数字节储存的。因此即使我们先列后行的储存,计算机也是一次读取一行,然后给你返回第二行同一列的元素。

unsigned char *ptr = img.ptr<unsigned char>(i);
           

这是一个模板类函数,将第i行的地址指针传给ptr,此时的ptr就是储存着第i行元素的首地址指针。由于该图片是24位3通道,即每三个字节去储存一个像素信息。bit()函数得到Image图片的首地址,bytesPerLine()函数得到一张图片每一行的字节数,乘以行数i,得到当前所需要遍历的行的首地址。然后每次3字节依次将Mat中颜色信息储存到Image中。

如果是32位4通道图片,就不需要使用bytesPerLine()去得出图片的宽度。比如下面的例子储存一个32位4通道的灰度图片。

for(i=;i<height;i++)
        {
            unsigned char *ptr = img.ptr<unsigned char>(i);
            for(j=;j<width;j++)
            {
                ((uchar*)testdata->Image->bits())[(width*4*i)+(j*4)] =  ptr[j];
                ((uchar*)testdata->Image->bits())[(width*4*i)+(j*4+)] =  ptr[j];
                ((uchar*)testdata->Image->bits())[(width*4*i)+(j*4+)] = ptr[j];
                ((uchar*)testdata->Image->bits())[(width*4*i)+(j*4+)] = ;
            }
        }
           

有三点不同之处:①计算图片宽度的字节数可以直接用width*4,但在24位的图片中这只是理论的宽度,实际上计算机每一行的字节数都是4的整倍数,用每3字节去储存一个像素,在换行时若需要内存对齐,会用空格去补全。②4通道不同于3通道,会用一个字节去储存该像素透明度的问题,用0-1或0-255去表述透明度,此处默认透明度为255。③灰度图片不同于RGB图片,前三位的值都是相同。

此处只做教学之用,以后在需要用到图片宽度时,都只用bytesPerLine(),这样更保险。

最后说一下imread()函数。

函数原型:

Mat imread( const String& filename, int flags = IMREAD_COLOR );

第一个参数是图片的绝对地址

第二个参数表示图片读入的方式(flags可以缺省,缺省时flags=1,表示以彩色图片方式读入图片)

flags>0时表示以彩色方式读入图片

flags=0时表示以灰度图方式读入图片

flags<0时表示以图片的本来的格式读入图片

此处缺省flags,默认读取彩色图片。