注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

鑫淼梦园的博客

圆你的梦想 从这里开始

 
 
 

日志

 
 

Delphi图像处理 -- 灰色浮雕  

2013-06-24 15:42:48|  分类: delphi xe4 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
分类: Delphi Delphi图像处理2008-08-28 08:13 6746人阅读 评论(31) 收藏 举报

阅读提示:

    《Delphi图像处理》系列以效率为侧重点,一般代码为PASCAL,核心代码采用BASM。

    《C++图像处理》系列以代码清晰,可读性为主,全部使用C++代码。

    尽可能保持二者内容一致,可相互对照。

    本文代码必须包括文章《Delphi图像处理 -- 数据类型及公用过程》中的ImageData.pas单元和《Delphi图像处理 -- 平面几何变换类TransformMatrix.pas单元

 

    实现图像浮雕效果的一般原理是,将图像上每个像素点与其对角线的像素点形成差值,使相似颜色值淡化,不同颜色值突出,从而产生纵深感,达到浮雕的效果,具体的做法是用处于对角线的2个像素值相减,再加上一个背景常数,一般为128而成。这种算法的特点是简单快捷,缺点是不能调节图像浮雕效果的角度和深度。

    用Photoshop实现的图像浮雕效果,可以任意调节浮雕角度和深度(2个像素点的距离),还可以调整浮雕像素差值的数量。其基本算法原理和一般浮雕效果相同,但是具体做法不一样:对每个要处理的像素点,首先按照浮雕角度和深度计算处2个相应点的位置,然后计算这2个位置的颜色值,并使之形成差值,再乘上浮雕差值数量百分比,最后加上128的背景色。注意,这里计算的2个相应点是逻辑点,而不是实际的像素点,比如实现一个45度角,深度为3的图像浮雕效果,对每个像素点P(x, y),其对应的2个逻辑点的位置分别是P0(x - 3 * 0.7071 / 2, y - 3 * 0.7071 / 2)和P1(x + 3 * 0.7071 / 2, y + 3 * 0.7071 / 2),显然,对于这样的2个逻辑点,是不能直接从图像中找到其对应的像素点的,如果简单地对其四舍五入处理,将会造成大量的,由不同角度和深度而形成的相同的浮雕效果,这可不是我们想要的结果,而且使浮雕角度和深度参数失去了它原本的意义。为此,必须对原始图像按浮雕角度和深度进行缩放后,再对每个像素点进行浮雕效果处理,完毕再缩放回原图的大小,从而完成整个浮雕效果过程。下面是我经过反复试验后,写的Photoshop浮雕效果实现过程代码:

 

  1. procedure GetSrcColor;  
  2. asm  
  3.     push      esi           // esi = src.Scan0  
  4.     mov       eax, ecx  
  5.     sar       eax, 12  
  6.     imul      eax, ebx  
  7.     add       esi, eax      // esi += (y / 4096 * src.Stride)  
  8.     mov       eax, edx  
  9.     sar       eax, 12  
  10.     shl       eax, 2  
  11.     add       esi, eax      // esi +=  (x / 4096 * 4)  
  12.     call      _GetBilinearColor  
  13.     movd      eax, xmm0  
  14.     movd      mm0, eax  
  15.     punpcklbw mm0, mm7      // return mm0 = ARGB (word * 4)  
  16.     pop       esi  
  17. end;  
  18.   
  19. procedure ImageGraySculpture(var Data: TImageData;  
  20.   Angle: Single; Size: LongWord; Num: LongWord = 100);  
  21. var  
  22.   x, y, Radius: Integer;  
  23.   xDelta, yDelta: Integer;  
  24.   width, height: Integer;  
  25.   dstOffset: Integer;  
  26.   src: TImageData;  
  27. begin  
  28.   Radius := (Size + 1shr 1// 图像边框扩展半径  
  29.   Angle := PI * Angle / 180;  
  30.   Size := Size shl 12;        // Size = Size * 256  
  31.   Num := (Num shl 9div 100// Num *= 5.12 转换为2的幂  
  32.   xDelta := Round(Cos(Angle) * Size);  
  33.   yDelta := Round(Sin(Angle) * Size);  
  34.   x := (Radius shl 12) - (xDelta div 2);  
  35.   y := (Radius shl 12) - (yDelta div 2);  
  36.   width := x + (Data.Width shl 12);  
  37.   height := y + (Data.Height shl 12);  
  38.   if Data.AlphaFlag then  
  39.     ArgbConvertPArgb(Data);  
  40.   src := _GetExpandData(Data, Radius);  
  41.   asm  
  42.     mov       eax, Data  
  43.     lea       edx, src  
  44.     call      _SetCopyRegs  
  45.     mov       dstOffset, ebx  
  46.     movq      mm5, qword ptr ArgbTab[128*8]// mm5 = 00 128 00 128 00 128 00 128  
  47.     movd      mm6, Num        // mm6 = 00 Num 00 Num 00 Num 00 Num  
  48.     punpcklwd mm6, mm6  
  49.     punpcklwd mm6, mm6  
  50.     pxor      mm7, mm7        // mm7 = 00 00 00 00 00 00 00 00  
  51.     pxor      xmm7, xmm7  
  52.     mov       esi, src.Scan0  
  53.     mov       ebx, src.Stride  
  54.     mov       ecx, y          // for (; y < Height; y += 4096)  
  55. @@yLoop:                      // {  
  56.         mov         edx, x          //   for (; x < Width; x += 4096)  
  57. @@xLoop:                      //   {  
  58.     add       ecx, yDelta     //     y1 = y + yDelta  
  59.     add       edx, xDelta     //     x1 = x + xDelta  
  60.     call      GetSrcColor     //  
  61.     movq      mm1, mm0        //     mm1 = 00 A1 00 R1 00 G1 00 B1  
  62.     sub       ecx, yDelta     //     y0 = y - yDelta  
  63.     sub       edx, xDelta     //     x0 = x - xDelta  
  64.     call      GetSrcColor     //     mm0 = 00 A0 00 R0 00 G0 00 B0  
  65.     psubw     mm0, mm1        //     mm0 = A0-A1 R0-R1 G0-G1 B0-B1  
  66.     psllw     mm0, 7          //     mm0 = mm0 * 128 * Num / 65536  
  67.     pmulhw    mm0, mm6  
  68.     paddw     mm0, mm5        //     mm0 = A+128 R+128 G+128 B+128  
  69.     packuswb  mm0, mm7        //     mm0 = 00 00 00 00 A R G B  
  70.     mov       al, [edi].TARGBQuad.Alpha  
  71.     movd      [edi], mm0      //     *edi = mm0  
  72.     mov       [edi].TARGBQuad.Alpha, al  
  73.     add       edi, 4          //     edi += 4  
  74.     add       edx, 1000h  
  75.     cmp       edx, width  
  76.     jl        @@xLoop         //   }  
  77.     add       ecx, 1000h  
  78.     add       edi, dstOffset  
  79.     cmp       ecx, height  
  80.     jl        @@yLoop         // }  
  81.     emms  
  82.   end;  
  83.   FreeImageData(src);  
  84.   if Data.AlphaFlag then  
  85.     PArgbConvertArgb(Data);  
  86. end;  

    下面是个演示例子代码:

 

  1. procedure TForm1.Button3Click(Sender: TObject);  
  2. var  
  3.   bmp: TGpBitmap;  
  4.   g: TGpGraphics;  
  5.   data: TImageData;  
  6. begin  
  7.   bmp := TGpBitmap.Create('..\media\20041001.jpg');  
  8.   g := TGpGraphics.Create(Canvas.Handle);  
  9.   g.DrawImage(bmp, 00);  
  10.   data := LockGpBitmap(bmp);  
  11.   ImageGraySculpture(data, 453100);  
  12.   UnlockGpBitmap(bmp, data);  
  13.   g.DrawImage(bmp, 0, data.Height);  
  14.   g.Free;  
  15.   bmp.Free;  
  16. end;  

    运行效果图:

    和Photoshop浮雕效果对比,基本一致。

     补记:在文章评论中,有人说灰色浮雕不带彩,其实是不正确的,我测试过网上和书上的很多代码,也测试过Photoshop,都是有可能带彩的,在浮雕深度很小而且原始图像色彩较平淡时也有可能不带彩,可以把我上面的原图裁下来,用Photoshop一试就清楚了。当然,如果你要达到完全不带彩也很简单,在浮雕处理前做一个图像灰度化即可。如果灰度浮雕完全不带彩,程序代码可得到简化,速度至少可再提高60%以上。

  评论这张
 
阅读(353)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017