您的位置:首页 > 编程语言 > Qt开发

openCV图片显示到Qt控件QLabel

2017-08-16 15:49 585 查看
初入坑openCV,记录学习收获,如有错误还望指正。

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

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

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

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

unix|win32: LIBS += -L$$PWD/../../Java/OpenCV3.2/install/x86/mingw/lib/ -llibopencv_imgproc320.dll
unix|win32: LIBS += -L$$PWD/../../Java/OpenCV3.2/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 = 0);
~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=0;i<height;i++)
{
unsigned char *ptr = img.ptr<unsigned char>(i);
//unsigned char *ptr = img.ptr<unsigned char>(i)[0];
for(j=0;j<width*3;j+=3)
{
Image->bits()[(Image->bytesPerLine()*i)+(j+2)] =  ptr[j+2];
Image->bits()[(Image->bytesPerLine()*i)+(j+1)] =  ptr[j+1];
Image->bits()[(Image->bytesPerLine()*i)+(j)] = ptr[j];
}
}

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

}

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


这次需要显示的图片



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

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

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



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=0;i<height;i++)
{
unsigned char *ptr = img.ptr<unsigned char>(i);
for(j=0;j<width;j++)
{
((uchar*)testdata->Image->bits())[(width*4*i)+(j*4)] =  ptr[j];
((uchar*)testdata->Image->bits())[(width*4*i)+(j*4+1)] =  ptr[j];
((uchar*)testdata->Image->bits())[(width*4*i)+(j*4+2)] = ptr[j];
((uchar*)testdata->Image->bits())[(width*4*i)+(j*4+3)] = 255;
}
}


有三点不同之处:①计算图片宽度的字节数可以直接用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,默认读取彩色图片。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: