浅谈Visual C#进行图像处理(读取、保存以及对像素的访问)

这里之所以说“浅谈”是因为我这里只是简单的介绍如何使用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属性为每行像素所占的字节。

声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:notice#nhooo.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。