Delphi图像处理 -- 中值滤波

来源:互联网 发布:红三兵炒股软件安卓版 编辑:程序博客网 时间:2024/05/26 09:55

阅读提示:

    《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     esiend;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     esiend;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图像处理 -- 文章索引》。

 

原创粉丝点击