zoukankan      html  css  js  c++  java
  • C#:优化图像像素操作

    以图像阈值化为例:

    # very slow solution 
    public static unsafe Bitmap ApplyThreshold(Bitmap scrBitmap, int lower_value, int upper_value)
    {
        Color newColor = Color.Red;
        Bitmap newBitmap = new Bitmap(scrBitmap.Width, scrBitmap.Height);
        //Locking the bitmap's bits allows you to iterate through it's color-data many times faster than using GetPixel, using unsafe code.
        lock (_imageLock)
        {
            var data = scrBitmap.LockBits(new Rectangle(0, 0, scrBitmap.Width, scrBitmap.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
    
            var offset = data.Stride - scrBitmap.Width * 3;
            var p = (byte*)data.Scan0.ToPointer();
    
            for (var i = 0; i < scrBitmap.Height; i++)
            {
                for (var j = 0; j < scrBitmap.Width; j++, p += 3)
                {
                    var v = (int)(p[0] + p[1] + p[2]) / 3;
                    var c = Color.FromArgb(p[2], p[1], p[0]);
                    if (v > upper_value || v < lower_value)
                        newBitmap.SetPixel(j, i, newColor);
                    else
                        newBitmap.SetPixel(j, i, c);
                }
                p += offset;
            }
    
            scrBitmap.UnlockBits(data);
        }
    
        return newBitmap;
    }
    
    # speed up using mutiple threads
    public static unsafe Bitmap ApplyThresholdParallel2(Bitmap scrBitmap, int lower_value, int upper_value)
    {
        //Locking the bitmap's bits allows you to iterate through it's color-data many times faster than using GetPixel, using unsafe code.
        lock (_imageLock)
        {
            var data = scrBitmap.LockBits(new Rectangle(0, 0, scrBitmap.Width, scrBitmap.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
            int bytesPerPixel = 3;
            int stride = data.Stride;
            var p = (byte*)data.Scan0.ToPointer();
    
            Task[] tasks = new Task[4];
            for (int i = 0; i < tasks.Length; i++)
            {
                int ii = i;
                tasks[i] = Task.Factory.StartNew(() =>
                {
                    int minY = ii < 2 ? 0 : data.Height / 2;
                    int maxY = ii < 2 ? data.Height / 2 : data.Height;
    
                    int minX = ii % 2 == 0 ? 0 : data.Width / 2;
                    int maxX = ii % 2 == 0 ? data.Width / 2 : data.Width;
    
                    for (int y = minY; y < maxY; y++)
                    {
                        byte* row = p + (y * data.Stride);
    
                        for (int x = minX; x < maxX; x++)
                        {
                            int bIndex = x * bytesPerPixel;
                            int gIndex = bIndex + 1;
                            int rIndex = bIndex + 2;
    
                            byte pixelR = row[rIndex];
                            byte pixelG = row[gIndex];
                            byte pixelB = row[bIndex];
    
                            int v = (pixelR + pixelG + pixelB) / 3;
    
                            if (v > upper_value || v < lower_value)
                            {
                                row[rIndex] = 255;
                                row[gIndex] = 0;
                                row[bIndex] = 0;
                            }
                        }
                    }
                });
            }
    
            Task.WaitAll(tasks);
            scrBitmap.UnlockBits(data);
        }
    
        return scrBitmap;
    }
    
    
    # speed up using Parallel for
    public static unsafe Bitmap ApplyThresholdParallel(Bitmap scrBitmap, int lower_value, int upper_value)
    {
        var rect = new Rectangle(0, 0, scrBitmap.Width, scrBitmap.Height);
        Bitmap targetBmp = scrBitmap.Clone(rect, PixelFormat.Format24bppRgb);
        //Locking the bitmap's bits allows you to iterate through it's color-data many times faster than using GetPixel, using unsafe code.
        lock (_imageLock)
        {
            var data = targetBmp.LockBits(rect, ImageLockMode.ReadWrite, targetBmp.PixelFormat);
            int bytesPerPixel = System.Drawing.Bitmap.GetPixelFormatSize(targetBmp.PixelFormat) / 8;
            int heightInPixels = data.Height;
            int widthInBytes = data.Width * bytesPerPixel;
            byte* PtrFirstPixel = (byte*)data.Scan0;
    
            Parallel.For(0, heightInPixels, y =>
            {
                byte* currentLine = PtrFirstPixel + (y * data.Stride);
                for (int x = 0; x < widthInBytes; x = x + bytesPerPixel)
                {
                    int b = currentLine[x];
                    int g = currentLine[x + 1];
                    int r = currentLine[x + 2];
    
                    var v = (b + g + r) / 3;
                    if (v > upper_value || v < lower_value)
                    {
                        currentLine[x] = (byte)0;
                        currentLine[x + 1] = (byte)0;
                        currentLine[x + 2] = (byte)255;
                    }
                }
            });
    
            targetBmp.UnlockBits(data);
        }
    
        return targetBmp;
    }
    

      

    参考:

    Fast Pixel Operations in .NET (With and Without unsafe)

    Why the use of GetPixel and SetPixel is so inefficient!

    Fast Image Processing in C#

  • 相关阅读:
    node中glob模块总结
    HTTP中分块编码(Transfer-Encoding: chunked)
    随笔记录--RegExp类型
    Innodb 表空间传输迁移数据
    千金良方说:"我现在奉上179341字的MySQL资料包,还来得及吗?有"代码段、附录、和高清图!!"
    一不小心,我就上传了 279674 字的 MySQL 学习资料到 github 上了
    MySQL InnoDB Update和Crash Recovery流程
    mysqldump与innobackupex备份过程你知多少
    MySQL 各种超时参数的含义
    mha安装使用手册
  • 原文地址:https://www.cnblogs.com/carsonzhu/p/12460872.html
Copyright © 2011-2022 走看看