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