4
\$\begingroup\$

I have written the following routines to work with digital images in various representations.

Can I optimize them for better accuracy and performance?

public static partial class ImageDataConverter
{
    #region Bitmap ToBitmap32(int[,] image)
    //Tested
    ///Working fine. 
    public static Bitmap ToBitmap32(int[,] image)
    {
        int Width = image.GetLength(0);
        int Height = image.GetLength(1);
        int i, j;
        Bitmap bitmap = new Bitmap(Width, Height);
        BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, Width, Height),
                                 ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);

        int bytesPerPixel = sizeof(int);

        unsafe
        {
            byte* address = (byte*)bitmapData.Scan0;

            for (i = 0; i < bitmapData.Height; i++)
            {
                for (j = 0; j < bitmapData.Width; j++)
                {
                    byte[] bytes = BitConverter.GetBytes(image[j, i]);

                    for (int k = 0; k < bytesPerPixel; k++)
                    {
                        address[k] = bytes[k];
                    }
                    //4 bytes per pixel
                    address += bytesPerPixel;
                }//end for j

                //4 bytes per pixel
                address += (bitmapData.Stride - (bitmapData.Width * bytesPerPixel));
            }//end for i
        }//end unsafe
        bitmap.UnlockBits(bitmapData);
        return bitmap;// col;
    } 
    #endregion

    #region int[,] ToInteger32(Bitmap bitmap)
    //Tested
    ///Working fine. 
    public static int[,] ToInteger32(Bitmap bitmap)
    {
        int[,] array2D = new int[bitmap.Width, bitmap.Height];

        BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
                                                 ImageLockMode.ReadWrite,
                                                 PixelFormat.Format32bppRgb);
        int bytesPerPixel = sizeof(int);

        unsafe
        {
            byte* address = (byte*)bitmapData.Scan0;

            int paddingOffset = bitmapData.Stride - (bitmap.Width * bytesPerPixel);//4 bytes per pixel

            for (int i = 0; i < bitmap.Width; i++)
            {
                for (int j = 0; j < bitmap.Height; j++)
                {
                    byte[] temp = new byte[bytesPerPixel];

                    for (int k = 0; k < bytesPerPixel; k++)
                    {
                        temp[k] = address[k];
                    }
                    array2D[j, i] = BitConverter.ToInt32(temp, 0);

                    //4-bytes per pixel
                    address += bytesPerPixel;//4-channels
                }
                address += paddingOffset;
            }
        }
        bitmap.UnlockBits(bitmapData);

        return array2D;
    } 
    #endregion

    public static int[,] ToInteger(Bitmap image)
    {
        Bitmap bitmap = (Bitmap)image.Clone();

        int[,] array2D = new int[bitmap.Width, bitmap.Height];

        BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
                                                 ImageLockMode.ReadWrite,
                                                 PixelFormat.Format8bppIndexed);
        int bytesPerPixel = sizeof(byte);

        unsafe
        {
            byte* address = (byte*)bitmapData.Scan0;

            int paddingOffset = bitmapData.Stride - (bitmap.Width * bytesPerPixel);

            for (int i = 0; i < bitmap.Width; i++)
            {
                for (int j = 0; j < bitmap.Height; j++)
                {
                    byte[] temp = new byte[bytesPerPixel];

                    for (int k = 0; k < bytesPerPixel; k++)
                    {
                        temp[k] = address[k];
                    }

                    int iii = 0;

                    if (bytesPerPixel >= sizeof(int))
                    {
                        iii = BitConverter.ToInt32(temp, 0);
                    }
                    else
                    {
                        iii = (int)temp[0];
                    }

                    array2D[j, i] = iii;

                    address += bytesPerPixel;
                }
                address += paddingOffset;
            }
        }
        bitmap.UnlockBits(bitmapData);

        return array2D;
    }

    public static Bitmap ToBitmap(int[,] image)
    {
        int Width = image.GetLength(0);
        int Height = image.GetLength(1);
        int i, j;

        Bitmap bitmap = new Bitmap(Width, Height, PixelFormat.Format8bppIndexed);

        BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, Width, Height),
                                 ImageLockMode.ReadOnly, PixelFormat.Format8bppIndexed);

        int bytesPerPixel = sizeof(byte);

        unsafe
        {
            byte* address = (byte*)bitmapData.Scan0;

            for (i = 0; i < bitmapData.Height; i++)
            {
                for (j = 0; j < bitmapData.Width; j++)
                {
                    byte[] bytes = BitConverter.GetBytes(image[j, i]);

                    for (int k = 0; k < bytesPerPixel; k++)
                    {
                        address[k] = bytes[k];
                    }

                    address += bytesPerPixel;
                }

                address += (bitmapData.Stride - (bitmapData.Width * bytesPerPixel));
            }
        }
        bitmap.UnlockBits(bitmapData);

        Grayscale.SetGrayscalePalette(bitmap);

        return bitmap;
    }

    public static int [,] ToInteger(Complex [,] image)
    {
        int Width = image.GetLength(0);
        int Height = image.GetLength(1);

        int[,] integer = new int[Width, Height];


            for (int j = 0; j <= Height - 1; j++)
            {
                for (int i = 0; i <= Width - 1; i++)
                {
                integer[i, j] =  ((int)image[i, j].Magnitude);
            }
        }

        return integer;
    }

    public static Complex [,] ToComplex(int[,] image)
    {
        int Width = image.GetLength(0);
        int Height = image.GetLength(1);

        Complex[,] comp = new Complex[Width, Height];

        for (int j = 0; j <= Height - 1; j++)
        {
        for (int i = 0; i <= Width - 1; i++)
        {
                Complex tempComp = new Complex((double)image[i,j], 0.0);
                comp[i,j] = tempComp;
            }
        }

        return comp;
    }

    public static Complex[,] ToComplexFaster(Bitmap image)
    {
        Bitmap bitmap = (Bitmap)image.Clone();

        Complex[,] comp = new Complex[bitmap.Width, bitmap.Height];

        BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
                                                 ImageLockMode.ReadWrite,
                                                 PixelFormat.Format8bppIndexed);
        int bytesPerPixel = sizeof(byte);

        unsafe
        {
            byte* address = (byte*)bitmapData.Scan0;

            int paddingOffset = bitmapData.Stride - (bitmap.Width * bytesPerPixel);

            for (int j = 0; j < bitmap.Height; j++)
            {
                for (int i = 0; i < bitmap.Width; i++)
                {

                    byte[] temp = new byte[bytesPerPixel];

                    for (int k = 0; k < bytesPerPixel; k++)
                    {
                        temp[k] = address[k];
                    }

                    int iii = 0;

                    if (bytesPerPixel >= sizeof(int))
                    {
                        iii = BitConverter.ToInt32(temp, 0);
                    }
                    else
                    {
                        iii = (int)temp[0];
                    }

                    Complex tempComp = new Complex((double)iii, 0.0);
                    comp[i,j] = tempComp;

                    address += bytesPerPixel;
                }

                address += paddingOffset;
            }
        }

        bitmap.UnlockBits(bitmapData);

        return comp;
    }

    public static Bitmap ToBitmapFaster(Complex[,] image)
    {
        int Width = image.GetLength(0);
        int Height = image.GetLength(1);
        int i, j;

        Bitmap bitmap = new Bitmap(Width, Height, PixelFormat.Format8bppIndexed);

        BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, Width, Height),
                                 ImageLockMode.ReadOnly, PixelFormat.Format8bppIndexed);

        int bytesPerPixel = sizeof(byte);

        unsafe
        {
            byte* address = (byte*)bitmapData.Scan0;

            for (i = 0; i < bitmapData.Height; i++)
            {
                for (j = 0; j < bitmapData.Width; j++)
                {

                    int integer = ((int)image[j, i].Magnitude);

                    byte[] bytes = BitConverter.GetBytes(integer);

                    for (int k = 0; k < bytesPerPixel; k++)
                    {
                        address[k] = bytes[k];
                    }

                    address += bytesPerPixel;
                }

                address += (bitmapData.Stride - (bitmapData.Width * bytesPerPixel));
            }
        }
        bitmap.UnlockBits(bitmapData);

        Grayscale.SetGrayscalePalette(bitmap);

        return bitmap;
    }
}
\$\endgroup\$
2
\$\begingroup\$

Loops

I do not really like this kind of loops :

for (int j = 0; j <= Height - 1; j++)

I would prefer :

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

but according to this stack overflow thread performance should not be harmed.

Operations within the loops

I notice that this operation : bitmapData.Width * bytesPerPixel is repeated in some of your loops. You can expect a (small) gain if you evaluate them outside the loop.

Towards better accessors ?

Actually the accessor a[i,j] can be improved, especially in loops like :

    for (int j = 0; j <= Height - 1; j++)
    {
        for (int i = 0; i <= Width - 1; i++)
        {
        integer[i, j] =  ((int)image[i, j].Magnitude);
    }
}

If integer was a 1-dimensional array, of size Height * Width, you could just have a single loop over all the elements, that would be faster. But this needs you to change all your code.

Parallel processing ?

We do not have information regarding the size of the images you are working with, and parallel processing can make you waste a lot of time, especially if the number of instructions per loop are small.

But these loops :

    for (int j = 0; j <= Height - 1; j++)
    {
        for (int i = 0; i <= Width - 1; i++)
        {
        integer[i, j] =  ((int)image[i, j].Magnitude);
    }
}

and:

for (int j = 0; j <= Height - 1; j++)
{
for (int i = 0; i <= Width - 1; i++)
{
        Complex tempComp = new Complex((double)image[i,j], 0.0);
        comp[i,j] = tempComp;
    }
}

could easily be parallelized over the rows or the columns.

|improve this answer|||||
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy