opencv学习-004-图像像素的读写操作(Mat.at方法,案例实现图像的颜色反转(数组遍历和指针方式遍历))

opencv学习-004-图像像素的读写操作和一些算术运算(Mat.at方法,案例实现图像的颜色反转(数组遍历和指针方式遍历))

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace cv;
using namespace std;

int main(int artc, char** argv) {
	Mat src = imread("E:/Desktop/y.jpg");
	if (src.empty()) {
		printf("could not load image...\n");
		return -1;
	}
	namedWindow("input", WINDOW_AUTOSIZE);
	imshow("input", src);
	
	// 直接读取图像像素
	int height = src.rows;
	int width = src.cols;
	int ch = src.channels();
	//for (int c = 0; c < ch; c++) {
		for (int row = 0; row < height; row++) {
			for (int col = 0; col < width; col++) {
				if (ch == 3) {
					Vec3b bgr = src.at<Vec3b>(row, col);
					bgr[0] = 255 - bgr[0];
					bgr[1] = 255 - bgr[1];
					bgr[2] = 255 - bgr[2];
					src.at<Vec3b>(row, col) = bgr;
				}
				else if (ch == 1) {
					int gray = src.at<uchar>(row, col);
					src.at<uchar>(row, col) = 255 - gray;
				}
			}
		}
	//}
	imshow("output", src);


	// 指针读取
	Mat result = Mat::zeros(src.size(), src.type());
	int blue = 0, green = 0, red = 0;
	int gray;
	//for (int c = 0; c < ch; c++) {
		for (int row = 0; row < height; row++) {
			uchar* curr_row = src.ptr<uchar>(row);
			uchar* result_row = result.ptr<uchar>(row);
			for (int col = 0; col < width; col++) {
				if (ch == 3) {
					blue = *curr_row++;
					green = *curr_row++;
					red = *curr_row++;

					*result_row++ = blue;
					*result_row++ = green;
					*result_row++ = red;
				/*
					*result_row++ = 255 - blue;
					*result_row++ = 255 - green;
					*result_row++ = 255 - red;
				*/
				}
				else if (ch == 1) {
					gray = *curr_row++;
					*result_row++ = gray;
				}
			}
		}
	//}
	imshow("result", result);
	
	waitKey(0);
	return 0;
}

输出:
在这里插入图片描述

以上使用了两种方式对图像进行颜色反转,一种是数组遍历的方式,另一种是指针方式的遍历。

1. 通道

代码中获取了图像的通道:

int ch = src.channels();

学过图像处理的小伙伴们应该知道,我们彩色图片是由BGR三种通道的图片混合叠加而成的,彩色图片通道数就是3,也就是ch=3,当ch=1时是黑白图像。
后期我们也会接触到额外增加的一个透明通道,后期再讲。

2. mat.at方法获取像素值

对于三通道来说,每一个像素的位置内含了三个uchar数据,所以对三通道获取像素值要使用Vec3bVec3b实质上是一个uchar的数组,最多能装三个数据。

对于单通道,可以直接使用mat.at<uchar>(row,col)即可获取像素值

三通道图像读取像素值的代码如下:

int main(){
	Mat src = Mat::zeros(5, 5, CV_8UC3);//建立一个三通道的图像
	cout << "src"<<endl<<src << endl;
	Vec3b i = src.at<Vec3b>(2, 2);//获取(2,2)位置的像素值,这里用了mat.at<Vec3b>(2,2),返回一个Vec3b类型的数组
	cout << "i" << endl << i << endl;
	int a = (int)i[0];//因为Vec3b是uchar型,i[0]中是\0,就是空格。这里要转换为int
	cout << a << endl;
	waitKey(0);
	return 0;
}

单通道的图像读取像素值的代码如下:

int main()
{
	Mat src = Mat::zeros(5, 5, CV_8UC1);//建立一个三通道的图像
	cout << "src"<<endl<<src << endl;
	uchar i = src.at<uchar>(2, 2);//获取(2,2)位置的像素值,这里用了mat.at<Vec3b>(2,2),返回一个Vec3b类型的数组
	cout << "i" << endl << (int)i << endl;//i是uchar型,是\0,即空格,无法在doc中显示,所以使用int强制转换。
	waitKey(0);
	return 0;
}

最后,这种方法访问速度很慢,使用mat.ptr(i,j)(单通道) mat,ptr(i,j) (3通道)会快很多

更多at方法参考:
opencv图像操作——at方法使用
使用mat.at方法获取像素值

3. Vec3b类型

在对彩色图片进行处理的时候我们注意到这行代码:

Vec3b bgr = src.at<Vec3b>(row, col);

Vec3b可以看作是vector<uchar, 3>

简单而言就是一个uchar类型的,长度为3的vector向量

由于在OpenCV中,使用imread读取到的Mat图像数据,都是用uchar类型的数据存储,对于RGB三通道的图像,每个点的数据都是一个Vec3b类型的数据。使用at定位方法如下:

  • img.at(row, col)[0] = 255;  // 这是指修改B通道数据
  • img.at(row, col)[1] = 255;  // 这是指修改G通道数据
  • img.at(row, col)[2] = 255;  // 这是指修改R通道数据

故:

bgr[0] = 255 - bgr[0];
bgr[1] = 255 - bgr[1];
bgr[2] = 255 - bgr[2];

这三行代码是对每个通道的像素数据取反(颜色取反是用255减去,因为像素值的取值范围是0~255)

3. 指针方式遍历中的要点

在指针读取的那段代码中有一句:

uchar* curr_row = src.ptr<uchar>(row);

这个API接口的意义是读取src按row读取的像素坐标的首地址赋给curr_row

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值