使用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常用类型如下:
示例代码:
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;
}
访问图像数据的方式有很多,这里只列出几种常用的方式,考虑到算法的效率问题,通常使用指针对数据进行访问。
转载至 https://blog.csdn.net/huqiang_823/article/details/80698670