第四章:
4.1 mat类的内容
一、基础知识
Mat: mat类的名称是从矩阵借用来的,是个n维数组。
灰度值:单通道,最小为0(黑色),最大为255(白色)
RGB:彩色图,三通道,每个像素点是三个值,对应红、绿、蓝
二、构造函数、属性与方法
创建一个10*10矩阵,每个元素有一个单通道8为无符号整数
Mat matrix(10, 10, CV_8UC(1));
创建相同的矩阵,并用0值初始化
Mat matrix(10, 10, CV_8UC(1), Scalar(0));
第三个参数是将类型,统计数,通道数统一到一个宏里面
CV_<bits><type>C(<channels>)
CV_ 8 U C(1) //当通道数为1的时候可以省略第三个参数
<bits>: 8、16有无符号的整数 32有无符号的整数和福电视 64有无符号的浮点数
<type>:U 无符号整数 S有符号整数 F:有符号浮点数
<channels>:通道数 一般不超过4 RGBA
创建一个立方体,变成边长为10,双精度(64)的双通道元素,初始化值为1.0
int sizes[] = {10, 10, 10};
Mat cube(3, sizes, CV_64FC(2), Scalar::all(1.0));
//还可以使用 create方法更改类型大小
Mat matrix;
matrix.create(10, 10, CV_8UC(1));
也可以使用一个Mat类的一部分,创建另一个Mat类,例如以一个图像的(25,25)为起点创建一个50*50像素的正方形RIO Mat类(RIO 感兴趣区域,Region of Interest)
Mat roi(image, Rect(25, 25, 50, 50)) //左上角是 (0,0)
//创建该区域会影响到原本的图像,因为没有复制图像
Mat imageCopy = image.clone();
可以直接通过赋值来改变颜色
Mat rio(image,Rect(500, 138, 63, 65));
roi = Scalar(0); //全变成黑色
还可以选择单行单列,多行多列
//单行单列
Mat r = image.row(0) //first row
Mat c = image.column //first column
//多行多列
Mat centraRows = image.rowRange(image.rows/2-10, image.rows/2+10)
Mat centraColumns = image.columnRange(image.cols/2-10, image.cols/2+10)
centraRows = Scalar(0);
centraColumns = Scalar(0);
使用locateROI函数来获取父图像的大小以及父图像内ROI的左上角位置
Mat centraRows = image.rowRange(image.rows/2-10, image.rows/2+10);
Size parentSize;
Point offset;
centraRows.locateROI(parentSize,offset);
int parentWidth = parentSize.width;
int parentHeight = parentSize.height;
int x = offset.x;
int y = offset.y;
Mat类还包含许多信息属性和函数:
depth、channel、type、cols、rows、elemSize、elemSize1(不考虑通道数,例如三通道要除以3)、empty、isContinuous、isSubmatrix(判断是不是子矩阵)、total、step、at(函数模板)、begin和end、forEach、adjustROI、clone、converTo、copyTo、ptr、release、reserve、reserveBuffer、reshape、resize、setTo、cross、diag、dot、eye、inv、ones、t、zeros。
特别注意"at" 假如image是CV_8UC(3)类型则可以用以下代码访问(x,y)处的像素:
image.at<Vec3b>(x,y) = c //把颜色改为c
//也可以使用typedef创建命名自己的Vec类型
typedef Vec<Type,c> NewType
typedef Vec<quint8,3> QCvVec3B
用四种方法实现一样的效果,将每个像素点的值除以5:
//法一
for(int i = 0; i < image.rows; i++)
{
for(int j = 0; j<image.cols; j++)
{
image.at<Vec3b>(i, j) /= 5;
}
}
//法二
MatIterator_<Vec3b> it_begin = image.begin<Vec3b>();
MatIterator_<Vec3b> it_end = image.end<Vec3b>();
for(; it_begin!= it_end;it_begin++)
{
*it_begin /= 5;
}
//法三 forEach(与Iambda一起用)
image.forEach<Vec3b>([](Vec3b &p, const int *))
{
p /= 5;
}//法四
Mat darkerImage = image / 5;
三、Mat_<_TP>类
这段代码创建了一个原始图像image的拷贝,并将拷贝中(10, 10)
位置的像素设置为黑色。
Mat_<Vec3b> imageCopy(image);
imageCopy(10, 10) = Vec3b(0,0,0);
四、Mat_<_TP,m,n>
五、UMat类
Mat与UMat类之间的转化用到两个函数,还会用到访问标志例如 ACCESS_READ等等。
Mat::getUMat
Umat::getMat
4.2 利用OpenCV读取图像
前文使用了imread函数从磁盘读取图像例如以下代码
Mat image = imread("c:/dev/test.jpg", IMREAD_GRAYSCALE | IMREAD_IGNORE_ORIENTATION);
第二个参数意思是加载为灰度图且忽略掉图像文件的EXIT数据中的朝向部分(这些图像可能包含EXIF(Exchangeable Image File Format)元数据,这些元数据描述了如何正确显示图像,包括方向)。
4.3 利用OpenCV写入图像
imwrite("c:/dev/test.jpg",image, params);
4.4 利用OpenCV视频读写
使用 VideoCapture类
4.5 QImage类
QImage image(320, 240 QImage::Format_RGB888);
//或者
QImage image(QSize(320, 240), QImage::Format_RGB888);
注意QImage类和Mat类的数据格式不一样,QImage类是RGB,而OpenCV的Mat类是BGR,
因此要先转换数据格式。
Mat mat = imread("c:/dev/test.jpg"); //RGB
cvtColor(mat, mat, CV_BGR2RGB); //交换红蓝通道数据
QImage image(mat.data,
mat.cols,
mat.rows,
mat.step,
QImage::Format_RGB888);
4.6 QPixmap类
与QImage类相似,但是当想要将图片在屏幕上展示,就需要用到QPixmap类,两个重要函数:
convertFromImage:将QImage的图片填充QPixmap
fromImage: 一个静态函数功能和convertFromImage一致
4.7 QPainter类
QPainter类可以在包括Qt空间在内的任何可以可视化显示的对象上进行绘制
4.7 QT中的视频和相机处理
要在pro文件中加入 QT += multimedia 确保多媒体模块可使用,部分多媒体模块如下:
QCamera、QCameraInfo、QMediaPlayer、QMediaRecorder、QVideoFrame、QVideoProbe、QVideoWidget。