Mat 简介:#####

Mat 用于管理图像在内存中的存储,在Opencv 3 中由于使用了内存自动管理机制,所以不必像最早的Opencv一样需要手动分配和释放内存空间,Mat是由两个部分组成的。一个图像数据矩阵头包括(矩阵尺寸、存储方法、存储地址等信息),另一个是指向存储图像所有像素值的矩阵空间的指针。
这样设计是由于一般图像数据都是比较大的,并且很多时候都是需要经过多个不同的函数处理,这就导致了需要在不同的函数间传递这个大数据结构,除非万不得已不会选择去传递比较大的Mat。所以Opencv设计了这种结构来完成Mat的快速传递,Mat矩阵头是一个常数值,而矩阵保存了图像所有的像素值,这部分通常会比矩阵头大几个数量级,在函数间传递参数的时候每个Mat都有自己的信息头,但是矩阵数据是共享的,也就是在传递Mat时,只复制矩阵头和指向矩阵的指针。

在Mat的实现中使用了引用计数机制,每次Mat对象的信息头被复制了,都会增加矩阵的引用次数加1;反之,当一个Mat的信息头被释放后,引用计数就会被减1;当计数被减到0时,矩阵就会被释放。

上述的方式我们可以知道这种情况下矩阵数据是共享的,任何一个函数改动都会影响到这个矩阵,但是有时候我们需要独立的矩阵空间,这时候可以使用clone和 copyTo。通过clone和copyTo创建的Mat,都有自己的矩阵,修改其中一个的矩阵不会对其他的造成影响。

Mat 属性:#####

data uchar型的指针。就是上面提到的指向矩阵数据的指针。
dims 矩阵的维度
rows 矩阵的行数
cols 矩阵的列数
size 矩阵的大小
channels 矩阵元素通道数

type
命名规则为CV_(位数)+(数据类型)+(通道数)。具体的有以下值:它表示的是每个像素的元素的存储方式
CV_8UC1 CV_8UC2 CV_8UC3 CV_8UC4
CV_8SC1 CV_8SC2 CV_8SC3 CV_8SC4 …

depth 色彩深度
depth 的类型如下所示:
CV_8U CV_8S CV_16U CV_16S CV_32S CV_32F CV_64F
elemSize
矩阵一个元素占用的字节数
elemSize1
矩阵元素一个通道占用的字节数

Mat 创建和初始化:#####
cv::Mat img(20,20,CV_8UC3,cv::Scalar(255,255,255));

上述代码创建了一个20行20列的矩阵,矩阵元素使用8位无符号char类型保存,具有3通道,每个像素的初始值是(255,255,255)黑色,这里需要注意Scalar的表示顺序为BGR
构造函数的前两个参数指定了矩阵的行和列
第三个参数指定矩阵元素的数据类型以及通道数,其指定规则如下:

img.create(20,20,CV_8UC(3));
该方法不能为矩阵设置初始值

特殊矩阵的创建:

cv::Mat e = cv::Mat::eye(20,20,CV_64F); 对角矩阵
cv::Mat z = cv::Mat::ones(20,20,CV_32F); 单位矩阵
cv::Mat o = cv::Mat::zeros(20,20,CV_8UC3); 零矩阵

小矩阵的创建:
一些如核等小矩阵的创建还可以使用如下方式:

Mat c =(Mat_<double>(3,3)<<1,0,0,0,1,0,0,0,1);
矩阵的直观表示:#####

颜色空间缩减:#####

将现有的颜色空间进行映射,以获得较少的颜色数,目的是为了加快部分算法的处理速度

矩阵的遍历:#####
#include <QCoreApplication>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>

void changeImageUsePointer(cv::Mat& sourceImage,cv::Mat& dstImage,uchar radio) {

dstImage = sourceImage.clone();
int rows = dstImage.rows;
int cols = dstImage.cols * dstImage.channels();
for(int rowindex = 0 ;rowindex < rows ;rowindex++) {
uchar *element = dstImage.ptr<uchar>(rowindex);
for(int colindex = 0; colindex < cols;colindex++) {
element[colindex] = static_cast<uchar>(element[colindex]/radio)*radio;
}
}
}

void changeImageByIterator(cv::Mat& sourceImage,cv::Mat& dstImage,uchar radio) {
dstImage = sourceImage.clone();
cv::MatIterator_<cv::Vec3b> beginIterator = dstImage.begin<cv::Vec3b>();
cv::MatIterator_<cv::Vec3b> endIterator = dstImage.end<cv::Vec3b>();
cv::MatIterator_<cv::Vec3b> iterator;
for(iterator = beginIterator ;iterator != endIterator; ++iterator) {
(*iterator)[0] = ((*iterator)[0]/radio)*radio;
(*iterator)[1] = ((*iterator)[1]/radio)*radio;
(*iterator)[2] = ((*iterator)[2]/radio)*radio;
}
}

void changeImageByLocation(cv::Mat& sourceImage,cv::Mat& dstImage,uchar radio) {
dstImage = sourceImage.clone();
int cols = dstImage.cols;
int rows = dstImage.rows;

for(int row = 0;row < rows;row++) {
for(int col = 0;col < cols;col++) {
uchar b = dstImage.at<cv::Vec3b>(row,col)[0];
dstImage.at<cv::Vec3b>(row,col)[0] = (b/radio)*radio;

uchar g = dstImage.at<cv::Vec3b>(row,col)[1];
dstImage.at<cv::Vec3b>(row,col)[1] = (g/radio)*radio;

uchar r = dstImage.at<cv::Vec3b>(row,col)[2];
dstImage.at<cv::Vec3b>(row,col)[2] = (b/radio)*radio;
}
}
}
int const PROCESS_TIME = 10;
int const COLOR_REDUCE = 10;
int main(int argc, char *argv[]) {

cv::Mat srcImage = cv::imread("/home/jimmy/QtOpenCV/image/test_access.png");
if(!srcImage.data) {
return -1;
}
cv::Mat dstImage;
dstImage.create(srcImage.rows,srcImage.cols,srcImage.type());

int64 startTime = cv::getTickCount();
for(int i = 0;i< PROCESS_TIME; i++) {
changeImageUsePointer(srcImage,dstImage,COLOR_REDUCE);
}
int64 endTime = cv::getTickCount();
qDebug("Consume Time by Pointer= %f",(endTime-startTime)/cv::getTickFrequency()/PROCESS_TIME);

startTime = cv::getTickCount();
for(int i = 0;i< PROCESS_TIME; i++) {
changeImageByIterator(srcImage,dstImage,COLOR_REDUCE);
}
endTime = cv::getTickCount();
qDebug("Consume Time by Pointer= %f",(endTime-startTime)/cv::getTickFrequency()/PROCESS_TIME);

startTime = cv::getTickCount();
for(int i = 0;i< PROCESS_TIME; i++) {
changeImageByLocation(srcImage,dstImage,COLOR_REDUCE);
}
endTime = cv::getTickCount();
qDebug("Consume Time by Pointer= %f",(endTime-startTime)/cv::getTickFrequency()/PROCESS_TIME);

cv::namedWindow("Test Access SRC");
cv::namedWindow("Test Access Dest");
cv::imshow("Test Access SRC",srcImage);
cv::imshow("Test Access Dest",dstImage);
int keycode = cv::waitKey(0);
if(keycode == 27) {
cv::destroyAllWindows();
}
}
Contents
  1. 1. Mat 简介:#####
  2. 2. Mat 属性:#####
  3. 3. Mat 创建和初始化:#####
  4. 4. 矩阵的直观表示:#####
  5. 5. 颜色空间缩减:#####
  6. 6. 矩阵的遍历:#####