• 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#

  • 相关阅读:
    (转)原始图像数据和PDF中的图像数据
    itextSharp 附pdf文件解析
    (转)pdf文件结构
    【iCore1S 双核心板_ARM】例程九:DAC实验——输出直流电压
    【iCore4 双核心板_FPGA】例程七:状态机实验——状态机使用
    【iCore4 双核心板_FPGA】例程六:触发器实验——触发器的使用
    【iCore4 双核心板_ARM】例程八:定时器PWM实验——呼吸灯
    【iCore4 双核心板_ARM】例程七:WWDG看门狗实验——复位ARM
    【iCore1S 双核心板_FPGA】例程七:基础逻辑门实验——逻辑门使用
    【iCore1S 双核心板_FPGA】例程六:状态机实验——状态机使用
  • 原文地址:https://www.cnblogs.com/carsonzhu/p/12460872.html
Copyright © 2020-2023  润新知