閱讀提示:
《Delphi影像處理》系列以效率為側重點,一般代碼為PASCAL,核心代碼採用BASM。
《C++影像處理》系列以代碼清晰,可讀性為主,全部使用C++代碼。
儘可能保持二者內容一致,可相互對照。
本文代碼必須包括文章《Delphi影像處理 -- 資料類型及公用過程》中的ImageData.pas單元。
前天有個朋友發郵件向我諮詢,怎樣使用GDI+的ImageAttributes.SetGamma方法。他說他在使用GDI+ SetGamma方法時,發現所給參數值越大,映像越暗,反之則越亮,似乎與自己理解的不一樣。我測試了一下,確實如此。我查了一下.NET2.0類庫文檔,關於該方法參數的說明是:
gamma 參數的典型值在 1.0 到 2.2 之間;但在某些情況下,0.1 到 5.0 範圍內的值也很有用。
ImageAttributes 對象維護五種調整類別的顏色和灰階設定:預設、位元影像、畫筆、鋼筆和文本。例如,可以為預設類別指定一個伽瑪值,為位元影像類別指定另一個伽瑪值,再為鋼筆類別指定另一個伽瑪值。
預設的顏色調整設定和灰階調整設定適用於本身沒有調整設定的所有類別。例如,如果從來沒有為鋼筆類別指定任何調整設定,則預設設定適用於鋼筆類別。
一旦為某一類別指定了顏色調整或灰階調整設定,預設調整設定就不再適用於該類別了。例如,假定您為預設類別指定了一個調整設定集合。如果通過將 Pen 傳遞給 SetGamma 方法來為鋼筆類別設定伽瑪值,則任何預設調整設定都將不會應用於鋼筆。
正常範圍以外的伽瑪值可用於舊式 CRT 監視器,或者用於處於非一般照明條件(例如工業環境或櫥窗陳設)下的監視器。
而且還有個例子,摘錄在下面:
void SetGammaExample( PaintEventArgs^ e ) { // Create an Image object from the file Camera.jpg, and draw it to // the screen. Image^ myImage = Image::FromFile( "Camera.jpg" ); e->Graphics->DrawImage( myImage, 20, 20 ); // Create an ImageAttributes object and set the gamma to 2.2. ImageAttributes^ imageAttr = gcnew ImageAttributes; imageAttr->SetGamma( 2.2f ); // Draw the image with gamma set to 2.2. Rectangle rect = Rectangle(250,20,200,200); e->Graphics->DrawImage( myImage, rect, 0, 0, 200, 200, GraphicsUnit::Pixel, imageAttr ); }
按說,按照例子代碼設定伽瑪校正值2.2後映像顯示的結果應該是比沒有使用伽瑪校正前要亮一些才對,可現在結果相反!是我們理解有錯,還是GDI+的BUG???
帶著疑惑,網上搜尋了一下,果然,在MSDN論壇上發現有同樣的疑問:http://social.msdn.microsoft.com/Forums/zh-HK/csharpgeneral/thread/efc76edd-adf1-4acb-aa34-fe5fdd01b183,但版主的解答卻說這樣的效果是正確的。
自己寫了一個設定伽瑪校正的函數,與GDI+的ImageAttributes.SetGamma方法一比較,也是剛好相反。但如果把GDI+的SetGamma方法參數用倒數的形式給出,倒是與我自己寫的函數效果是一樣的(也可以說,把我寫的函數中的exponent := 1 / Gamma語句 改為exponent := Gamma,與GDI+的SetGamma方法效果一樣):
procedure ImageSetGamma(var Data: TImageData; Gamma: Single);var I: Integer; exponent: Double; gammaTab: array[0..255] of byte;begin exponent := 1 / Gamma; // 這一句改為exponent := Gamma;,與GDI+的SetGamma參數效果相同 for I := 0 to 255 do begin gammaTab[I] := Round(Power((I + 0.5) / 256, exponent) * 256 - 0.5); end; asm push ebp push esi push edi push ebx mov eax, data call _SetDataRegs lea esi, gammaTab mov ebp, edx@@yLoop: push ecx@@xLoop: movzx eax, [edi].TARGBQuad.Blue movzx edx, [edi].TARGBQuad.Green mov al, [esi+eax] mov dl, [esi+edx] mov [edi].TARGBQuad.Blue, al mov [edi].TARGBQuad.Green, dl movzx eax, [edi].TARGBQuad.Red mov al, [esi+eax] mov [edi].TARGBQuad.Red, al add edi, 4 loop @@xLoop pop ecx add edi, ebx dec ebp jnz @@yLoop pop ebx pop edi pop esi pop ebp end;end;//---------------------------------------------------------------------------procedure TForm1.Button3Click(Sender: TObject);var bmp: TGpBitmap; g: TGpGraphics; data: TImageData;begin bmp := TGpBitmap.Create('..\media\source.bmp'); g := TGpGraphics.Create(Canvas.Handle); g.DrawImage(bmp, 0, 0); data := LockGpBitmap(bmp); ImageSetGamma(data, 2.2); UnlockGpBitmap(bmp, data); g.DrawImage(bmp, 0, data.Height); g.Free; bmp.Free;end;
《Delphi影像處理》系列使用GDI+單元和說明見文章《GDI+ for VCL基礎 -- GDI+ 與 VCL》。
因水平有限,錯誤在所難免,歡迎指正和指導。郵箱地址:maozefa@hotmail.com
這裡可訪問《Delphi影像處理 -- 文章索引》。