Opencv 基本操作一 c++的常用数组运算方法

本文详细介绍了OpenCV库在图像处理中的基本操作,包括图像读取与Mat初始化、类型转换、色彩空间转换、数学运算、通道分离与合并、遍历与取值赋值、值域截取以及统计值计算。通过实例展示了如何进行图像的预处理和分析,对于理解OpenCV的图像处理功能十分有帮助。
摘要由CSDN通过智能技术生成

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());
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

万里鹏程转瞬至

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值