浅谈Visual C#进行图像处理(读取、保存以及对像素的访问)
浅谈Visual C#进行图像处理(读取、保存以及对像素的访问)
发布时间:2016-12-28 来源:查字典编辑
摘要:这里之所以说“浅谈”是因为我这里只是简单的介绍如何使用VisualC#进行图像的读入、保存以及对像素的访问。而不涉及太多的算法。一、读取图像...

这里之所以说“浅谈”是因为我这里只是简单的介绍如何使用Visual C#进行图像的读入、保存以及对像素的访问。而不涉及太多的算法。

一、读取图像

在Visual C#中我们可以使用一个Picture Box控件来显示图片,如下:

复制代码 代码如下:

private void btnOpenImage_Click(object sender, EventArgs e)

{

OpenFileDialog ofd = new OpenFileDialog();

ofd.Filter = "BMP Files(*.bmp)|*.bmp|JPG Files(*.jpg;*.jpeg)|*.jpg;*.jpeg|All Files(*.*)|*.*";

ofd.CheckFileExists = true;

ofd.CheckPathExists = true;

if (ofd.ShowDialog() == DialogResult.OK)

{

//pbxShowImage.ImageLocation = ofd.FileName;

bmp = new Bitmap(ofd.FileName);

if (bmp==null)

{

MessageBox.Show("加载图片失败!", "错误");

return;

}

pbxShowImage.Image = bmp;

ofd.Dispose();

}

}

其中bmp为类的一个对象:private Bitmap bmp=null;

在使用Bitmap类和BitmapData类之前,需要使用using System.Drawing.Imaging;

二、保存图像

复制代码 代码如下:

private void btnSaveImage_Click(object sender, EventArgs e)

{

if (bmp == null) return;

SaveFileDialog sfd = new SaveFileDialog();

sfd.Filter = "BMP Files(*.bmp)|*.bmp|JPG Files(*.jpg;*.jpeg)|*.jpg;*.jpeg|All Files(*.*)|*.*";

if (sfd.ShowDialog() == DialogResult.OK)

{

pbxShowImage.Image.Save(sfd.FileName);

MessageBox.Show("保存成功!","提示");

sfd.Dispose();

}

}

三、对像素的访问

我们可以来建立一个GrayBitmapData类来做相关的处理。整个类的程序如下:

复制代码 代码如下:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Drawing;

using System.Drawing.Imaging;

using System.Windows.Forms;

namespace ImageElf

{

class GrayBitmapData

{

public byte[,] Data;//保存像素矩阵

public int Width;//图像的宽度

public int Height;//图像的高度

public GrayBitmapData()

{

this.Width = 0;

this.Height = 0;

this.Data = null;

}

public GrayBitmapData(Bitmap bmp)

{

BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);

this.Width = bmpData.Width;

this.Height = bmpData.Height;

Data = new byte[Height, Width];

unsafe

{

byte* ptr = (byte*)bmpData.Scan0.ToPointer();

for (int i = 0; i < Height; i++)

{

for (int j = 0; j < Width; j++)

{

//将24位的RGB彩色图转换为灰度图

int temp = (int)(0.114 * (*ptr++)) + (int)(0.587 * (*ptr++))+(int)(0.299 * (*ptr++));

Data[i, j] = (byte)temp;

}

ptr += bmpData.Stride - Width * 3;//指针加上填充的空白空间

}

}

bmp.UnlockBits(bmpData);

}

public GrayBitmapData(string path)

: this(new Bitmap(path))

{

}

public Bitmap ToBitmap()

{

Bitmap bmp=new Bitmap(Width,Height,PixelFormat.Format24bppRgb);

BitmapData bmpData=bmp.LockBits(new Rectangle(0,0,Width,Height),ImageLockMode.WriteOnly,PixelFormat.Format24bppRgb);

unsafe

{

byte* ptr=(byte*)bmpData.Scan0.ToPointer();

for(int i=0;i<Height;i++)

{

for(int j=0;j<Width;j++)

{

*(ptr++)=Data[i,j];

*(ptr++)=Data[i,j];

*(ptr++)=Data[i,j];

}

ptr+=bmpData.Stride-Width*3;

}

}

bmp.UnlockBits(bmpData);

return bmp;

}

public void ShowImage(PictureBox pbx)

{

Bitmap b = this.ToBitmap();

pbx.Image = b;

//b.Dispose();

}

public void SaveImage(string path)

{

Bitmap b=ToBitmap();

b.Save(path);

//b.Dispose();

}

//均值滤波

public void AverageFilter(int windowSize)

{

if (windowSize % 2 == 0)

{

return;

}

for (int i = 0; i < Height; i++)

{

for (int j = 0; j < Width; j++)

{

int sum = 0;

for (int g = -(windowSize - 1) / 2; g <= (windowSize - 1) / 2; g++)

{

for (int k = -(windowSize - 1) / 2; k <= (windowSize - 1) / 2; k++)

{

int a = i + g, b = j + k;

if (a < 0) a = 0;

if (a > Height - 1) a = Height - 1;

if (b < 0) b = 0;

if (b > Width - 1) b = Width - 1;

sum += Data[a, b];

}

}

Data[i,j]=(byte)(sum/(windowSize*windowSize));

}

}

}

//中值滤波

public void MidFilter(int windowSize)

{

if (windowSize % 2 == 0)

{

return;

}

int[] temp = new int[windowSize * windowSize];

byte[,] newdata = new byte[Height, Width];

for (int i = 0; i < Height; i++)

{

for (int j = 0; j < Width; j++)

{

int n = 0;

for (int g = -(windowSize - 1) / 2; g <= (windowSize - 1) / 2; g++)

{

for (int k = -(windowSize - 1) / 2; k <= (windowSize - 1) / 2; k++)

{

int a = i + g, b = j + k;

if (a < 0) a = 0;

if (a > Height - 1) a = Height - 1;

if (b < 0) b = 0;

if (b > Width - 1) b = Width - 1;

temp[n++]= Data[a, b];

}

}

newdata[i, j] = GetMidValue(temp,windowSize*windowSize);

}

}

for (int i = 0; i < Height; i++)

{

for (int j = 0; j < Width; j++)

{

Data[i, j] = newdata[i, j];

}

}

}

//获得一个向量的中值

private byte GetMidValue(int[] t, int length)

{

int temp = 0;

for (int i = 0; i < length - 2; i++)

{

for (int j = i + 1; j < length - 1; j++)

{

if (t[i] > t[j])

{

temp = t[i];

t[i] = t[j];

t[j] = temp;

}

}

}

return (byte)t[(length - 1) / 2];

}

//一种新的滤波方法,是亮的更亮、暗的更暗

public void NewFilter(int windowSize)

{

if (windowSize % 2 == 0)

{

return;

}

for (int i = 0; i < Height; i++)

{

for (int j = 0; j < Width; j++)

{

int sum = 0;

for (int g = -(windowSize - 1) / 2; g <= (windowSize - 1) / 2; g++)

{

for (int k = -(windowSize - 1) / 2; k <= (windowSize - 1) / 2; k++)

{

int a = i + g, b = j + k;

if (a < 0) a = 0;

if (a > Height - 1) a = Height - 1;

if (b < 0) b = 0;

if (b > Width - 1) b = Width - 1;

sum += Data[a, b];

}

}

double avg = (sum+0.0) / (windowSize * windowSize);

if (avg / 255 < 0.5)

{

Data[i, j] = (byte)(2 * avg / 255 * Data[i, j]);

}

else

{

Data[i,j]=(byte)((1-2*(1-avg/255.0)*(1-Data[i,j]/255.0))*255);

}

}

}

}

//直方图均衡

public void HistEqual()

{

double[] num = new double[256] ;

for(int i=0;i<256;i++) num[i]=0;

for (int i = 0; i < Height; i++)

{

for (int j = 0; j < Width; j++)

{

num[Data[i, j]]++;

}

}

double[] newGray = new double[256];

double n = 0;

for (int i = 0; i < 256; i++)

{

n += num[i];

newGray[i] = n * 255 / (Height * Width);

}

for (int i = 0; i < Height; i++)

{

for (int j = 0; j < Width; j++)

{

Data[i,j]=(byte)newGray[Data[i,j]];

}

}

}

}

}

在GrayBitmapData类中,只要我们对一个二维数组Data进行一系列的操作就是对图片的操作处理。在窗口上,我们可以使用

一个按钮来做各种调用:

复制代码 代码如下:

//均值滤波

private void btnAvgFilter_Click(object sender, EventArgs e)

{

if (bmp == null) return;

GrayBitmapData gbmp = new GrayBitmapData(bmp);

gbmp.AverageFilter(3);

gbmp.ShowImage(pbxShowImage);

}

//转换为灰度图

private void btnToGray_Click(object sender, EventArgs e)

{

if (bmp == null) return;

GrayBitmapData gbmp = new GrayBitmapData(bmp);

gbmp.ShowImage(pbxShowImage);

}

四、总结

在Visual c#中对图像进行处理或访问,需要先建立一个Bitmap对象,然后通过其LockBits方法来获得一个BitmapData类的对象,然后通过获得其像素数据的首地址来对Bitmap对象的像素数据进行操作。当然,一种简单但是速度慢的方法是用Bitmap类的GetPixel和SetPixel方法。其中BitmapData类的Stride属性为每行像素所占的字节。

推荐文章
猜你喜欢
附近的人在看
推荐阅读
拓展阅读
相关阅读
网友关注
最新C#教程学习
热门C#教程学习
编程开发子分类