Delphi图像处理 -- 中值滤波

阅读提示:

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

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

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

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

 

    图像的中值滤波,就是在以某一像素为中心的n阶像素矩阵中,找出R、G、B各分量的中间值来分别替代该像素的RGB值,从而达到对图像噪声滤波的目的。这里的中间值并非像素矩阵R、G、B各分量的的算术平均值,而是像素矩阵R、G、B各分量排序后的中位数值。

    下面是Delphi图像中值滤波的实现代码:

 

procedure MedianValues(var Dest: TImageData; const Source: TImageData;
  buf: Pointer; SortSize, Size, MatrixOffset: Integer);
var
  width, height: Integer;
  dstOffset, srcOffset: Integer;
  median: Pointer;

  procedure MedianSort;
  asm
    mov     edx, edi            // i = count - 1
    mov     al, [esi]           // al = r(gb)
  @@Loop:                       // while (i >= 0 && buf[i].r(rb) > al) i --;
    sub     edx, 4
    js      @@1
    cmp     al, [ebx+edx]
    jb      @@Loop
  @@1:
    add     edx, 4              // i ++
    mov     ecx, edi            //
  @@moveLoop:
    cmp     ecx, edx            // memmove(buf[i], buf[i+1], count - i)
    je      @@2
    mov     ah, [ebx+ecx-4]
    mov     [ebx+ecx], ah
    sub     ecx, 4
    jmp     @@moveLoop
  @@2:
    mov     [ebx+edx], al       // buf[i] = al
    inc     ebx
    inc     esi
  end;

asm
    push    esi
    push    edi
    push    ebx
    push    ecx
    call    _SetCopyRegs
    mov     width, ecx
    mov     height, edx
    mov     dstOffset, ebx
    mov     srcOffset, eax
    pop     ebx
    mov     eax, ebx
    add     eax, SortSize
    sub     eax, 4
    mov     median, eax
@@yLoop:
    push    width
@@xLoop:
    push    esi
    push    edi
    xor     edi, edi
    mov     ecx, Size
@@iLoop:
    push    ecx
    mov     ecx, Size
@@jLoop:
    push    ecx
    call    MedianSort
    call    MedianSort
    call    MedianSort
    inc     esi
    sub     ebx, 3
    cmp     edi, SortSize
    je      @@1
    add     edi, 4
@@1:
    pop     ecx
    loop    @@jLoop
    add     esi, MatrixOffset
    pop     ecx
    loop    @@iLoop
    pop     edi
    pop     esi
    mov     eax, median
    mov     eax, [eax]
    mov     cl, [edi].TARGBQuad.Alpha
    mov     [edi], eax
    mov     [edi].TARGBQuad.Alpha, cl
    add     esi, 4
    add     edi, 4
    dec     width
    jnz     @@xLoop
    add     esi, srcOffset
    add     edi, dstOffset
    pop     width
    dec     height
    jnz     @@yLoop
    pop     ebx
    pop     edi
    pop     esi
end;

procedure MedianValues3(var Dest: TImageData; const Source: TImageData; buf: Pointer; MatrixOffset: Integer);
var
  width, height: Integer;
  dstOffset, srcOffset: Integer;
  median: Pointer;

  procedure AssortValue;
  asm
    mov     ah, [esi]
    mov     dl, [esi+4]
    mov     al, [esi+8]
    cmp     ah, al
    jae     @@1
    xchg    ah, al
  @@1:
    cmp     ah, dl
    jae     @@2
    xchg    ah, dl
  @@2:
    cmp     al, dl
    jbe     @@3
    xchg    al, dl
  @@3:
    mov     [ebx], ah           // ah = large
    mov     [ebx+4], dl         // dl = center
    mov     [ebx+8], al         // al = small
    inc     esi
    inc     ebx
  end;

  procedure GetValue;
  asm
    mov     ah, [ebx]           // large  group: ebx   ebx+12 ebx+24
    mov     dl, [ebx+4]         // center group: ebx+4 ebx+16 ebx+28
    mov     al, [ebx+8]         // small  group: ebx+8 ebx+20 ebx+32
    mov     dh, [ebx+16]
    cmp     ah, [ebx+12]        // ah = min of large group
    jbe     @@1
    mov     ah, [ebx+12]
  @@1:
    cmp     ah, [ebx+24]
    jbe     @@2
    mov     ah, [ebx+24]        
  @@2:
    cmp     dh, dl
    jae     @@3
    xchg    dh, dl
  @@3:
    cmp     dh, [ebx+28]
    jae     @@4
    xchg    dh, [ebx+28]
  @@4:
    cmp     dl, [ebx+28]        // dl = median of center group
    jae     @@5
    mov     dl, [ebx+28]
  @@5:
    cmp     al, [ebx+20]        // al = max of small group
    jae     @@6
    mov     al, [ebx+20]
  @@6:
    cmp     al, [ebx+32]
    jae     @@7
    mov     al, [ebx+32]
  @@7:
    cmp     ah, al
    jae     @@8
    xchg    al, ah
  @@8:
    cmp     ah, dl
    jae     @@9
    xchg    ah, dl
  @@9:
    cmp     al, dl              // al = median of [ah, dl, al]
    jae     @@10
    mov     al, dl
  @@10:
    mov     [edi], al
    inc     edi
    inc     ebx
  end;

asm
    push    esi
    push    edi
    push    ebx
    push    ecx
    call    _SetCopyRegs
    mov     width, ecx
    mov     height, edx
    mov     dstOffset, ebx
    mov     srcOffset, eax
    add     MatrixOffset, 9
    pop     ebx
@@yLoop:
    push    width
@@xLoop:
    push    esi
    push    ebx
    mov     ecx, 3
@@mLoop:
    call    AssortValue
    call    AssortValue
    call    AssortValue
    add     ebx, 9
    add     esi, MatrixOffset
    loop    @@mLoop
    pop     ebx
    pop     esi
    call    GetValue
    call    GetValue
    call    GetValue
    add     esi, 4
    sub     ebx, 3
    inc     edi
    dec     width
    jnz     @@xLoop
    add     esi, srcOffset
    add     edi, dstOffset
    pop     width
    dec     height
    jnz     @@yLoop
    pop     ebx
    pop     edi
    pop     esi
end;

procedure ImageMedianValues(var Data: TImageData; Radius: Integer);
var
  exp: TImageData;
  Buf: array of Byte;
  Size, SortSize: Integer;
  MatrixOffset: Integer;
begin
  Size := (Radius shl 1) + 1;
  exp := _GetExpandData(Data, Radius);
  MatrixOffset := exp.Stride - (Size shl 2);
  try
    if Radius = 1 then
    begin
      SetLength(Buf, 9 * Sizeof(TARGBQuad));
      MedianValues3(Data, exp, Buf, MatrixOffset);
    end
    else
    begin
      SortSize := ((Size * Size + 1) shr 1) * Sizeof(TARGBQuad);
      SetLength(Buf, SortSize + Sizeof(TARGBQuad));
      MedianValues(Data, exp, Buf, SortSize, Size, MatrixOffset);
    end;
  finally
    FreeImageData(exp);
  end;
end;



    由于中值滤波要对每个像素都采用n阶矩阵排序的方法找出其R、G、B分量的中间值,因此该操作是非常耗时的。最大的耗时主要是排序过程,尽管本文中值滤波过程用了BASM代码,但这个滤波过程还是较慢,显然排序算法是提高操作速度的关键,我试验了多种排序算法,都不理想,没办法,只好将最常用的3阶中值滤波排序进行了改进,所以,本文中值滤波过程处理图像的3阶中值滤波速度相对还是较快的;对于半径大于1(即3*3以上的)的中值滤波排序,改为插入排序,只比较小于中值的数据,大于或等于中值的数据直接忽略,因为我们需要只是的中间值,对于大于中间值的数据排序无疑是浪费时间!如此节省了不少时间,处理时间比以前平均节省了20%。不过还是比较耗时。

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

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

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

 

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值