opencv改变图片的亮度和对比度(c++实现)
Changing the contrast and brightness of an image!
- 访问像素值
- 用零初始化一个矩阵
- 了解cv :: saturate_cast做什么以及为什么它有用
- 获取有关像素变换的一些很酷的信息
理论
图像处理
- 一般的图像处理操作符是一个获取一个或多个输入图像并产生输出图像的功能。
- 图像转换可以被看作是:
- 点运算符(像素变换)
- 邻域(区域)操作
像素变换
- 在这种图像处理变换中,每个输出像素的值仅取决于对应的输入像素值(可能还有一些全局收集的信息或参数)。
- 这样的操作者的例子包括亮度和对比度调整以及颜色校正和变换。
亮度和对比度调整
- 两个常用的点过程是乘法和加法常量:
g(x)=g(x)=α∗f(x)+α∗f(x)+ββ - 参数αα> 0和ββ通常被称为增益和偏置参数; 有时这些参数分别被称为控制对比度和亮度。
- 您可以将f(x)f(x)视为源图像像素,将g(x)g(x)视为输出图像像素。 那么,我们可以更方便地写出这个表达式:
g(i,j)g(i,j)=ααf(x)f(x)+ββ
其中ii和jj表示像素位于第ii行第jj列。
代码
- 下面的代码执行操作g(i,j)g(i,j) = αα ⋅⋅ f(i,j)f(i,j) + ββ:
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
double alpha; /*< Simple contrast control */
int beta; /*< Simple brightness control */
int main(int argc, char** argv)
{
Mat image = imread(argv[1]);
Mat new_image = Mat::zeros(image.size(), image.type()); //与image 大小(h*w*c) 类型一致
std::cout << " Basic Linear Transforms " << std::endl;
std::cout << "-------------------------" << std::endl;
std::cout << "* Enter the alpha value [1.0-3.0]: "; std::cin >> alpha;
std::cout << "* Enter the beta value [0-100]: "; std::cin >> beta;
for (int y = 0; y < image.rows; y++) {
for (int x = 0; x < image.cols; x++) {
for (int c = 0; c < 3; c++) {
new_image.at<Vec3b>(y, x)[c] =
saturate_cast<uchar>(alpha*(image.at<Vec3b>(y, x)[c]) + beta);
}
}
}
namedWindow("Original Image", 1);
namedWindow("New Image", 1);
imshow("Original Image", image);
imshow("New Image", new_image);
waitKey();
return 0;
}
解释
1、我们首先创建参数来保存要由用户输入的αα和ββ:
double alpha;
int beta;
2、我们使用cv :: imread加载图像,并将其保存在Mat对象中:
Mat image = imread( argv[1] );
3、现在,由于我们将对这个图像进行一些转换,我们需要一个新的Mat对象来存储它。 另外,我们希望这具有以下特点:
- 初始像素值等于零
- 与原始图像大小和类型相同
Mat new_image = Mat::zeros( image.size(), image.type() );
我们观察到cv :: Mat :: zeros返回一个基于image.size()和image.type()的Matlab风格的零初始化器,
4、现在,执行操作g(i,j)g(i,j)=αα⋅·f(i,j)f(i,j)+ββ,我们将访问图像中的每个像素。 由于我们使用BGR图像进行操作,因此每像素(B,G和R)将有三个值,因此我们也将分别访问它们。 这是一段代码:
for( int y = 0; y < image.rows; y++ ) {
for( int x = 0; x < image.cols; x++ ) {
for( int c = 0; c < 3; c++ ) {
new_image.at<Vec3b>(y,x)[c] =
saturate_cast<uchar>( alpha*( image.at<Vec3b>(y,x)[c] ) + beta );
}
}
}
注意以下几点:
- 要访问图像中的每个像素,我们使用这个语法: image.at(y,x)[c] 其中y是行,x是列,c是R,G或B(0,1或2)。
- 由于ααp(i,j)p(i,j)+ββ的运算可以给出超出范围或不是整数(如果α是浮点数),我们使用cv::saturate_cast来确保这些值是有效的。
5、最后,我们创建窗口,并显示图像,通常的方式。
namedWindow("Original Image", 1);
namedWindow("New Image", 1);
imshow("Original Image", image);
imshow("New Image", new_image);
waitKey(0);
注意:
不使用for循环来访问每个像素,我们可以简单地使用这个命令:
image.convertTo(new_image, -1, alpha, beta);
其中cv :: Mat :: convertTo将有效地执行* new_image = a * image + beta *。 不过,我们想告诉你如何访问每个像素。 在任何情况下,这两种方法给出了相同的结果,但convertTo更优化,工作速度更快。
参考:https://blog.csdn.net/wc781708249/article/details/78448280