利用模版矩阵进行卷积操作,可以实现图片的彩色浮雕效果,下面的代码使用《Delphi图像处理 -- 图像卷积及高斯模糊》中介绍的通用卷积过程,来实现图片的彩色浮雕效果:
var Data: TImageData; begin Data := GetImageData(TGpBitmap.Create('d:\56-3.jpg'), True); ImageConvolution(Data, [1, 1, 0, 0, 0, 0, 1, 0, -2], 1); DrawImage(Canvas, 0, 0, Data); FreeImageData(Data); end;
但是,同一般灰色浮雕的实现一样,没法实现任意角度的浮雕,为此,采用《Delphi图像处理 -- Photoshop浮雕效果》同样的方法,可灵活的完成任意角度和大小的图片彩色浮雕效果,下面是整个代码:
过程定义: // 彩色浮雕。参数: // Dest输出图,Source原图,Data自身操作图像 // Angle 角度, Size 长度 // Callback回调函数,返回True终止操作,CallbackData回调函数参数地址 procedure ImageColorSculpture(var Data: TImageData; Angle: Single; Size: LongWord); overload; {$IF RTLVersion >= 17.00}inline;{$IFEND} procedure ImageColorSculpture(var Dest: TImageData; const Source: TImageData; Angle: Single; Size: LongWord); overload; {$IF RTLVersion >= 17.00}inline;{$IFEND} // 无效参数或者被回调函数终止操作返回False。 function ImageColorSculpture(var Dest: TImageData; const Source: TImageData; Angle: Single; Size: LongWord; Callback: TImageAbort; CallbackData: Pointer): Boolean; overload; 实现代码: procedure GetSrcColor; asm push edx // edx = x push ecx // ecx = y mov esi, ecx // esi = y / 256 * Data.Stride + mov eax, edx // x / 256 * 4 + Data.Scan0 sar esi, 8 sar eax, 8 shl eax, 2 imul esi, [ebx].TImageData.Stride add esi, eax add esi, [ebx].TImageData.Scan0 call GetBilinearColor pop ecx // return eax = mm0 = ARGB pop edx end; procedure ColorSculpture(Radius, xDelta, yDelta: Integer); pascal; var width, height: Integer; dstOffset: Integer; data: TImageData; asm mov dstOffset, ebx lea ebx, data mov [ebx].TImageData.Scan0, esi shl ecx, 2 add eax, ecx // Stride = srcOffset + width * 4 mov [ebx].TImageData.Stride, eax shl ecx, 6 add ecx, Radius mov width, ecx // width = width * 256 + x shl edx, 8 add edx, Radius mov height, edx // height = height * 256 + y pxor mm7, mm7 // mm7 = 00 00 00 00 00 00 00 00 mov ecx, Radius // for (; y < Height; y += 256) @@yLoop: // { mov edx, Radius // for (; x < Width; x += 256 @@xLoop: // { push edx push ecx sub ecx, yDelta sub edx, xDelta // x1 = x - xDelta, y1 = y - yDelta call GetSrcColor // mm0 = 00 00 00 00 A1 R1 G1 B1 punpcklbw mm0, mm7 // mm0 = 00 A1 00 R1 00 G1 00 B1 movq mm6, mm0 // mm6 = mm0(ARGB1) add edx, xDelta // x2 = x, y2 = y - yDelta call GetSrcColor // mm0 = 00 00 00 00 A2 R2 G2 B2 punpcklbw mm0, mm7 // mm0 = 00 A2 00 R2 00 G2 00 B2 paddw mm6, mm0 // mm6 += mm0(ARGB2) add ecx, yDelta add ecx, yDelta sub edx, xDelta // x3 = x - xDelta, y3 = y + yDelta call GetSrcColor // mm0 = 00 00 00 00 A3 R3 G3 B3 punpcklbw mm0, mm7 // mm0 = 00 A3 00 R3 00 G3 00 B3 paddw mm6, mm0 // mm6 += mm0(ARGB3) add edx, xDelta add edx, xDelta // x0 = x + xDelta, y0 = y + yDelta call GetSrcColor // mm0 = 00 00 00 00 A0 R0 G0 B0 punpcklbw mm0, mm7 // mm0 = 00 A0 00 R0 00 G0 00 B0 psllw mm0, 1 // mm0 = A0*2 R0*2 G0*2 B0*2 psubsw mm6, mm0 // mm6 = (ARGB1+ARGB2+ARGB3) - ARGB0*2 packuswb mm6, mm7 // mm6 = 00 00 00 00 A R G B mov al, [edi].TARGBQuad.Alpha movd [edi], mm6 // *edi = mm0 mov [edi].TARGBQuad.Alpha, al pop ecx pop edx add edi, 4 // edi += 4 add edx, 256 cmp edx, Width jl @@xLoop // } add ecx, 256 add edi, dstOffset cmp ecx, Height jl @@yLoop // } emms end; function ImageColorSculpture(var Dest: TImageData; const Source: TImageData; Angle: Single; Size: LongWord; Callback: TImageAbort; CallbackData: Pointer): Boolean; var Radius: Integer; xDelta, yDelta: Integer; dst, src: TImageData; begin Result := False; if ImageEmpty(Dest) or ImageEmpty(Source) or (Size = 0) then Exit; Radius := (Size + 1) shr 1; // 图像边框扩展半径 Angle := PI * Angle / 180; Size := Size shl 7; // Size = Size * 128 xDelta := Round(Cos(Angle) * Size); yDelta := Round(Sin(Angle) * Size); if @Dest <> @Source then CopyAlpha(Dest, Source); GetExpandData(Dest, Source, Radius, dst, src); try Radius := Radius shl 8; if Assigned(Callback) then Result := ExecuteAbort(dst, src, @ColorSculpture, [Radius, xDelta, yDelta], Callback, CallbackData) else Result := ExecuteProc(dst, src, @ColorSculpture, [Radius, xDelta, yDelta]); finally FreeImageData(src); end; end; procedure ImageColorSculpture(var Dest: TImageData; const Source: TImageData; Angle: Single; Size: LongWord); begin ImageColorSculpture(Dest, Source, Angle, Size, nil, nil); end; procedure ImageColorSculpture(var Data: TImageData; Angle: Single; Size: LongWord); begin ImageColorSculpture(Data, Data, Angle, Size, nil, nil); end;
代码还是采用二次线性插值法为每个象素点寻找邻近的4个逻辑点进行差值运算,差值运算的原理同前面所举的利用卷积矩阵实现彩色浮雕效果的例子。
下面是一个简单的测试代码:
var Data: TImageData; begin Data := GetImageData(TGpBitmap.Create('d:\56-3.jpg'), True); ImageColorSculpture(Data, 45, 3); DrawImage(Canvas, 0, 0, Data); FreeImageData(Data); end;
例子中的DrawImage过程见《Delphi图像处理 -- 图像显示》。效果如下:
原始图:
彩色浮雕效果图:
文章中使用GDI+版本下载地址和说明见《GDI+ for VCL基础 -- GDI+ 与 VCL》。
文章中所用数据类型及一些过程见《Delphi图像处理 -- 数据类型及内部过程》,《Delphi图像处理 -- 图像像素结构与图像数据转换》和《Delphi图像处理 -- 图像缩放》。
尽管我十分努力,但水平有限,错误在所难免,欢迎指正和指导。邮箱地址:
本文代码于2010.5.20重新修订过。增加了拷贝形式的调整过程和响应回调函数的调整过程。代码中的ExecuteAbort过程和ExecuteProc过程见《Delphi图像处理 -- 图像像素结构与图像数据转换》。