一.Bitmap類
Bitmap對象封裝了GDI+中的一個位圖,此位圖由圖形圖像及其屬性的像素數據組成.因此Bitmap是用於處理由像素數據定義的圖像的對象.該類的主要方法和屬性如下:
1. GetPixel方法和 SetPixel方法:獲取和設置一個圖像的指定像素的顏色.
2. PixelFormat屬性:返回圖像的像素格式.
3. Palette屬性:獲取和設置圖像所使用的顏色調色板.
4. Height Width屬性:返回圖像的高度和寬度.
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對象,它有兩種函數形式:
public static Image FromFile(string filename);
public static Image FromFile(string filename, bool useEmbeddedColorManagement);
2.FromHBitmap方法:它從一個windows句柄處創建一個bitmap對象, 它也包括兩種函數形式:
public static bitmap fromhbitmap(intptr hbitmap);
public static bitmap fromhbitmap(intptr hbitmap, intptr hpalette);
3. FromStream方法:從一個數據流中創建一個image對象,它包含三種函數形式 :
public static image fromstream(stream stream);
public static image fromstream(stream stream, bool useembeddedcolormanagement);
fromstream(stream stream, bool useembeddedcolormanagement, bool validateimagedata);
有了上面的瞭解,我們便可以開始利用C#做圖像處理,下面介紹幾種方法:
一. 打開、保存、顯示圖像
private Bitmap srcBitmap = null;
private Bitmap showBitmap = null;
//打開文件
private void menuFileOpen_Click(object sender, EventArgs e)
{
OpenFileDialog openFileDialog = new OpenFileDialog();
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 = new Size((int)(showBitmap.Width), (int)(showBitmap.Height));
this.Invalidate();
}
}
//保存圖像文件
private void menuFileSave_Click(object sender, EventArgs e)
{
if (showBitmap != null)
{
SaveFileDialog saveFileDialog = new SaveFileDialog();
saveFileDialog.Filter = @"Bitmap文件(*.bmp)|*.bmp|Jpeg文件(*.jpg)|*.jpg|所有合適文件(*.bmp,*.jpg)|*.bmp;*.jpg";
saveFileDialog.FilterIndex = 3;
saveFileDialog.RestoreDirectory = true;
if (DialogResult.OK == saveFileDialog.ShowDialog())
{
ImageFormat format = ImageFormat.Jpeg;
switch (Path.GetExtension(saveFileDialog.FileName).ToLower())
{
case ".jpg":
format = ImageFormat.Jpeg;
break;
case ".bmp":
format = ImageFormat.Bmp;
break;
default:
MessageBox.Show(this, "Unsupported image format was specified", "Error",
MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
try
{
showBitmap.Save(saveFileDialog.FileName,format );
}
catch (Exception)
{
MessageBox.Show(this, "Failed writing image file", "Error",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
}
//窗口重繪,在窗體上顯示圖像,重載Paint
private void frmMain_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
{
if (showBitmap != null)
{
Graphics g = e.Graphics;
g.DrawImage(showBitmap, new Rectangle(this.AutoScrollPosition.X, this.AutoScrollPosition.Y ,
(int)(showBitmap.Width), (int)(showBitmap.Height)));
}
}
//灰度化
private void menu2Gray_Click(object sender, EventArgs e)
{
if (showBitmap == null) return;
showBitmap = RGB2Gray(showBitmap);//下面都以RGB2Gray爲例
this.Invalidate();
}
二. 提取像素法
這種方法簡單易懂,但相當耗時,完全不可取.
public static Bitmap RGB2Gray(Bitmap srcBitmap)
{
Color srcColor;
int wide = srcBitmap.Width;
int height = srcBitmap.Height;
for (int y = 0; y < height; y++)
for (int x = 0; x < wide; x++)
{
//獲取像素的RGB顏色值
srcColor = srcBitmap.GetPixel(x, y);
byte temp = (byte)(srcColor.R * .299 + srcColor.G * .587 + srcColor.B * .114);
//設置像素的RGB顏色值
srcBitmap.SetPixel(x, y, Color.FromArgb(temp, temp, temp));
}
return srcBitmap ;
}//#
三. 內存法
這是比較常用的方法
public static Bitmap RGB2Gray(Bitmap srcBitmap)
{
int wide = srcBitmap.Width;
int height = srcBitmap.Height;
Rectangle rect = new Rectangle(0, 0, wide, height);
// 將Bitmap鎖定到系統內存中, 獲得BitmapData
BitmapData srcBmData = srcBitmap.LockBits(rect,
ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
//創建Bitmap
Bitmap dstBitmap = CreateGrayscaleImage(wide, height);//這個函數在後面有定義
BitmapData dstBmData = dstBitmap.LockBits(rect,
ImageLockMode.ReadWrite, PixelFormat.Format8bppIndexed);
// 位圖中第一個像素數據的地址。它也可以看成是位圖中的第一個掃描行
System.IntPtr srcPtr = srcBmData.Scan0;
System.IntPtr dstPtr = dstBmData.Scan0;
// 將Bitmap對象的信息存放到byte數組中
int src_bytes = srcBmData.Stride * height;
byte[] srcValues = new byte[src_bytes];
int dst_bytes = dstBmData.Stride * height;
byte[] dstValues = new byte[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 (int i = 0; i < height; i++)
for (int j = 0; j < wide; j++)
{
//只處理每行中圖像像素數據,捨棄未用空間
//注意位圖結構中RGB按BGR的順序存儲
int k = 3 * j;
byte temp = (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);
return dstBitmap;
}//#