Delphi图像处理 -- USM锐化
USM锐化是用来锐化图像边缘的,它通过调整图像边缘细节的对比度,并在边缘的两侧生成一条亮线一条暗线,使画面整体更加清晰。
USM锐化用公式描述很麻烦,这里干脆实现步骤列于下面:
1、备份图像原数据;
2、按给定半径对图像进行高斯模糊;
3、用原像素与高斯模糊后的像素相减,形成一个差值;
4、将差值乘以数量;
5、将差值分为正负2部分,取绝对值;
6、正负差值分别减去给定的阈值;
7、原像素加上正差值减去负差值,锐化完毕。
下面是USM锐化代码,包括高斯模糊代码(关于高斯模糊见文章《Delphi图像处理 -- 高斯模糊》,下面的高斯模糊代码也是从该文拷贝来的):
[delphi]
procedure CrossBlur(var Dest: TImageData; const Source: TImageData; Weights: Pointer; Radius: Integer);
var
height, srcStride: Integer;
dstOffset, srcOffset: Integer;
asm
push esi
push edi
push ebx
push ecx
mov ecx, [edx].TImageData.Stride
mov srcStride, ecx
call _SetCopyRegs
mov height, edx
mov srcOffset, eax
mov dstOffset, ebx
pop ebx
pxor xmm7, xmm7
push esi // pst = Source.Scan0
push edi
push edx
push ecx
// blur col
mov eax, srcStride
mov edx, eax
shr edx, 2 // width = Source.Width
mov edi, Radius
shl edi, 1
imul edi, eax
add edi, esi // psb = pst + Radius * 2 * Source.Stride
@@cyLoop:
push edx
@@cxLoop:
push esi
push edi
push ebx
mov ecx, Radius
pxor xmm0, xmm0 // sum = 0
@@cblurLoop:
movd xmm1, [esi] // for (i = 0; i < Radius; i ++)
movd xmm2, [edi] // {
punpcklbw xmm1, xmm7
punpcklbw xmm2, xmm7
paddw xmm1, xmm2 // ps = pst + psb
punpcklwd xmm1, xmm7
cvtdq2ps xmm1, xmm1 // pfs (flaot * 4) = ps (int * 4)
mulps xmm1, [ebx] // pfs *= Weights[i]
addps xmm0, xmm1 // sum += pfs
add ebx, 16
add esi, eax // pst += Source.Stride
sub edi, eax // psb -= Source.Stride
loop @@cblurLoop // }
movd xmm1, [esi]
punpcklbw xmm1, xmm7
punpcklwd xmm1, xmm7
cvtdq2ps xmm1, xmm1 // pfs (flaot * 4) = pst (int * 4)
mulps xmm1, [ebx] // pfs *= Weights[Radius]
addps xmm0, xmm1 // sum += pfs
pop ebx
pop edi
pop esi
cvtps2dq xmm0, xmm0 // ps (int * 4) = sum (flaot * 4)
packssdw xmm0, xmm7
packuswb xmm0, xmm7
movd [esi], xmm0 // pst (byte * 4) = ps (int * 4) pask
add esi, 4
add edi, 4
dec edx
jnz @@cxLoop
pop edx
dec height
jnz @@cyLoop
pop edx
pop height
pop edi // pd = Dest.Scan0
pop esi // psl = pst
mov eax, Radius
shl eax, 1+2
add eax, esi // psr = psl + Radius * 2
// blur row
@@ryLoop:
push edx // width = Dest.Width
@@rxLoop:
push esi
push ebx
push eax
mov ecx, Radius
pxor xmm0, xmm0 // sum = 0
@@rblurLoop:
movd xmm1, [esi] // for (i = 0; i < Radius; i ++)
movd xmm2, [eax] // {
punpcklbw xmm1, xmm7
punpcklbw xmm2, xmm7
paddw xmm1, xmm2 // ps = psl + psr