影象編輯之對比度調整 亮度對比度的演算法公式
對比度,具體的概念解釋可以參考Wiki或者百度百科。簡單的講對比度反應了圖片上亮區域和暗區域的層次感。而反應到影象編輯上,調整對比度就是在保證平均亮度不變的情況下,擴大或縮小亮的點和暗的點的差異。既然是要保證平均亮度不變,所以對每個點的調整比例必須作用在該值和平均亮度的差值之上,這樣才能夠保證計算後的平均亮度不變,故有調整公式:
Out = Average + (In – Average) * ( 1 + percent)
其中In表示原始畫素點亮度,Average表示整張圖片的平均亮度,Out表示調整後的亮度,而percent即調整範圍[-1,1]。證明這個公式的正確性相當簡單:
設圖上有n個畫素點,各個點亮度為Ai,平均亮度為A,變化率為alpha,則有:
|
但是實際處理中,並沒有太多的必要去計算一張圖的平均亮度:一來耗時間,二來在平均亮度上的精確度並不會給影象的處理帶來太多的好處—-一般就假設一張圖的平均亮度為128,即一半亮度,而一張正常拍照拍出來的圖平均亮度應該是在[100,150]。在肉眼看來兩者基本沒有任何區別,而如果真實地去計算平均亮度還會帶來很大的計算量。如下:
通過計算平均亮度來調整對比度
view source print ?01 |
void AdjustContrastUsingAverageThreshold(TiBitmapData& bitmap, double level) |
02 |
{ |
03 |
|
04 |
TINYIMAGE_ASSERT_VOID(level >= -1.0 && level <= 1.0); |
05 |
|
06 |
double rThresholdSum = 0,gThresholdSum = 0,bThresholdSum = 0; |
07 |
double detal= level + 1; |
08 |
int width = bitmap.GetWidth(); |
09 |
int height = bitmap.GetHeight(); |
10 |
int stride = bitmap.GetStride(); |
11 |
int bpp = bitmap.GetBpp(); |
12 |
u8* bmpData = bitmap.GetBmpData(); |
13 |
int offset = stride - width * bpp; |
14 |
long pixels = bitmap.GetTotalPixels(); |
15 |
|
16 |
for ( int i = 0; i < height; i ++) |
17 |
{ |
18 |
for ( int j = 0; j < width; j++) |
19 |
{ |
20 |
rThresholdSum += bmpData[rIndex]; |
21 |
gThresholdSum += bmpData[gIndex]; |
22 |
bThresholdSum += bmpData[bIndex]; |
23 |
bmpData += bpp; |
24 |
} |
25 |
bmpData += offset; |
26 |
} |
27 |
|
28 |
int rThreshold = ( int )(rThresholdSum/pixels); |
29 |
int gThreshold = ( int )(gThresholdSum/pixels); |
30 |
int bThreshold = ( int )(bThresholdSum/pixels); |
31 |
|
32 |
u8 r_lookup[256],g_lookup[256],b_lookup[256]; |
33 |
|
34 |
for ( int i = 0; i < 256; i++) |
35 |
{ |
36 |
r_lookup[i] = (u8)CLAMP0255(rThreshold + (i - rThreshold)* detal); |
37 |
g_lookup[i] = (u8)CLAMP0255(gThreshold + (i - gThreshold)* detal); |
38 |
b_lookup[i] = (u8)CLAMP0255(bThreshold + (i - bThreshold)* detal); |
39 |
} |
40 |
|
41 |
AdjustCurve(bitmap,r_lookup,g_lookup,b_lookup); |
42 |
} |
不計算平均亮度:
view source print ?01 |
void AdjustContrastUsingConstThreshold(TiBitmapData& bitmap, double level) |
02 |
{ |
03 |
|
04 |
TINYIMAGE_ASSERT_VOID(level >= -1.0 && level <= 1.0); |
05 |
|
06 |
u8 lookup[256]; |
07 |
double delta = 1 + level; |
08 |
const int threshold = 0x7F; //128 可以認為是平均亮度 |
09 |
|
10 |
for ( int i = 0; i < 256; i++) |
11 |
{ |
12 |
lookup[i] = (u8)CLAMP0255(threshold + (i - threshold)* delta); |
13 |
} |
14 |
|
15 |
AdjustCurve(bitmap,lookup,TINYIMAGE_CHANEL_RGB); |
16 |
} |
而在呼叫演算法的時候完全可以通過一個開關來控制到底是呼叫哪個—-個人推薦下一種,雖然不嚴格符合調整對比度的語義,但效果基本一致。在Release下下一種基本是瞬間完成,對於3K*2K的圖也能保證在100ms內完成。
view source print ?1 |
void AdjustContrast(TiBitmapData& bitmap, double level) |
2 |
{ |
3 |
#ifdef CONSTTHRESHOLD |
4 |
AdjustContrastUsingConstThreshold(bitmap,level); |
5 |
#else |
6 |
AdjustContrastUsingAverageThreshold(bitmap,level); |
7 |
#endif |
8 |
} |
一、Photoshop對比度演算法。可以用下面的公式來表示:
(1)、nRGB = RGB + (RGB - Threshold) * Contrast / 255
公式中,nRGB表示影象畫素新的R、G、B分量,RGB表示影象畫素R、G、B分量,Threshold為給定的閥值,Contrast為處理過的對比度增量。
Photoshop對於對比度增量,是按給定值的正負分別處理的:
當增量等於-255時,是影象對比度的下端極限,此時,影象RGB各分量都等於閥值,影象呈全灰色,灰度圖上只有1條線,即閥值灰度;
當增量大於-255且小於0時,直接用上面的公式計算影象畫素各分量;
當增量等於 255時,是影象對比度的上端極限,實際等於設定影象閥值,影象由最多八種顏色組成,灰度圖上最多8條線,即紅、黃、綠、青、藍、紫及黑與白;
當增量大於0且小於255時,則先按下面公式(2)處理增量,然後再按上面公式(1)計算對比度:
(2)、nContrast = 255 * 255 / (255 - Contrast) - 255
公式中的nContrast為處理後的對比度增量,Contrast為給定的對比度增量。
二、影象亮度調整。本文采用的是最常用的非線性亮度調整(Phoposhop CS3以下版本也是這種亮度調整方式,CS3及以上版本也保留了該亮度調整方式的選項),本文亮度調整採用MMX,對亮度增量分正負情況分別進行了處理,每次處理2個畫素,速度相當快,比常規BASM程式碼的亮度處理過程還要快幾倍(參見《GDI+ 在Delphi程式的應用 -- 調整影象亮度》)。
三、影象亮度/對比度綜合調整演算法。這個很簡單,當亮度、對比度同時調整時,如果對比度大於0,現調整亮度,再調整對比度;當對比度小於0時,則相反,先調整對比度,再調整亮度。
亮度對比度的演算法公式
一副影象的亮度對比度調節屬於影象的灰度線性變換,其公式如下:
y = [x - 127.5 * (1 - B)] * k + 127.5 * (1 + B);
x為調節前的畫素值,y為調節後的畫素值。
其中B取值[-1,1],調節亮度;
k調節對比度,arctan(k)取值[1,89],所以
k = tan( (45 + 44 * c) / 180 * pi );
其中c取值[-1,1]。通常我們用該值來設定對比度
特別的,
當B=0 時:y = (x - 127.5) * k + 127.5; 這時只調節對比度。
當c=0 時,k = 1:y = x + 255 * B; 這時只調節亮度。
評論這張 轉發至微博 轉發至微博再分享一下我老師大神的人工智慧教程吧。零基礎!通俗易懂!風趣幽默!希望你也加入到我們人工智慧的隊伍中來!http://www.captainbed.net