本文为GDI+ for VCL基础系列文章之一,主要供GDI+初学者入门参考,例子使用GDI+版本下载地址和说明见《GDI+ for VCL基础 -- GDI+ 与 VCL》。如有错误或者建议请来信:maozefa@hotmail.com
GDI+ for VCL的TGpImageAttributes是个图像显示辅助类,可以通过该类,对图像显示时的颜色调整进行各种设置,包括颜色调整矩阵、灰度调整矩阵、灰度校正值、颜色映射表、颜色阈值、关键色(透明色)和通道输出等,从而改变图像显示状态。
颜色调整矩阵和灰度调整矩阵我已经在《GDI+ for VCL基础 -- 颜色调整矩阵ColorMatrix详解》一文中作了较详细的叙述,这里不再重复,对其它一些调整作些基础的介绍。
一、伽玛灰度校正。有关图像伽玛的概念比较复杂,如指CRT显示器的伽玛失真、伽玛度量、对伽玛失真的校正以及模拟图像信号转换为数字图像信号的伽玛失真以及数字图像还原为图像模拟信号的伽玛校正等,也就是说,对一般图像显示来说,涉及到两方面的伽玛失真,一是显示器的物理伽玛失真,二是图像模拟信号转数字图像文件时的失真(有的照相机或者扫描仪在转换时可以进行伽玛校正),在图像显示时,进行伽玛校正可在图像灰度级对图像实施的一种明暗校正,以改善图像失真状况(更具体的概念解释和校正理论请参考有关资料)。
TGpImageAttributes是通过其SetGamma方法来设置伽玛校正值的,其原型为:
procedure SetGamma(gamma: Single; catype: TColorAdjustType = ctDefault);
其中的gamma参数(注:方法中catype参数已经在《GDI+ for VCL基础 -- 颜色调整矩阵ColorMatrix详解》介绍了,本文介绍的所有方法中该参数请参见该文)为要设置的伽玛值,一般情况下,该值在1.0 - 2.2之间,特殊情况下也可设置到0.1 - 5.0,默认值为1.0(指不设置伽玛值,GDI+显示图像时的gamma值),下面的代码分别以伽玛值1.0、1.5和2.2显示图像:
var
Image: TGpImage;
attr: TGpImageAttributes;
W, H: Integer;
begin
Image : = TGpImage.Create( ' ..mediaFRUIT.jpg ' );
attr : = TGpImageAttributes.Create;
W : = Image.Width;
H : = Image.Height;
// 使用默认值显示
g.DrawImage(Image, GpRect( 0 , 0 , W, H), 0 , 0 , W, H, utPixel, attr);
// 设置Gamma 1.5显示
attr.SetGamma( 1.5 );
g.TranslateTransform(W + 5 , 0 );
g.DrawImage(Image, GpRect( 0 , 0 , W, H), 0 , 0 , W, H, utPixel, attr);
// 设置Gamma 2.2显示
attr.SetGamma( 2.2 );
g.TranslateTransform(W + 5 , 0 );
g.DrawImage(Image, GpRect( 0 , 0 , W, H), 0 , 0 , W, H, utPixel, attr);
image.Free;
end;
效果图如下,可见Gamma越大,灰度越暗:
二、设置颜色阀值。TGpImageAttributes的SetThreshold方法用来设置图像的颜色阀值,其原型为:
procedure SetThreshold(threshold: Single; catype: TColorAdjustType = ctDefault);
参数threshold为颜色阀值,可在0.0 - 1.0之间设定。所谓设置颜色阀值,是指指定颜色像素中每种颜色分量的分界点。假定当前像素颜色中的红色、绿色和蓝色分量分别为 230、50 和 220,又假定阈值设置为 0.7,显示时, 红色分量 230 大于 0.7 * 255,因此,红色分量将更改为 255;绿色分量 50 小于 0.7 * 255,因此,绿色分量将更改为 0;而蓝色分量 220 大于 0.7 * 255,因此,蓝色分量将更改为 255。可见,该像素的ARGB颜色值为$FFE632DC,设置0.7的阀值后,显示的颜色值值为$FFFF00FF。
所以,通过颜色阀值的设置后,颜色R、G、B各个分量的值只能是0或者255,最终,图像呈现出来的颜色最多为8种,即红、绿、蓝、黄、紫、青以及白和黑,相当于图像的对比度按阀值调节到了极致。通过设置颜色阀值,可以很直观的查看某种大范围颜色所表示的趋势,如气象云图。
设置一个阀值,配合颜色调整矩阵,可以把一张彩色图像二值化显示:
procedure GrayImage(Image: TGpImage; Threshold: Single = 0.0 );
const
ColorMatrix: TColorMatrix =
(( 0.3 , 0.3 , 0.3 , 0.0 , 0.0 ),
( 0.59 , 0.59 , 0.59 , 0.0 , 0.0 ),
( 0.11 , 0.11 , 0.11 , 0.0 , 0.0 ),
( 0.0 , 0.0 , 0.0 , 1.0 , 0.0 ),
( 0.0 , 0.0 , 0.0 , 0.0 , 1.0 ));
var
Tmp: TGpImage;
attr: TGpImageAttributes;
g: TGpGraphics;
begin
Tmp : = Image.Clone;
g : = TGpGraphics.Create(Image);
attr : = TGpImageAttributes.Create;
try
attr.SetColorMatrix(ColorMatrix);
if Threshold > 0.0 then
attr.SetThreshold(Threshold);
g.DrawImage(Tmp, GpRect( 0 , 0 , Image.Width, Image.Height),
0 , 0 , Tmp.Width, Tmp.Height, utPixel, attr);
finally
g.Free;
attr.Free;
Tmp.Free;
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
Image: TGpImage;
g: TGpGraphics;
begin
Image : = TGpImage.Create( ' ..mediaFRUIT.jpg ' );
g : = TGpGraphics.Create(Handle, False);
g.DrawImage(Image, 0 , 0 , Image.Width, Image.Height);
// 灰度显示
GrayImage(Image);
g.TranslateTransform(Image.Width + 5 , 0 );
g.DrawImage(Image, 0 , 0 , Image.Width, Image.Height);
// 设置0.52的阀值显示二值图
GrayImage(Image, 0.52 );
g.TranslateTransform(Image.Width + 5 , 0 );
g.DrawImage(Image, 0 , 0 , Image.Width, Image.Height);
g.Free;
image.Free;
end;
效果图如下:
三、颜色映射。所谓颜色映射,就是对某些颜色用另外一些颜色进行替换。方法原型为:
procedure SetRemapTable(const map: array of TColorMap; catype: TColorAdjustType = ctDefault);
其中的map参数为颜色替换表数组,颜色替换表TColorMap类型定义如下:
// Color Map
// ----------------------------------------------------------------------------
TColorMap = packed record
oldColor: TARGB; // 现有的颜色值
newColor: TARGB; // 设置的新值
end;
PColorMap = ^ TColorMap;
配合上面所说的阀值设置,下面用颜色映射方法显示另外一种方式的二值图:
const
maps: array[ 0 .. 7 ] of TColorMap =
(
(OldColor: $FFFF0000; NewColor: $FF000000),
(OldColor: $FF00FF00; NewColor: $FFFFFFFF),
(OldColor: $FF0000FF; NewColor: $FF000000),
(OldColor: $FF000000; NewColor: $FF000000),
(OldColor: $FFFFFF00; NewColor: $FFFFFFFF),
(OldColor: $FFFF00FF; NewColor: $FFFFFFFF),
(OldColor: $FF00FFFF; NewColor: $FFFFFFFF),
(OldColor: $FFFFFFFF; NewColor: $FFFFFFFF)
);
var
Image: TGpImage;
tmp: TGpImage;
g, gt: TGpGraphics;
attr: TGpImageAttributes;
W, H: Integer;
begin
Image : = TGpImage.Create( ' ..mediaFRUIT.jpg ' );
g : = TGpGraphics.Create(Handle, False);
attr : = TGpImageAttributes.Create;
W : = Image.Width;
H : = Image.Height;
// 显示原图
g.DrawImage(Image, GpRect( 0 , 0 , W, H), 0 , 0 , W, H, utPixel, attr);
// 设置阀值为0.46 显示
attr.SetThreshold( 0.46 );
g.TranslateTransform(W + 5 , 0 );
g.DrawImage(Image, GpRect( 0 , 0 , W, H), 0 , 0 , W, H, utPixel, attr);
// 克隆一张图像,并将阀值图显示在图像中
tmp : = Image.Clone;
gt : = TGpGraphics.Create(tmp);
gt.DrawImage(Image, GpRect( 0 , 0 , W, H), 0 , 0 , W, H, utPixel, attr);
gt.Free;
attr.Reset;
// 对该图实施颜色映射成二值图,并显示
attr.SetRemapTable(maps);
g.TranslateTransform(W + 5 , 0 );
g.DrawImage(tmp, GpRect( 0 , 0 , W, H), 0 , 0 , W, H, utPixel, attr);
g.Free;
image.Free;
tmp.Free;
end;
前面的二值图,是通过颜色调整矩阵将图像转变为灰度图,然后对灰度图设置阀值,形成二值图显示;而现在我们直接在彩色图基础上设置阀值,使图像颜色的对比度达到极致,形成最多8种颜色的彩图,然后对这8种颜色进行黑白替换,最终也可形成二值图,而且,什么颜色成黑,什么颜色成白,全取决于这张颜色映射表。从代码中,我把红色和蓝色设置为黑色,加上已有的黑色,共三种颜色替换为黑色,其余五种颜色设置为白色。为什么这样设置呢?考虑前面颜色调整矩阵转换灰度图时的公式是0.3R * 0.59G * 0.11B,可见红色和蓝色分量的比重在灰度图中加起来只有0.41,所以,直接把红色和蓝色设置为了黑色,而绿色及其他混合色在灰度图中大部分所在比重较大,所以设置白色,最后形成的效果图如下:
比较这2种二值图,发现差别不大,至于有何意义?我也不知道。我只是测试TGpImageAttributes的功能而已,这种二值图的有没有实用价值是专家们的事,呵呵。
四、设置 CMYK 输出通道。CMYK 颜色模式是在印刷业中使用的颜色通道,分别为青色、洋红色、黄色和黑色。利用TGpImageAttributes的SetOutputChannel方法可以把RGB模式图像转换为CMYK各通道进行显示,其原型如下:
procedure SetOutputChannel(channelFlags: TColorChannelFlags; catype: TColorAdjustType = ctDefault);
其中的channelFlags参数可设置要输出的通道,下面的代码和效果图输出了上面图像的CMYK通道:
var
Image: TGpImage;
g: TGpGraphics;
attr: TGpImageAttributes;
I, W, H: Integer;
begin
Image : = TGpImage.Create( ' ..mediaFRUIT.jpg ' );
g : = TGpGraphics.Create(Handle, False);
attr : = TGpImageAttributes.Create;
W : = Image.Width;
H : = Image.Height;
for I : = 0 to 3 do
begin
if I = 2 then
g.TranslateTransform( - (W + 5 ), H + 5 );
if I mod 2 = 1 then
g.TranslateTransform(W + 5 , 0 );
attr.SetOutputChannel(Gdiplus.TColorChannelFlags(I));
g.DrawImage(Image, GpRect( 0 , 0 , W, H), 0 , 0 , W, H, utPixel, attr);
end;
attr.Free;
g.Free;
image.Free;
end;
其实,右下角的CMYK中黑色通道也可近似的作为灰度图处理。
五、设置图像的关键颜色(透明色)范围。这个设置很简单,可参见我的文章《GDI+ 在Delphi程序的应用 -- 图像的透明显示技巧》的有关章节,这里不再累叙。