• [转]C#图像处理 (各种旋转、改变大小、柔化、锐化、雾化、底片、浮雕、黑白、滤镜效果)


    C#图像处理
    (各种旋转、改变大小、柔化、锐化、雾化、底片、浮雕、黑白、滤镜效果)
     
    一、各种旋转、改变大小
    注意:先要添加画图相关的using引用。
    //向右旋转图像90°代码如下:
    private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
    {
    Graphics g = e.Graphics;
    Bitmap bmp = new Bitmap("rama.jpg");//加载图像
    g.FillRectangle(Brushes.White, this.ClientRectangle);//填充窗体背景为白色
    Point[] destinationPoints = {
    new Point(100, 0), // destination for upper-left point of original
    new Point(100, 100),// destination for upper-right point of original
    new Point(0, 0)}; // destination for lower-left point of original
    g.DrawImage(bmp, destinationPoints);
    }
    
    //旋转图像180°代码如下:
    private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
    {
    Graphics g = e.Graphics;
    Bitmap bmp = new Bitmap("rama.jpg");
    g.FillRectangle(Brushes.White, this.ClientRectangle);
    Point[] destinationPoints = {
    new Point(0, 100), // destination for upper-left point of original
    new Point(100, 100),// destination for upper-right point of original
    new Point(0, 0)}; // destination for lower-left point of original
    g.DrawImage(bmp, destinationPoints);
    }
    
    //图像切变代码:
    private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
    {
    Graphics g = e.Graphics;
    Bitmap bmp = new Bitmap("rama.jpg");
    g.FillRectangle(Brushes.White, this.ClientRectangle);
    Point[] destinationPoints = {
    new Point(0, 0), // destination for upper-left point of original
    new Point(100, 0), // destination for upper-right point of original
    new Point(50, 100)};// destination for lower-left point of original
    g.DrawImage(bmp, destinationPoints);
    }
    
    //图像截取:
    private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
    {
    Graphics g = e.Graphics;
    Bitmap bmp = new Bitmap("rama.jpg");
    g.FillRectangle(Brushes.White, this.ClientRectangle);
    Rectangle sr = new Rectangle(80, 60, 400, 400);//要截取的矩形区域
    Rectangle dr = new Rectangle(0, 0, 200, 200);//要显示到Form的矩形区域
    g.DrawImage(bmp, dr, sr, GraphicsUnit.Pixel);
    }
    
    //改变图像大小:
    private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
    {
    Graphics g = e.Graphics;
    Bitmap bmp = new Bitmap("rama.jpg");
    g.FillRectangle(Brushes.White, this.ClientRectangle);
    int width = bmp.Width;
    int height = bmp.Height;
    // 改变图像大小使用低质量的模式
    g.InterpolationMode = InterpolationMode.NearestNeighbor;
    g.DrawImage(bmp, new Rectangle(10, 10, 120, 120), // source rectangle
    new Rectangle(0, 0, width, height), // destination rectangle
    GraphicsUnit.Pixel);
    // 使用高质量模式
    //g.CompositingQuality = CompositingQuality.HighSpeed;
    g.InterpolationMode = InterpolationMode.HighQualityBicubic;
    g.DrawImage(
    bmp,
    new Rectangle(130, 10, 120, 120), 
    new Rectangle(0, 0, width, height),
    GraphicsUnit.Pixel);
    }
    
    //设置图像的分辩率:
    private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
    {
    Graphics g = e.Graphics;
    Bitmap bmp = new Bitmap("rama.jpg");
    g.FillRectangle(Brushes.White, this.ClientRectangle);
    bmp.SetResolution(300f, 300f);
    g.DrawImage(bmp, 0, 0);
    bmp.SetResolution(1200f, 1200f);
    g.DrawImage(bmp, 180, 0);
    }
    
    //用GDI+画图
    private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
    {
    Graphics gForm = e.Graphics;
    gForm.FillRectangle(Brushes.White, this.ClientRectangle);
    for (int i = 1; i <= 7; ++i)
    {
    //在窗体上面画出橙色的矩形
    Rectangle r = new Rectangle(i*40-15, 0, 15,
    this.ClientRectangle.Height);
    gForm.FillRectangle(Brushes.Orange, r);
    }
    //在内存中创建一个Bitmap并设置CompositingMode
    Bitmap bmp = new Bitmap(260, 260,
    System.Drawing.Imaging.PixelFormat.Format32bppArgb);
    Graphics gBmp = Graphics.FromImage(bmp);
    gBmp.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceCopy;
    // 创建一个带有Alpha的红色区域
    // 并将其画在内存的位图里面
    Color red = Color.FromArgb(0x60, 0xff, 0, 0);
    Brush redBrush = new SolidBrush(red);
    gBmp.FillEllipse(redBrush, 70, 70, 160, 160);
    // 创建一个带有Alpha的绿色区域
    Color green = Color.FromArgb(0x40, 0, 0xff, 0);
    Brush greenBrush = new SolidBrush(green);
    gBmp.FillRectangle(greenBrush, 10, 10, 140, 140);
    //在窗体上面画出位图 now draw the bitmap on our window
    gForm.DrawImage(bmp, 20, 20, bmp.Width, bmp.Height);
    // 清理资源
    bmp.Dispose();
    gBmp.Dispose();
    redBrush.Dispose();
    greenBrush.Dispose();
    }
    
    //在窗体上面绘图并显示图像
    private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
    {
    Graphics g = e.Graphics;
    Pen blackPen = new Pen(Color.Black, 1);
    if (ClientRectangle.Height / 10 > 0)
    {
    for (int y = 0; y < ClientRectangle.Height; y += ClientRectangle.Height / 10)
    {
    g.DrawLine(blackPen, new Point(0, 0), new Point(ClientRectangle.Width, y));
    }
    }
    blackPen.Dispose();
    }
     
    C# 使用Bitmap类进行图片裁剪
     
     在Mapwin(手机游戏地图编辑器)生成的地图txt文件中添加自己需要处理的数据后转换成可在手机(Ophone)开发环境中使用的字节流地图文件的小工具,其中就涉及到图片的裁剪和生成了。有以下几种方式。
     
    方法一:拷贝像素。
     
    当然这种方法是最笨的,效率也就低了些。
    在Bitmap类中我们可以看到这样两个方法:GetPixel(int x, int y)和SetPixel(int x, int y, Color color)方法。从字面的含以上就知道前者是获取图像某点像素值,是用Color对象返回的;后者是将已知像素描画到制定的位置。
    下面就来做个实例检验下:
    1.首先创建一个Windows Form窗体程序,往该窗体上拖放7个PictureBox控件,第一个用于放置并显示原始的大图片,其后6个用于放置并显示裁剪后新生成的6个小图;
    2.放置原始大图的PictureBox控件name属性命名为pictureBoxBmpRes,其后pictureBox1到pictureBox6依次命名,并放置在合适的位置;
    3.双击Form窗体,然后在Form1_Load事件中加入下面的代码即可。
    //导入图像资源
                Bitmap bmpRes = null;
                String strPath = Application.ExecutablePath;
                try{
                    int nEndIndex = strPath.LastIndexOf('//');
                    strPath = strPath.Substring(0,nEndIndex) + "//Bmp//BmpResMM.bmp";
                    bmpRes = new Bitmap(strPath);
     
                    //窗体上显示加载图片
                    pictureBoxBmpRes.Width = bmpRes.Width;
                    pictureBoxBmpRes.Height = bmpRes.Height;
                    pictureBoxBmpRes.Image = bmpRes;
                }
                catch(Exception ex)
                {
                   System.Windows.Forms.MessageBox.Show("图片资源加载失败!/r/n" + ex.ToString());
                }
     
                //裁剪图片(裁成2行3列的6张图片)
                int nYClipNum = 2, nXClipNum = 3;
                Bitmap[] bmpaClipBmpArr = new Bitmap[nYClipNum * nXClipNum];            
                for (int nYClipNumIndex = 0; nYClipNumIndex < nYClipNum; nYClipNumIndex++)
                {
                    for (int nXClipNumIndex = 0; nXClipNumIndex < nXClipNum; nXClipNumIndex++)
                    {
                        int nClipWidth = bmpRes.Width / nXClipNum;
                        int nClipHight = bmpRes.Height / nYClipNum;
                        int nBmpIndex = nXClipNumIndex + nYClipNumIndex * nYClipNum + (nYClipNumIndex > 0?1:0);
                        bmpaClipBmpArr[nBmpIndex] = new Bitmap(nClipWidth, nClipHight);
     
                        for(int nY = 0; nY < nClipHight; nY++)
                        {
                            for(int nX = 0; nX < nClipWidth; nX++)
                            {
                                int nClipX = nX + nClipWidth * nXClipNumIndex;
                                int nClipY = nY + nClipHight * nYClipNumIndex;
                                Color cClipPixel = bmpRes.GetPixel(nClipX, nClipY);
                                bmpaClipBmpArr[nBmpIndex].SetPixel(nX, nY, cClipPixel);
                            }
                        }                   
                    }
                }
                PictureBox[] picbShow = new PictureBox[nYClipNum * nXClipNum];
                picbShow[0] = pictureBox1;
                picbShow[1] = pictureBox2;
                picbShow[2] = pictureBox3;
                picbShow[3] = pictureBox4;
                picbShow[4] = pictureBox5;
                picbShow[5] = pictureBox6;
                for (int nLoop = 0; nLoop < nYClipNum * nXClipNum; nLoop++)
                {
                    picbShow[nLoop].Width = bmpRes.Width / nXClipNum;
                    picbShow[nLoop].Height = bmpRes.Height / nYClipNum;
                    picbShow[nLoop].Image = bmpaClipBmpArr[nLoop];               
                }
     现在看看那些地方需要注意的了。其中
    int nBmpIndex =
    nXClipNumIndex + nYClipNumIndex * nYClipNum + (nYClipNumIndex > 0?1:0);
     这句定义了存储裁剪图片对象在数组中的索引,需要注意的就是后面的(nYClipNumIndex > 0?1:0)——因为只有当裁剪的对象处于第一行以外的行时需要将索引加1;
    另外,因为这种方法的效率不高,程序运行起来还是顿了下。如果有兴趣的话,可以将以上的代码放到一个按钮Click事件函数中,当单击该按钮时就可以感觉到了。
     
     方法二:运用Clone函数局部复制。
     
    同样在Bitmap中可以找到Clone()方法,该方法有三个重载方法。Clone(),Clone(Rectangle, PixelFormat)和Clone(RectangleF, PixelFormat)。第一个方法将创建并返回一个精确的实例对象,后两个就是我们这里需要用的局部裁剪了(其实后两个方法本人觉得用法上差不多)。
    将上面的程序稍稍改进下——将裁剪的处理放到一个按钮事件函数中,然后再托一个按钮好窗体上,最后将下面的代码复制到该按钮的事件函数中。
    for (int nYClipNumIndex = 0; nYClipNumIndex < nYClipNum; nYClipNumIndex++)
    {
           for (int nXClipNumIndex = 0; nXClipNumIndex < nXClipNum; nXClipNumIndex++)
             {
                  int nClipWidth = bmpRes.Width / nXClipNum;
                          int nClipHight = bmpRes.Height / nYClipNum;
                    int nBmpIndex =
    nXClipNumIndex + nYClipNumIndex * nYClipNum + (nYClipNumIndex > 0 ? 1 : 0);
                 
            Rectangle rClipRect = new Rectangle(nClipWidth * nXClipNumIndex,
                                                                nClipHight * nYClipNumIndex,
                                                                nClipWidth,
                                                                nClipHight);
                 
                    bmpaClipBmpArr[nBmpIndex] = bmpRes.Clone(rClipRect, bmpRes.PixelFormat);
                }
    }
     
     运行程序,单击按钮检验下,发现速度明显快可很多。
    其实这种方法较第一中方法不同的地方仅只是变换了for循环中的拷贝部分的处理,
    Rectangle rClipRect = new Rectangle(nClipWidth * nXClipNumIndex,
                                                                nClipHight * nYClipNumIndex,
                                                                nClipWidth,
                                                                nClipHight);
     
    bmpaClipBmpArr[nBmpIndex] = bmpRes.Clone(rClipRect, bmpRes.PixelFormat);
     
     
     
     
    一. 底片效果
    原理: GetPixel方法获得每一点像素的值, 然后再使用SetPixel方法将取反后的颜色值设置到对应的点.
    效果图:
    
    代码实现:
              private void button1_Click(object sender, EventArgs e)
            {
                //以底片效果显示图像
                try
                {
                    int Height = this.pictureBox1.Image.Height;
                    int Width = this.pictureBox1.Image.Width;
                    Bitmap newbitmap = new Bitmap(Width, Height);
                    Bitmap oldbitmap = (Bitmap)this.pictureBox1.Image;
                    Color pixel;
                    for (int x = 1; x < Width; x++)
                    {
                        for (int y = 1; y < Height; y++)
                        {
                            int r, g, b;
                            pixel = oldbitmap.GetPixel(x, y);
                            r = 255 - pixel.R;
                            g = 255 - pixel.G;
                            b = 255 - pixel.B;
                            newbitmap.SetPixel(x, y, Color.FromArgb(r, g, b));
                        }
                    }
                    this.pictureBox1.Image = newbitmap;
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message, "信息提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
            }
    二. 浮雕效果
    原理: 对图像像素点的像素值分别与相邻像素点的像素值相减后加上128, 然后将其作为新的像素点的值.
    效果图:
     
     
    
    
     
     
     
    代码实现:
    
           private void button1_Click(object sender, EventArgs e)
            {
                //以浮雕效果显示图像
                try
                {
                    int Height = this.pictureBox1.Image.Height;
                    int Width = this.pictureBox1.Image.Width;
                    Bitmap newBitmap = new Bitmap(Width, Height);
                    Bitmap oldBitmap = (Bitmap)this.pictureBox1.Image;
                    Color pixel1, pixel2;
                    for (int x = 0; x < Width - 1; x++)
                    {
                        for (int y = 0; y < Height - 1; y++)
                        {
                            int r = 0, g = 0, b = 0;
                            pixel1 = oldBitmap.GetPixel(x, y);
                            pixel2 = oldBitmap.GetPixel(x + 1, y + 1);
                            r = Math.Abs(pixel1.R - pixel2.R + 128);
                            g = Math.Abs(pixel1.G - pixel2.G + 128);
                            b = Math.Abs(pixel1.B - pixel2.B + 128);
                            if (r > 255)
                                r = 255;
                            if (r < 0)
                                r = 0;
                            if (g > 255)
                                g = 255;
                            if (g < 0)
                                g = 0;
                            if (b > 255)
                                b = 255;
                            if (b < 0)
                                b = 0;
                            newBitmap.SetPixel(x, y, Color.FromArgb(r, g, b));
                        }
                    }
                    this.pictureBox1.Image = newBitmap;
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message, "信息提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
            }
    三. 黑白效果
    原理: 彩色图像处理成黑白效果通常有3种算法;
    (1).最大值法: 使每个像素点的 R, G, B 值等于原像素点的 RGB (颜色值) 中最大的一个;
    (2).平均值法: 使用每个像素点的 R,G,B值等于原像素点的RGB值的平均值;
    (3).加权平均值法: 对每个像素点的 R, G, B值进行加权
          ---自认为第三种方法做出来的黑白效果图像最 "真实".
    效果图:
     
    
    
     
     
     
    代码实现:
    
            private void button1_Click(object sender, EventArgs e)
            {
                //以黑白效果显示图像
                try
                {
                    int Height = this.pictureBox1.Image.Height;
                    int Width = this.pictureBox1.Image.Width;
                    Bitmap newBitmap = new Bitmap(Width, Height);
                    Bitmap oldBitmap = (Bitmap)this.pictureBox1.Image;
                    Color pixel;
                    for (int x = 0; x < Width; x++)
                        for (int y = 0; y < Height; y++)
                        {
                            pixel = oldBitmap.GetPixel(x, y);
                            int r, g, b, Result = 0;
                            r = pixel.R;
                            g = pixel.G;
                            b = pixel.B;
                            //实例程序以加权平均值法产生黑白图像
                            int iType =2;
                            switch (iType)
                            {
                                case 0://平均值法
                                    Result = ((r + g + b) / 3);
                                    break;
                                case 1://最大值法
                                    Result = r > g ? r : g;
                                    Result = Result > b ? Result : b;
                                    break;
                                case 2://加权平均值法
                                    Result = ((int)(0.7 * r) + (int)(0.2 * g) + (int)(0.1 * b));
                                    break;
                            }
                            newBitmap.SetPixel(x, y, Color.FromArgb(Result, Result, Result));
                        }
                    this.pictureBox1.Image = newBitmap;
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message, "信息提示");
                }
            }
     
    四. 柔化效果
    原理: 当前像素点与周围像素点的颜色差距较大时取其平均值.
    效果图:
     
     
    
    
     
     
    代码实现:
    
            private void button1_Click(object sender, EventArgs e)
            {
                //以柔化效果显示图像
                try
                {
                    int Height = this.pictureBox1.Image.Height;
                    int Width = this.pictureBox1.Image.Width;
                    Bitmap bitmap = new Bitmap(Width, Height);
                    Bitmap MyBitmap = (Bitmap)this.pictureBox1.Image;
                    Color pixel;
                    //高斯模板
                    int[] Gauss ={ 1, 2, 1, 2, 4, 2, 1, 2, 1 };
                    for (int x = 1; x < Width - 1; x++)
                        for (int y = 1; y < Height - 1; y++)
                        {
                            int r = 0, g = 0, b = 0;
                            int Index = 0;
                            for (int col = -1; col <= 1; col++)
                                for (int row = -1; row <= 1; row++)
                                {
                                    pixel = MyBitmap.GetPixel(x + row, y + col);
                                    r += pixel.R * Gauss[Index];
                                    g += pixel.G * Gauss[Index];
                                    b += pixel.B * Gauss[Index];
                                    Index++;
                                }
                            r /= 16;
                            g /= 16;
                            b /= 16;
                            //处理颜色值溢出
                            r = r > 255 ? 255 : r;
                            r = r < 0 ? 0 : r;
                            g = g > 255 ? 255 : g;
                            g = g < 0 ? 0 : g;
                            b = b > 255 ? 255 : b;
                            b = b < 0 ? 0 : b;
                            bitmap.SetPixel(x - 1, y - 1, Color.FromArgb(r, g, b));
                        }
                    this.pictureBox1.Image = bitmap;
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message, "信息提示");
                }
            }
    五.锐化效果
    原理:突出显示颜色值大(即形成形体边缘)的像素点.
    效果图:
     
    
    
     
     
     
    实现代码:
    
           private void button1_Click(object sender, EventArgs e)
            {
                //以锐化效果显示图像
                try
                {
                    int Height = this.pictureBox1.Image.Height;
                    int Width = this.pictureBox1.Image.Width;
                    Bitmap newBitmap = new Bitmap(Width, Height);
                    Bitmap oldBitmap = (Bitmap)this.pictureBox1.Image;
                    Color pixel;
                    //拉普拉斯模板
                    int[] Laplacian ={ -1, -1, -1, -1, 9, -1, -1, -1, -1 };
                    for (int x = 1; x < Width - 1; x++)
                        for (int y = 1; y < Height - 1; y++)
                        {
                            int r = 0, g = 0, b = 0;
                            int Index = 0;
                            for (int col = -1; col <= 1; col++)
                                for (int row = -1; row <= 1; row++)
                                {
                                    pixel = oldBitmap.GetPixel(x + row, y + col); r += pixel.R * Laplacian[Index];
                                    g += pixel.G * Laplacian[Index];
                                    b += pixel.B * Laplacian[Index];
                                    Index++;
                                }
                            //处理颜色值溢出
                            r = r > 255 ? 255 : r;
                            r = r < 0 ? 0 : r;
                            g = g > 255 ? 255 : g;
                            g = g < 0 ? 0 : g;
                            b = b > 255 ? 255 : b;
                            b = b < 0 ? 0 : b;
                            newBitmap.SetPixel(x - 1, y - 1, Color.FromArgb(r, g, b));
                        }
                    this.pictureBox1.Image = newBitmap;
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message, "信息提示");
                }
            }
    六. 雾化效果
    原理: 在图像中引入一定的随机值, 打乱图像中的像素值
    效果图:
     
    
    
     
    
    实现代码:
    
           private void button1_Click(object sender, EventArgs e)
            {
                //以雾化效果显示图像
                try
                {
                    int Height = this.pictureBox1.Image.Height;
                    int Width = this.pictureBox1.Image.Width;
                    Bitmap newBitmap = new Bitmap(Width, Height);
                    Bitmap oldBitmap = (Bitmap)this.pictureBox1.Image;
                    Color pixel;
                    for (int x = 1; x < Width - 1; x++)
                        for (int y = 1; y < Height - 1; y++)
                        {
                            System.Random MyRandom = new Random();
                            int k = MyRandom.Next(123456);
                            //像素块大小
                            int dx = x + k % 19;
                            int dy = y + k % 19;
                            if (dx >= Width)
                                dx = Width - 1;
                            if (dy >= Height)
                                dy = Height - 1;
                            pixel = oldBitmap.GetPixel(dx, dy);
                            newBitmap.SetPixel(x, y, pixel);
                        }
                    this.pictureBox1.Image = newBitmap;
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message, "信息提示");
                }
            }
     
     
     
     
     
     
     
     
     
     
     
     
    浅谈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属性为每行像素所占的字节。
     
     
     
     
    
    
     
     
     
     
     
     
     
    C# colorMatrix 对图片的处理 : 亮度调整 抓屏 翻转 随鼠标画矩形
     
    1.图片亮度处理
     
            private void btn_Grap_Click(object sender, EventArgs e)
            {
                //亮度百分比
                int percent = 50;
                Single v = 0.006F * percent;    
                Single[][] matrix = {         
                    new Single[] { 1, 0, 0, 0, 0 },         
                    new Single[] { 0, 1, 0, 0, 0 },          
                    new Single[] { 0, 0, 1, 0, 0 },         
                    new Single[] { 0, 0, 0, 1, 0 },         
                    new Single[] { v, v, v, 0, 1 }     
                };    
                System.Drawing.Imaging.ColorMatrix cm = new System.Drawing.Imaging.ColorMatrix(matrix);
                System.Drawing.Imaging.ImageAttributes attr = new System.Drawing.Imaging.ImageAttributes();    
                attr.SetColorMatrix(cm);    
                //Image tmp 
                Image tmp = Image.FromFile("1.png");
     
                this.pictureBox_Src.Image = Image.FromFile("1.png");
     
                Graphics g = Graphics.FromImage(tmp);  
                try  
                {
                    Rectangle destRect = new Rectangle(0, 0, tmp.Width, tmp.Height);        
                    g.DrawImage(tmp, destRect, 0, 0, tmp.Width, tmp.Height, GraphicsUnit.Pixel, attr);    
                }    
                finally    
                {        
                    g.Dispose();    
                }
     
                this.pictureBox_Dest.Image = (Image)tmp.Clone();
            }
     
     
    2.抓屏将生成的图片显示在pictureBox
     
            private void btn_Screen_Click(object sender, EventArgs e)
            {
                Image myImage = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
                Graphics g = Graphics.FromImage(myImage);
                g.CopyFromScreen(new Point(0, 0), new Point(0, 0), new Size(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height));
                //IntPtr dc1 = g.GetHdc();      //此处这两句多余,具体看最后GetHdc()定义
                //g.ReleaseHdc(dc1);           
                g.Dispose();
                this.pictureBox_Src.SizeMode = PictureBoxSizeMode.StretchImage;
                this.pictureBox_Src.Image = myImage;
                myImage.Save("Screen", ImageFormat.Png);
         }
     
    3.翻转
     
            private void btn_RotateFlip_Click(object sender, EventArgs e)
            {
                this.pictureBox_Src.Image = Image.FromFile("1.png");
     
                Image tmp = Image.FromFile("1.png");
     
                tmp.RotateFlip(RotateFlipType.Rotate90FlipNone);
                this.pictureBox_Dest.Image = tmp;
            }
    4.跟随鼠标在 pictureBox的图片上画矩形
            private int intStartX = 0;
            private int intStartY = 0;
            private bool isMouseDraw = false;
     
            private void pictureBox_Src_MouseDown(object sender, MouseEventArgs e)
            {
                isMouseDraw = true;
     
                intStartX = e.X;
                intStartY = e.Y;
            }
     
            private void pictureBox_Src_MouseMove(object sender, MouseEventArgs e)
            {
                if (isMouseDraw)
                {
                    try
                    {
                        //Image tmp = Image.FromFile("1.png");
                        Graphics g = this.pictureBox_Src.CreateGraphics();
                        //清空上次画下的痕迹
                        g.Clear(this.pictureBox_Src.BackColor);
                        Brush brush = new SolidBrush(Color.Red);
                        Pen pen = new Pen(brush, 1);
                        pen.DashStyle = DashStyle.Solid;
                        g.DrawRectangle(pen, new Rectangle(intStartX > e.X ? e.X : intStartX, intStartY > e.Y ? e.Y : intStartY, Math.Abs(e.X - intStartX), Math.Abs(e.Y - intStartY)));
                        g.Dispose();
                        //this.pictureBox_Src.Image = tmp;
                    }
                    catch (Exception ex)
                    {
                        ex.ToString();
                    }
                }
            }
     
            private void pictureBox_Src_MouseUp(object sender, MouseEventArgs e)
            {
                isMouseDraw = false;
     
                intStartX = 0;
                intStartY = 0;
            }
    5.取灰度
     
            private void btn_GetGray_Click(object sender, EventArgs e)
            {
                this.pictureBox_Src.Image = Image.FromFile("1.png");
                Bitmap currentBitmap = new Bitmap(this.pictureBox_Src.Image);
                Graphics g = Graphics.FromImage(currentBitmap);
                ImageAttributes ia = new ImageAttributes();
                float[][] colorMatrix =   {    
                    new   float[]   {0.299f,   0.299f,   0.299f,   0,   0},
                    new   float[]   {0.587f,   0.587f,   0.587f,   0,   0},
                    new   float[]   {0.114f,   0.114f,   0.114f,   0,   0},
                    new   float[]   {0,   0,   0,   1,   0},
                    new   float[]   {0,   0,   0,   0,   1}
                };
                ColorMatrix cm = new ColorMatrix(colorMatrix);
                ia.SetColorMatrix(cm, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
                g.DrawImage(currentBitmap, new Rectangle(0, 0, currentBitmap.Width, currentBitmap.Height), 0, 0, currentBitmap.Width, currentBitmap.Height, GraphicsUnit.Pixel, ia);
                this.pictureBox_Dest.Image = (Image)(currentBitmap.Clone());
                g.Dispose();
            }
     
     
    
     
    
     
    Graphics.GetHdc 方法
    .NET Framework 4
    获取与此 Graphics 关联的设备上下文的句柄。
    命名空间:  System.Drawing
    程序集:  System.Drawing(在 System.Drawing.dll 中)
    语法
    [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags =
    SecurityPermissionFlag.UnmanagedCode)]
    public IntPtr GetHdc()
    返回值
    类型:System.IntPtr
    与此 Graphics 关联的设备上下文的句柄。
    实现
    IDeviceContext.GetHdc()
    备注
    设备上下文是一个基于 GDI 的 Windows 结构,它定义一组图形对象及其关联的特性,以及影响输出的图形模式。 此方法返回该设备上下文(字体除外)。由于未选择字体,使用 GetHdc 方法返回的句柄对 FromHdc 方法进行调用将会失败。
    GetHdc 方法调用和 ReleaseHdc 方法调用必须成对出现。 在 GetHdc 和 ReleaseHdc 方法对的范围内,通常仅调用 GDI 函数。 在该范围内对 Graphics(它产生 hdc 参数)的 GDI+ 方法的调用因 ObjectBusy 错误而失败。 此外,GDI+ 忽略后续操作中对 hdc 参数的 Graphics 所做的所有状态更改。
    示例
    下面的代码示例设计为与 Windows 窗体一起使用,它需要 PaintEventArgse,即 Paint 事件处理程序的一个参数。 该示例演示如何调用 Windows GDI 函数以执行与 GDI+ Graphics 方法相同的任务。 代码执行下列操作:
    为 Windows DLL 文件 gdi32.dll 定义互操作性 DllImportAttribute 特性。 此 DLL 包含所需的 GDI 函数。
    将该 DLL 中的 Rectangle 函数定义为外部函数。
    创建一支红色钢笔。
    利用该钢笔,使用 GDI+ DrawRectangle 方法将矩形绘制到屏幕。
    定义内部指针类型变量 hdc 并将它的值设置为窗体的设备上下文句柄。
    使用 GDI Rectangle 函数将矩形绘制到屏幕。
    释放由 hdc 参数表示的设备上下文。
     
    public class GDI
    {
        [System.Runtime.InteropServices.DllImport("gdi32.dll")]
        internal static extern bool Rectangle(
           IntPtr hdc,
           int ulCornerX, int ulCornerY,
           int lrCornerX, int lrCornerY);
    }
     
    [System.Security.Permissions.SecurityPermission(
    System.Security.Permissions.SecurityAction.LinkDemand, Flags =
    System.Security.Permissions.SecurityPermissionFlag.UnmanagedCode)]           
    private void GetHdcForGDI1(PaintEventArgs e)
    {
        // Create pen.
        Pen redPen = new Pen(Color.Red, 1);
     
        // Draw rectangle with GDI+.
        e.Graphics.DrawRectangle(redPen, 10, 10, 100, 50);
     
        // Get handle to device context.
        IntPtr hdc = e.Graphics.GetHdc();
     
        // Draw rectangle with GDI using default pen.
        GDI.Rectangle(hdc, 10, 70, 110, 120);
     
        // Release handle to device context.
        e.Graphics.ReleaseHdc(hdc);
    }
  • 相关阅读:
    冲刺第十三天
    冲刺第十二天
    冲刺第十一天
    Android Studio三种运行方法
    第十三周学习进度
    冲刺第一阶段意见评论
    第十二周学习进度
    冲刺第十天
    大二暑假周总结(五)
    大二暑假周总结(四)
  • 原文地址:https://www.cnblogs.com/qq1223558/p/3090832.html
Copyright © 2020-2023  润新知