zoukankan      html  css  js  c++  java
  • 【转】浅谈Visual C#进行图像处理

    作者:彭军 http://pengjun.org.cn

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

  • 相关阅读:
    if语法案例
    其他6-break,continue,exit,return区别
    其他5-6种产生随机数的方法
    其他4-shell脚本后台运行知识
    算法练习 第三周
    回顾MySQL基础
    jsp中使用jQuery获取窗口高度不正确的问题
    初学java 学生管理系统——v04版本 改用web
    web项目中跳转路径的使用
    tomcat部署项目的方式
  • 原文地址:https://www.cnblogs.com/ae6623/p/4416772.html
Copyright © 2011-2022 走看看