C# 处理图像三种方法对比

C#本身自带有一定的图像处理能力,即使在不依赖Emgu CV的情况下,也是有很大的潜质的。

不过,最近在处理大量图片时,发现图片数量较少时,处理本身所带来的延时不会让人敏感,但是数量较大时,程序花费大量时间在预处理图片上,导致程序很容易误报线程时延过大,导致误判程序异常。对于这个问题苦恼很久,毕竟不是CS专业出身,对于图像处理以及一些算法和库的运用上感到毕竟吃力。

今天在阅读了一些数字图像处理的书之后感到收益很大,现在来做点试验对照一下之前自己的错误在哪里。

之前看MS的C#API时候发现有一个Graphics挺适合我现在使用,于是便二话不说开干,今天才发现越来封装的太好,反而会带来许多拖累,不如操起指针畅快的运行。

不多说,试验对比的是Graphics、操作内存、操作指针三者在性能上差距。

试验内容:对同一张照片进行灰度处理,直接看三者之间延时有多大

 

1.试验基本场景,比较丑陋,就凑合看着。。。

C# 处理图像三种方法对比_第1张图片

2.提取像素Button中,调用Graphics灰度化处理

private void button2_Click(object sender, EventArgs e)
        {
            if (curBitMap1 != null)
            {
                Color curColor;
                int ret;
                //个人运行时间判断类
                GetRunTime getRunTime = new GetRunTime();
                //stopWatch启动
                getRunTime.Start();
                //Graphics//灰度化
                for (int i = (int)(0); i < (int)(curBitMap1.Width ); i++)
                {
                    for (int j = 0; j < curBitMap1.Height; j++)
                    {
                        //获取像素
                        curColor = curBitMap1.GetPixel(i, j);
                        //获取RGB
                        ret = (int)(curColor.R * 0.299 + curColor.G * 0.587 + curColor.B * 0.114);
                        //设置像素
                        curBitMap1.SetPixel(i, j, Color.FromArgb(ret, ret, ret));
                    }
                }
                Invalidate();

                labelGetPixel.Text = "提取像素花费时间:" + getRunTime.getRunTime() + "ms";

            }
        }

  

3.内存法Button中,直接复制数据到内存,直接操作

private void button5_Click(object sender, EventArgs e)
        {
            if (curBitMap2 != null)
            {
                GetRunTime getRunTime = new GetRunTime();
                getRunTime.Start();
                Rectangle rect = new Rectangle(0, 0, curBitMap2.Width, curBitMap2.Height);
                //以读写方式锁定位图
                System.Drawing.Imaging.BitmapData bmpData =
                    curBitMap2.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadOnly, curBitMap2.PixelFormat);
                //首地址
                IntPtr ptr = bmpData.Scan0;
                //24位bmp的总字节数
                int bytes = curBitMap2.Width * curBitMap2.Height * 3;
                byte[] rgbValues = new byte[bytes];
                //复制被锁定的图像到rgbValues
                System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes);
                double colorTemp = 0;
                //灰度化
                for (int i = 0; i < bmpData.Height; i++)
                {
                    for (int j = 0; j < bmpData.Width * 3; j+=3)
                    {
                        //跳过空白块
                        colorTemp = rgbValues[i * bmpData.Stride + j + 2] * 0.299 
                            + rgbValues[i * bmpData.Stride + j + 1] * 0.587 
                            + rgbValues[i * bmpData.Stride + j] * 0.114;
                        rgbValues[i * bmpData.Stride + j + 2] 
                            = rgbValues[i * bmpData.Stride + j + 1] 
                            = rgbValues[i * bmpData.Stride + j] = (byte)colorTemp;
                    }
                }
                //复制回位图
                System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, bytes);
                curBitMap2.UnlockBits(bmpData);
                Invalidate();
                labelCaChe.Text = "提取像素内存法花费时间:" + getRunTime.getRunTime() + "ms";
            }
        }

  

4.指针法Button中,直接复制数据到内存,指针操作 

private void button6_Click(object sender, EventArgs e)
        {
            GetRunTime getRunTime = new GetRunTime();
            getRunTime.Start();
            Rectangle rect = new Rectangle(0, 0, curBitMap3.Width, curBitMap3.Height);
            //以读写方式锁定位图
            System.Drawing.Imaging.BitmapData bmpData =
                    curBitMap3.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadOnly, curBitMap3.PixelFormat);
            byte temp = 0;
            unsafe
            {
                //首地址
                byte* ptr = (byte*)(bmpData.Scan0);
                //灰度化
                for (int i = 0; i < bmpData.Height; i++)
                {
                    for (int j = 0; j < bmpData.Width;j++ )
                    {
                        temp = (byte)(0.299 * ptr[2] + 0.587 * ptr[1] + 0.114 * ptr[0]);
                        ptr[0] = ptr[1] = ptr[2] = temp;
                        ptr += 3;
                    }
                    //跳过空白块
                    ptr += bmpData.Stride - bmpData.Width * 3;
                }
            }
            //解锁位图
            curBitMap3.UnlockBits(bmpData);

            Invalidate();
            labelPoint.Text = "提取像素内存法花费时间:" + getRunTime.getRunTime() + "ms";
        }

5,简单完善一下就开始打开图片看看运行时间之间的对比吧

C# 处理图像三种方法对比_第2张图片

总结:虽然电脑烂,但还是看得出三者之间的差距吧。复制进内存直接操作和用指针操作都是极大的提高效率,如果处理一张图片节约60ms,那处理大量的图片时候将会节约多少时间?所以今后处理图像的时候,如果不用Emgu,尽量也别用Graphics,还是自己动手操作内存。(肯定会有人说,你为毛不去用C++,好吧,我其实就是在黑Graphics,你咬我呀~)

 

你可能感兴趣的:(C#)