opencv之Mat的访问像素点

学习内容:

1、Mat的访问 2、调整图像亮度与对比度

学习产出:

1、Mat的访问
我们经常要用循环访问Mat中的像素点,此时我们可以用at来对某个像素点进行赋值操作,将某点的像素值反转,实现类似灰度的效果,例如

int ds = dst.at<uchar>(row, col);
dst.at<uchar>(row, col) = 255 - ds;

但是在单通道和三通道图像中略有不同,类似于一维矩阵和多维矩阵,这里的结构形式在图像遍历中十分常用,基本形式为

Mat.at<char>(row, col)//单通道
Mat.at<Vec3b>(row, col)[i]//三通道

其中i对应Scalar(b,g,r)中的列数,即可以分别将B,G,R三个分量分别读出,单独赋值,我们来看具体的实例

#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
#include
#include

using namespace std;
using namespace cv;

int main(int argc, char** argv)
{
	Mat src,gray_src;
	src = imread("resources/test.png");
	if (!src.data)
	{
		cout << "could not load image..." << endl;
		return -1;
	}
	namedWindow("input", CV_WINDOW_AUTOSIZE);
	imshow("input", src);

	cvtColor(src, gray_src, CV_BGR2GRAY);
	namedWindow("output", CV_WINDOW_AUTOSIZE);
	//imshow("output", gray_src);

	int height = gray_src.rows;
	int width = gray_src.cols;

	单通道
	//for (int i = 0; i < height; i++) {
	//	for (int j = 0; j < width; j++) {
	//		int gray = gray_src.at(i, j);
	//		gray_src.at(i, j) = 255 - gray;
	//	}
	//}
	//三通道
	Mat dst;
	dst.create(src.size(), src.type());
	 height = src.rows;
	 width = src.cols;
	int nc = src.channels();

	for (int i = 0; i < height; i++) {
		for (int j = 0; j < width; j++) {
			if (nc == 1)
			{
			int gray = gray_src.at<uchar>(i, j);
			gray_src.at<uchar>(i, j) = 255 - gray;
			}
			else if (nc == 3)
			{
				int b = src.at<Vec3b>(i, j)[0];
				int g = src.at<Vec3b>(i, j)[1];
				int r = src.at<Vec3b>(i, j)[2];
				dst.at<Vec3b>(i, j)[0] = 255 - b;
				dst.at<Vec3b>(i, j)[1] = 255 - g;
				dst.at<Vec3b>(i, j)[2] = 255 - r;

				gray_src.at<uchar>(i, j) = max(r, max(b, g));
			}
		}
	}
	//bitwise_not(src, dst);
	//namedWindow("gray invert", CV_WINDOW_AUTOSIZE);
	imshow("gray invert", dst);
	imshow("output", gray_src);
	waitKey(0);
	system("pause");
	return EXIT_SUCCESS;
}

当然上述代码opencv也给出了相应函数,即bitwise_not函数

void bitwise_not(InputArray src, OutputArray dst,InputArray mask=noArray());

bitwise_not是对二进制数据进行“非”操作,即对图像(灰度图像或彩色图像均可)每个像素值进行二进制“非”操作,出来的效果和上述代码一样,大家可以尝试。

2、调整图像亮度与对比度
可以用循环对像素点赋值的方式来调整图像亮度与对比度,这里引入两个算子alpha、beta,即对像素值进行线性运算,参考如下代码

#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
#include
#include

using namespace std;
using namespace cv;

int main(int argc, char** argv)
{
	Mat src, dst;
	src = imread("resources/hsv.jpg");

	if (!src.data)
	{
		cout << "could not load image src..." << endl;
		return -1;
	}
	
	char input_win[] = "input image";
	namedWindow(input_win, CV_WINDOW_AUTOSIZE);
	imshow(input_win, src);
	
	int height = src.rows;
	int width = src.cols;
	dst = Mat::zeros(src.size(), src.type());
	float alpha = 1.5;
	float beta = 10.0;

	/*Mat m1;
	src.convertTo(m1, CV_8UC3, alpha, beta);*/

	for (int row = 0; row < height; row++)
	{
		for (int col = 0; col < width; col++)
		{
			if (m1.channels() == 3)
			{
				float b = m1.at<Vec3b>(row, col)[0];
				float g = m1.at<Vec3b>(row, col)[1];
				float r = m1.at<Vec3b>(row, col)[2];

				dst.at<Vec3b>(row, col)[0] = saturate_cast<uchar>(b*alpha + beta);
				dst.at<Vec3b>(row, col)[1] = saturate_cast<uchar>(g*alpha + beta);
				dst.at<Vec3b>(row, col)[2] = saturate_cast<uchar>(r*alpha + beta);
				//saturate_cast函数避免转换过程中可能出现的溢出
			}
			else if (m1.channels() == 1)
			{
				float v = m1.at<uchar>(row, col);
				dst.at<uchar>(row, col) = saturate_cast<uchar>(v*alpha + beta);
			}
		}
	}

	char output_title[] = "contrast and brightness change demo";
	namedWindow(output_title, CV_WINDOW_AUTOSIZE);
	imshow(output_title, dst);
	//imshow(output_title, m1);

	waitKey(0);
	system("pause");
	return EXIT_SUCCESS;
}

也可以用convertTo函数,即上述代码注释部分

void Mat::convertTo( Mat& m, int rtype, double alpha=1, double beta=0 )

输入参数:
m 目标矩阵。如果m的大小与原矩阵不一样,或者数据类型与参数不匹配,那么在函数convertTo内部会先给m重新分配空间。
rtype 指定从原矩阵进行转换后的数据类型,即目标矩阵m的数据类型。当然,矩阵m的通道数应该与原矩阵一样的。如果rtype是负数,那么m矩阵的数据类型应该与原矩阵一样。
alpha 缩放因子。默认值是1。即把原矩阵中的每一个元素都乘以alpha。
beta 增量。默认值是0。即把原矩阵中的每一个元素都乘以alpha,再加上beta。
————————————————
原文链接:https://blog.csdn.net/weixin_36340947/article/details/78065791

你可能感兴趣的:(opencv图像处理,opencv,计算机视觉,c++)