• c#图像处理入门的一个好方法bitmap类和图像像素值获取方法


    c#图像处理入门的一个好方法-bitmap类和图像像素值获取方法

    一.Bitmap类

    Bitmap对象封装了GDI+中的一个位图,此位图由图形图像及其属性的像素数据组成.因此Bitmap是用于处理由像素数据定义的图像的对象.该类的主要方法和属性如下:

    1. 1.       GetPixel方法和 SetPixel方法:获取和设置一个图像的指定像素的颜色.
    2. 2.       PixelFormat属性:返回图像的像素格式.
    3. 3.       Palette属性:获取和设置图像所使用的颜色调色板.
    4. 4.       Height Width属性:返回图像的高度和宽度.
    5. 5.       LockBits 方法和UnlockBits方法:分别锁定和解锁系统内存中的位图像素.在基于像素点的图像处理方法中使用LockBits 和UnlockBits是一个很好的方式,这两种方法可以使我们指定像素的范围来控制位图的任意一部分,从而消除了通过循环对位图的像素逐个进行处理,每调用LockBits 之后都应该调用一次UnlockBits.

    二.BitmapData类

    BitmapData对象指定了位图的属性

    1. 1.       Height属性:被锁定位图的高度.
    2. 2.       Width属性:被锁定位图的高度.
    3. 3.       PixelFormat属性:数据的实际像素格式.
    4. 4.       Scan0属性:被锁定数组的首字节地址,如果整个图像被锁定,则是图像的第一个字节地址.
    5. 5.       Stride属性:步幅,也称为扫描宽度.

    如上图所示,数组的长度并不一定等于图像像素数组的长度,还有一部分未用区域,这涉及到位图的数据结构,系统要保证每行的字节数必须为4的倍数.

    三.Graphics类

    Graphics对象是GDI+的关键所在,许多对象都是由Graphics类表示的,该类定义了绘制和填充图形对象的方法和属性,一个应用程序只要需要进行绘制或着色,它就必须使用Graphics对象.

    四.Image类

      这个类提供了位图和元文件操作的函数.Image类被声明为abstract,也就是说Image类不能实例化对象,而只能做为一个基类.

    1.FromFile方法:它根据输入的文件名产生一个Image对象,它有两种函数形式:

    public static Image FromFile(string filename);

    public static Image FromFile(string filename, bool useEmbeddedColorManagement);

    2.FromHBitmap方法:它从一个windows句柄处创建一个bitmap对象, 它也包括两种函数形式:

    public static bitmap fromhbitmap(intptr hbitmap);

    public static bitmap fromhbitmap(intptr hbitmap, intptr hpalette);

    3. FromStream方法:从一个数据流中创建一个image对象,它包含三种函数形式 :

    public static image fromstream(stream stream);

    public static image fromstream(stream stream, bool useembeddedcolormanagement);

    fromstream(stream stream, bool useembeddedcolormanagement, bool validateimagedata);

    有了上面的了解,我们便可以开始利用C#做图像处理,下面介绍几种方法:

    一.   打开、保存、显示图像

            private Bitmap srcBitmap = null;

             private Bitmap showBitmap = null;

            //打开文件

            private void menuFileOpen_Click(object sender, EventArgs e)

            {

                OpenFileDialog openFileDialog = new OpenFileDialog();

                openFileDialog.Filter = @"Bitmap文件(*.bmp)|*.bmp|Jpeg文件(*.jpg)|*.jpg|所有合适文件(*.bmp,*.jpg)|*.bmp;*.jpg";

                openFileDialog.FilterIndex = 3;

                openFileDialog.RestoreDirectory = true;

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

                {

                    srcBitmap = (Bitmap)Bitmap.FromFile(openFileDialog.FileName, false);

                    showBitmap = srcBitmap;

                    this.AutoScroll = true;

                    this.AutoScrollMinSize = new Size((int)(showBitmap.Width), (int)(showBitmap.Height));

                    this.Invalidate();

                   

                   

                }

            }

            //保存图像文件

            private void menuFileSave_Click(object sender, EventArgs e)

            {

                if (showBitmap != null)

                {

                    SaveFileDialog saveFileDialog = new SaveFileDialog();

                    saveFileDialog.Filter = @"Bitmap文件(*.bmp)|*.bmp|Jpeg文件(*.jpg)|*.jpg|所有合适文件(*.bmp,*.jpg)|*.bmp;*.jpg";

                    saveFileDialog.FilterIndex = 3;

                    saveFileDialog.RestoreDirectory = true;

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

                    {  

                        ImageFormat format = ImageFormat.Jpeg;

                        switch (Path.GetExtension(saveFileDialog.FileName).ToLower())

                        {

                            case ".jpg":

                                format = ImageFormat.Jpeg;

                                break;

                            case ".bmp":

                                format = ImageFormat.Bmp;

                                break;

                            default:

                                MessageBox.Show(this, "Unsupported image format was specified", "Error",

                                    MessageBoxButtons.OK, MessageBoxIcon.Error);

                                return;

                        }

                        try

                        {

                            showBitmap.Save(saveFileDialog.FileName,format );

                        }

                        catch (Exception)

                        {

                            MessageBox.Show(this, "Failed writing image file", "Error",

                                MessageBoxButtons.OK, MessageBoxIcon.Error);

                        }

                    }

                }

     

            }

        //窗口重绘,在窗体上显示图像,重载Paint

            private void frmMain_Paint(object sender, System.Windows.Forms.PaintEventArgs e)

            {

                if (showBitmap != null)

                {

                    Graphics g = e.Graphics;

                    g.DrawImage(showBitmap, new Rectangle(this.AutoScrollPosition.X, this.AutoScrollPosition.Y ,

                    (int)(showBitmap.Width), (int)(showBitmap.Height)));

                }

            }

             //灰度化

            private void menu2Gray_Click(object sender, EventArgs e)

            {

                if (showBitmap == null) return;

                showBitmap = RGB2Gray(showBitmap);//下面都以RGB2Gray为例

                this.Invalidate();

            }

    二.   提取像素法

           这种方法简单易懂,但相当耗时,完全不可取.

    public static Bitmap RGB2Gray(Bitmap srcBitmap)

            {

                Color srcColor;

                int wide = srcBitmap.Width;

                int height = srcBitmap.Height;

                for (int y = 0; y < height; y++)

                    for (int x = 0; x < wide; x++)

                    {

                        //获取像素的RGB颜色值

                        srcColor = srcBitmap.GetPixel(x, y);

                        byte temp = (byte)(srcColor.R * .299 + srcColor.G * .587 + srcColor.B * .114);

                        //设置像素的RGB颜色值

                        srcBitmap.SetPixel(x, y, Color.FromArgb(temp, temp, temp));

                    }

                return srcBitmap ;

     

            }//#

    三.   内存法

    这是比较常用的方法

    public static Bitmap RGB2Gray(Bitmap srcBitmap)

            {

                int wide = srcBitmap.Width;

                int height = srcBitmap.Height;

                Rectangle rect = new Rectangle(0, 0, wide, height);

                // 将Bitmap锁定到系统内存中, 获得BitmapData

                BitmapData srcBmData = srcBitmap.LockBits(rect,

                          ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

                //创建Bitmap

                 Bitmap dstBitmap = CreateGrayscaleImage(wide, height);//这个函数在后面有定义

                BitmapData dstBmData = dstBitmap.LockBits(rect,

                          ImageLockMode.ReadWrite, PixelFormat.Format8bppIndexed);

                // 位图中第一个像素数据的地址。它也可以看成是位图中的第一个扫描行

                System.IntPtr srcPtr = srcBmData.Scan0;

                System.IntPtr dstPtr = dstBmData.Scan0;

                // 将Bitmap对象的信息存放到byte数组中

                int src_bytes = srcBmData.Stride * height;

                byte[] srcValues = new byte[src_bytes];

                int dst_bytes = dstBmData.Stride * height;

                byte[] dstValues = new byte[dst_bytes];

                //复制GRB信息到byte数组

                System.Runtime.InteropServices.Marshal.Copy(srcPtr, srcValues, 0, src_bytes);

                System.Runtime.InteropServices.Marshal.Copy(dstPtr, dstValues, 0, dst_bytes);

                // 根据Y=0.299*R+0.114*G+0.587B,Y为亮度

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

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

                    {

                      //只处理每行中图像像素数据,舍弃未用空间

                      //注意位图结构中RGB按BGR的顺序存储

                        int k = 3 * j;

                        byte temp = (byte)(srcValues[i * srcBmData.Stride + k + 2] * .299

                             + srcValues[i * srcBmData.Stride + k + 1] * .587 + srcValues[i * srcBmData.Stride + k] * .114);

                        dstValues[i * dstBmData.Stride + j] = temp;

                    }

                //将更改过的byte[]拷贝到原位图

                System.Runtime.InteropServices.Marshal.Copy(dstValues, 0, dstPtr, dst_bytes);

               

                // 解锁位图

                srcBitmap.UnlockBits(srcBmData);

                dstBitmap.UnlockBits(dstBmData);

                return dstBitmap;

     

            }//#

    四   指针法

    C/C++的习惯,不是C#的特点

    public static Bitmap RGB2Gray(Bitmap srcBitmap)

            {

                int wide = srcBitmap.Width;

                int height = srcBitmap.Height ;

                Rectangle rect = new Rectangle(0, 0, wide, height);

                BitmapData srcBmData = srcBitmap.LockBits(rect,

                          ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

                Bitmap dstBitmap = CreateGrayscaleImage(wide, height);

                BitmapData dstBmData = dstBitmap.LockBits(rect,

                          ImageLockMode.ReadWrite, PixelFormat.Format8bppIndexed);

       

                System.IntPtr srcScan = srcBmData.Scan0;

                System.IntPtr dstScan = dstBmData.Scan0;

                Unsafe //启动不安全代码

                {

                    byte* srcP = (byte*)(void*) srcScan;

                    byte* dstP = (byte*)(void*) dstScan;

                    int srcOffset = srcBmData.Stride - wide * 3;

                    int dstOffset = dstBmData.Stride - wide ;

                    byte red, green, blue;

                    for (int y = 0; y < height; y++)

                    {

                        for (int x = 0; x <wide ; x++, srcP += 3, dstP++)

                        {

                            blue = srcP [0];

                            green = srcP [1];

                            red = srcP [2];

                            * dstP = (byte)(.299 * red + .587 * green + .114 * blue);

                           

                        }

                        srcP += srcOffset;

                        dstP += dstOffset;

                    }

                }

                srcBitmap.UnlockBits(srcBmData);

                dstBitmap.UnlockBits(dstBmData );

                return dstBitmap;

     

            }//#

    五.   矩阵法

    并不是什么新方法,只是将图像数据分做R,G,B三个矩阵(二维数组)存储,类似MATLAB的习惯.

           public static bool GetRGB(Bitmap Source, out int[,] R, out int[,] G, out int[,] B)

            {

                try

                {

                    int iWidth = Source.Width;

                    int iHeight = Source.Height;

     

                    Rectangle rect = new Rectangle(0, 0, iWidth, iHeight);

                    System.Drawing.Imaging.BitmapData bmpData = Source.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, Source.PixelFormat);

                    IntPtr iPtr = bmpData.Scan0;

     

                    int iBytes = iWidth * iHeight * 3;

                    byte[] PixelValues = new byte[iBytes];

                    System.Runtime.InteropServices.Marshal.Copy(iPtr, PixelValues, 0, iBytes);

                    Source.UnlockBits(bmpData);

     

                    // 注意这个地方图像的两维方向与数组两维的方向是转置的关系

     

                    R = new int[iHeight, iWidth];

                    G = new int[iHeight, iWidth];

                    B = new int[iHeight, iWidth];

     

                    int iPoint = 0;

     

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

                    {

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

                        {

                            // 注意,Windows 中三基色的排列顺序是 BGR 而不是 RGB!

                            B[i, j] = Convert.ToInt32(PixelValues[iPoint++]);

                            G[i, j] = Convert.ToInt32(PixelValues[iPoint++]);

                            R[i, j] = Convert.ToInt32(PixelValues[iPoint++]);

                        }

                    }

     

                    return true;

                }

                catch (Exception)

                {

                    R = null;

                    G = null;

                    B = null;

     

                    return false;

                }

            }//#

            public static Bitmap FromRGB(int[,] R, int[,] G, int[,] B)

            {

                int iWidth = G.GetLength(1);

                int iHeight = G.GetLength(0);

                Bitmap Result = new Bitmap(iWidth, iHeight, System.Drawing.Imaging.PixelFormat.Format24bppRgb);

     

                Rectangle rect = new Rectangle(0, 0, iWidth, iHeight);

                System.Drawing.Imaging.BitmapData bmpData = Result.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, System.Drawing.Imaging.PixelFormat.Format24bppRgb);

                IntPtr iPtr = bmpData.Scan0;

                int iStride = bmpData.Stride;

               int iBytes = iWidth * iHeight * 3;

                byte[] PixelValues = new byte[iBytes];

                int iPoint = 0;

     

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

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

                    {

                        int iG = G[i, j];

                        int iB = B[i, j];

                        int iR = R[i, j];

                        PixelValues[iPoint] = Convert.ToByte(iB);

                        PixelValues[iPoint + 1] = Convert.ToByte(iG);

                        PixelValues[iPoint + 2] = Convert.ToByte(iR);

                        iPoint += 3;

                    }

                System.Runtime.InteropServices.Marshal.Copy(PixelValues, 0, iPtr, iBytes);

                Result.UnlockBits(bmpData);

                return Result;

            }//#

            public static bool GetGray(Bitmap srcBitmap, out byte [,] gray)

            {

     

                Bitmap tempBitmap;

                if (srcBitmap.PixelFormat != PixelFormat.Format8bppIndexed)

                    tempBitmap = ImageProcess.Image.Gray(srcBitmap);

                else

                    tempBitmap = srcBitmap;

                int wide = tempBitmap.Width;

                int height = tempBitmap.Height;

                gray = new byte [height, wide];

                BitmapData gbmData = tempBitmap.LockBits(new Rectangle(0, 0, wide, height),

                      ImageLockMode.ReadWrite, PixelFormat.Format8bppIndexed);

                System.IntPtr ScanG = gbmData.Scan0;

                int gOffset = gbmData.Stride - wide;

                unsafe

                {

                    byte* g = (byte*)(void*)ScanG;

                    // for each pixel

                    for (int y = 0; y < height; y++)

                    {

                        // for each pixel

                        for (int x = 0; x < wide; x++, g++)

                        {

                            gray[y ,x ] =*g;

                        }

                        g += gOffset;

                    }

                }

                tempBitmap.UnlockBits(gbmData);

               return true ;

            }//#

            public static Bitmap FromGray(byte [,] Gray)

            {

                int iWidth = Gray.GetLength(1);

                int iHeight = Gray.GetLength(0);

                Bitmap dstBitmap = ImageProcess.Image.CreateGrayscaleImage(iWidth, iHeight);

                BitmapData gbmData = dstBitmap.LockBits(new Rectangle(0, 0, iWidth, iHeight),

                          ImageLockMode.ReadWrite, PixelFormat.Format8bppIndexed);

                System.IntPtr ScanG = gbmData.Scan0;

                int gOffset = gbmData.Stride - iWidth;

                unsafe

                {

                    byte* g = (byte*)(void*)ScanG;

     

                    // 注意这个地方图像的两维方向与数组两维的方向是转置的关系

     

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

                    {

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

                        {

     

                            *g=(byte )Gray[i, j] ;

                            g++;

                        }

                        g += gOffset;

                    }

                }

     

                dstBitmap.UnlockBits(gbmData);

     

                return dstBitmap;

            } //#

    /*********************************补充******************************************/

             /// <summary>

             /// Create and initialize grayscale image

             /// </summary>

             public static Bitmap CreateGrayscaleImage( int width, int height )

             {

                  // create new image

                  Bitmap bmp = new Bitmap( width, height, PixelFormat.Format8bppIndexed );

                  // set palette to grayscale

                  SetGrayscalePalette( bmp );

                  // return new image

                  return bmp;

             }//#

     

             /// <summary>

             /// Set pallete of the image to grayscale

             /// </summary>

             public static void SetGrayscalePalette( Bitmap srcImg )

             {

                  // check pixel format

                  if ( srcImg.PixelFormat != PixelFormat.Format8bppIndexed )

                       throw new ArgumentException( );

     

                  // get palette

                  ColorPalette cp = srcImg.Palette;

                  // init palette

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

                  {

                       cp.Entries[i] = Color.FromArgb( i, i, i );

                  }

                  // set palette back

                  srcImg.Palette = cp;

             }//#

    /*********************************END********************************************/

    哪里有天才,我是把别人喝咖啡的工夫都用在了工作上了。——鲁迅

  • 相关阅读:
    [九、实用进阶]24App内容文本的本地化
    真正在大厂干了几年,我学会了反内卷[转]
    【Spine】Spine使用一 简单的人物移动
    【问题】Cocos Layout自适应高度,当里面Label变化时会闪一下
    【Spine】Spine使用二 姿势、事件、边界框、皮肤、IK约束、路径约束、网格
    (1.1)网路概念基础
    prometheus多个配置文件,prometheus文件发现
    node_exporter自定义监控
    mysqld_exporter
    prometheus监控redis集群
  • 原文地址:https://www.cnblogs.com/yangchuncool/p/3118599.html
Copyright © 2020-2023  润新知