Delphi图像处理 -- 设置图像关键颜色

阅读提示:

    《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       @@yLoop
end;

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       @@yLoop
end;

// 设置色键(透明范围)。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       edi
end;

// 按坐标颜色设置色键。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)
    punpcklbw	mm2, mm7
    movq	    mm3, mm2
    paddsw		mm3, mm0		    // mm3 += mm0 (colorHigh)
    psubsw		mm2, mm0		    // mm2 -= mm0 (colorLow)
    packuswb	mm3, mm3
    packuswb	mm2, 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       edi
end;

 

    上面的代码中,提供了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图像处理 -- 文章索引》。

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值