C#图像处理.docx
《C#图像处理.docx》由会员分享,可在线阅读,更多相关《C#图像处理.docx(14页珍藏版)》请在冰豆网上搜索。
C#图像处理
一.Bitmap类
Bitmap对象封装了GDI+中的一个位图,此位图由图形图像及其属性的像素数据组成.因此Bitmap是用于处理由像素数据定义的图像的对象.该类的主要方法和属性如下:
1.GetPixel方法和SetPixel方法:
获取和设置一个图像的指定像素的颜色.
2.PixelFormat属性:
返回图像的像素格式.
3.Palette属性:
获取和设置图像所使用的颜色调色板.
4.HeightWidth属性:
返回图像的高度和宽度.
5.LockBits方法和UnlockBits方法:
分别锁定和解锁系统内存中的位图像素.在基于像素点的图像处理方法中使用LockBits和UnlockBits是一个很好的方式,这两种方法可以使我们指定像素的范围来控制位图的任意一部分,从而消除了通过循环对位图的像素逐个进行处理,每调用LockBits之后都应该调用一次UnlockBits.
二.BitmapData类
BitmapData对象指定了位图的属性
1.Height属性:
被锁定位图的高度.
2.Width属性:
被锁定位图的高度.
3.PixelFormat属性:
数据的实际像素格式.
4.Scan0属性:
被锁定数组的首字节地址,如果整个图像被锁定,则是图像的第一个字节地址.
5.Stride属性:
步幅,也称为扫描宽度.
如上图所示,数组的长度并不一定等于图像像素数组的长度,还有一部分未用区域,这涉及到位图的数据结构,系统要保证每行的字节数必须为4的倍数.
三.Graphics类
Graphics对象是GDI+的关键所在,许多对象都是由Graphics类表示的,该类定义了绘制和填充图形对象的方法和属性,一个应用程序只要需要进行绘制或着色,它就必须使用Graphics对象.
四.Image类
这个类提供了位图和元文件操作的函数.Image类被声明为abstract,也就是说Image类不能实例化对象,而只能做为一个基类.
1.FromFile方法:
它根据输入的文件名产生一个Image对象,它有两种函数形式:
publicstaticImageFromFile(stringfilename);
publicstaticImageFromFile(stringfilename,booluseEmbeddedColorManagement);
2.FromHBitmap方法:
它从一个windows句柄处创建一个bitmap对象,它也包括两种函数形式:
publicstaticbitmapfromhbitmap(intptrhbitmap);
publicstaticbitmapfromhbitmap(intptrhbitmap,intptrhpalette);
3.FromStream方法:
从一个数据流中创建一个image对象,它包含三种函数形式:
publicstaticimagefromstream(streamstream);
publicstaticimagefromstream(streamstream,booluseembeddedcolormanagement);
fromstream(streamstream,booluseembeddedcolormanagement,boolvalidateimagedata);
有了上面的了解,我们便可以开始利用C#做图像处理,下面介绍几种方法:
一.打开、保存、显示图像
privateBitmapsrcBitmap=null;
privateBitmapshowBitmap=null;
//打开文件
privatevoidmenuFileOpen_Click(objectsender,EventArgse)
{
OpenFileDialogopenFileDialog=newOpenFileDialog();
openFileDialog.Filter=@"Bitmap文件(*.bmp)|*.bmp|Jpeg文件(*.jpg)|*.jpg|所有合适文件(*.bmp,*.jpg)|*.bmp;*.jpg";
openFileDialog.FilterIndex=3;
openFileDialog.RestoreDirectory=true;
if(DialogResult.OK==openFileDialog.ShowDialog())
{
srcBitmap=(Bitmap)Bitmap.FromFile(openFileDialog.FileName,false);
showBitmap=srcBitmap;
this.AutoScroll=true;
this.AutoScrollMinSize=newSize((int)(showBitmap.Width),(int)(showBitmap.Height));
this.Invalidate();
}
}
//保存图像文件
privatevoidmenuFileSave_Click(objectsender,EventArgse)
{
if(showBitmap!
=null)
{
SaveFileDialogsaveFileDialog=newSaveFileDialog();
saveFileDialog.Filter=@"Bitmap文件(*.bmp)|*.bmp|Jpeg文件(*.jpg)|*.jpg|所有合适文件(*.bmp,*.jpg)|*.bmp;*.jpg";
saveFileDialog.FilterIndex=3;
saveFileDialog.RestoreDirectory=true;
if(DialogResult.OK==saveFileDialog.ShowDialog())
{
ImageFormatformat=ImageFormat.Jpeg;
switch(Path.GetExtension(saveFileDialog.FileName).ToLower())
{
case".jpg":
format=ImageFormat.Jpeg;
break;
case".bmp":
format=ImageFormat.Bmp;
break;
default:
MessageBox.Show(this,"Unsupportedimageformatwasspecified","Error",
MessageBoxButtons.OK,MessageBoxIcon.Error);
return;
}
try
{
showBitmap.Save(saveFileDialog.FileName,format);
}
catch(Exception)
{
MessageBox.Show(this,"Failedwritingimagefile","Error",
MessageBoxButtons.OK,MessageBoxIcon.Error);
}
}
}
}
//窗口重绘,在窗体上显示图像,重载Paint
privatevoidfrmMain_Paint(objectsender,System.Windows.Forms.PaintEventArgse)
{
if(showBitmap!
=null)
{
Graphicsg=e.Graphics;
g.DrawImage(showBitmap,newRectangle(this.AutoScrollPosition.X,this.AutoScrollPosition.Y,
(int)(showBitmap.Width),(int)(showBitmap.Height)));
}
}
//灰度化
privatevoidmenu2Gray_Click(objectsender,EventArgse)
{
if(showBitmap==null)return;
showBitmap=RGB2Gray(showBitmap);//下面都以RGB2Gray为例
this.Invalidate();
}
二.提取像素法
这种方法简单易懂,但相当耗时,完全不可取.
publicstaticBitmapRGB2Gray(BitmapsrcBitmap)
{
ColorsrcColor;
intwide=srcBitmap.Width;
intheight=srcBitmap.Height;
for(inty=0;yfor(intx=0;x{
//获取像素的RGB颜色值
srcColor=srcBitmap.GetPixel(x,y);
bytetemp=(byte)(srcColor.R*.299+srcColor.G*.587+srcColor.B*.114);
//设置像素的RGB颜色值
srcBitmap.SetPixel(x,y,Color.FromArgb(temp,temp,temp));
}
returnsrcBitmap;
}//#
三.内存法
这是比较常用的方法
publicstaticBitmapRGB2Gray(BitmapsrcBitmap)
{
intwide=srcBitmap.Width;
intheight=srcBitmap.Height;
Rectanglerect=newRectangle(0,0,wide,height);
//将Bitmap锁定到系统内存中,获得BitmapData
BitmapDatasrcBmData=srcBitmap.LockBits(rect,
ImageLockMode.ReadWrite,PixelFormat.Format24bppRgb);
//创建Bitmap
BitmapdstBitmap=CreateGrayscaleImage(wide,height);//这个函数在后面有定义
BitmapDatadstBmData=dstBitmap.LockBits(rect,
ImageLockMode.ReadWrite,PixelFormat.Format8bppIndexed);
//位图中第一个像素数据的地址。
它也可以看成是位图中的第一个扫描行
System.IntPtrsrcPtr=srcBmData.Scan0;
System.IntPtrdstPtr=dstBmData.Scan0;
//将Bitmap对象的信息存放到byte数组中
intsrc_bytes=srcBmData.Stride*height;
byte[]srcValues=newbyte[src_bytes];
intdst_bytes=dstBmData.Stride*height;
byte[]dstValues=newbyte[dst_bytes];
//复制GRB信息到byte数组
System.Runtime.InteropServices.Marshal.Copy(srcPtr,srcValues,0,src_bytes);
System.Runtime.InteropServices.Marshal.Copy(dstPtr,dstValues,0,dst_bytes);
//根据Y=0.299*R+0.114*G+0.587B,Y为亮度
for(inti=0;ifor(intj=0;j{
//只处理每行中图像像素数据,舍弃未用空间
//注意位图结构中RGB按BGR的顺序存储
intk=3*j;
bytetemp=(byte)(srcValues[i*srcBmData.Stride+k+2]*.299
+srcValues[i*srcBmData.Stride+k+1]*.587+srcValues[i*srcBmData.Stride+k]*.114);
dstValues[i*dstBmData.Stride+j]=temp;
}
//将更改过的byte[]拷贝到原位图
System.Runtime.InteropServices.Marshal.Copy(dstValues,0,dstPtr,dst_bytes);
//解锁位图
srcBitmap.UnlockBits(srcBmData);
dstBitmap.UnlockBits(dstBmData);
returndstBitmap;
}//#
四指针法
C/C++的习惯,不是C#的特点
publicstaticBitmapRGB2Gray(BitmapsrcBitmap)
{
intwide=srcBitmap.Width;
intheight=srcBitmap.Height;
Rectanglerect=newRectangle(0,0,wide,height);
BitmapDatasrcBmData=srcBitmap.LockBits(rect,
ImageLockMode.ReadWrite,PixelFormat.Format24bppRgb);
BitmapdstBitmap=CreateGrayscaleImage(wide,height);
BitmapDatadstBmData=dstBitmap.LockBits(rect,
ImageLockMode.ReadWrite,PixelFormat.Format8bppIndexed);
System.IntPtrsrcScan=srcBmData.Scan0;
System.IntPtrdstScan=dstBmData.Scan0;
Unsafe//启动不安全代码
{
byte*srcP=(byte*)(void*)srcScan;
byte*dstP=(byte*)(void*)dstScan;
intsrcOffset=srcBmData.Stride-wide*3;
intdstOffset=dstBmData.Stride-wide;
bytered,green,blue;
for(inty=0;y{
for(intx=0;x{
blue=srcP[0];
green=srcP[1];
red=srcP[2];
*dstP=(byte)(.299*red+.587*green+.114*blue);
}
srcP+=srcOffset;
dstP+=dstOffset;
}
}
srcBitmap.UnlockBits(srcBmData);
dstBitmap.UnlockBits(dstBmData);
returndstBitmap;
}//#
五.矩阵法
并不是什么新方法,只是将图像数据分做R,G,B三个矩阵(二维数组)存储,类似MATLAB的习惯.
publicstaticboolGetRGB(BitmapSource,outint[,]R,outint[,]G,outint[,]B)
{
try
{
intiWidth=Source.Width;
intiHeight=Source.Height;
Rectanglerect=newRectangle(0,0,iWidth,iHeight);
System.Drawing.Imaging.BitmapDatabmpData=Source.LockBits(rect,System.Drawing.Imaging.ImageLockMode.ReadWrite,Source.PixelFormat);
IntPtriPtr=bmpData.Scan0;
intiBytes=iWidth*iHeight*3;
byte[]PixelValues=newbyte[iBytes];
System.Runtime.InteropServices.Marshal.Copy(iPtr,PixelValues,0,iBytes);
Source.UnlockBits(bmpData);
//注意这个地方图像的两维方向与数组两维的方向是转置的关系
R=newint[iHeight,iWidth];
G=newint[iHeight,iWidth];
B=newint[iHeight,iWidth];
intiPoint=0;
for(inti=0;i{
for(intj=0;j{
//注意,Windows中三基色的排列顺序是BGR而不是RGB!
B[i,j]=Convert.ToInt32(PixelValues[iPoint++]);
G[i,j]=Convert.ToInt32(PixelValues[iPoint++]);
R[i,j]=Convert.ToInt32(PixelValues[iPoint++]);
}
}
returntrue;
}
catch(Exception)
{
R=null;
G=null;
B=null;
returnfalse;
}
}//#
publicstaticBitmapFromRGB(int[,]R,int[,]G,int[,]B)
{
intiWidth=G.GetLength
(1);
intiHeight=G.GetLength(0);
BitmapResult=newBitmap(iWidth,iHeight,System.Drawing.Imaging.PixelFormat.Format24bppRgb);
Rectanglerect=newRectangle(0,0,iWidth,iHeight);
System.Drawing.Imaging.BitmapDatabmpData=Result.LockBits(rect,System.Drawing.Imaging.ImageLockMode.ReadWrite,System.Drawing.Imaging.PixelFormat.Format24bppRgb);
IntPtriPtr=bmpData.Scan0;
intiStride=bmpData.Stride;
intiBytes=iWidth*iHeight*3;
byte[]PixelValues=newbyte[iBytes];
intiPoint=0;
for(inti=0;ifor(intj=0;j{
intiG=G[i,j];
intiB=B[i,j];
intiR=R[i,j];
PixelValues[iPoint]=Convert.ToByte(iB);
PixelValues[iPoint+1]=Convert.ToByte(iG);
PixelValues[iPoint+2]=Convert.ToByte(iR);
iPoint+=3;
}
System.Runtime.InteropServices.Marshal.Copy(PixelValues,0,iPtr,iBytes);
Result.UnlockBits(bmpData);
returnResult;
}//#
publicstaticboolGetGray(BitmapsrcBitmap,outbyte[,]gray)
{
BitmaptempBitmap;
if(srcBitmap.PixelFormat!
=PixelFormat.Format8bppIndexed)
tempBitmap=ImageProcess.Image.Gray(srcBitmap);
else
tempBitmap=srcBitmap;
intwide=tempBitmap.Width;
intheight=tempBitmap.Height;
gray=newbyte[height,wide];
BitmapDatagbmData=tempBitmap.LockBits(newRectangle(0,0,wide,height),
ImageLockMode.ReadWrite,PixelFormat.Format8bppIndexed);
System.IntPtrScanG=gbmData.Scan0;
intgOffset=gbmData.Stride-wide;
unsafe
{
byte*g=(byte*)(void*)ScanG;
//foreachpixel
for(inty=0;y{
//foreachpixel
for(intx=0;x{
gray[y,x]=*g;
}
g+=gOffset;
}
}
tempBitmap.UnlockBits(gbmData);
returntrue;
}//#
publicstaticBitmapFromGray(byte[,]Gray)
{
intiWidth=Gray.GetLength
(1);
intiHeight=Gray.GetLength(0);
BitmapdstBitmap=ImageProcess.Image.CreateGrayscaleImage(iWidth,iHeight);
BitmapDatagbmData=dstBitmap.LockBits(newRectangle(0,0,iWidth,iH