OpenCV實現Photoshop算法(四): 色階調整


色階調整( Levles Adjustment )

(一)色階調整原理

色階是什么:色階就是用直方圖描述出的整張圖片的明暗信息。如圖

從左至右是從暗到亮的像素分布,黑色三角代表最暗地方(純黑),白色三角代表最亮地方(純白)。灰色三角代表中間調。

每一個色階定義有兩組值:

一組是輸入色階值,包含黑灰白三個值, 上圖中: 黑點值為0, 灰點為1.00,白點為255

另一組是輸入色階值,包含黑白兩個值,上圖中:輸出色階黑為0,白為255

對於一個RGB圖像,  可以對R,  G,  B 通道進行獨立的色階調整,即,對三個通道分別使用三個色階定義值。還可以再對 三個通道進行整體色階調整。 因此,對一個圖像,可以用四次色階調整。最終的結果,是四次調整后合並產生的結果。

我們先來分析對單通道的色階原理,比如:對紅色通道定義色階調整如下:

則此時:  輸入色階值為: 黑13,   灰1.29,    白240,   輸出色階值為:黑11,白242

則色階調整的實現是: 當輸入值<黑點值(13)時,全部變為輸出色階的黑值。 當輸入值>白點(240)時,全部變為輸出色階的白值

當輸入值介於黑值與白值之間(13-240)時,則結合灰度系數,按比例重新計算,變為一個新的值。

對紅、綠、藍三個獨立通道調整方式都與上述算法相同。各通道調整是互不相關的。

對RGB通道進行整體調整時,則對RGB三個值進行同時變換。

(二)色階調整的OpenCV實現

我用opencv寫了兩個 C++ 類: Levels類實現了多通道的色階的定義、實施調整。  Level類是一個通道的色階定義類。

源碼共兩個文件:    Levels.hpp,  Levels.cpp

源碼有一定的長度,不具體解釋了,請見注釋。

補充說明幾點:

1, Levels類中定義了四個Level對象(即四個通道),分別是RedChannel, GreenChannel, BlueChannel 和 RGBChannel.

2,每個Level對象有五個屬性值:

1 int   Shadow;  //輸入色階黑點值
2 float Midtones; //輸入色階灰點值(注意是浮點數)
3 int   Highlight; //輸入色階白點值
4 int   OutputShadow; //輸出色階黑點值
5 int   OutputHighlight; //輸出色階白點值

3, 使用方法:創建一個Levels對象,然后對其所屬的Level對象的屬性值進行賦值,然后調整 Levels類的adjust()方法,即可實現色階調整。

(三)例程

寫一個例程,使用Levels類,實現色階調整。

程序中定義了兩個窗口,一個是圖片窗口,一個是色階定義窗口。

 1 #include <cstdio>
 2 #include <iostream>
 3 #include "opencv2/core.hpp"
 4 #include "opencv2/imgproc.hpp"
 5 #include "opencv2/highgui.hpp"
 6  
 7 #include "Levels.hpp"
 8  
 9 using namespace std;  10 using namespace cv;  11  
 12 static string window_name = "Photo";  13 static Mat src;  14  
 15 static Mat levels_mat;  16 static string levels_window = "Adjust Levels";  17 static int channel = 0;  18 Levels levels;  19  
 20 int Shadow;  21 int   Midtones = 100;  22 int Highlight;  23 int OutputShadow;  24 int OutputHighlight;  25  
 26 static void invalidate()  27 {  28  Mat dst;  29  levels.adjust(src, dst);  30  imshow(window_name, dst);  31  
 32  imshow(levels_window, levels_mat);  33 }  34  
 35 static void channelRead(int which_channel)  36 {  37     channel = which_channel;  38     Level * CurrentChannel = NULL;  39     switch (channel) {  40     case 0: CurrentChannel = &levels.RGBChannel; break;  41     case 1: CurrentChannel = &levels.RedChannel; break;  42     case 2: CurrentChannel = &levels.GreenChannel; break;  43     case 3: CurrentChannel = &levels.BlueChannel; break;  44  }  45     if ( CurrentChannel == NULL ) return;  46  
 47     Shadow = CurrentChannel->Shadow;  48     Midtones = int (CurrentChannel->Midtones * 100);  49     Highlight = CurrentChannel->Highlight;  50     OutputShadow = CurrentChannel->OutputShadow;  51     OutputHighlight = CurrentChannel->OutputHighlight;  52  
 53 }  54  
 55 static void channelWrite()  56 {  57     Level * CurrentChannel = NULL;  58     switch (channel) {  59     case 0: CurrentChannel = &levels.RGBChannel; break;  60     case 1: CurrentChannel = &levels.RedChannel; break;  61     case 2: CurrentChannel = &levels.GreenChannel; break;  62     case 3: CurrentChannel = &levels.BlueChannel; break;  63  }  64  
 65     if ( CurrentChannel == NULL )  66         return ;  67  
 68     CurrentChannel->Shadow = Shadow;  69     CurrentChannel->Midtones = Midtones / 100.0;  70     CurrentChannel->Highlight = Highlight;  71     CurrentChannel->OutputShadow = OutputShadow;  72     CurrentChannel->OutputHighlight = OutputHighlight;  73  
 74  invalidate();  75 }  76  
 77  
 78 static void callbackAdjust(int , void *)  79 {  80  channelWrite();  81  invalidate();  82 }  83  
 84  
 85 static void callbackAdjustChannel(int , void *)  86 {  87  channelRead(channel);  88     setTrackbarPos("Shadow", levels_window, Shadow);  89     setTrackbarPos("Midtones", levels_window, Midtones);  90     setTrackbarPos("Highlight", levels_window, Highlight);  91     setTrackbarPos("OutShadow", levels_window, OutputShadow);  92     setTrackbarPos("OutHighlight", levels_window, OutputHighlight);  93  invalidate();  94 }  95  
 96  
 97 int main()  98 {  99     //read image file
100     src = imread("building.jpg"); 101     if ( !src.data ) { 102         cout << "error read image" << endl; 103         return -1; 104  } 105  
106     //create window
107  namedWindow(window_name); 108  imshow(window_name, src); 109  
110  
111     //create window for levels
112  namedWindow(levels_window); 113     levels_mat = Mat::ones(100,400, CV_8UC3); 114     levels_mat.setTo( Scalar(255,255,255) ); 115  imshow(levels_window, levels_mat); 116  
117     channelRead(0); 118     createTrackbar("Channel", levels_window, &channel,  3, callbackAdjustChannel); 119     createTrackbar("Shadow", levels_window, &Shadow,  255, callbackAdjust); 120     createTrackbar("Midtones", levels_window, &Midtones,  200, callbackAdjust); 121     createTrackbar("Highlight", levels_window, &Highlight,  255, callbackAdjust); 122     createTrackbar("OutShadow", levels_window, &OutputShadow,  255, callbackAdjust); 123     createTrackbar("OutHighlight", levels_window, &OutputHighlight,  255, callbackAdjust); 124  
125  waitKey(); 126  
127     return 0; 128  
129 }

運行效果:

原圖:

先對紅色通道(Channel = 1)調整各項色階定義值,進行單通道色階調整,效果如下:

再對RGB通道(Channel = 0)進行整體色階調整,效果如下:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM