zoukankan      html  css  js  c++  java
  • 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);
    }
     
     
  • 相关阅读:
    Druid 使用 Kafka 将数据载入到 Kafka
    Druid 使用 Kafka 数据加载教程——下载和启动 Kafka
    Druid 集群方式部署 —— 启动服务
    Druid 集群方式部署 —— 端口调整
    Druid 集群方式部署 —— 配置调整
    Druid 集群方式部署 —— 配置 Zookeeper 连接
    Druid 集群方式部署 —— 元数据和深度存储
    Druid 集群方式部署 —— 从独立服务器部署上合并到集群的硬件配置
    Druid 集群方式部署 —— 选择硬件
    Druid 独立服务器方式部署文档
  • 原文地址:https://www.cnblogs.com/anbylau2130/p/3166383.html
Copyright © 2011-2022 走看看