现在的位置: 首页 > 综合 > 正文

Delphi图像处理 — 表面模糊

2013年08月08日 ⁄ 综合 ⁄ 共 2844字 ⁄ 字号 评论关闭

阅读提示:

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

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

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

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

    图像的表面模糊处理是Photoshop CS2以后才有的新功能,其作用是在保留图像边缘的情况下,对图像的表面进行模糊处理。在对人物皮肤处理上,比高斯模糊更有效。因为高斯模糊在使人物皮肤光洁的同时,也将一些边缘特征如脸部的眉毛、嘴唇等给模糊了,不得不用蒙版小心的抹去这些地方的模糊部分。

    在处理手法上,表面模糊也与其它卷积处理手段不同,如高斯模糊等在处理图像时都是采用统一的卷积矩阵进行,而表面模糊却是每一个像素点都有自己的卷积矩阵,而且还是3(4)套,用以对应于像素的R、G、B(A、R、G、B)分量。所以表面模糊在编程处理时,比其它卷积操作更复杂、更耗时,因为它要对每一个像素计算自己的卷积矩阵。表面模糊编程的难点也在计算卷积矩阵上,其它与一般图像卷积处理一样。

    表面模糊处理有2个参数,即模糊半径和模糊阈值,前者确定模糊的范围,后者确定模糊的程度。模糊范围就是卷积矩阵大小,如模糊半径为1,则模糊矩阵直径为1*2+1等于3,矩阵元素个数为3*3等于9,矩阵的中间元素即是当前像素点。

    矩阵元素值的计算公式为:

    1) mij = 1 - (|pij - p0|) / 2.5T

    变形后可得:

    2) mij = (2.5T - ([pij - p0])) / 2.5T

    其中,mij为矩阵的各元素值,pij为矩阵元素对应的像素分量值,p0为矩阵中心元素对应的像素分量值,T为阈值,|pij - p0|为矩阵元素对应像素分量值与中心元素对应像素分量值的绝对差值。如果mij < 0,则mij = 0。

    对ARGB格式图像数据来说,因有4个分量,故需要4套卷积矩阵。

    矩阵元素确定后,就可按照一般图像卷积操作进行处理了,即分别累计矩阵元素值和与之对应的像素分量值乘积,用累计像素分量值除以累计元素值,即可得到当前像素分量模糊处理后的值。

    下面是表面模糊处理代码:

// ARGB图像数据表面模糊处理.
// 参数: 图像数据, 模糊半径, 阈值
procedure SurfaceBlur(var Data: TImageData; Radius, Threshold: Integer);
const
  _fc2_5: Single = 2.5;
var
  width, height, size: Integer;
  srcOffset, dstOffset: Integer;
  src: TImageData;
begin
  if not (Radius in [1..100]) or not (Threshold in [2..255]) then Exit;
  if Data.AlphaFlag then              // 如果图像数据含Alpha信息, 转换为PARGB格式
    ArgbConvertPArgb(Data);
  src := _GetExpandData(Data, Radius);// 获取扩展半径后的备份图像数据
  asm
    push      esi
    push      edi
    push      ebx
    mov       eax, Data
    lea       edx, src
    call      _SetCopyRegs
    mov       width, ecx
    mov       height, edx
    mov       srcOffset, eax
    mov       dstOffset, ebx
    mov       eax, src.Stride
    mov       ebx, Radius
    shl       ebx, 1
    inc       ebx
    mov       size, ebx
    shl       ebx, 2
    neg       ebx
    add       ebx, eax
    add       eax, 4
    mul       Radius
    pxor      xmm7, xmm7
    cvtsi2ss  xmm6, Threshold // xmm6 = 4 * (Threshold * 2.5)
    movss     xmm0, _fc2_5
    mulss     xmm6, xmm0
    pshufd    xmm6, xmm6, 0
@@yLoop:
    push      width
@@xLoop:
    push      esi
    mov       edx, Size
    pxor      xmm0, xmm0      // Total Pixels
    pxor      xmm5, xmm5      // Nuclear
    movd      xmm4, [esi+eax] // xmm4 = p0 = 4 * word(a,r,g,b)
    punpcklbw xmm4, xmm7
@@iLoop:
    mov       ecx, Size
@@jLoop:
    movd      xmm3, [esi]
    punpcklbw xmm3, xmm7
    movaps    xmm1, xmm3
    movaps    xmm2, xmm4
    // 计算模糊矩阵元素值
    psubw     xmm1, xmm4      // xmm1 = xij - x0
    psubw     xmm2, xmm3      // xmm2 = x0 - xij
    packuswb  xmm1, xmm7      // 字节饱和去掉xmm1中各分量差值中的负值
    packuswb  xmm2, xmm7      // 字节饱和去掉xmm2中各分量差值中的负值
    por       xmm2, xmm1      // xmm2 = |xij - x0|
    punpcklbw xmm2, xmm7
    punpcklwd xmm2, xmm7
    punpcklwd xmm3, xmm7
    cvtdq2ps  xmm3, xmm3
    cvtdq2ps  xmm2, xmm2
    movaps    xmm1, xmm6
    subps     xmm1, xmm2
    divps     xmm1, xmm6      // xmm1 = (xmm6 - xmm2) / xmm6
    maxps     xmm1, xmm7      // 去掉xmm1中的负值
    mulps     xmm3, xmm1      // xij *= xmm1
    // 累计模糊矩阵元素值和与对应像素值的乘积
    addps     xmm5, xmm1      // Nuclear += xmm1
    addps     xmm0, xmm3      // Total Pixels += xij
    add       esi, 4
    loop      @@jLoop
    add       esi, ebx
    dec       edx
    jnz       @@iLoop
    divps     xmm0, xmm5      // p0 = Total Pixels /= Nuclear
    cvtps2dq  xmm0, xmm0
    packssdw  xmm0, xmm7
    packuswb  xmm0, xmm7
    movd      [edi], xmm0
    pop       esi
    add       esi, 4
    add       edi, 4
    dec       width
    jnz       @@xLoop
    pop       width
    add       esi, srcOffset
    add       edi, dstOffset
    dec       height
    jnz       @@yLoop
    pop       ebx
    pop       edi
    pop       esi
  end;
  FreeImageData(src);
  if Data.AlphaFlag then      // 如果图像数据含Alpha信息, 还原为ARGB格式
    PArgbConvertArgb(Data);
end;

    例子运行效果截图:

    《Delphi图像处理》系列使用GDI+单元下载地址和说明见文章《GDI+ for VCL基础 -- GDI+ 与 VCL》。

    因水平有限,错误在所难免,欢迎指正和指导。邮箱地址:maozefa@hotmail.com

    这里可访问《Delphi图像处理 -- 文章索引》。

抱歉!评论已关闭.