1. OpenCV使用指针遍历图像

存取像素值

获取像素值:
灰度图片:

pixel = img.at<uchar>(100, 200);

彩色图片:

pixel = img.at<Vec3b>(100, 200);//对于彩色图像,Mat会返回一个有三个8位数组成的unsigned char类型向量

修改像素值:
灰度图片:

 img.at<uchar>(100, 200) = 255;

彩色图片:

for(int i=0; i<3; i++){
	img.at<Vec3b>(100, 200)[i] = 255
}  

下述代码为一张图片随机加入噪声

void salt(Mat& image, int n) {
	for (int k = 0; k < n; k++) {
		int i = rand() % image.cols;
		int j = rand() % image.rows;
		if (image.channels() == 1)
			image.at<uchar>(j, i) = 255;
		else if (image.channels() == 3){
			image.at<Vec3b>(j, i)[0] = 255;
			image.at<Vec3b>(j, i)[1] = 255;
			image.at<Vec3b>(j, i)[2] = 255;
		}
	}
}

使用指针遍历图像

遍历方式

void colorReduce(Mat& image, int div = 64) {
	//注意opencv默认BGR通道数。缓冲区前三个字节是第一行第一列像素BGR值,之后是第一行第二列三个元素BGR值,以此类推。
	int rows = image.rows;
	int num = image.cols * image.channels();
	for (int i = 0; i < rows; i++) {
		uchar* data = image.ptr<uchar>(i);//ptr函数返回图像任意一行的首地址
		for (int j = 0; j < num; j++) {
			data[j] = data[j] / div * div + div / 2;
		}
	}
}

缩减图像颜色数量

void colorReduce(Mat& image, int div = 64) {
	int rows = image.rows;
	int num = image.cols * image.channels();
	for (int i = 0; i < rows; i++) {
		uchar* data = image.ptr<uchar>(i);//ptr函数返回图像任意一行的首地址
		for (int j = 0; j < num; j++) {
			data[j] = data[j] / div * div + div / 2;
		}
	}
}

上述颜色缩减函数在传入图片和缩减比例后,将直接在原图上对图片进行更改,如果我们想保留原图,可以拷贝一份图片进行更改。我们可以根据用户需要决定是否在原图上更改图片,代码如下:

void colorReduce(Mat& image_in, Mat& image_out, int div = 64) {
	int rows = image_in.rows;
	int num = image_in.cols * image_in.channels();
	for (int i = 0; i < rows; i++) {
		uchar* data_in = image_in.ptr<uchar>(i);
		uchar* data_out = image_out.ptr<uchar>(i);
		for (int j = 0; j < num; j++) {
			data_out[j] = data_in[j] / div * div + data_in[j] / div;
		}
	}
}

int main() {
	Mat img = imread("picture.png");   
	Mat result;
	result.create(img.rows, img.cols, img.type());
	colorReduce(img, img, 32);//在原图修改
	colorReduce(img, result, 32);、、将修改后图片拷贝到result
	imshow("hello", img);
	waitKey(0);  
	imshow("hello", result);

	waitKey(0);  
	destroyAllWindows();   
	return 0;
}

OpenCV中的图像填补

理论上来说,对于一张W×H的彩色图片,应该需要W×H×3个uchar构成的内存块来存储。但实际上由于一些媒体处理芯片(intel或者MMX)在行的长度为4或者8时可以更高效的处理图片,opencv往往会在行之后进行扩充,在行后加上几个元素,这些元素不会被处理和现实,填补的值会被忽略。图片是否被填充可以通过isContinuous()函数确定。

更加高效的遍历方式

在一些图像算法中如果图片没有被填充,利用图像存储的连续性,我们可以更高效的遍历图像。

void colorReduce(Mat& image, int div = 64) {
	//注意opencv默认BGR通道数。缓冲区前三个字节是第一行第一列像素BGR值,之后是第一行第二列三个元素BGR值,以此类推。
	int rows = image.rows;
	int num = image.cols * image.channels();
	if (image.isContinuous()) {
		num = rows * num;
		rows = 1;
	}
	for (int i = 0; i < rows; i++) {
		uchar* data = image.ptr<uchar>(i);//ptr函数返回图像任意一行的首地址
		for (int j = 0; j < num; j++) {
			data[j] = data[j] / div * div + div / 2;
		}
	}
}

图片的指针运算

void pointerOperation(Mat& image) {
	uchar *data = image.data;//获取图像首地址
	data += image.step;//获取下一行地址
	//获取第 i=10 行第 j=24 列的像素值
	data = image.data + 100 * image.step + 225 * image.elemSize();
	cout <<"像素值为"<< * data << endl;
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
首次接触图像处理,通过次来记录自己的学习记录,以方便回忆。 //指针访问像素 void colorReduce(Mat& temImage, int div) { //行数 int rowNumber = temImage.rows; cout << "图像通道数:" << temImage.channels() << endl; //列数*通道数=每一行的元素个数 int colNumber = temImage.cols * temImage.channels(); for (int row = 0; row < rowNumber;row++) { uchar* data = temImage.ptr<uchar>(row); for (int col = 0; col < colNumber;col++) { data[col] = data[col] / div*div + div / 2; } } } //迭代器iterator操作像素 void iterColorReduce(Mat& temImage,int div) { Mat_<Vec3b>::iterator it = temImage.begin<Vec3b>(); Mat_<Vec3b>::iterator itend = temImage.end<Vec3b>(); //存取彩色图像的像素 while (it != itend) { //开始处理每个像素 (*it)[0] = (*it)[0] / div*div + div / 2; (*it)[1] = (*it)[1] / div*div + div / 2; (*it)[2] = (*it)[2] / div*div + div / 2; ++it; } } //动态地址计算像素 void atColorReduce(Mat& temImage, int div) { int rowNumber = temImage.rows; int colNumber = temImage.cols; //存取彩色图像 for (int row = 0; row < rowNumber; row++) { for (int col = 0; col < colNumber; col++) { //开始处理每个图像 //蓝色通道 temImage.at<Vec3b>(row, col)[0] = temImage.at<Vec3b>(row, col)[0] / div*div + div / 2; //绿色通道 temImage.at<Vec3b>(row, col)[1] = temImage.at<Vec3b>(row, col)[1] / div*div + div / 2; //红色通道 temImage.at<Vec3b>(row, col)[2] = temImage.at<Vec3b>(row, col)[2] / div*div + div / 2; } } }

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值