閱讀提示:
《Delphi影像處理》系列以效率為側重點,一般代碼為PASCAL,核心代碼採用BASM。
《C++影像處理》系列以代碼清晰,可讀性為主,全部使用C++代碼。
儘可能保持二者內容一致,可相互對照。
本文代碼必須包括文章《Delphi影像處理 -- 資料類型及公用過程》中的ImageData.pas單元。
設定映像關鍵顏色,使映像的某種或某個範圍的顏色成為透明色,是圖片合成、動畫顯示中經常用的影像處理手段。下面是實現代碼:
procedure ColorKeyEQ;asm punpckldq mm2, mm2 // mm2 = ColorKey ColorKey mov eax, ecx shr ecx, 1 // 每次比較2個像素@@yLoop: push ecx@@xLoop: dec ecx js @@1 movq mm0, [edi] // mm0 = A1 R1 G1 B1 A0 R0 G0 B0 pcmpeqd mm0, mm2 // 按32位元對2個像素進行比較 pandn mm0, [edi] // 比較結果取非後同原象素值作與運算 movq [edi], mm0 // 存入結果 add edi, 8 jmp @@xLoop@@1: test eax, 1 // 比較可能存在的最後一個像素 jz @@2 movd mm0, [edi] pcmpeqd mm0, mm2 movd ecx, mm0 not ecx and [edi], ecx add edi, 4@@2: pop ecx add edi, ebx dec edx jnz @@yLoopend;procedure ColorKeyArea;asm pxor mm7, mm7 // 比較命令是按有符號數進行的,因此 punpcklbw mm2, mm7 // ColorLow按位元組擴充為字 punpcklbw mm3, mm7 // ColorHigh按位元組擴充為字@@yLoop: push ecx@@xLoop: movd mm0, [edi] // mm0 = 00 00 00 00 A R G B punpcklbw mm0, mm7 // mm0 = 00 A 00 R 00 G 00 B movq mm1, mm2 pcmpgtw mm1, mm0 // 比較 ColorLow 是否大於 mm0 packsswb mm1, mm1 // 比較結果按字壓縮為位元組 movd eax, mm1 test eax, eax jnz @@Next // 如果 ColorLow 小於等於 mm0 pcmpgtw mm0, mm3 // 比較 mm0 是否大於 ColorHigh packsswb mm0, mm0 // 比較結果按字壓縮為位元組 movd eax, mm0 test eax, eax jnz @@Next // if (argb < ColorLow || argb > ColorLor) and [edi], eax // *(int* )edi = 0@@Next: add edi, 4 loop @@xLoop pop ecx add edi, ebx dec edx jnz @@yLoopend;// 設定色鍵(透明範圍)。colorLow 低色索引值; colorHigh 高色索引值// 當像素A、R、G、B值同時大於等於colorLow和小於等於colorHigh時為透明色procedure ImageSetColorKey(var Data: TImageData; ColorLow, ColorHigh: LongWord);asm push edi push ebx movd mm2, edx movd mm3, ecx xor edx, ecx push edx call _SetDataRegs pop eax test eax, eax jz @@1 call ColorKeyArea jmp @@Exit@@1: call ColorKeyEQ@@Exit: emms pop ebx pop ediend;// 按座標顏色設定色鍵。x,y 映像座標點, Precision 色鍵容差procedure ImageSetColorKeyPoint(var Data: TImageData; x, y: Integer; Precision: LongWord);asm push edi push ebx test edx, edx js @@Exit cmp edx, [eax].TImageData.Width jae @@Exit test ecx, ecx js @@Exit cmp ecx, [eax].TImageData.Height jae @@Exit imul ecx, [eax].TImageData.Stride shl edx, 2 // edx = data->Scan0 + add edx, ecx // y * data->Stride + x * 4 add edx, [eax].TImageData.Scan0 pxor mm7, mm7 movd mm0, precision// mm0 = precision (4 word) punpcklwd mm0, mm0 punpcklwd mm0, mm0 movd mm2, [edx] // mm2 = mm3 = argb (byte --> word) punpcklbwmm2, mm7 movq mm3, mm2 paddswmm3, mm0 // mm3 += mm0 (colorHigh) psubswmm2, mm0 // mm2 -= mm0 (colorLow) packuswbmm3, mm3 packuswbmm2, mm2 call _SetDataRegs movq mm0, mm2 pxor mm0, mm3 movd eax, mm0 test eax, eax jz @@2 call ColorKeyArea jmp @@end@@2: call ColorKeyEQ@@end: emms@@Exit: pop ebx pop ediend;
上面的代碼中,提供了2種設定映像關鍵顏色過程:
ImageSetColorKey過程,設定映像的關鍵色彩範圍,ColorLow和ColorHigh分別為映像關鍵顏色的低色索引值和高色索引值,只要是處於高低色鍵範圍內的顏色都會成為透明色,如果ColorLow與ColorHigh相等,只有一種顏色成為透明色。
ImageSetColorKeyPoint過程,是通過映像的位置和顏色容差來設定關鍵顏色的。因為很多映像的背景色都不是單純的某種顏色,靠ImageSetColorKey過程也不好確定關鍵顏色的高低色鍵,這時可以給定一個映像座標,以這個座標位置的像素顏色為基準,凡是在基準顏色上下容差範圍內的顏色都會成為透明色。
下面是個簡單的調用例子:
procedure TForm1.Button3Click(Sender: TObject);var bmp: TGpBitmap; g: TGpGraphics; data: TImageData;begin bmp := TGpBitmap.Create('..\media\56-3.jpg'); g := TGpGraphics.Create(Canvas.Handle); g.DrawImage(bmp, 0, 0); data := LockGpBitmap(bmp); ImageSetColorKeyPoint(data, 175, 5, 39); UnlockGpBitmap(bmp, data); g.DrawImage(bmp, data.Width, 0); g.Free; bmp.Free;end;
下面是運行效果:
《Delphi影像處理》系列使用GDI+單元和說明見文章《GDI+ for VCL基礎 -- GDI+ 與 VCL》。
因水平有限,錯誤在所難免,歡迎指正和指導。郵箱地址:maozefa@hotmail.com
這裡可訪問《Delphi影像處理 -- 文章索引》。