C++影象處理 -- 影象黑白調整應用

pamxy發表於2013-03-21

轉自:http://blog.csdn.net/maozefa/article/details/6595831

閱讀提示

    《C++影象處理》系列以程式碼清晰,可讀性為主,全部使用C++程式碼。

    《Delphi影象處理》系列以效率為側重點,一般程式碼為PASCAL,核心程式碼採用BASM。

    儘可能保持二者內容一致,可相互對照。

    本文程式碼必須包括《C++影象處理 -- 資料型別及公用函式文章中的BmpData.h標頭檔案。

 

    Photoshop CS的影象黑白調整功能,是通過對紅、黃、綠、青、藍和洋紅等6種顏色的比例調節來完成的。能更精細地將彩色圖片轉換為高質量的黑白照片。

    Photoshop CS影象黑白調整功能的計算公式為:

    gray = (max - min) * ratio_max + (mid - min) * ratio_max_mid + min

    公式中:gray為畫素灰度值,max、mid和min分別為影象畫素R、G、B分量顏色的最大值、中間值和最小值,ratio_max為max所代表的分量顏色(單色)比率,ratio_max_mid則為max與mid兩種分量顏色所形成的複色比率。

    用上面公式計算的灰度值,與我們通常所用的灰度計算方法有很大不同,通常所用的灰度公式為,是直接將顏色各分量乘以相應的比率相加而成,如:gray = 0.3R + 0.59G + 0.11B,而上面公式則是在最小值代表的顏色分量基礎上,用最大值與最小值之差表示單色部分(紅、綠、藍),用中間值與最小值之差表示複色部分(黃、青、洋紅),將單色和複色部分分別乘以與之對應的比率後相加,再加上最小值而得到灰度值。對於每個單獨的畫素來說,計算灰度值只需要用到上述6種顏色比率中的2種即可。在計算過程中可根據畫素RGB相互關係選擇對應的單色和複色比率,如畫素RGB的大小關係為R>G>B,單色比率選最大值R紅色,複色比率則為最大值R與中間值G所形成的複色黃色。

    用程式程式碼實現上面的灰度計算公式並不複雜,難點還是前面所說的根據畫素RGB相互關係選擇對應的單色和複色比率。在前天我寫的《C++影象處理 -- 影象顏色混合(上)》文章中,已經實現了這項功能,同時,Photoshop影象黑白調整功能中附加的著色功能,也在文章中實現。本文的在上面文章程式碼基礎上,編寫一個相對簡單的影象黑白調整介面,來實現影象動態黑白調整。

    下面是用BCB2007寫的一個介面程式程式碼:

    程式標頭檔案部分:

  1. //---------------------------------------------------------------------------  
  2.   
  3. #ifndef bwMainH  
  4. #define bwMainH  
  5. //---------------------------------------------------------------------------  
  6. #include <Classes.hpp>  
  7. #include <Controls.hpp>  
  8. #include <StdCtrls.hpp>  
  9. #include <Forms.hpp>  
  10. #include <ComCtrls.hpp>  
  11. #include <Dialogs.hpp>  
  12. #include <ExtCtrls.hpp>  
  13.   
  14. #define USE_GDIPLUS  
  15.   
  16. #include "BmpData.h"  
  17. //---------------------------------------------------------------------------  
  18. enum TLockType {ltEdit, ltTrack};  
  19. typedef Set<TLockType, ltEdit, ltTrack> TLockTypes;  
  20.   
  21. class TForm1 : public TForm  
  22. {  
  23. __published:    // IDE-managed Components  
  24.     TPaintBox *PaintBox1;  
  25.     TLabel *Label1;  
  26.     TLabel *Label2;  
  27.     TLabel *Label3;  
  28.     TLabel *Label4;  
  29.     TLabel *Label5;  
  30.     TLabel *Label6;  
  31.     TLabel *Label7;  
  32.     TLabel *Label8;  
  33.     TLabel *Label9;  
  34.     TLabel *Label10;  
  35.     TLabel *Label11;  
  36.     TLabel *Label12;  
  37.     TLabel *Label13;  
  38.     TLabel *Label18;  
  39.     TComboBox *ComboBox1;  
  40.     TEdit *Edit1;  
  41.     TTrackBar *TrackBar1;  
  42.     TEdit *Edit2;  
  43.     TTrackBar *TrackBar2;  
  44.     TEdit *Edit3;  
  45.     TTrackBar *TrackBar3;  
  46.     TEdit *Edit4;  
  47.     TTrackBar *TrackBar4;  
  48.     TEdit *Edit5;  
  49.     TTrackBar *TrackBar5;  
  50.     TEdit *Edit6;  
  51.     TTrackBar *TrackBar6;  
  52.     TCheckBox *CheckBox1;  
  53.     TGroupBox *GroupBox1;  
  54.     TLabel *Label14;  
  55.     TLabel *Label15;  
  56.     TLabel *Label16;  
  57.     TLabel *Label17;  
  58.     TPaintBox *PaintBox2;  
  59.     TEdit *Edit7;  
  60.     TTrackBar *TrackBar7;  
  61.     TEdit *Edit8;  
  62.     TTrackBar *TrackBar8;  
  63.     TColorDialog *ColorDialog1;  
  64.     void __fastcall FormCreate(TObject *Sender);  
  65.     void __fastcall FormDestroy(TObject *Sender);  
  66.     void __fastcall ComboBox1Change(TObject *Sender);  
  67.     void __fastcall TrackBar1Change(TObject *Sender);  
  68.     void __fastcall Edit1Change(TObject *Sender);  
  69.     void __fastcall Edit1KeyPress(TObject *Sender, char &Key);  
  70.     void __fastcall Edit1Exit(TObject *Sender);  
  71.     void __fastcall CheckBox1Click(TObject *Sender);  
  72.     void __fastcall TrackBar7Change(TObject *Sender);  
  73.     void __fastcall Edit7Change(TObject *Sender);  
  74.     void __fastcall Edit7KeyPress(TObject *Sender, char &Key);  
  75.     void __fastcall PaintBox2Click(TObject *Sender);  
  76.     void __fastcall PaintBox1Paint(TObject *Sender);  
  77.     void __fastcall PaintBox2Paint(TObject *Sender);  
  78.     void __fastcall TrackBar8Change(TObject *Sender);  
  79. private:    // User declarations  
  80.     Bitmap *Source;                 // 源影象  
  81.     Bitmap *Dest;                   // 調整後的影象  
  82.     BitmapData srcData;  
  83.     BitmapData dstData;  
  84.     float bwColors[6];              // 灰度選項陣列  
  85.     int Bright;                     // 亮度  
  86.     TTrackBar *TrackBars[6];        // 灰度選項條元件陣列  
  87.     TEdit *Edits[6];                // 灰度選項編輯框陣列  
  88.     TLockTypes Lock;  
  89.     Gdiplus::Rect rect;  
  90.     ARGBQuad MixColor;              // 混合顏色  
  91.   
  92.     int __fastcall GetHue(void);  
  93.     int __fastcall GetSat(void);  
  94.     void __fastcall SetHue(int hue);  
  95.     void __fastcall SetSat(int sat);  
  96.   
  97.     void __fastcall MixColorToHSV(void);  
  98.     void __fastcall HSVToMixColor(void);  
  99.     void __fastcall Execute(void);  
  100.     void __fastcall MixColorChange(void);  
  101. public:     // User declarations  
  102.     __fastcall TForm1(TComponent* Owner);  
  103.   
  104.     __property int Hue = {read=GetHue, write=SetHue};   // 色相  
  105.     __property int Sat = {read=GetSat, write=SetSat};   // 飽和度  
  106. };  
  107. //---------------------------------------------------------------------------  
  108. const CustomIndex = 11;             // 自定義選項索引  
  109. const DefaultTint = 0xe1d3b3;       // 預設混合顏色  
  110. const int DefOptions[][6] =         // 預定義灰度選項  
  111. {  
  112.     {40, 60, 40, 60, 20, 80},  
  113.     {128, 128, 100, 100, 128, 100},  
  114.     {100, 100, 100, 100, 100, 100},  
  115.     {0, 0, 0, 0, 0, 0},  
  116.     {-40, 235, 144, -68, -3, -107},  
  117.     {120, 110, -10, -50, 0, 120},  
  118.     {50, 120, 90, 50, 0, 0},  
  119.     {0, 0, 0, 110, 110, 110},  
  120.     {120, 120, -10, -50, -50, 120},  
  121.     {-50, -50, -50, 150, 150, 150},  
  122.     {120, 110, 40, -30, 0, 70}  
  123. };  
  124.   
  125. extern PACKAGE TForm1 *Form1;  
  126. //---------------------------------------------------------------------------  
  127. #endif  

     程式碼檔案部分:

  1. //---------------------------------------------------------------------------  
  2.   
  3. #include <vcl.h>  
  4. #pragma hdrstop  
  5.   
  6. #include "bwMain.h"  
  7. //---------------------------------------------------------------------------  
  8. #pragma package(smart_init)  
  9. #pragma resource "*.dfm"  
  10. TForm1 *Form1;  
  11. //---------------------------------------------------------------------------  
  12. __fastcall TForm1::TForm1(TComponent* Owner)  
  13.     : TForm(Owner)  
  14. {  
  15. }  
  16. //---------------------------------------------------------------------------  
  17. ULONG gdiplusToken;  
  18.   
  19. typedef FLOAT       BWParams, *PBWParams;  
  20.   
  21. // 黑白調整預設引數:紅,黃,綠,洋紅,藍,青  
  22. CONST INT _BWDefault[] = {410, 614, 410, 819, 205, 614};  
  23.   
  24. enum  
  25. {  
  26.     BWIndexBlue     = 0x40000,  
  27.     BWIndexGreen    = 0x20000,  
  28.     BWIndexRed      = 0x00000  
  29. };  
  30.   
  31. enum  
  32. {  
  33.     IndexBlue   = 0x00000,  
  34.     IndexGreen  = 0x10000,  
  35.     IndexRed    = 0x20000  
  36. };  
  37.   
  38. typedef union               // 顏色分量交換結構  
  39. {  
  40.     INT tmp;                // 交換時用的臨時變數  
  41.     struct  
  42.     {  
  43.         SHORT value;        // 顏色分量值  
  44.         SHORT index;        // 顏色分量索引  
  45.     };  
  46. }RGBIndex;  
  47. //---------------------------------------------------------------------------  
  48.   
  49. // 交換畫素分量  
  50. FORCEINLINE  
  51. VOID SwapRgb(RGBIndex &a, RGBIndex &b)  
  52. {  
  53.     a.tmp ^= b.tmp;  
  54.     b.tmp ^= a.tmp;  
  55.     a.tmp ^= b.tmp;  
  56. }  
  57. //---------------------------------------------------------------------------  
  58.   
  59. // 獲取黑白灰度  
  60. FORCEINLINE  
  61. INT GetBWGray(CONST PARGBQuad pixel, CONST PINT bwParams)  
  62. {  
  63.     RGBIndex max, mid, min;  
  64.     min.tmp = pixel->Blue | BWIndexBlue;  
  65.     mid.tmp = pixel->Green | BWIndexGreen;  
  66.     max.tmp = pixel->Red | BWIndexRed;  
  67.   
  68.     if (max.value < mid.value)  
  69.         SwapRgb(max, mid);  
  70.     if (max.value < min.value)  
  71.         SwapRgb(max, min);  
  72.     if (min.value > mid.value)  
  73.         SwapRgb(min, mid);  
  74.   
  75.     return (((max.value - mid.value) * bwParams[max.index] +  
  76.         (mid.value - min.value) * bwParams[max.index + mid.index - 1] +  
  77.         512) >> 10) + min.value;  
  78. }  
  79. //---------------------------------------------------------------------------  
  80.   
  81. VOID ColorMix(PARGBQuad pd, CONST PARGBQuad ps, INT gray)  
  82. {  
  83.     // 灰度計算常數:藍,綠、紅  
  84.     CONST INT ys[3] = {113, 604, 307};  
  85.   
  86.     RGBIndex max, mid, min;  
  87.     min.tmp = ps->Blue | IndexBlue;  
  88.     mid.tmp = ps->Green | IndexGreen;  
  89.     max.tmp = ps->Red | IndexRed;  
  90.   
  91.     if (max.value < mid.value)  
  92.         SwapRgb(max, mid);  
  93.     if (max.value < min.value)  
  94.         SwapRgb(max, min);  
  95.     if (min.value > mid.value)  
  96.         SwapRgb(min, mid);  
  97.   
  98.     INT max_min = max.value - min.value;  
  99.     // 飽和度為0,返回灰度  
  100.     if (max_min == 0)  
  101.     {  
  102.         pd->Blue = pd->Green = pd->Red = gray;  
  103.         return;  
  104.     }  
  105.     INT mid_min = mid.value - min.value;  
  106.   
  107.     INT newMax, newMid, newMin;  
  108.     gray <<= 10;  
  109.     newMax = (gray + (max_min - mid_min) * ys[mid.index] + max_min * ys[min.index] + 512) >> 10;  
  110.     newMin = newMax - max_min;  
  111.     if (newMax > 255)  
  112.     {  
  113.         INT hueCoef = (mid_min << 10) / max_min;  
  114.         INT v0 = (ys[mid.index] * hueCoef) >> 10;  
  115.         INT v1 = ys[min.index] + ys[mid.index] - v0;  
  116.         newMin = (gray - (ys[max.index] + v0) * 255 + (v1 >> 1)) / v1;  
  117.         newMid = newMin + (((255 ^ newMin) * hueCoef + 512) >> 10);  
  118.         newMax = 255;  
  119.   
  120.     }  
  121.     else if (newMin < 0)  
  122.     {  
  123.         INT hueCoef = (mid_min << 10) / max_min;  
  124.         INT tmp = ys[max.index] + ((ys[mid.index] * hueCoef + 512) >> 10);  
  125.         newMax = (gray + (tmp >> 1)) / tmp;  
  126.         newMid = (newMax * hueCoef + 512) >> 10;  
  127.         newMin = 1;  
  128.     }  
  129.     else  
  130.         newMid = newMin + mid_min;  
  131.   
  132.     ((LPBYTE)pd)[max.index] = newMax;  
  133.     ((LPBYTE)pd)[mid.index] = newMid;  
  134.     ((LPBYTE)pd)[min.index] = newMin;  
  135. }  
  136. //---------------------------------------------------------------------------  
  137.   
  138. // 影象黑白調整。  
  139. // 調整引數bwParams為元素數等於6的陣列指標,分別為紅,黃,綠,青,藍,洋紅  
  140. VOID ImageBWCopy(BitmapData *dest, CONST BitmapData *source, CONST PBWParams bwParams = NULL)  
  141. {  
  142.     // 拷貝畫素灰度引數,並交換青色和洋紅色  
  143.     INT params[6], *pparams;  
  144.     if (bwParams)  
  145.     {  
  146.         for (INT i = 0; i < 6; i ++)  
  147.             params[i] = (INT)(bwParams[i] * 1024 + 0.5);  
  148.         params[3] ^= params[5];  
  149.         params[5] ^= params[3];  
  150.         params[3] ^= params[5];  
  151.         pparams = params;  
  152.     }  
  153.     else  
  154.         pparams = (INT*)_BWDefault;  
  155.   
  156.     PARGBQuad pd, ps;  
  157.     UINT width, height;  
  158.     INT dstOffset, srcOffset;  
  159.     GetDataCopyParams(dest, source, width, height, pd, ps, dstOffset, srcOffset);  
  160.   
  161.     for (UINT y = 0; y < height; y ++, pd += dstOffset, ps += srcOffset)  
  162.     {  
  163.         for (UINT x = 0; x < width; x ++, pd ++, ps ++)  
  164.         {  
  165.             INT gray = GetBWGray(ps, pparams);  
  166.             pd->Blue = pd->Green = pd->Red =  
  167.                 (gray & ~0xff) == 0? gray : gray > 255? 255 : 0;  
  168.         }  
  169.     }  
  170. }  
  171. //---------------------------------------------------------------------------  
  172.   
  173. // 灰度影象染色。  
  174. VOID ImageTint(BitmapData *grayData, ARGB color)  
  175. {  
  176.     ARGBQuad colorTable[256];  
  177.     PARGBQuad p = colorTable;  
  178.   
  179.     for (INT i = 0; i < 256; i ++, p ++)  
  180.     {  
  181.         ColorMix(p, (PARGBQuad)&color, i);  
  182.         p->Alpha = 255;  
  183.     }  
  184.   
  185.     p = (PARGBQuad)grayData->Scan0;  
  186.     INT dataOffset = (grayData->Stride >> 2) - (INT)grayData->Width;  
  187.   
  188.     for (UINT y = 0; y < grayData->Height; y ++, p += dataOffset)  
  189.     {  
  190.         for (UINT x = 0; x < grayData->Width; x ++, p ++)  
  191.         {  
  192.             p->Color = colorTable[p->Blue].Color;  
  193.         }  
  194.     }  
  195. }  
  196. //---------------------------------------------------------------------------  
  197.   
  198. void __fastcall TForm1::FormCreate(TObject *Sender)  
  199. {  
  200.     Gdiplus::GdiplusStartupInput gdiplusStartupInput;  
  201.     GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);  
  202.   
  203.     TrackBars[0] = TrackBar1;  
  204.     TrackBars[1] = TrackBar2;  
  205.     TrackBars[2] = TrackBar3;  
  206.     TrackBars[3] = TrackBar4;  
  207.     TrackBars[4] = TrackBar5;  
  208.     TrackBars[5] = TrackBar6;  
  209.     Edits[0] = Edit1;  
  210.     Edits[1] = Edit2;  
  211.     Edits[2] = Edit3;  
  212.     Edits[3] = Edit4;  
  213.     Edits[4] = Edit5;  
  214.     Edits[5] = Edit6;  
  215.   
  216.     // 從檔案裝入影象到tmp  
  217.     Bitmap *tmp = new Bitmap(L"source1.jpg");  
  218.     rect.Width = tmp->GetWidth();  
  219.     rect.Height = tmp->GetHeight();  
  220.     // 分別建立新的源和目標影象資料到srcData和dstData  
  221.     GetBitmapData(rect.Width, rect.Height, &srcData);  
  222.     GetBitmapData(rect.Width, rect.Height, &dstData);  
  223.     // 將tmp影象資料分別鎖定拷貝到srcData和dstData  
  224.     tmp->LockBits(&rect,  
  225.         ImageLockModeRead | ImageLockModeWrite | ImageLockModeUserInputBuf,  
  226.         PixelFormat32bppARGB, &srcData);  
  227.     tmp->UnlockBits(&srcData);  
  228.     tmp->LockBits(&rect,  
  229.         ImageLockModeRead | ImageLockModeWrite | ImageLockModeUserInputBuf,  
  230.         PixelFormat32bppARGB, &dstData);  
  231.     tmp->UnlockBits(&dstData);  
  232.     delete tmp;  
  233.     // 分別用影象資料srcData和dstData建立點陣圖Source和Dest  
  234.     // 注:影象資料結構用於資料處理,點陣圖用於顯示,這樣即可繫結資料結構和點陣圖,  
  235.     //     又能避免每次處理影象資料時的鎖定和解鎖操作  
  236.     Source = new Bitmap(srcData.Width, srcData.Height, srcData.Stride,  
  237.         PixelFormat32bppARGB, (BYTE*)srcData.Scan0);  
  238.     Dest = new Bitmap(dstData.Width, dstData.Height, dstData.Stride,  
  239.         PixelFormat32bppARGB, (BYTE*)dstData.Scan0);  
  240.   
  241.     ComboBox1Change(NULL);  
  242. }  
  243. //---------------------------------------------------------------------------  
  244.   
  245. void __fastcall TForm1::FormDestroy(TObject *Sender)  
  246. {  
  247.     delete Dest;  
  248.     delete Source;  
  249.     FreeBitmapData(&dstData);  
  250.     FreeBitmapData(&srcData);  
  251.     GdiplusShutdown(gdiplusToken);  
  252. }  
  253. //---------------------------------------------------------------------------  
  254.   
  255. // 執行影象黑白調整  
  256. void __fastcall TForm1::Execute(void)  
  257. {  
  258.     for (int i = 0; i < 6; i ++)             // 獲取灰度選項條資料  
  259.         bwColors[i] = TrackBars[i]->Position / 100.0;  
  260.     ImageBWCopy(&dstData, &srcData, bwColors);  // 源圖黑白調整到目標圖  
  261.     if (CheckBox1->Checked && Sat)               // 如果色調選項被選,著色  
  262.         ImageTint(&dstData, MixColor.Color);  
  263.     PaintBox1Paint(NULL);                       // 顯示影象  
  264. }  
  265. //---------------------------------------------------------------------------  
  266.   
  267. // 預設黑白調整選項改變  
  268. void __fastcall TForm1::ComboBox1Change(TObject *Sender)  
  269. {  
  270.     if (ComboBox1->ItemIndex == CustomIndex)  
  271.         return;  
  272.     MixColor.Color = DefaultTint;       // 設定預設混合顏色  
  273.     MixColorToHSV();                    // 計算並設定預設色相、飽和度控制元件  
  274.     Lock = TLockTypes() << ltEdit << ltTrack;  
  275.     try  
  276.     {  
  277.         for (int i = 0; i < 6; i ++) // 裝入預設的選項資料到相應的控制元件  
  278.         {  
  279.             TrackBars[i]->Position = DefOptions[ComboBox1->ItemIndex][i];  
  280.             Edits[i]->Text = DefOptions[ComboBox1->ItemIndex][i];  
  281.         }  
  282.         if (CheckBox1->Checked)  
  283.             CheckBox1->Checked = false;  // 取消色調選項  
  284.         else  
  285.             Execute();  
  286.     }  
  287.     __finally  
  288.     {  
  289.         Lock.Clear();  
  290.     }  
  291. }  
  292. //---------------------------------------------------------------------------  
  293.   
  294. // 黑白調整資料選項條改變  
  295. void __fastcall TForm1::TrackBar1Change(TObject *Sender)  
  296. {  
  297.     if (Lock.Contains(ltTrack)) return;  
  298.     Lock = TLockTypes() << ltEdit;  
  299.     try  
  300.     {  
  301.         TTrackBar *bar = (TTrackBar*)Sender;  
  302.         Edits[bar->Tag]->Text = bar->Position;  
  303.         ComboBox1->ItemIndex = CustomIndex;  // 預設下拉框設定為自定義  
  304.         Execute();  
  305.     }  
  306.     __finally  
  307.     {  
  308.         Lock.Clear();  
  309.     }  
  310. }  
  311. //---------------------------------------------------------------------------  
  312.   
  313. // 黑白調整資料編輯框改變  
  314. void __fastcall TForm1::Edit1Change(TObject *Sender)  
  315. {  
  316.     if (Lock.Contains(ltEdit)) return;  
  317.     TEdit *edit = (TEdit*)Sender;  
  318.     if (edit->Text != "" && edit->Text != "-")  
  319.         TrackBars[edit->Tag]->Position = StrToInt(edit->Text);  
  320. }  
  321. //---------------------------------------------------------------------------  
  322.   
  323. void __fastcall TForm1::Edit1KeyPress(TObject *Sender, char &Key)  
  324. {  
  325.     if (Key >= ' ' && Key != '-' && (Key < '0' || Key > '9'))  
  326.         Key = 0;  
  327. }  
  328. //---------------------------------------------------------------------------  
  329.   
  330. void __fastcall TForm1::Edit1Exit(TObject *Sender)  
  331. {  
  332.     TEdit *edit = (TEdit*)Sender;  
  333.     if (edit->Text == "")  
  334.         edit->Text = TrackBars[edit->Tag]->Position;  
  335. }  
  336. //---------------------------------------------------------------------------  
  337.   
  338. // 混合顏色改變,畫混合顏色,顯示其RGB值  
  339. void __fastcall TForm1::MixColorChange(void)  
  340. {  
  341.     PaintBox2Paint(NULL);  
  342.     Label18->Caption = "R: " + IntToStr(MixColor.Red) +  
  343.                     ", G: " + MixColor.Green +  
  344.                     ", B: " + MixColor.Blue;  
  345.     Execute();  
  346. }  
  347. //---------------------------------------------------------------------------  
  348.   
  349. inline void RgbSwap(int &a, int &b)  
  350. {  
  351.     a ^= b;  
  352.     b ^= a;  
  353.     a ^= b;  
  354. }  
  355.   
  356. // 按混合顏色計算並改變HSV  
  357. void __fastcall TForm1::MixColorToHSV(void)  
  358. {  
  359.     int max, mid, min;  
  360.   
  361.     max = MixColor.Red;  
  362.     mid = MixColor.Green;  
  363.     min = MixColor.Blue;  
  364.     if (max < mid) RgbSwap(max, mid);  
  365.     if (max < min) RgbSwap(max, min);  
  366.     if (min > mid) RgbSwap(min, mid);  
  367.   
  368.     int max_min = max - min;  
  369.     if (max_min == 0)  
  370.     {  
  371.         Hue = 0;  
  372.         Sat = 0;  
  373.     }  
  374.     else  
  375.     {  
  376.         int H;  
  377.         if (max == MixColor.Red)  
  378.             H = ((MixColor.Green - MixColor.Blue) * 60 + 30) / max_min;  
  379.         else if (max == MixColor.Green)  
  380.             H = ((MixColor.Blue - MixColor.Red) * 60 + 30) / max_min + 120;  
  381.         else  
  382.             H = ((MixColor.Red - MixColor.Green) * 60 + 30) / max_min + 240;  
  383.         Hue = H < 0? H + 360 : H;  
  384.         Sat = (max_min * 100) / max;  
  385.   
  386.     }  
  387.     Bright = max;  
  388. }  
  389. //---------------------------------------------------------------------------  
  390.   
  391. inline ARGB RgbToColor(int r, int g, int b)  
  392. {  
  393.     return (r << 16) | (g << 8) | b;  
  394. }  
  395.   
  396. // 按HSV計算並改變混合顏色  
  397. void __fastcall TForm1::HSVToMixColor(void)  
  398. {  
  399.     if (Sat == 0)  
  400.     {  
  401.         MixColor.Blue = MixColor.Green = MixColor.Red = Bright;  
  402.     }  
  403.     else  
  404.     {  
  405.         int index = Hue / 60;  
  406.         int f = Hue % 60;  
  407.         if ((index & 1) == 0) f = 60 - f;  
  408.         int a = Bright;  
  409.         int b = (Bright * (6000 - Sat * f)) / 6000;  
  410.         int c = (Bright * (100 - Sat)) / 100;  
  411.         switch (index)  
  412.         {  
  413.             case 0:  
  414.                 MixColor.Color = RgbToColor(a, b, c);  
  415.                 break;  
  416.             case 1:  
  417.                 MixColor.Color = RgbToColor(b, a, c);  
  418.                 break;  
  419.             case 2:  
  420.                 MixColor.Color = RgbToColor(c, a, b);  
  421.                 break;  
  422.             case 3:  
  423.                 MixColor.Color = RgbToColor(c, b, a);  
  424.                 break;  
  425.             case 4:  
  426.                 MixColor.Color = RgbToColor(b, c, a);  
  427.                 break;  
  428.             case 5:  
  429.                 MixColor.Color = RgbToColor(a, c, b);  
  430.         }  
  431.     }  
  432.     MixColorChange();  
  433. }  
  434. //---------------------------------------------------------------------------  
  435.   
  436. int __fastcall TForm1::GetHue(void)  
  437. {  
  438.     return TrackBar7->Position;  
  439. }  
  440. //---------------------------------------------------------------------------  
  441.   
  442. int __fastcall TForm1::GetSat(void)  
  443. {  
  444.     return TrackBar8->Position;  
  445. }  
  446. //---------------------------------------------------------------------------  
  447.   
  448. void __fastcall TForm1::SetHue(int hue)  
  449. {  
  450.     if (Hue == hue) return;  
  451.     Lock = TLockTypes() << ltEdit << ltTrack;  
  452.     try  
  453.     {  
  454.         TrackBar7->Position = hue;  
  455.         Edit7->Text = hue;  
  456.     }  
  457.     __finally  
  458.     {  
  459.         Lock.Clear();  
  460.     }  
  461. }  
  462. //---------------------------------------------------------------------------  
  463.   
  464. void __fastcall TForm1::SetSat(int sat)  
  465. {  
  466.     if (Sat == sat) return;  
  467.     Lock = TLockTypes() << ltEdit << ltTrack;  
  468.     try  
  469.     {  
  470.         TrackBar8->Position = sat;  
  471.         Edit8->Text = sat;  
  472.     }  
  473.     __finally  
  474.     {  
  475.         Lock.Clear();  
  476.     }  
  477. }  
  478. //---------------------------------------------------------------------------  
  479.   
  480. // 色調選盒改變  
  481. void __fastcall TForm1::CheckBox1Click(TObject *Sender)  
  482. {  
  483.     Label14->Enabled = CheckBox1->Checked;  
  484.     Label15->Enabled = CheckBox1->Checked;  
  485.     Label16->Enabled = CheckBox1->Checked;  
  486.     Label17->Enabled = CheckBox1->Checked;  
  487.     Label18->Visible = CheckBox1->Checked;  
  488.     Edit7->Enabled = CheckBox1->Checked;  
  489.     Edit8->Enabled = CheckBox1->Checked;  
  490.     TrackBar7->SliderVisible = CheckBox1->Checked;  
  491.     TrackBar8->SliderVisible = CheckBox1->Checked;  
  492.   
  493.     if (CheckBox1->Checked)  
  494.         ComboBox1->ItemIndex = CustomIndex;  
  495.     MixColorChange();  
  496. }  
  497. //---------------------------------------------------------------------------  
  498.   
  499. // 色相選項條改變  
  500. void __fastcall TForm1::TrackBar7Change(TObject *Sender)  
  501. {  
  502.     if (!Lock.Contains(ltTrack))  
  503.         Edit7->Text = TrackBar7->Position;  
  504. }  
  505. //---------------------------------------------------------------------------  
  506.   
  507. // 飽和度選項條改變  
  508. void __fastcall TForm1::TrackBar8Change(TObject *Sender)  
  509. {  
  510.     if (!Lock.Contains(ltTrack))  
  511.         Edit8->Text = TrackBar8->Position;  
  512. }  
  513. //---------------------------------------------------------------------------  
  514.   
  515. // 色相或者飽和度編輯框改變  
  516. void __fastcall TForm1::Edit7Change(TObject *Sender)  
  517. {  
  518.     TEdit *edit = (TEdit*)Sender;  
  519.     if (Lock.Contains(ltEdit) || edit->Text == "")  
  520.         return;  
  521.     Lock = TLockTypes() << ltTrack;  
  522.     try  
  523.     {  
  524.         int val = StrToInt(edit->Text);  
  525.         TTrackBar *bar = edit->Tag == 0? TrackBar7 : TrackBar8;  
  526.         if (bar->Position != val)  
  527.             bar->Position = val;  
  528.         HSVToMixColor();  
  529.     }  
  530.     __finally  
  531.     {  
  532.         Lock.Clear();  
  533.     }  
  534. }  
  535. //---------------------------------------------------------------------------  
  536.   
  537. void __fastcall TForm1::Edit7KeyPress(TObject *Sender, char &Key)  
  538. {  
  539.     if (Key >= ' ' && (Key < '0' || Key > '9'))  
  540.         Key = 0;  
  541. }  
  542. //---------------------------------------------------------------------------  
  543.   
  544. // 呼叫顏色對話方塊選擇混合顏色  
  545. void __fastcall TForm1::PaintBox2Click(TObject *Sender)  
  546. {  
  547.     if (CheckBox1->Checked && ColorDialog1->Execute(Handle))  
  548.     {  
  549.         MixColor.Color = (ARGB)ColorDialog1->Color;  
  550.         MixColor.Blue = MixColor.Red;  
  551.         MixColor.Red = (BYTE)ColorDialog1->Color;  
  552.         MixColorToHSV();  
  553.         MixColorChange();  
  554.     }  
  555. }  
  556. //---------------------------------------------------------------------------  
  557.   
  558. // 畫黑白調整影象和源影象  
  559. void __fastcall TForm1::PaintBox1Paint(TObject *Sender)  
  560. {  
  561.     Gdiplus::Graphics *g = new Gdiplus::Graphics(PaintBox1->Canvas->Handle);  
  562.     try  
  563.     {  
  564.         g->DrawImage(Dest, rect);  
  565.         if (Sender != NULL)  
  566.         {  
  567.             g->TranslateTransform(0, rect.Height);  
  568.             g->DrawImage(Source, rect);  
  569.         }  
  570.     }  
  571.     __finally  
  572.     {  
  573.         delete g;  
  574.     }  
  575. }  
  576. //---------------------------------------------------------------------------  
  577.   
  578. // 畫混合顏色  
  579. void __fastcall TForm1::PaintBox2Paint(TObject *Sender)  
  580. {  
  581.     if (CheckBox1->Checked)  
  582.         PaintBox2->Canvas->Brush->Color =  
  583.             (MixColor.Blue << 16) | (MixColor.Green << 8) | MixColor.Red;  
  584.     else  
  585.         PaintBox2->Canvas->Brush->Color = Color;  
  586.     PaintBox2->Canvas->Pen->Color = Color;  
  587.     PaintBox2->Canvas->Rectangle(PaintBox2->ClientRect);  
  588. }  
  589. //---------------------------------------------------------------------------  

    介面程式中,實現影象黑白調整功能主要靠Execute函式完成。

    下面是幾張程式執行介面圖:

    1、預設黑白調整引數執行介面,其中右上邊的下拉編輯框顯示的是一些預設黑白效果選項:

    2、選擇紅外線效果黑白調整引數執行介面:

    3、使用預設引數進行黑白調整後,再用所選顏色進行著色的介面:

    4、在上面介面基礎上,色調不變,加大黃色調引數,使圖中人物衣服顏色明亮一些,同時減少藍色調引數,使人物的圍脖顏色變暗一些:

 

    因水平有限,錯誤在所難免,歡迎指正和指導。郵箱地址:maozefa@hotmail.com

    這裡可訪問《C++影象處理 -- 文章索引


相關文章