目录
说在前面
- opencv版本:4.0.1
- 操作系统:win10
- vs版本:2017
- 官方文档:Changing the contrast and brightness of an image!
- 其他说明:自学,记录,demo
Theory
-
Image Process(图像处理)
- 将一张或多张图像作为输入,输出另外一张图像
(广义的定义?) - 图像变换包括两种:
- 点的操作(pixel transform) [Point operators (pixel transforms)]
- 区域的操作 [Neighborhood (area-based) operators]
- 将一张或多张图像作为输入,输出另外一张图像
-
Pixels Transform(像素变换)
- 每个输出像素的值只取决于相关输入像素点的值(可能也会有其他全局信息或者参数)
-
Brightness and contrast adjustments(亮度&对比度调整)
- 公式
g
(
x
)
=
α
f
(
x
)
+
β
g(x) = \alpha f(x) + \beta
g(x)=αf(x)+β
将 f ( x ) f(x) f(x)作为输入图像的像素点, g ( x ) g(x) g(x)作为输出图像的像素点,那么有
g ( i , j ) = α ⋅ f ( i , j ) + β g(i,j) = \alpha \cdot f(i,j) + \beta g(i,j)=α⋅f(i,j)+β
f ( i , j ) f(i,j) f(i,j)为输入图像第 i i i 行第 j j j 列的像素点, g ( i , j ) g(i,j) g(i,j)同理。 - 参数
α
>
0
\alpha > 0
α>0 称为增益(gain)参数,用来控制对比度;参数
β
\beta
β 称为偏置(bias)参数,用来控制亮度。解释一下控制的原理,假设一张 灰度图(单通道) 某部分的像素值如下:
20 50 20 10 60 10 0 10 10 \begin{matrix} 20 & 50 & 20 \\ 10 & 60 & 10 \\ 0 & 10 & 10 \\ \end{matrix} 20100506010201010
假设 α = 2 \alpha=2 α=2, β = 0 \beta=0 β=0,那么上述像素值变为如下:
40 100 40 20 120 20 0 20 20 \begin{matrix} 40 & 100 & 40 \\ 20 & 120 & 20 \\ 0 & 20 & 20 \\ \end{matrix} 4020010012020402020
可以看到,像素之间的差异变大,(比如60-50=10,120-100=20),也就表现出对比度增大。
对于亮度,同样我们来考虑灰度图(单通道),像素值0是黑色、255是白色,当 β \beta β越来越大,像素值就越接近255,也就越白,表现出来就是亮度提高。
多通道同理。
- 公式
g
(
x
)
=
α
f
(
x
)
+
β
g(x) = \alpha f(x) + \beta
g(x)=αf(x)+β
Code
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include <iostream>
// we're NOT "using namespace std;" here,
//to avoid collisions between the beta variable and std::beta in c++17
using std::cin;
using std::cout;
using std::endl;
using namespace cv;
int alpha;
int beta;
Mat image;
void on_trackbar(int, void*)
{
double alpha_t = alpha / 100.0;
Mat new_image = Mat::zeros(image.size(), image.type());
for (int y = 0; y < image.rows; y++) {
for (int x = 0; x < image.cols; x++) {
for (int c = 0; c < image.channels(); c++) {
new_image.at<Vec3b>(y, x)[c] =
saturate_cast<uchar>(alpha_t*image.at<Vec3b>(y, x)[c] + beta);
}
}
}
//或者使用opencv提供的方法
//image.convertTo(new_image, -1, alpha_t, beta);
imshow("Original Image", image);
imshow("bright&contrast", new_image);
}
int main()
{
image = imread("lena.jpg");
if (image.empty())
{
cout << "Could not open or find the image!\n" << endl;
return -1;
}
alpha = 100; /*< Simple contrast control */
beta = 0; /*< Simple brightness control */
namedWindow("bright&contrast");
createTrackbar("contrast:", "bright&contrast", &alpha, 300, on_trackbar);
createTrackbar("bright: ", "bright&contrast", &beta, 100, on_trackbar);
on_trackbar(alpha, 0);
on_trackbar(beta, 0);
while (char(waitKey(1)) != 'q') { }
return 0;
}
- 这部分应该好理解,对每个像素每个通道应用一遍上面那个公式:
for (int y = 0; y < image.rows; y++) {
for (int x = 0; x < image.cols; x++) {
for (int c = 0; c < image.channels(); c++) {
new_image.at<Vec3b>(y, x)[c] =
saturate_cast<uchar>(alpha_t*image.at<Vec3b>(y, x)[c] + beta);
//saturate_cast,这个讲过,防止值溢出
//at<Vec3b>也讲过
}
}
}
- 然后就是这部分,创建一个滑动条(createTrackBar)
namedWindow("bright&contrast");
//在窗口“bright&contrast”上创建一个名叫“contrast”的滑动条;
//滑动条改变的值是全局变量alpha,改变的最大值是300,在每次值改变后调用函数on_trackbar
createTrackbar("contrast:", "bright&contrast", &alpha, 300, on_trackbar);
createTrackbar("bright: ", "bright&contrast", &beta, 100, on_trackbar);
Result
Practical example(重点)
-
引出问题
- 在上述调整对比度与亮度的方法中,我们使用了 saturate_cast 来防止值溢出,但是,这种方式可能会导致:
- 在调整亮度时降低图像的对比度
这里我的理解是这样的,以下面这部分原始像素为例
200 250 200 200 250 200 200 200 200 \begin{matrix} 200 & 250 & 200 \\ 200 & 250 & 200 \\ 200 & 200 & 200 \\ \end{matrix} 200200200250250200200200200
若 α = 1 , β = 50 \alpha=1,\beta=50 α=1,β=50,那么就有
250 255 250 250 255 250 250 250 250 \begin{matrix} 250 & 255 & 250 \\ 250 & 255 & 250 \\ 250 & 250 & 250 \\ \end{matrix} 250250250255255250250250250
可以看到,像素之间的差异变小,也就是对比度降低 - 在调整对比度的时候使图片在原本就很亮的地方失去一些细节
我们同样以上面那部分像素为例:
200 250 200 200 250 200 200 200 200 \begin{matrix} 200 & 250 & 200 \\ 200 & 250 & 200 \\ 200 & 200 & 200 \\ \end{matrix} 200200200250250200200200200
若 α = 1.2 , β = 0 \alpha=1.2,\beta=0 α=1.2,β=0,那么就有
255 255 255 255 255 255 255 255 255 \begin{matrix} 255 & 255 & 255 \\ 255 & 255 & 255 \\ 255 & 255 & 255 \\ \end{matrix} 255255255255255255255255255
全是255,很明显,原来的细节没有了。(ง •_•)ง
-
Gamma correction
-
theory
用于亮度调整,使用非线性变换(之前用的是线性变换)
O = ( I 255 ) γ × 255 O = \left( \frac{I}{255} \right)^{\gamma} \times 255 O=(255I)γ×255
I I I为输入图像(或者像素值), O O O为输出图像(或者像素值)
当 γ < 1 \gamma<1 γ<1时,亮度提高;当 γ > 1 \gamma>1 γ>1时,亮度降低。
偷一张官方图
-
code
使用了LUT,之前有讲过image = imread("gamma.jpg"); if (image.empty()) { cout << "Could not open or find the image!\n" << endl; return -1; } Mat lookUpTable(1, 256, CV_8U); uchar* p = lookUpTable.ptr(); for (int i = 0; i < 256; ++i) p[i] = saturate_cast<uchar>(pow(i / 255.0, 0.4) * 255.0); Mat res = image.clone(); LUT(image, lookUpTable, res); imshow("source", image); imshow("gamma", res); waitKey();
-
result
这里使用的测试图片也是官方文档里那张,没找到合适的
-
找到张好点的图
上面的是gamma校正,下面直接调亮度,可以看框起来的区域的对比。
-
END-(CSDN)2019.6.29
(。・∀・)ノ