1、遍历图像像素
int height = gray_src.rows;//获取图像行数
int width = gray_src.cols;//获取图像列数
for (int row = 0; row < height; row++) {//遍历图像各个像素点的像素值
for (int col = 0; col < width; col++) { }
}
2、获取图像像素值
- 读一个GRAY像素点的像素值
int gray = image.at<uchar>(row, col);
- 读一个RGB像素点的像素值
int b = image.at<Vec3b>(row, col)[0];//获取row行col列0通道的像素值,Vec3b可以用来读取三通道的RGB图像像素值
int g = image.at<Vec3b>(row, col)[1];//获取row行col列1通道的像素值
int r = image.at<Vec3b>(row, col)[2];//获取row行col列2通道的像素值
注:
Vec3b:blue,green,red的uchar类型;Vec3f则表示blue,green,red的float类型
把CV_8UC1转换到CV32F1: src.convertTo(dst,CV_32F);
3、修改像素值
- 灰度图像
image.at<uchar> (row,col) = 目标像素值;
- RGB三通道图像:
image.at<Vec3b>(row, col)[0] = 目标像素值;//修改row行col列0通道的像素值
image.at<Vec3b>(row, col)[1] = 目标像素值;//修改row行col列1通道的像素值
image.at<Vec3b>(row, col)[2] = 目标像素值;//修改row行col列2通道的像素值
- 空间图像赋值
image = Scalar(0);
- ROI选择
Rect r(10,10,100,100);
Mat smallImg = img(r);
- 生成灰度图:
gray_src.at<uchar>(row, col) = min(r, min(b,g));//取RGB中的最小值作为灰度值
gray_src.at<uchar>(row, col) = max(r, max(b,g));//取RGB中的最大值作为灰度值
4、反转图像色彩
- 反转灰度图像
gray_image.at<uchar>(row, col) = 255 - gray;
- 反转RGB图像
image.at<Vec3b>(row, col)[0] = 255 - b;//反转row行col列0通道的像素值
image.at<Vec3b>(row, col)[1] = 255 - g;//反转row行col列1通道的像素值
image.at<Vec3b>(row, col)[2] = 255 - r;//反转row行col列2通道的像素值
- 利用函数实现图像色彩反转bitwise_not(原图像, 反转后图像);
5、去掉图像某一通道色彩
image.at<Vec3b>(row, col)[0] = b;//保持row行col列0通道的像素值
image.at<Vec3b>(row, col)[1] = g;//保持row行col列1通道的像素值
image.at<Vec3b>(row, col)[2] = 0;//清零row行col列2通道的像素值
反转图像色彩示例代码:
Mat src;
src = imread("C:/Users/26839/Pictures/测试.png");
if (src.empty()) {
cout << "could not load image...\n" << endl;
return -1;
}
imshow("src", src);
Mat dst;
dst.create(src.size(), src.type());//构造一张与src大小类型一致的图片dst
int height = src.rows;
int width = src.cols;
int nc = src.channels();
for (int row = 0; row < height; row++) {//遍历图像各个像素点的像素值
for (int col = 0; col < width; col++) {
if (nc == 1) {//使单通道图片色彩反转
int gray = src.at<uchar>(row, col);//获取像素值
dst.at<uchar>(row, col) = 255 - gray;//反转图像
} else if (nc == 3) {//使3通道图片色彩反转
int r = src.at<Vec3b>(row, col)[0];//获取row行col列0通道的像素值,Vec3b可以用来读取三通道的RGB图像像素值
int g = src.at<Vec3b>(row, col)[1];//获取row行col列1通道的像素值
int b = src.at<Vec3b>(row, col)[2];//获取row行col列2通道的像素值
dst.at<Vec3b>(row, col)[0] = 255 - r;//反转row行col列0通道的像素值
dst.at<Vec3b>(row, col)[1] = 255 - g;//反转row行col列1通道的像素值
dst.at<Vec3b>(row, col)[2] = 255 - b;//反转row行col列2通道的像素值
}}}
//bitwise_not(src, dst);//反转图像色彩的函数
imshow("invert", dst);
waitKey(0);
destroyAllWindows();
return 0;
输出运行结果如下所示:
原始图像
反转处理后的图像
使用迭代器
迭代器(iterator)可以方便地遍历所有元素。Mat 也增加了迭代器的支持,以便于矩阵元素的遍历。使用迭代器,则无需用行数和列数遍历,所以没 i 、 j 变量,图像的像素值设置为一个随机数。
Mat grayim(600, 800, CV_8UC1);
Mat colorim(600, 800, CV_8UC3);
//遍历所有像素,并设置像素值
MatIterator_<uchar> grayit, grayend;
for (grayit = grayim.begin<uchar>( ), grayend =grayim.end<uchar>( ); grayit != grayend; ++grayit)
*grayit = rand() % 255;
//遍历所有像素,并设置像素值
MatIterator_<Vec3b> colorit, colorend;
for (colorit = colorim.begin<Vec3b>( ), colorend =colorim.end<Vec3b>( ); colorit != colorend; ++colorit)
{
(*colorit)[0] = rand() % 255; //Blue
(*colorit)[1] = rand() % 255; //Green
(*colorit)[2] = rand() % 255; //Red}
//显示结果
imshow("grayim", grayim);
imshow("colorim", colorim);
waitKey(0);
return 0;
输出结果:
通过数据指针
用 IplImage 结构时,会经常使用数据指针来直接操作像素。通过指针操作来访问像素非常高效。C/C++中的指针操作是不进行类型以及越界检查的,如果指针访问出错,程序运行时可能看上去一切正常,有时却突然弹出“段错误”(segment fault)。当程序规模较大且逻辑复杂时,查找指针错误十分困难。【注重程序运行速度,那么遍历像素时建议使用指针。】
用指针遍历图像中所有像素。
Mat grayim(600, 800, CV_8UC1);
Mat colorim(600, 800, CV_8UC3);
//遍历所有像素,并设置像素值
for (int i = 0; i < grayim.rows; ++i)
{
//获取第 i 行首像素指针
uchar * p = grayim.ptr<uchar>(i);
//对第 i 行的每个像素(byte)操作
for (int j = 0; j < grayim.cols; ++j)
p[j] = (i + j) % 255;
}
//遍历所有像素,并设置像素值
for (int i = 0; i < colorim.rows; ++i)
{
//获取第 i 行首像素指针
Vec3b * p = colorim.ptr<Vec3b>(i);
for (int j = 0; j < colorim.cols; ++j)
{
p[j][0] = i % 255; //Blue
p[j][1] = j % 255; //Green
p[j][2] = 0; //Red}}
//显示结果
imshow("grayim", grayim);
imshow("colorim", colorim);
waitKey(0);
return 0;
参考:
OpenCV4---像素操作(读写像素、修改像素值)_image.at<ushort>(row, col)-CSDN博客