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;
}
}
1 Answer 1
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.