赞
踩
使用C++开发图像处理算法时,不需要去调用OpenCV的内置算法函数,主要是利用OpenCV完成图像文件的输入、输出以及自动内存管理(重点)。所以,只要需要掌握一些简单的OpenCV的操作即可。
1、图像读取
OpenCV支持bmp、jpg、png、tiff等常用图像格式的解析,所用API为imread。imread函数原型如下:
CV_EXPORTS_W Mat imread( const String& filename, int flags = IMREAD_COLOR );
filename参数为图像文件的路径,可以是相对路径,也可以是绝对路径;flags参数为图像文件解析的方式,支持的方式有如下:
IMREAD_UNCHANGED:不对图像文件进行任何转换,直接读取。
IMREAD_GRAYSCALE :将任何图像均转换为灰度图像(单通道)进行读取。
IMREAD_COLOR:将任何图像均转为RGB彩色图像(三通道)进行读取。
IMREAD_ANYDEPTH:如果不设置这个参数,16/32位图像将会自动转为8位图像。
IMREAD_ANYCOLOR:将按照图像文件设定的颜色格式进行图像读取。
IMREAD_LOAD_GDAL:调用gdal库进行图像文件读取。(可以简单地理解为读取TIFF图像文件)
示例代码:
- //不做任何转化进行读取
- cv::Mat matUnchanged = cv::imread("./lena.jpg", cv::IMREAD_UNCHANGED); cv::imshow("UNCHANGED", matUnchanged);
-
- //彩色模式进行读取
- cv::Mat matColor = cv::imread("./lena.jpg", cv::IMREAD_COLOR); cv::imshow("COLOR", matColor);
-
- //灰度模式进行读取
- cv::Mat matGrayScale = cv::imread("./lena.jpg", cv::IMREAD_GRAYSCALE);
- cv::imshow("GRAYSCALE", matGrayScale);
运行结果:
2、图像显示
OpenCV的图像显示函数为imshow,函数原型如下:
CV_EXPORTS_W void imshow(const String& winname, InputArray mat);
winname参数表示显示图像窗口的名称(任意字符),mat参数表示需要显示的图像。对于这个函数,需要注意的是(特别是新手),imshow函数只支持8位灰度图像、8位彩色图像和32位灰度图像(像素值范围0-1),具体原因大家可以自行百度关键词【显示器灰度等级】。
3、获取图像的属性
图像的常用属性有图像的宽度、高度、数据缓存区指针(图像像素存储地址)、图像的通道数、深度。示例代码:
- cv::Mat matUnchanged = cv::imread("./lena.jpg", cv::IMREAD_UNCHANGED);
- //宽度
- std::cout << "宽度:"<<matUnchanged.cols << std::endl;
- //高度
- std::cout << "高度:" << matUnchanged.rows << std::endl;
- //数据缓存区指针
- unsigned char* pData = matUnchanged.data;
- std::cout << "数据地址:" << &pData << std::endl;
- //通道数
- std::cout << "通道数:" << matUnchanged.channels() << std::endl;
- //深度
- //elemSize函数返回的是一个像素占用的字节数
- std::cout << "深度:" << matUnchanged.elemSize() / matUnchanged.channels() * 8 << std::endl;
- cv::imshow("UNCHANGED", matUnchanged);
- cv::waitKey(0);
4、图像遍历的几种方式
作为示例,读取一副RGB彩色图像,将每个像素的R值置0作为测试。(在Windows下,RGB存储的顺序为BGR)
(1)、使用OpenCV的at成员函数
OpenCV提供了便利的访问图像数据的接口,at函数原型:
template<typename _Tp> inline _Tp& Mat::at(int i0, int i1)
参数i0为行号,i1为列号;模板参数_Tp常用类型如下:
图像类型 | _Tp参数 |
单通道灰度 | unsigned char |
三通道彩色(8位) | cv::Vec3b |
16位灰度 | unsigned short |
32位浮点型 | float |
双通道32位 | cv::Vec2f |
示例代码:
- for (size_t r = 0; r < matUnchanged.rows; r++)//行
- for (size_t c = 0; c < matUnchanged.cols; c++)//列
- {
- cv::Vec3b& bgr = matUnchanged.at<cv::Vec3b>(r, c);
- bgr[2] = 0;
- }
(2)、使用指针
- for (size_t r = 0; r < matUnchanged.rows; r++)//行
- {
- //step返回图像一行的字节数
- unsigned char* pRow = matUnchanged.data + r * matUnchanged.step[0];//计算图像行首指针
- for (size_t c = 0; c < matUnchanged.cols; c++)//列
- {
- pRow[3 * c + 2] = 0;
- }
- }
(3)、行首指针存储法
- //存储图像行首指针
- std::vector<unsigned char*> rowPtr(matUnchanged.rows);
- for (size_t r = 0; r < matUnchanged.rows; r++)
- rowPtr[r] = matUnchanged.data + r * matUnchanged.step[0];
-
- //遍历图像
- for (size_t r = 0; r < matUnchanged.rows; r++)//行
- for (size_t c = 0; c < matUnchanged.cols; c++)//列
- {
- rowPtr[r][c * 3 + 2] = 0;
- }
访问图像数据的方式有很多,这里只列出几种常用的方式,考虑到算法的效率问题,通常使用指针对数据进行访问。
关注公众号【图像大师】,更多内容
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。