第09章 二维图形图像处理.docx
《第09章 二维图形图像处理.docx》由会员分享,可在线阅读,更多相关《第09章 二维图形图像处理.docx(47页珍藏版)》请在冰豆网上搜索。
![第09章 二维图形图像处理.docx](https://file1.bdocx.com/fileroot1/2023-1/2/99330f80-a7fc-4df4-9ca2-d79f84a17572/99330f80-a7fc-4df4-9ca2-d79f84a175721.gif)
第09章二维图形图像处理
第9章二维图形图像处理
本章介绍在C#中如何利用GDI+进行二维图形图像处理。
GDI+是GDI(GraphicsDeviceInterface,图形设备接口)的后续版本,提供了高级图形图像处理功能。
在C#中,可利用GDI+提供的一套托管类编写各种设备无关的图形应用程序,例如游戏、计算机辅助设计、绘图程序等等。
9.1GDI+概述
GDI+是微软在Windows2000以后操作系统中提供的新接口,.NETFramework通过一套部署为托管代码的类来展现提供的图形图像处理功能,这套类被称为GDI+的托管类。
利用GDI+可以轻松实现一般图形图像处理、颜色渐变、透明处理、纹理处理、拉伸和缩放等多种高级功能。
GDI+主要提供了以下三类服务:
1.二维矢量图形:
GDI+提供了构造和绘制基本图形的类。
例如,可以利用Rectangle类构造矩形的位置和大小;利用Pen类提供线条颜色、粗细和线型的信息;利用Brush的扩充类提供如何利用颜色或图案来填充封闭图形和路径的信息;而Graphics类则提供了对图形进行各种处理的方法。
2.图像处理:
由于大多数图像并不是直线和曲线的简单组合,无法直接使用二维矢量图形方式进行处理。
因此,GDI+提供了Bitmap、Image等类,用于显示、操作和保存BMP、JPG、GIF等图像格式。
3.文字显示:
GDI+支持使用各种字体、字号和样式来显示文本。
另外,在GDI+中还提供了许多实用的功能,比如渐变画刷、基样条曲线、Alpha混合、反锯齿处理、矩阵变换、浮动坐标等。
实际上,在托管代码中,我们不需要考虑GDI+内部是如何实现的,直接使用提供的类进行编程就可以了。
所有图形图像处理功能都包含在下面介绍的命名空间下。
1)System.Drawing命名空间
System.Drawing命名空间提供了对GDI+基本图形功能的访问,主要有Graphics类、Bitmap类、从Brush类继承的类、Font类、Icon类、Image类、Pen类和Color类等。
2)System.Drawing.Drawing2D命名空间
System.Drawing.Drawing2D命名空间提供了高级的二维和矢量图形处理功能,主要有:
梯度型画刷、Matrix类(用于定义几何变换)和GraphicsPath类等。
3)System.Drawing.Imaging命名空间
System.Drawing.Imaging命名空间提供了高级图像处理功能。
4)System.Drawing.Text命名空间
System.Drawing.Text命名空间提供了字体和文本排版功能。
9.1.1GDI+使用的坐标系
开发Windows应用程序时,GDI+提供的坐标系为我们提供了很大的方便。
它就如同给设计者一个导航图,使设计者能方便的使用各种图形命令。
1.GDI+坐标系中的基本结构
在GDI+坐标系中,有三种最基本的结构,分别是Point、Size和Rectangle。
1)Point
Point在三种结构中是最简单的,GDI+使用Point表示某个特定位置相对于原点的水平和垂直距离。
许多GDI+函数都是以Point作为参数的。
声明和构造Point的代码示例如下:
Pointp=newPoint(1,1);
2)Size
在GDI+中,Size也表示一个尺寸,它也有两个整型属性来表示水平和垂直距离——Width和Height。
但是Point和Size的含义是不同的,Point是用来说明实体具体位置的,而Size是用来说明实体有多大的。
声明和构造Size代码示例如下:
Sizes=newSize(5,5);
3)Rectangle
Rectangle是用来指定矩形的坐标的,它由一个Point和一个Size组成,其中Point表示矩形左上角,Size表示矩形大小。
声明和构造Rectangle有两种方式:
1)在构造函数中分别指定x坐标、y坐标、宽度和高度。
例如:
Rectangler1=newRectangle(1,2,5,6);
2)在构造函数中指定Point位置和Size结构。
例如:
Pointp=newPoint(1,2);
Sizes=newSize(5,6);
Rectangler2=newRectangle(p,s);
2.GDI+中坐标系的分类
图9-1世界坐标系示意图
GDI+中的坐标系分为三类:
世界坐标系(Worldcoordinates)、设备坐标系(Devicecoordinates)和页面坐标系(Pagecoordinates)。
世界坐标系是用于建立特殊图形世界模型的坐标系,也是在程序中调用方法时传递参数使用的坐标系。
世界坐标系是一种通用的坐标系,可以适用于任何计算机设备。
默认情况下,X轴正方向水平向右,Y轴正方向垂直向下,如图9-1所示。
设备坐标系是指显示设备或打印设备使用的坐标系,它的特点是以设备上的像素点为单位。
对于窗体中的视图而言,设备坐标的原点在窗体绘图区的左上角,x坐标从左向右递增,y坐标自上而下递增。
由于设备的分辨率不同,相同坐标值的物理位置可能不同。
如对于边长为100的正方形,显示器为800×600和1024×768时的大小是不一样的。
页面坐标系指某种映射模式下的一种坐标系。
所谓映射是指将世界坐标系通过某种方式进行的变换。
通俗些说,页面坐标系就是指绘图图面(如窗体或控件)使用的坐标系。
页面坐标系统与设备坐标系统的差异在于X,Y的单位不同:
页面坐标系中的X,Y单位可以任意设定,如英寸、毫米等;而设备坐标系中,只有一种单位,对显示器而言就是像素,对打印机而言就是1/72英寸。
图9-2屏幕坐标示意图
默认情况下,设备坐标和页面坐标是相同的,均使用像素作为度量单位。
图9-2演示了计算机屏幕中坐标的位置情况。
如果将度量单位设置为像素以外的其他单位(例如英寸),则设备坐标和页面坐标就不相同了。
3.不同坐标系的转换
实际上,我们调用GDI+的Graphics对象进行操作时,调用对应的方法时传递给方法的坐标为世界坐标系中的坐标,而在屏幕或者打印机上显示的是设备坐标系中的坐标。
因此,每次输出时,系统都会自动进行两次坐标变换——第一次是从世界坐标向页面坐标的变换,称之为世界变换(worldtransformation);第二次是从页面坐标向设备坐标的变换,称之为页面变换(pagetransformation)。
在程序中,我们也可以通过调用Graphics对象的TranslateTransform方法改变世界变换的原点,通过设置Graphics对象的PageUnit和PageScale属性改变页面变换的度量单位。
除此之外,Graphics类还提供了两个只读属性:
DpiX和DpiY,用于检查显示设备每英寸的水平点数和垂直点数。
【例9-1】
图9-3坐标转换示例
分别调用Graphics对象的世界变换和页面变换,使用英寸作为度量单位,并让坐标系的原点距工作区左边缘0.5英寸、距工作区顶部0.5英寸,然后从(0,0)到(2,2)绘制一条直线。
privatevoidForm1_Paint(objectsender,PaintEventArgse)
{
GraphicsmyGraphics=e.Graphics;
myGraphics.TranslateTransform(0.5F,0.5F);
myGraphics.PageUnit=GraphicsUnit.Inch;
PenmyPen=newPen(Color.Black,1/myGraphics.DpiX);
myGraphics.DrawLine(myPen,0,0,2,2);
}
图9-3为绘制的直线,图中标出的坐标系不是这段代码绘制的,仅是为了观察方便。
如果假定显示设备在水平方向和垂直方向每英寸都有100个像素,则例9-1中直线的起点和终点在三种坐标系中分别具有表9-1所示的坐标值。
表9-1直线在三种坐标系统中的坐标值
世界坐标系统
(0,0)到(0.5,0.5)
页面坐标系统
(0.5,0.5)到(2.5,2.5)
设备坐标系统
(50,50)到(250,250)
9.1.2Graphics类
Graphics类包含在System.Drawing命名空间下,它提供了简单的图形图像处理功能。
在绘制图形图像前,首先必须创建Graphics对象,然后利用这个对象绘制直线、曲线、椭圆等图形图像。
有三种常见的创建Graphics对象的方法。
第一种方法是在窗体或控件的Paint事件中获取Graphics对象。
例如:
privatevoidForm1_Paint(objectsender,System.Windows.Forms.PaintEventArgse)
{
Graphicsg=e.Graphics;
}
在每一个窗体或控件中,都有一个Paint事件,该事件的参数包括了当前窗体或控件的Graphics对象,在为窗体或控件创建绘图代码时,一般使用此方法来获取对图形的引用。
第二种方法是通过当前窗体的CreateGraphics方法,把当前窗体的画笔、字体、颜色作为默认值,获取对Graphics对象的引用。
例如:
Graphicsg;
g=this.CreateGraphics();
……
注意这种对象只有在处理当前Windows窗体消息的过程中有效,如果想在已经存在的窗体或控件中绘图,可以使用此种方法。
第三种方法是从继承自图像的任何对象创建Graphics对象,例如:
BitmapmyBitmap=newBitmap(@"C:
\mytest1\Pics\myPic.bmp");
Graphicsg=Graphics.FromImage(myBitmap);
这个方法适用于需要更改已经存在的图像的情况。
9.1.3颜色
颜色是进行图形操作的基本要素,它封装在System.Drawing.Color结构中。
人眼可以分辨的显示的颜色都是由一定的红、绿、蓝三色光组合而成。
任何一种颜色都可以有四个分量,分别是:
R、G、B、A。
其中:
R:
红色,取值范围0~255,0表示没有红色成分,255为饱和红色;
G:
绿色,取值范围0~255,0表示没有绿色成分,255为饱和绿色;
B:
蓝色,取值范围0~255,0表示没有蓝色成分,255为饱和蓝色;
A:
Alpha值,即透明度,取值范围0~255,0表示完全透明,255表示完全不透明。
在代码中声明颜色的方式常用有两种:
1.调用静态方法Color.FromArgb()指定任意颜色
这种方法有两种常用形式。
第一种形式为直接指定三种颜色,方法原型为:
PublicstaticColorFromArgb(intred,intgreen,intblue)
三个参数分别表示R、G、B三色,Alpha值使用默认值255,即完全不透明。
例如:
Colorred=Color.FromArgb(255,0,0);
Colorgreen=Color.FromArgb(0,255,0);
Colorblue=Color.FromArgb(0,0,0xff);
其中0xff为十六进制表示形式。
第二种形式为四个参数,方法原型为:
PublicstaticColorFromArgb(intalpha,intred,intgreen,intblue)
四个参数分别表示透明度、R、G、B三色值。
2.系统预定义颜色
System.Drawing.Color结构中提供了许多静态属性,每个属性返回一个命名颜色,在Color结构中已经预定义了141种颜色,可以直接使用。
例如:
this.BackColor=Color.White;
9.1.4画笔和画刷
本节介绍Pen类和Brush类,在绘制图形时需要使用画笔和画刷绘制或填充图形、文本和图像。
画笔是Pen类的实例,用于绘制各种直线、空心图形和实心图形等。
画刷是从Brush类派生的任何类的实例,用来填充形状或绘制文本。
1.画笔(Pen)
画笔可用于绘制具有指定宽度和样式的直线、曲线或轮廓形状。
下面的示例说明如何创建一支基本的蓝色画笔:
PenmyPen=newPen(Color.Blue);//创建一支蓝色画笔,宽度默认为1个像素
PenmyPen=newPen(Color.Blue,10.5f);//创建一支宽度为10.5个像素的蓝色画笔
也可以从画刷对象创建画笔对象,例如:
SolidBrushmyBrush=newSolidBrush(Color.Red);//实心画刷,默认宽度为1个像素
PenmyPen=newPen(myBrush);//从现有画刷创建红色画笔
PenmyPen=newPen(myBrush,5);//从现有画刷创建宽度为5个像素的红色画笔
创建画笔后,即可使用它来绘制直线、曲线或空心形状。
还可以修改画笔的各种属性,比如使用Width属性修改画笔的宽度;使用Color属性修改画笔的颜色;使用StartCap和EndCap属性将预设或自定义的形状添加到线条的开始和结尾;使用DashStyle属性指定画笔绘制的虚线样式等。
【例9-2】画笔的用法。
(1)新建一个名为PenExample的Windows应用程序,调整窗体到适当大小。
然后切换到代码方式,添加命名空间引用:
usingSystem.Drawing.Drawing2D;
(2)在窗体的属性中找到Paint事件,双击此事件,添加Form1_Paint事件代码:
privatevoidForm1_Paint(objectsender,PaintEventArgse)
{
//创建Graphics对象
Graphicsg=e.Graphics;
//创建一支黑色的画笔
Penblackpen=newPen(Color.Black,10.0f);
//绘制字符串
g.DrawString("黑色,宽度为10.0",this.Font,Brushes.Black,5,5);
//绘制宽度为10.0f的黑色直线
g.DrawLine(blackpen,newPoint(110,12),newPoint(400,12));
//创建一支红色的画笔
Penredpen=newPen(Color.Red,5.0f);
//绘制字符串
g.DrawString("红色,宽度为5",this.Font,Brushes.Black,5,25);
//绘制宽度为5的红色直线
g.DrawLine(redpen,newPoint(110,30),newPoint(400,30));
//创建一支蓝色的画笔
Penbluepen=newPen(Color.Blue,6);
//定义直线的样式
bluepen.StartCap=LineCap.Flat;
bluepen.EndCap=LineCap.ArrowAnchor;
//绘制字符串
g.DrawString("蓝色箭头线",this.Font,Brushes.Black,5,45);
//绘制宽度为6的蓝色箭头线
g.DrawLine(bluepen,newPoint(110,50),newPoint(400,50));
//再创建一支黑色的画笔
Peniblackpen=newPen(Color.Black,2.0f);
//定义直线的样式
iblackpen.DashStyle=DashStyle.Custom;
iblackpen.DashPattern=newfloat[]{4,4};
iblackpen.EndCap=LineCap.NoAnchor;
//绘制字符串
g.DrawString("自定义虚线",this.Font,Brushes.Black,5,65);
//绘制宽度为2的自定义虚线
g.DrawLine(iblackpen,newPoint(110,70),newPoint(400,70));
//再创建一支红色的画笔
Peniredpen=newPen(Color.Red,2.0f);
//定义直线的样式
iredpen.DashStyle=DashStyle.Dot;
//绘制字符串
g.DrawString("点划线",this.Font,Brushes.Black,5,85);
//绘制宽度为2的点划线
g.DrawLine(iredpen,newPoint(110,90),newPoint(400,90));
}
(3)运行程序,结果如图9-4所示。
图9-4画笔的用法演示
2.画刷(Brush)
画刷是可以与Graphics对象一起使用来创建实心形状和呈现文本的对象。
可以用来填充各种图形形状,如矩形、椭圆、扇形和多边形等。
表9-2列出了几种不同类型的画刷。
表9-2画刷类型
类
说明
SolidBrush
用纯色填充图形
TextureBrush
用基于光栅的图像(位图、JPG等)填充图形
LinearGradientBrush
用颜色渐变填充图形——颜色渐变是指一种颜色沿着指定方向或在两个指定的(平行)边界线之间逐渐变成另一种颜色
PathGradientBrush
用渐变效果填充图形,渐变的方向是从由路径定义的图形边界指向图形的中心。
这种渐变可以让人想起中学的彩色地图,即用较深的颜色给国土的轮廓着色,而用较浅的颜色给国土的中心着色
HatchBrush
用各种图案填充图形
1)使用SolidBrush类定义画刷
SolidBrush类用于定义单色画刷。
该类可以填充图形,比如矩形、椭圆、多边形和路径。
例9-3演示了如何在窗体中填充一个纯红色的椭圆。
【例9-3】单色画刷演示示例。
图9-5单色画刷示例运行图
(1)新建一个名为SolidBrushExample的Windows应用程序,调整窗体到适当大小。
(2)在窗体的属性中找到Paint事件,双击此事件,添加Form1_Paint事件代码。
privatevoidForm1_Paint(objectsender,PaintEventArgse)
{
Graphicsg=e.Graphics;
SolidBrushmySolidBrush=newSolidBrush(Color.Red);
g.FillEllipse(mySolidBrush,30,30,130,100);
}
(3)运行程序,结果如图9-5所示。
2)使用HatchBrush类填充简单图案
HatchBrush类提供的画刷可以用各种图案填充图形。
通过Hatch类型可以设置影线样式。
在创建影线的画刷时,能设定前景色、背景色和影线样式。
有56种不同的影线样式枚举,该枚举可以参看System.Drawing.Drawing2D.HatchStyle枚举。
例9-4演示了如何创建一个HatchBrush,例子使用垂直影线,白色为前景色,红色为背景色。
【例9-4】填充简单图案示例。
(1)新建一个名为HatchBrushExample的应用程序,调整窗体到适当大小。
然后切换到代码方式,添加命名空间引用:
usingSystem.Drawing.Drawing2D;
(2)在窗体的属性中找到Paint事件,双击此事件,添加Form1_Paint事件代码。
图9-6HatchBrush类示例
图
privatevoidFom1_Paint(objectsender,PaintEventArgse)
{
Graphicsg=e.Graphics;
HatchBrushmyHatchBrush=
newHatchBrush(HatchStyle.Cross,Color.White,
Color.Red);
g.FillEllipse(myHatchBrush,this.ClientRectangle);
}
(3)运行程序,结果如图9-6所示。
3)使用TextureBrush类填充复杂图像
TextureBrush类使用图像作为填充的样式,它可以使用例如.bmp、.jpg、.png等格式的图像。
初始化一个新的TextureBrush对象需要指定填充的图像。
①TextureBrush类提供了5个重载的构造函数,分别是:
publicTextureBrush(Image)
publicTextureBrush(ImageRectangle)
publicTextureBrush(Image,WrapMode)
publicTextureBrush(Image,Rectangle,ImageAttributes)
publicTextureBrush(Image,WrapMode,Rectangle)
其中,Image用于指定画刷所要填充的图案;Rectangle用于指定图像上用于画刷的矩形区域,其位置不能超越图像的范围;WrapMode枚举成员用于指定如何排布图像,其值见表9-3。
表9-3WrapMode枚举值
WrapMode值
说明
Clamp
完全由绘制对象的边框决定
Tile
平铺
TileFlipX
水平方向翻转并平铺图像
TileFlipY
垂直方向翻转并平铺图像
TileFlipXY
水平和垂直方向翻转并平铺图像
ImageAttributes:
ImageAttributes对象用于指定图像的附加特性参数。
②TextureBrush类有3个属性,如表9-4所示。
表9-4TextureBrush类属性
名称
属性
Image
Image类型,与画刷关联的图像对象
Transform
Matrix类型,画刷的变换矩阵
WrapMode
WrapMode枚举成员,指定图像的排布方式
例9-5说明了如何创建一个TextureBrush,该例使用名为xue.jpg的图像进行填充。
【例9-5】创建TextureBrush示例。
(1)新建一个名为TextureBrushExample的Windows应用程序,调整窗体到适当大小。
(2)鼠标右键单击【解决方案资源管理器】中的项目名,选择【添加】【添加现有项】,在弹出的窗体中选择添加的文件类型为“ImageFiles”,找到需要使用的图片,将其添加到当前项目中,并修改图