1 前言
介绍两种遍历像素的方法(非指针、指针)。注意:.at() .ptr()的作用、用法。相关API:
-
Mat对象.ptr()
-
Mat对象.at()
2 代码及内容
#include "iostream"
#include "opencv2/opencv.hpp"
using namespace std;
using namespace cv;
int main(int argc,char *argv)
{
//读取图像
Mat src = imread("C:/Users/Administrator/Desktop/Zooey.png", IMREAD_COLOR);
if (src.empty())
{
cout << "could not find image file" << endl;
return -1;
}
//获取图像信息
int height = src.rows;
int width = src.cols;
int ch = src.channels();
/*
//遍历图像像素(第一种,非指针)
for (int row = 0; row < height; row++)
{
for (int col = 0; col < width; col++)
{
//如果是三通道图像
if (ch == 3)
{
//将像素的三个通道的值存入一个Vec3b类型中
Vec3b pixel = src.at<Vec3b>(row, col); //Vec3b,三通道字节类型。at()获取图像中某一像素的值。
//获取每个通道的值,根据BGR顺序。
int blue = pixel[0];
int green = pixel[1];
int red = pixel[2];
//修改图片像素每个通道的值
src.at<Vec3b>(row, col)[0] = 255 - blue;
src.at<Vec3b>(row, col)[1] = 255 - green;
src.at<Vec3b>(row, col)[2] = 255 - red;
}
//如果是单通道图像
if (ch == 1)
{
//获取像素值。
int pv = src.at<uchar>(row, col);
//修改图片像素值
src.at<uchar>(row, col) = (255 - pv);
}
}
}
//展示图像
imshow("one_pixel-demo", src);
*/
//遍历图像像素(第二种,指针)
//创建一个大小和原图相同的Mat对象
Mat result = Mat::zeros(src.size(), src.type());
for (int row = 0; row < height; row++)
{
uchar* curr_row = src.ptr<uchar>(row);//获得原图当前行的指针(指向这行第一个值,类似于数组那样)
uchar* result_row = result.ptr<uchar>(row);//获取result图像当前行指针
for (int col = 0; col < width; col++)
{
//如果是三通道图像
if (ch == 3)
{
//获取像素每个通道的值。从这一行得一个值开始往后逐个获取三个。经列循环,以三个为单位继续获取。
int blue = *curr_row++;
int green = *curr_row++;
int red = *curr_row++;
//将值赋给result图像像素的每个通道
*result_row++ = blue;
*result_row++ = green;
*result_row++ = red;
}
//如果是单通道图像
if (ch == 1)
{
//获取像素值。获取这一行第一个。经列循环往后逐个获取。
int pv = *curr_row++;
//将值赋给result图像像素
*result_row++ = pv;
}
}
}
//展示图像,可以result图和原图是一样的
imshow("result图", result);
waitKey(0);
destroyAllWindows();
return 0;
}
两种方法,代码中我把第一种注释了,测试第一种时,记得把第二种注释掉。
第一种时非指针的方式,用一个vec3b类型来获得一个像素三个通道的值,vec代表向量的意思,可以简单理解为一个数组。3b代表3通道字节类型,即有可以存放三个数值且是字节类型。总之vector是C++里的内容,不再多提了。
第二种指针方式,我在代码中也有标注,要理解在内存中的机制,指针是沿着内存地址逐步向后进行的。
演示:
第一种遍历操作。
3 结束语
没啦。