matlab读取图像博客园,c#图像处理入门的一个好方法-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属性:步幅,也称为扫描宽度.

a4c26d1e5885305701be709a3d33442f.png

如上图所示,数组的长度并不一定等于图像像素数组的长度,还有一部分未用区域,这涉及到位图的数据结构,系统要保证每行的字节数必须为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();

}

二.提取像素法

这种方法简单易懂,但相当耗时,完全不可取.

publicstatic 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

;

}//#

三.内存法

这是比较常用的方法

publicstatic 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;

}//#

四指针法

C/C++的习惯,不是C#的特点

publicstatic Bitmap RGB2Gray(Bitmap srcBitmap)

{

int wide

= srcBitmap.Width;

int height

= srcBitmap.Height ;

Rectangle rect

= new Rectangle(0, 0, wide, height);

BitmapData srcBmData

= srcBitmap.LockBits(rect,

ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

Bitmap dstBitmap

= CreateGrayscaleImage(wide, height);

BitmapData dstBmData

= dstBitmap.LockBits(rect,

ImageLockMode.ReadWrite, PixelFormat.Format8bppIndexed);

System.IntPtr srcScan =

srcBmData.Scan0;

System.IntPtr dstScan =

dstBmData.Scan0;

Unsafe //启动不安全代码

{

byte*

srcP = (byte*)(void*) srcScan;

byte*

dstP = (byte*)(void*) dstScan;

int srcOffset

= srcBmData.Stride - wide * 3;

int dstOffset

= dstBmData.Stride - wide ;

byte red,

green, blue;

for (int y

= 0; y < height; y++)

{

for (int x

= 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 );

return dstBitmap;

}//#

五.矩阵法

并不是什么新方法,只是将图像数据分做R,G,B三个矩阵(二维数组)存储,类似MATLAB的习惯.

publicstatic bool GetRGB(Bitmap Source, out int[,]

R, out int[,] G, out int[,] B)

{

try

{

int iWidth

= Source.Width;

int iHeight

= Source.Height;

Rectangle rect

= new Rectangle(0, 0, iWidth, iHeight);

System.Drawing.Imaging.BitmapData bmpData =

Source.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite,

Source.PixelFormat);

IntPtr iPtr

= bmpData.Scan0;

int iBytes

= iWidth * iHeight * 3;

byte[]

PixelValues = new byte[iBytes];

System.Runtime.InteropServices.Marshal.Copy(iPtr, PixelValues, 0,

iBytes);

Source.UnlockBits(bmpData);

//注意这个地方图像的两维方向与数组两维的方向是转置的关系

R = new int[iHeight, iWidth];

G = new int[iHeight, iWidth];

B = new int[iHeight, iWidth];

int iPoint

= 0;

for (int i

= 0; i < iHeight; i++)

{

for (int j

= 0; j < iWidth; 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++]);

}

}

return true;

}

catch (Exception)

{

R = null;

G = null;

B = null;

return false;

}

}//#

public static Bitmap FromRGB(int[,]

R, int[,]

G, int[,]

B)

{

int iWidth

= G.GetLength(1);

int iHeight

= G.GetLength(0);

Bitmap Result

= new Bitmap(iWidth, iHeight,

System.Drawing.Imaging.PixelFormat.Format24bppRgb);

Rectangle rect

= new Rectangle(0, 0, iWidth, iHeight);

System.Drawing.Imaging.BitmapData bmpData =

Result.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite,

System.Drawing.Imaging.PixelFormat.Format24bppRgb);

IntPtr iPtr

= bmpData.Scan0;

int iStride

= bmpData.Stride;

int iBytes

= iWidth * iHeight * 3;

byte[]

PixelValues = new byte[iBytes];

int iPoint

= 0;

for (int i

= 0; i < iHeight; i++)

for (int j

= 0; j < iWidth; j++)

{

int iG

= G[i, j];

int iB

= B[i, j];

int iR

= 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);

return Result;

}//#

public static bool GetGray(Bitmap srcBitmap, out byte [,]

gray)

{

Bitmap tempBitmap;

if (srcBitmap.PixelFormat

!= PixelFormat.Format8bppIndexed)

tempBitmap = ImageProcess.Image.Gray(srcBitmap);

else

tempBitmap = srcBitmap;

int wide

= tempBitmap.Width;

int height

= tempBitmap.Height;

gray = new byte [height,

wide];

BitmapData gbmData

= tempBitmap.LockBits(new Rectangle(0, 0, wide, height),

ImageLockMode.ReadWrite, PixelFormat.Format8bppIndexed);

System.IntPtr ScanG =

gbmData.Scan0;

int gOffset

= gbmData.Stride - wide;

unsafe

{

byte*

g = (byte*)(void*)ScanG;

//

for each pixel

for (int y

= 0; y < height; y++)

{

//

for each pixel

for (int x

= 0; x < wide; x++, g++)

{

gray[y ,x ] =*g;

}

g += gOffset;

}

}

tempBitmap.UnlockBits(gbmData);

return true ;

}//#

public static Bitmap FromGray(byte [,]

Gray)

{

int iWidth

= Gray.GetLength(1);

int iHeight

= Gray.GetLength(0);

Bitmap dstBitmap

= ImageProcess.Image.CreateGrayscaleImage(iWidth,

iHeight);

BitmapData gbmData

= dstBitmap.LockBits(new Rectangle(0, 0, iWidth, iHeight),

ImageLockMode.ReadWrite, PixelFormat.Format8bppIndexed);

System.IntPtr ScanG =

gbmData.Scan0;

int gOffset

= gbmData.Stride - iWidth;

unsafe

{

byte*

g = (byte*)(void*)ScanG;

//注意这个地方图像的两维方向与数组两维的方向是转置的关系

for (int i

= 0; i < iHeight; i++)

{

for (int j

= 0; j < iWidth; j++)

{

*g=(byte )Gray[i, j]

;

g++;

}

g += gOffset;

}

}

dstBitmap.UnlockBits(gbmData);

return dstBitmap;

} //#

/// 

///Create

and initialize grayscale image

/// 

public static Bitmap CreateGrayscaleImage( int width, int height

)

{

//

create new image

Bitmap bmp

= new Bitmap( width,

height, PixelFormat.Format8bppIndexed );

//

set palette to grayscale

SetGrayscalePalette( bmp );

//

return new image

return bmp;

}//#

/// 

///Set

pallete of the image to grayscale

/// 

public static void SetGrayscalePalette( Bitmap srcImg

)

{

//

check pixel format

if (

srcImg.PixelFormat != PixelFormat.Format8bppIndexed )

throw new ArgumentException(

);

//

get palette

ColorPalette cp

= srcImg.Palette;

//

init palette

for ( int i

= 0; i < 256; i++ )

{

cp.Entries[i] = Color.FromArgb( i, i, i );

}

//

set palette back

srcImg.Palette = cp;

}//#

/*********************************END********************************************

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值