初入坑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
#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(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*ptr = img.ptr(i);
for(j=0;j*)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,默认读取彩色图片。