Delphi画像処理--中値フィルタリング


ヒントを読む:
「Delphi画像処理」シリーズは効率に重点を置き、一般コードはPASCAL、コアコードはBASMを採用している.
「C++画像処理」シリーズはコードがはっきりしていて、可読性が主で、すべてC++コードを使用しています.
できるだけ両者の内容を一致させ、互いに対照することができる.
本明細書のコードは、文書「Delphi画像処理--データ型および共通プロセス」のImageDataを含む必要がある.pasユニット.
 
画像の中値フィルタリングとは、ある画素を中心としたn次画素マトリクスにおいて、その画素のRGB値の代わりにR、G、Bの各成分の中間値を探し出し、画像ノイズフィルタリングの目的を達成することである.ここでの中間値は、画素マトリクス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」を参照してください.
レベルが限られているため、間違いは避けられないので、指摘と指導を歓迎します.メールアドレス:[email protected]
ここでは『Delphi画像処理--記事インデックス』にアクセスできます.