1、图像读取与Mat初始化
-1 表示原始格式(对于彩色图像就是BGR), 0 表示灰度图,1表示BGR图像
除了读取图像的方式外还可以通过Mat::zeros, Mat::ones, Mat::eye等函数初始化Mat
string path= "image.jpg";
cv::Mat m= imread(path, -1);
cv::Mat m2=Mat::zeros(m.rows, m.cols, CV_8UC1);
2、类型转换
只会改变Mat的数据类型,并不会改变mat的值。imread加载的mat均为CV_8UC3格式,8表示8位(此外还有16位,32位,64位),U表示无符号整数(此外还有短整型S,浮点数F),C3表示3个通道(此外还有一通道C1,二通道C2,四通道C4,n通道C(n))
可以通过mat.type()来获取类型信息
m.convertTo(m, CV_32FC3);
int dtype = m.type();//dtype==CV_32FC3
opencv中的数据类型具体如下所示
3、色彩空间转换
共有HSV,LAB,XYZ、Luv等等色彩空间可以转换。
色彩空间转换后请注意查看目标mat的值域与理论值域是否相对应,如果不对应则转换原mat的数据类型,如CV_32FC3【该类型下的BRG图像的最大值应该为1】、CV_8UC1【该类型下的BRG图像的最大值应该为255】
cv::Mat hsv;
cv::cvtColor(m/255, hsv, cv::COLOR_BGR2HSV);
4、数学运算
cv::Mat间可以进行加减乘除运算,其运算方式与正常变量无二异
在运算时最好将mat类型转换为64位float,这样子可以避免运算结果溢出带来不必要的麻烦。如:在CV_8UC1的类型下1-255=254(减法只是表示数值的距离)
cv::Mat mat9 = cv::Mat::ones(9, 9, CV_16FC1)*9;
cv::Mat mat2 = cv::Mat::ones(9, 9, CV_16FC1)*2;
cv::Mat result_18 = mat2.mul(mat9);//逐像素值相乘,得到的还是一个矩阵
cv::Mat resutl_7=mat9-mat2;
cv::Mat resutl_11=mat9+mat2;
cv::Mat resutl_4_5=mat9/mat2;
5、Mat通道的分离与合并
多通道Mat分离为vector<Mat>数组,vector<Mat>数组可以合并为多通道Mat
//分割lab三通道mat为包含三个单通道的vector
vector<cv::Mat> mv;
cv::split(lab, mv);
mv[0] = (mv[0] -50)/2;//把LAB色彩空间的坐标原点移到球模型中间
//将vector内的多个mat合并为一个多通道mat
cv::merge(mv, lab);
6、遍历与取值赋值
其中取值赋值需要区分是单通道mat还是多通道mat,其次要注意mat的元素类型是浮点数还是整形。赋值时只需要交换变量的位置即可 mat.at<uchar>(i,j)=12;
cv::Mat mat = cv::Mat::ones(9, 9, CV_8UC1)*9; //单通道 uchar
cv::Mat mat3 = cv::Mat::ones(9, 9, CV_16FC3)*9;//多通道 float
for (i = 0;i < mat.rows;i++) {
for (j = 0;j < mat.cols;j++) {
int kk= mat.at<uchar>(i,j);//单通道 uchar
float f1=dis.at<Vec3f>(i, j)[0];//3通道 float
float f2=dis.at<Vec3f>(i, j)[1];//3通道 float
float f3=dis.at<Vec3f>(i, j)[2];//3通道 float
}
}
使用行指针
for (int i = 0; i < nm1.rows; i++) {
Vec3f* nm1r = nm1.ptr<Vec3f>(i);
uchar* nm2r = nm2.ptr<uchar>(i);
float* dis = dismat.ptr<float>(i);
for (int j = 0; j < nm2.cols; j++) {
dis[j] = nm1r[j]+nm2r[j];
}
}
7、值域的截取
opencv下值域的截取需要通过threshold函数实现,通过threshold函数可以将大于阈值的部分置0,也可以将小于阈值的部分置0
如下列代码,通过组合操作,即提取出了im中[0.05,0.3)的值域部分的mask,将目标值域外的数值置0。注意区间是左开右闭。
//将大于0.3的部分置1
Mat mat_maxout_mask = cut_value(im, .3, 0);
//将小于0.05的部分置1
Mat mat_minout_mask = cut_value(im, .05, 1);
//值域外的mask
Mat all_out_mask=mat_maxout_mask +mat_minout_mask
//值域内的mask
Mat all_mask=1-all_out_mask;
//目标数据 0*n=0 1*n=1
Mat dst_data=all_mask*im;
易错代码:cv::threshold(tmp, result, thres_, 255, THRESH_BINARY_INV);//小于等于阈值返回最大值 255 ,是小于等于请牢记。
//int type:0 获取大于阈值的部分,1 获取小于阈值的部分
//该函数只适用于值域为0,1的float形mat,因为测试中发现threshold函数只支持CV_8UC1,所以针对性的缩放了值域。
//对于不同值域的mat需要自行调整参数
cv::Mat cut_value(cv::Mat im,float thres_,int type) {
cv::Mat result,tmp;
thres_ = thres_ * 255;
tmp = im * 255;
tmp.convertTo(tmp, CV_8UC1);
if (type == 0) {
cv::threshold(tmp, result, thres_, 255,THRESH_BINARY);//大于阈值返回 最大值 255 小于返回0
}
else {
cv::threshold(tmp, result, thres_, 255, THRESH_BINARY_INV);//小于等于阈值返回最大值 255
}
result.convertTo(result, CV_32FC1);
result = result / 255;
return result;
}
#将im中小于等于minv的部分和大于maxv的部分置0
cv::Mat get_dst(cv::Mat im,float minv=0.05, float maxv=0.3){
//将大于0.3的部分置1
cv::Mat mat_maxout_mask = cut_value(im, maxv, 0);
//将小于0.05的部分置1
cv::Mat mat_minout_mask = cut_value(im, minv, 1);
//值域外的mask
cv::Mat all_out_mask=mat_maxout_mask +mat_minout_mask;
//值域内的mask
cv::Mat all_mask=1-all_out_mask;
//目标数据 0*n=0 1*n=1
cv::Mat dst_data=all_mask*im;
return dst_data;
}
8、最大值、最小值、均值、求和等统计值的计算
其中最大值和最小值是针对所有通道。而sum、mean函数的作用域是按单通道计算,所以针对多个通道有多个结果
double minv = 0.0, maxv = 0.0;
double* minp = &minv;
double* maxp = &maxv;
cv::minMaxIdx(mat, minp, maxp);
//假设mat为三通道
printf_s("channel 1 sum:%f mean:%f ,channel 2 sum:%f mean:%f ,channel 3 sum:%f mean:%f ,min:%f max:%f\n", sum(mat)[0], mean(mat)[0],sum(mat)[1], mean(mat)[1],sum(mat)[2], mean(mat)[2], minv, maxv);
封装成函数调用
void print_max_min(Mat mat) {
double minv = 0.0, maxv = 0.0;
double* minp = &minv;
double* maxp = &maxv;
cv::minMaxIdx(mat, minp, maxp);
//假设mat为三通道
if (mat.channels() == 3) {
printf_s("channel 1 sum:%f mean:%f ,channel 2 sum:%f mean:%f ,channel 3 sum:%f mean:%f ,min:%f max:%f type:%f\n", sum(mat)[0], mean(mat)[0], sum(mat)[1], mean(mat)[1], sum(mat)[2], mean(mat)[2], minv, maxv, mat.type());
}
else {
printf_s( "sum: % f mean : % f min : % f max : % f type:%f\n", sum(mat)[0], mean(mat)[0], minv, maxv, mat.type());
}
}