注:原創不易,轉載請務必注明原作者和出處,感謝支持!
一 提升圖像對比度和亮度
一般來說圖像的變換可以分成以下兩類:
(1)像素變換
在像素變換中,僅僅根據輸入的像素值(有時可能加上某些全局信息或者參數)來計算相應的輸出像素值。該類變換的常見方法有亮度和對比度調整、顏色校正和顏色變換等等。該類變換可以用下面的通用變換公式來表示。\(f(x,y)\)表示原圖像\((x,y)\)處的像素值,\(T\)表示變換函數,\(g(x,y)\)表示輸出圖像\((x,y)\)處的像素值。可以看到輸入僅有當個位置的像素值。
(2)鄰域變換
在鄰域變換中,變換函數的輸入可以是多個像素所構成的一個鄰域,然后根據變換函數計算相應的像素值輸出。鄰域變換最常見的方法有圖像卷積操作。對於圖像卷積,假設中心錨點位置為\((x,y)\),濾波器大小為\(m \times n\),且\(m\)和\(n\)均為奇數(濾波器大小一般均為奇數)。令\(a = (m-1)/2\),\(b = (n-1)/2\),矩陣\(w\)為濾波器系數,原圖像為\(f\),輸出圖像為\(g\),則圖像的卷積操作可以用下面的通用公式表示。
而提升圖像對比度和亮度是一個典型的像素變換操作,它的變換公式表示如下。如果你想要提升圖像亮度(針對灰度圖),那你只需要令\(\alpha = 1\),並使\(\beta\)的值大於0,使圖像的亮度得到一個增益即可。此時,圖像的每個像素都將提升\(\beta\)個灰度值。如果你想要提升圖像對比度,那你只需要令\(\beta = 0\),並使\(\alpha\)的值大於1,使得圖像相鄰像素差值變大從而提升圖像的對比度。如果你既要提升對比度和亮度,則只需要選擇\(\alpha\)為大於1的合適值和\(\beta\)為大於0的合適值即可。
二 代碼實現
OpenCV中提供了一個實現提升圖像對比度和亮度的APIconvertTo()
如下。
void cv::Mat::convertTo(
OutputArray m, // 輸出圖像
int rtype, // 輸出圖像類型,取-1則表示類型與原圖相同
double alpha = 1, // alpha值
double beta = 0 // beta值
) const;
如果不使用convertTo()
,則可以將手寫代碼實現如下。
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main(int argc, char **argv)
{
// load source image and show it
Mat src = imread("D:\\IMG\\lena.jpg", IMREAD_UNCHANGED);
if (!src.data)
{
cout << "Error : could not load image." << endl;
return -1;
}
imshow("input", src);
// parameters for enhance contrast
double alpha = 2.0;
double beta = 0.0;
Mat dst(src.size(), src.type());
decltype(src.rows) row, col;
for (row = 0; row < src.rows; ++row)
{
for (col = 0; col < src.cols; ++col)
{
// single channel (gray image) or three channels (BGR image) only
if (src.channels() == 1)
{
int gray = src.at<uchar>(row, col);
dst.at<uchar>(row, col) = saturate_cast<uchar>(gray * alpha + beta);
}
else if (src.channels() == 3)
{
int b = src.at<Vec3b>(row, col)[0];
int g = src.at<Vec3b>(row, col)[1];
int r = src.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);
}
}
}
imshow("output (alpha = 2)", dst);
waitKey(0);
return 0;
}
如果使用APIconvertTo()
,則可以簡單地作如下實現。
src.convertTo(dst, -1, alpha, beta);
三 實現效果
(1) 單純提升亮度
原圖
手寫代碼實現,\(\beta\)分別為50、100、150
調用API實現,\(\beta\)分別為50、100、150
(2) 單純提升對比度
原圖
手寫代碼實現,\(\alpha\)分別為2、3、4
調用API實現,\(\alpha\)分別為2、3、4
(3) 同時提升對比度和亮度,\(\alpha = 3\),\(\beta = 50\)
可以看到,手寫代碼實現的效果與調用API實現的效果略有不同,但大體效果是不差多少的。在熟悉了API實現原理之后,以后就可以直接調用API進行實現而無需自己手動寫代碼實現。