Delphi图像处理 -- 表面模糊
2012-07-03 07:55:35 来源:WEB开发网核心提示: 图像的表面模糊处理是Photoshop CS2以后才有的新功能,其作用是在保留图像边缘的情况下,Delphi图像处理 -- 表面模糊,对图像的表面进行模糊处理,在对人物皮肤处理上,即分别累计矩阵元素值和与之对应的像素分量值乘积,用累计像素分量值除以累计元素值,比高斯模糊更有效,因为高斯模糊在使人物皮肤光洁的同时
图像的表面模糊处理是Photoshop CS2以后才有的新功能,其作用是在保留图像边缘的情况下,对图像的表面进行模糊处理。在对人物皮肤处理上,比高斯模糊更有效。因为高斯模糊在使人物皮肤光洁的同时,也将一些边缘特征如脸部的眉毛、嘴唇等给模糊了,不得不用蒙版小心的抹去这些地方的模糊部分。
在处理手法上,表面模糊也与其它卷积处理手段不同,如高斯模糊等在处理图像时都是采用统一的卷积矩阵进行,而表面模糊却是每一个像素点都有自己的卷积矩阵,而且还是3(4)套,用以对应于像素的R、G、B(A、R、G、B)分量。所以表面模糊在编程处理时,比其它卷积操作更复杂、更耗时,因为它要对每一个像素计算自己的卷积矩阵。表面模糊编程的难点也在计算卷积矩阵上,其它与一般图像卷积处理一样。
表面模糊处理有2个参数,即模糊半径和模糊阈值,前者确定模糊的范围,后者确定模糊的程度。模糊范围就是卷积矩阵大小,如模糊半径为1,则模糊矩阵直径为1*2+1等于3,矩阵元素个数为3*3等于9,矩阵的中间元素即是当前像素点。
矩阵元素值的计算公式为:
mij = (1 - |pij - p0|) / 2.5T
其中,mij为矩阵的各元素值,pij为矩阵元素对应的像素分量值,p0为矩阵中心元素对应的像素分量值,T为阈值,|pij - p0|为矩阵元素对应像素分量值与中心元素对应像素分量值的绝对差值。对ARGB格式图像数据来说,因有4个分量,故需要4套卷积矩阵。
矩阵元素确定后,就可按照一般图像卷积操作进行处理了,即分别累计矩阵元素值和与之对应的像素分量值乘积,用累计像素分量值除以累计元素值,即可得到当前像素分量模糊处理后的值。
下面是表面模糊处理代码:
// ARGB图像数据表面模糊处理.
// 参数: 图像数据, 模糊半径, 阈值
procedure SurfaceBlur(var Data: TImageData; Radius, Threshold: Integer);
const
_fc2_5: Single = 2.5;
var
width, height, size: Integer;
srcOffset, dstOffset: Integer;
src: TImageData;
begin
if Data.AlphaFlag then // 如果图像数据含Alpha信息, 转换为PARGB格式
ArgbConvertPArgb(Data);
src := _GetExpandData(Data, Radius);// 获取扩展半径后的备份图像数据
asm
push esi
push edi
push ebx
mov eax, Data
lea edx, src
call _SetCopyRegs
mov width, ecx
mov height, edx
mov srcOffset, eax
mov dstOffset, ebx
mov eax, src.Stride
mov ebx, Radius
shl ebx, 1
inc ebx
mov size, ebx
shl ebx, 2
neg ebx
add ebx, eax
add eax, 4
mul Radius
pxor xmm7, xmm7
cvtsi2ss xmm6, Threshold // xmm6 = 4 * (Threshold * 2.5)
movss xmm0, _fc2_5
mulss xmm6, xmm0
pshufd xmm6, xmm6, 0
@@yLoop:
push width
@@xLoop:
push esi
mov edx, Size
pxor xmm0, xmm0 // Total Pixels
pxor xmm5, xmm5 // Nuclear
movd xmm4, [esi+eax] // xmm4 = p0 = 4 * word(a,r,g,b)
punpcklbw xmm4, xmm7
@@iLoop:
mov ecx, Size
@@jLoop:
movd xmm1, [esi]
punpcklbw xmm1, xmm7
movaps xmm3, xmm1
// 计算模糊矩阵元素值
psubw xmm1, xmm4 // xmm1 = pij - p0 (+)
pxor xmm2, xmm2
psubw xmm2, xmm1 // xmm2 = pij - p0 (-) 零减xmm1实现各分量差值的正负转换
packuswb xmm1, xmm7 // 字节饱和去掉xmm1中各分量差值中的负值
packuswb xmm2, xmm7 // 字节饱和去掉xmm2中各分量差值中的负值
por xmm2, xmm1 // xmm2 = |pij - p0| xmm2与xmm1相与得到各分量绝对差值
punpcklbw xmm2, xmm7
punpcklwd xmm2, xmm7
cvtdq2ps xmm2, xmm2
movaps xmm1, xmm6
subps xmm1, xmm2
divps xmm1, xmm6 // xmm1 = ((xmm6 - xmm2) / xmm6)
maxps xmm1, xmm7 // 去掉xmm1中的负值
// 累计模糊矩阵元素值
addps xmm5, xmm1 // Nuclear += xmm1
punpcklwd xmm3, xmm7
cvtdq2ps xmm3, xmm3
mulps xmm1, xmm3 // xmm1 *= (ARGB)ij
// 累计模糊矩阵元素值与对应像素的乘积
addps xmm0, xmm1 // Total Pixels += xmm1
add esi, 4
loop @@jLoop
add esi, ebx
dec edx
jnz @@iLoop
divps xmm0, xmm5 // p0 = Total Pixels /= Nuclear
cvtps2dq xmm0, xmm0
packssdw xmm0, xmm7
packuswb xmm0, xmm7
movd [edi], xmm0
pop esi
add esi, 4
add edi, 4
dec width
jnz @@xLoop
pop width
add esi, srcOffset
add edi, dstOffset
dec height
jnz @@yLoop
pop ebx
pop edi
pop esi
end;
FreeImageData(src);
if Data.AlphaFlag then // 如果图像数据含Alpha信息, 还原为ARGB格式
PArgbConvertArgb(Data);
end;
- ››Delphi实现把10进制转换成16进制的函数进制转化
- ››Delphi中将字符串按给定字符分隔(似split函数功能...
- ››Delphi 动态创建窗体,锁定窗口赋值
- ››Delphi 与 VC 共享接口和对象
- ››Delphi图像处理 -- 表面模糊
- ››Delphi之多线程实例
- ››Delphi SelectSingleNode的使用 根据节点属性获取...
- ››Delphi接口详述
- ››delphi 远程调试
- ››Delphi与DirectX之DelphiX(34): TDIB.Lightness()...
- ››Delphi Application.MessageBox详解
- ››Delphi只能运行一个程序实例的两种方法
更多精彩
赞助商链接
