Changing the contrast and brightness of an image!
此为OpenCV官方教程的个人翻译
目标
在本教程中,您将学习如何:
- 访问像素值
- 使用零初始化矩阵
- 了解saturate_cast以及为什么它有用
- 获取有关像素转换的一些很酷的信息
理论
注意:下面的理论源自Richard Szeliski的《Computer Vision: Algorithms and Applications》一书。
图像处理
- 通用图像处理运算符是输入一个或多个图像,并生成输出图像的函数
- 图像转换可以视作:
- Point operators (pixel transforms) (像素级别的转换) (点运算符)
- Neighborhood (area-based) operators (区域级别的转换)(邻域运算符)
像素转换
- 在这种图像处理变换中,每个输出像素的值仅取决于相应的输入像素值(加上一些可能全局收集的信息或参数)。
- 此类运算符的包括亮度和对比度调整以及颜色校正和变换。
亮度和对比度调整
-
两个常用的点过程(point process)为乘法和常数加法
\[g(x)=\alpha f(x) + \beta \] -
参数\(\alpha >0\),并且\(\beta\)经常被叫做增益和偏置参数(gain and bias parameters);有时这些参数分别控制对比度和亮度
-
您可以将\(f(x)\)是做原图像像素而将\(g(x)\)视作输出图像像素,然后我们便可以将表达式改写为:
\[g(i,j)=\alpha f(i,j)+\beta \]其中\(i\)和\(j\)分别指出了像素的行与列.
代码
下面的代码进行了\(g(i,j)=\alpha f(i,j)+\beta\)操作:
/*
* @LastEditors: 帝皇の惊
* @Date: 2022-06-26 16:17:00
* @Description: Edit Here
* @LastEditTime: 2022-06-26 16:57:00
*/
#include <iostream>
#include "opencv.hpp"
using namespace cv;
double alpha; //简易对比度控制
int beta; //简易亮度控制
int main(int argc, char** argv) {
// Read image
Mat image = imread("E:\\Work\\Visual Studio Code\\fengmian.jpg");
Mat new_image = Mat::zeros(image.size(), image.type());
// "initialize values"
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;
// 进行操作g(i,j)=alpha*f(i,j)+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);
}
}
}
// Craete Window
namedWindow("Original Image", WINDOW_NORMAL);
namedWindow("New Image", WINDOW_NORMAL);
// Show Stuff
imshow("Original Image", image);
imshow("New Image", new_image);
waitKey(0);
return 0;
}
解释
-
我们首先创建并保存\(\alpha,\beta\),这两个都是用户输入的参数:
double alpha; int beta; -
我们使用 imread 加载图像并将其保存在 Mat 对象中:
Mat image = imread("E:\\Work\\Visual Studio Code\\fengmian.jpg"); -
现在,由于我们将对此图像进行一些转换,因此我们需要一个新的 Mat 对象来存储它。此外,我们希望它具有以下特点:
- 初始像素值等于零
- 与原始图像相同的大小和类型
Mat new_image = Mat::zeros( image.size(), image.type() );我们观察到 Mat::zeros 返回一个基于 image.size() 和 image.type() 的 Matlab 样式的零初始值设定项。
-
现在,要执行该操作\(g(x)=\alpha f(x) + \beta\),我们将访问图像中的每个像素。由于我们使用的是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)。 - 由于该操作的运算结果可能无效或超出范围,因此我们使用saturate_cast来确保值有效。
- 为了访问图像中的每个像素,我们使用以下语法:image.at
-
最后,我们创建窗口显示图像。
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);其中 convertTo 将有效地执行 new_image = a*image + beta。但是,我们想向您展示如何访问每个像素。无论如何,这两种方法都给出了相同的结果,但convertTo更加优化,并且工作速度更快。
结果


浙公网安备 33010602011771号