Delphi图像处理 -- 图像的中值滤波

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

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

过程定义: // 中值滤波。参数: // Dest输出图,Source原图,Data自身操作图像 // Radius半径 // Callback回调函数,返回True终止操作,CallbackData回调函数参数地址 procedure ImageMedianValues(var Data: TImageData; Radius: LongWord); overload; {$IF RTLVersion >= 17.00}inline;{$IFEND} procedure ImageMedianValues(var Dest: TImageData; const Source: TImageData; Radius: Integer); overload; {$IF RTLVersion >= 17.00}inline;{$IFEND} // 无效参数或者被回调函数终止操作返回False。 function ImageMedianValues(var Dest: TImageData; const Source: TImageData; Radius: Integer; Callback: TImageAbort; CallbackData: Pointer): Boolean; overload; 代码实现: procedure MedianValues(buf: Pointer; SortSize, Size, MatrixOffset: Integer); pascal; 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 mov width, ecx mov height, edx mov dstOffset, ebx mov srcOffset, eax mov ebx, Buf 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 end; procedure MedianValues3(buf: Pointer; MatrixOffset: Integer); pascal; 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 mov width, ecx mov height, edx mov dstOffset, ebx mov srcOffset, eax add MatrixOffset, 9 mov ebx, Buf @@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 end; function ImageMedianValues(var Dest: TImageData; const Source: TImageData; Radius: Integer; Callback: TImageAbort; CallbackData: Pointer): Boolean; var dst, src: TImageData; Buf: array of Byte; Size, SortSize: Integer; MatrixOffset: Integer; begin Result := False; if ImageEmpty(Dest) or ImageEmpty(Source) or (Radius <= 0) then Exit; Size := (Radius shl 1) + 1; if @Dest <> @Source then CopyAlpha(Dest, Source); GetExpandData(Dest, Source, Radius, dst, src); MatrixOffset := src.Stride - (Size shl 2); try if Radius = 1 then begin SetLength(Buf, 9 * Sizeof(TARGBQuad)); if Assigned(Callback) then Result := ExecuteAbort(dst, src, @MedianValues3, [Buf, MatrixOffset], Callback, CallbackData) else Result := ExecuteProc(dst, src, @MedianValues3, [Buf, MatrixOffset]); end else begin SortSize := ((Size * Size + 1) shr 1) * Sizeof(TARGBQuad); SetLength(Buf, SortSize + Sizeof(TARGBQuad)); if Assigned(Callback) then Result := ExecuteAbort(dst, src, @MedianValues, [Buf, SortSize, Size, MatrixOffset], Callback, CallbackData) else Result := ExecuteProc(dst, src, @MedianValues, [Buf, SortSize, Size, MatrixOffset]); end; finally FreeImageData(src); end; end; procedure ImageMedianValues(var Data: TImageData; Radius: LongWord); begin ImageMedianValues(Data, Data, Radius, nil, nil); end; procedure ImageMedianValues(var Dest: TImageData; const Source: TImageData; Radius: Integer); begin ImageMedianValues(Dest, Source, Radius, nil, nil); end;

由于中值滤波要对每个像素都采用n阶矩阵排序的方法找出其R、G、B分量的中间值,因此该操作是非常耗时的。最大的耗时主要是排序过程,尽管本文中值滤波过程用了BASM代码,但这个滤波过程还是较慢,显然排序算法是提高操作速度的关键,我试验了多种排序算法,都不理想,没办法,只好将最常用的3阶中值滤波排序进行了改进,所以,本文中值滤波过程处理图像的3阶中值滤波速度相对还是较快的。

文章中所用数据类型及一些过程见《Delphi图像处理 -- 数据类型及内部过程》和《Delphi图像处理 -- 图像像素结构与图像数据转换》。

尽管我十分努力,但水平有限,错误在所难免,欢迎指正和指导。邮箱地址:

maozefa@hotmail.com

本文代码于2010.5.20重新修订过。增加了拷贝形式的调整过程和响应回调函数的调整过程。滤波参数也由以前的Size改为Radius,主要是防止偶数长度。代码中的ExecuteAbort过程和ExecuteProc过程见《Delphi图像处理 -- 图像像素结构与图像数据转换》。

另外,这次修订重写了半径大于1(即3*3以上的)的中值滤波排序代码,以前是对全部像素数据进行选择排序,现在改为插入排序,只比较小于中值的数据,大于或等于中值的数据直接忽略,因为我们需要只是的中间值,对于大于中间值的数据排序无疑是浪费时间!如此节省了不少时间,处理时间比以前平均节省了20%。不过还是比较耗时,我仔细分析过,除非改变算法,如改矩阵为十字型进行滤波,否则,速度难以得到大幅度提高。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值