Search code examples
c#.netwinformsdrawing

why does editing an image with Lockbits still take 7 secs?


My Application

I am writing an application that needs to convert RGB to grayscale images. The conversion works but converting an image of 3648 * 2736 pixel takes round about 7 secs. I know that set and getpixel take some time. But I think that it shouldn't take so long if you are using Lockbits even though the image is not small. (please correct me if that is wrong). Maybe I just did a fatal mistake within my code.

The code

public static long ConvertToGrayScaleV2(Bitmap imageColor, bool useHDTVConversion)
        {
            Stopwatch stpw = new Stopwatch();
            stpw.Start();
            System.Drawing.Imaging.BitmapData imageColorData = imageColor.LockBits(new Rectangle(new Point(0, 0), imageColor.Size),
                System.Drawing.Imaging.ImageLockMode.ReadWrite, imageColor.PixelFormat);

            IntPtr PtrColor = imageColorData.Scan0;
            int strideColor = imageColorData.Stride;
            byte[] byteImageColor = new byte[Math.Abs(strideColor) * imageColor.Height];
            System.Runtime.InteropServices.Marshal.Copy(PtrColor, byteImageColor, 0, Math.Abs(strideColor) * imageColor.Height);

            int bytesPerPixel = getBytesPerPixel(imageColor);
            byte value;
            if (bytesPerPixel == -1)
                throw new Exception("Can't get bytes per pixel because it is not defined for this image format.");
            for (int x = 0, position; x < imageColor.Width * imageColor.Height; x++)
            {
                position = x * bytesPerPixel;
                if (useHDTVConversion)
                {
                    value = (byte)(byteImageColor[position] * 0.0722 + byteImageColor[position + 1] * 0.7152 + byteImageColor[position + 2] * 0.2126);                    
                }
                else
                {
                    value = (byte)(byteImageColor[position] * 0.114 + byteImageColor[position + 1] * 0.587 + byteImageColor[position + 2] * 0.299);
                }
                byteImageColor[position] = value;
                byteImageColor[position+1] = value;
                byteImageColor[position+2] = value;

            }

            System.Runtime.InteropServices.Marshal.Copy(byteImageColor, 0, PtrColor, Math.Abs(strideColor) * imageColor.Height);
            imageColor.UnlockBits(imageColorData);
            stpw.Stop();
            return stpw.ElapsedMilliseconds;
        }

        public static int getBytesPerPixel(Image img)
        {
            switch (img.PixelFormat)
            {
                case System.Drawing.Imaging.PixelFormat.Format16bppArgb1555:    return 2;
                case System.Drawing.Imaging.PixelFormat.Format16bppGrayScale:   return 2;
                case System.Drawing.Imaging.PixelFormat.Format16bppRgb555: return 2;
                case System.Drawing.Imaging.PixelFormat.Format16bppRgb565: return 2;
                case System.Drawing.Imaging.PixelFormat.Format1bppIndexed: return 1;
                case System.Drawing.Imaging.PixelFormat.Format24bppRgb: return 3;
                case System.Drawing.Imaging.PixelFormat.Format32bppArgb: return 4;
                case System.Drawing.Imaging.PixelFormat.Format32bppPArgb: return 4;
                case System.Drawing.Imaging.PixelFormat.Format32bppRgb: return 4;
                case System.Drawing.Imaging.PixelFormat.Format48bppRgb: return 6;
                case System.Drawing.Imaging.PixelFormat.Format4bppIndexed: return 1;
                case System.Drawing.Imaging.PixelFormat.Format64bppArgb: return 8;
                case System.Drawing.Imaging.PixelFormat.Format64bppPArgb: return 8;
                case System.Drawing.Imaging.PixelFormat.Format8bppIndexed: return 1;
                default: return -1;
            }

        }

Solution

  • If you're converting to greyscale, try using a ColorMatrix transformation instead. from: https://web.archive.org/web/20141230145627/http://bobpowell.net/grayscale.aspx

       Image img = Image.FromFile(dlg.FileName);
            Bitmap bm = new Bitmap(img.Width,img.Height);
            Graphics g = Graphics.FromImage(bm); 
    
      
    
            
            ColorMatrix cm = new ColorMatrix(new float[][]{   new float[]{0.5f,0.5f,0.5f,0,0},
                                      new float[]{0.5f,0.5f,0.5f,0,0},
                                      new float[]{0.5f,0.5f,0.5f,0,0},
                                      new float[]{0,0,0,1,0,0},
                                      new float[]{0,0,0,0,1,0},
                                      new float[]{0,0,0,0,0,1}}); 
    
            
    
            /* 
    
            //Gilles Khouzams colour corrected grayscale shear
            ColorMatrix cm = new ColorMatrix(new float[][]{   new float[]{0.3f,0.3f,0.3f,0,0},
                                      new float[]{0.59f,0.59f,0.59f,0,0},
                                      new float[]{0.11f,0.11f,0.11f,0,0},
                                      new float[]{0,0,0,1,0,0},
                                      new float[]{0,0,0,0,1,0},
                                      new float[]{0,0,0,0,0,1}}); 
    
            */ 
    
    
            ImageAttributes ia = new ImageAttributes();
            ia.SetColorMatrix(cm);
            g.DrawImage(img,new Rectangle(0,0,img.Width,img.Height),0,0,img.Width,img.Height,GraphicsUnit.Pixel,ia);
            g.Dispose();