opencv中遍历每一个像素点进行处理

1.用动态地址操作像素:

	Mat srcImage(100, 100, CV_8UC3, Scalar(200,20,100));

	imshow("显示图像", srcImage);


	int rowNumber = srcImage.rows;
	int colNumber = srcImage.cols;


	for (int i = 0; i < rowNumber; i++)
	{
		for (int j = 0; j < colNumber; j++)
		{

			if (srcImage.at<Vec3b>(i, j)[0] > 180) 
			{
				srcImage.at<Vec3b>(i, j)[0] = 0;			
			}
			
			if (srcImage.at<Vec3b>(i, j)[1] < 50) 
			{
				srcImage.at<Vec3b>(i, j)[1] = 255;
			}

			if (srcImage.at<Vec3b>(i, j)[2] < 120) 
			{
				srcImage.at<Vec3b>(i, j)[2] = 0;
			}

		}
	}


	imshow("处理后的图像", srcImage);
cv::mat的成员函数: .at(int y, int x)可以用来存取图像中对应坐标为(x,y)的元素坐标。(Mat类中的cols和rows给出了图像的宽和高。而成员函数at(int x, int y)可以用来存取图像的元素。)由于at方法本身不会对任何数据类型进行转化,故一定要确保指定的数据类型和矩阵中的数据类型相符合。

假设提前已知一幅图像img的数据类型为 unsigned char型灰度图(单通道),对像素的赋值操作为image.at<uchar>(i,j) = value。而对于彩色图像,每个像素由三个部分构成:蓝色通道、绿色通道和红色通道(BGR),对于一个包含彩色图像的Mat,会返回一个由三个8位数组组成的量。OpenCV将此类型定义为Vec3b,即由三个unsigned char组成的向量。这也解释了为什么存取彩色图像像素的代码可以写成:image.at<Vec3b>(i,j)[channel] = value;


以下是统计canndy后的0像素点与255像素点之间的数量的比值:

#define _CRT_SECURE_NO_WARNINGS

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

using namespace std;
using namespace cv;

int main() 
{
	Mat graySrc = imread("../../11.bmp", 0);

	Mat canImage;
	Canny(graySrc, canImage, 60, 120);

	int PicZero = 0;
	int PicFull = 0;

	for (int i = 0; i < graySrc.rows; ++i) 
	{
		for (int j = 0; j < graySrc.cols; ++j) 
		{
			if (canImage.at<unsigned char>(i, j) == 0) 
			{
				PicZero++;
			}
			else
			{
				PicFull++;
			}	
		}
	
	}

	cout << "0像素点比255像素点的比值为" << (double)PicZero / PicFull << endl;

	system("pause");
}





2.用指针的方法:

有时候我们需要遍历Mat中的每一个像素点,并且对像素点进行处理,这里以图像所有像素点都减去div(div属于int类型)

void colorReduce(Mat& inputImage, Mat& outputImage, int div)
{
	// 参数准备
	outputImage = inputImage.clone();

	int rowNumber = outputImage.rows;
	int colNumber = outputImage.cols*outputImage.channels();

	for (int i = 0; i < rowNumber; i++)
	{
		// 获取第i行的首地址
		uchar* data = outputImage.ptr<uchar>(i);

		for (int j = 0; j < colNumber; j++)  // 列循环
		{
			// 开始处理每一个像素值,每一个像素值都减去div
			data[j] = data[j] - div;
		}
	}
}

也可以写成如下形式:

Mat inverseColor1(Mat srcImage) 
{
	Mat tempImage = srcImage.clone();
	int row = tempImage.rows;
	int col = tempImage.cols * tempImage.channels();

	for (int i = 0; i < row; ++i) 
	{

		const unsigned char* sourcedata = srcImage.ptr(i);

		unsigned char* data = tempImage.ptr(i);

		for (int j = 0; j < col; j++)
		{
			data[j] = sourcedata[j] - div;
		}
	}
	return tempImage;
}
此时是定义了两个指针类型: const unsigned char*和 unsigned char*,其中const unsigned char* 中的内容只能够被读取,不能被修改

特别需要注意的是:Mat中每一行元素的个数=列数*通道数


如需要打印M,

	Mat M(3, 2, CV_8UC3, Scalar(0, 0, 255));
	cout << M << endl;
打印结果为:验证了每一行元素的个数为: 列数*通道数

另外需要注意的是:Mat 除了拥有成员变量cols,rows,成员函数channels()之外,还提供了ptr函数可以返回得到图像任意行的首地址。





3.用迭代器Matlterator_:

        Matlterator_是Mat数据操作的迭代器,:begin()表示指向Mat数据的起始迭代器,:end()表示指向Mat数据的终止迭代器。迭代器方法是一种更安全的用来遍历图像的方式,首先获取到数据图像的矩阵起始,再通过递增迭代实现移动数据指针。

Mat inverseColor4(Mat srcImage) 
{
	Mat tempImage = srcImage.clone();

	// 初始化原图像迭代器
	MatConstIterator_<Vec3b> srcIterStart = srcImage.begin<Vec3b>();
	MatConstIterator_<Vec3b> srcIterEnd = srcImage.end<Vec3b>();

	// 初始化输出图像迭代器
	MatIterator_<Vec3b> resIterStart = tempImage.begin<Vec3b>();
	MatIterator_<Vec3b> resIterEnd = tempImage.end<Vec3b>();

	while (srcIterStart != srcIterEnd) 
	{
		(*resIterStart)[0] = 255 - (*srcIterStart)[0];
		(*resIterStart)[1] = 255 - (*srcIterStart)[1];
		(*resIterStart)[2] = 255 - (*srcIterStart)[2];

		srcIterStart++;
		resIterStart++;
	}

	return tempImage;

}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值