OpenCV基础: 图像矩阵Mat的数据类型与访问等

质量声明:原创文章,内容质量问题请评论吐槽。如对您产生干扰,可私信删除。
主要参考:<学习Opencv 3 中文版>, Mat数据类型总结, 像素值读取at()函数



摘要: 随时更新完善opencv中Mat相关的定义,类型,访问和应用.


Mat矩阵的定义

opencv中的cv::Mat类用于定义任意维度的稠密数组,所谓稠密,是指该数组任一位置的元素都有确定值,即使是0.

独立定义

  • 定义变量的同时进行初始化:

    cv::Mat img(640, 480, CV_8UC1,  cv::Scalar(100));                // 定义单通道灰度图, 640x480, 100
    
    cv::Mat src(800, 640, CV_8UC3,  cv::Scalar(70, 160, 70));        // 定义三通道彩色图,数据类型为8位无符号整型
    
    cv::Mat dst(960, 540, CV_32FC3, cv::Scalar(1.0f, 0.0f, 0.0f));   // 定义三通道彩色图,数据类型为32位浮点型
    
  • 先定义,再初始化:

    cv::Mat src;
    src.create(800, 640, CV_8UC1);
    img.setTo(cv::Scalar(0));
    
    cv::Mat src(800, 640, CV_8UC3);
    src.setTo(cv::Scalar(255, 0, 0));
    

引用定义(内存相同)

cv::Mat dst(src);
cv::Mat dst = src;
cv::Mat& dst = src;
cv::Mat roi(src, cv::Rect(0, 0, 200, 100));

复制定义(内存独立)

  • clone与copyTo:

    cv::Mat dst = src.clone();
    
    cv::Mat dst;
    src.copyTo(dst);
    
  • 构造同型矩阵:

    cv::Mat dst(src.size(), CV_8UC1, cv::Scalar(0));
    
  • 独立提取ROI:

    cv::Mat roi = src(cv::Rect(0, 0, 200, 100)).clone();
    
    cv::Rect roi_rect(0, 0, 200, 100);
    cv::Mat roi = src(roi_rect).clone();
    
    cv::Rect roi_rect(0, 0, 200, 100);
    cv::Mat roi;
    src(roi_rect).copyTo(roi);
    

特殊定义

  • 零矩阵:

    cv::Mat zeros = cv::Mat::zeros(100, 100, CV_8UC1);
    
  • 幺矩阵:

    cv::Mat ones = cv::Mat::ones(100, 100, CV_8UC1);
    
  • 单位阵:

    cv::Mat eye = cv::Mat::eye(100, 100, CV_8UC1);
    
  • 特别注意: 如果创建多通道数组, 则只有第一通道被赋值, 其余通道为全0. 以下示例创建的是个蓝色图像, 而不是纯白图像:

    cv::Mat blue= cv::Mat::ones(100, 100, CV_8UC3) * 255;
    

模板定义

(待完善)

cv::Mat m(const cv::Vec<T, n>& vec, bool = copyData = true);
cv::Mat(const cv::Matx<T, m, n>& vec, bool copyData = true);
cv::Mat(const std::vector<T>& vec, bool copyData = true);

Mat矩阵的数据类型

基本类型

  • 明确矩阵元素的数据类型,对于访问数组元素和元素运算至关重要,选错数据类型会产生错误结果,误导后续处理.
  • 一个有效的数据类型需要同时指明数据的类型和通道数,格式为CV_{8U,8S,16U,16S,32S,32F,64F }C{1,2,3}
数值位数bits具体类型取值范围等同C++变量
CV_8U8 位无符号整数(0……255)uchar , unsigned char
CV_8S8 位带符号整数(-128……127)char
CV_16U16 位无符号整数(0……65535)ushort , unsigned short , unsigned short int
CV_16S16 位带符号整数(-32768……32767)short , short int
CV_32S32 位带符号整数(-2147483648……2147483647 )int , long
CV_32F32 位单精度浮点数±(1.18e-38……3.40e38)float
CV_64F64 位双精度浮点数±(2.23e-308……1.79e308)double
  • 注:CV_USRTYPE1 support has been dropped in OpenCV 4.0.
  • 如何获取未知矩阵的数据类型, 最直接的方法是查阅接口文档, 熟记常用变量的数据类型
  • 也可以通过成员函数type()获得Mat矩阵元素的数据类型,不建议使用depth()获取通道中的元素类型. 但type()函数返回的是int型数值,需进一步查表, 才能得到对应的数据类型.
类型C1C2C3C4
CV_8U081624
CV_8S191725
CV_16U2101826
CV_16S3111927
CV_32S4122028
CV_32F5132129
CV_64F6142230

提示: PNG 格式的彩色图像除了 BGR 3个通道外,还有一个透明度通道,所以存在 C4.
示例:

cv::Mat src = cv::Mat::ones(100, 100, CV_8SC3);
cout << "type = " << src.type() << endl;
cout << "depth = " << src.depth() << endl;

输出:
type = 17 查表知, 数据类型为 CV_8SC3
depth = 1 查表知, 通道中的数据类型为 CV_8S, 但未指明通道数. 因此, 不建议使用depth()获取通道中的元素类型

数据类型转换 convertTo

  • 转浮点数
img.convertTo(img, CV_32F);
  • 转整型
img.convertTo(img, CV_8U);
  • 转为可显示图像Mat
// 必须是[0,1]的浮点数, 缩放
img.convertTo(img, CV_32F, 1./255);  

// 或者是[0,255]的整数, 不缩放
img.convertTo(img, CV_8U);

归一化 cv::normalize

  • 区间化为 [ 0 , 255 ] [0,255] [0,255] 整数
img.convertTo(img, CV_8U);
cv::normalize(img, img, 0, 255, cv::NORM_MINMAX);
cv::imshow("range.jpg", img);
  • 归一化为 [ 0.0 , 1.0 ] [0.0,1.0] [0.0,1.0] 的浮点数
img.convertTo(img, CV_32F);
cv::normalize(img, img, 1, 0, cv::NORM_MINMAX);
cv::imshow("normalization.jpg", img);

Mat数组的访问

独立访问数组元素

  • 模板函数at<>()可以实现对数组元素进行独立访问, 但对不同数据类型的数组有不同的参数要求.
  • 以单通道为例,at 方法接受的数据类型是 uchar ,而非 CV_8U, 即 img.at<uchar>(2,3)
数据类型/at参数C1C2C3C4C6
CV_8Uucharcv::Vec2bcv::Vec3bcv::Vec4b
CV_8S////
CV_16Uushortcv::Vec2wcv::Vec3wcv::Vec4w
CV_16Sshortcv::Vec2scv::Vec3scv::Vec4s
CV_32Sintcv::Vec2icv::Vec3icv::Vec4i
CV_32Ffloatcv::Vec2fcv::Vec3fcv::Vec4fcv::Vec6f
CV_64Fdoublecv::Vec2dcv::Vec3dcv::Vec4dcv::Vec6d
  • 常见的对应关系
CV_8UCV_32SCV_32FCV_64F
ucharintfloatdouble

示例:

cv::Mat img = cv::Mat::ones(20, 4, CV_64FC3) * CV_PI;
auto vec3d = img.at<cv::Vec3d>(2, 1);
auto vec3d0 = img.at<cv::Vec3d>(2, 1)[0];
auto vec3d1 = img.at<cv::Vec3d>(2, 1)[1];
auto vec3d2 = img.at<cv::Vec3d>(2, 1)[2];
std::cout << "vec3d = " << vec3d << std::endl;
std::cout << "vec3d0 = " << vec3d0 << std::endl;
std::cout << "vec3d1 = " << vec3d1 << std::endl;
std::cout << "vec3d2 = " << vec3d2 << std::endl;

输出:
vec3d = [3.14159, 0, 0]
vec3d0 = 3.14159
vec3d1 = 0
vec3d2 = 0

提示: 错误的数据类型将输出错误的取值. 如cv::Vec3i的取值是全零.

区块访问与赋值

  • 单行/单列

    src.row(30) = cv::Scalar(255, 255, 255); // 将图像第30行设为白色
    src.col(30) = cv::Scalar(255, 255, 255); // 将图像第30列设为白色
    
  • 多行/多列

    src.rowRange(30, 50) = cv::Scalar(255, 255, 255); // 将图像第30~50行设为白色
    src.colRange(30, 50) = cv::Scalar(255, 255, 255); // 将图像第30~50列设为白色
    
  • 矩形区域 (x1, y1, w, h)

    src(cv::Rect(0, 0, 200, 100)) = cv::Scalar(200, 0, 150);
    
    cv::Rect roi_rect(0, 0, 200, 100);   
    src(roi_rect).setTo(cv::Scalar(200, 0, 150));
    
    src(cv::Range(0, 100), cv::Range(0, 200)) = cv::Scalar(200, 0, 150);
    

区域替换

cv::Mat src(800, 640, CV_8UC3, cv::Scalar(70, 160, 70));  
cv::Mat dst(800, 640, CV_8UC3, cv::Scalar(10, 10, 200));  
cv::Rect roi_rect(0, 0, 200, 100);
src(roi_rect).copyTo(dst(roi_rect));
// 无效替换 dst(roi_rect) = src(roi_rect);
// 无效替换 dst(roi_rect) = src(roi_rect).clone();
  • 1
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值