The following code converts a color image to Grayscale and then computes its FFT:
private void button1_Click(object sender, EventArgs e)
{
Bitmap source = pictureBox1.Image as Bitmap;
Bitmap gray = Grayscale.ToGrayscale(source);
Complex[,] cpxImage = ImageDataConverter.ToComplex(gray);
Complex[,] fftCpxImage = FourierTransform.ForwardFFT(cpxImage);
Complex[,] shiftedFftCpxImage = FourierShifter.ShiftFft(fftCpxImage);
Bitmap mag = FourierPlot.FftMagnitudePlot(shiftedFftCpxImage, PixelFormat.Format8bppIndexed);
Bitmap phase = FourierPlot.FftPhasePlot(shiftedFftCpxImage, PixelFormat.Format8bppIndexed);
pictureBox2.Image = gray;
pictureBox3.Image = mag;
pictureBox4.Image = phase;
}
The following code splits a color image into three channels computes their FFTs and merges them together to form an RGB image of the FFT.
private void button2_Click(object sender, EventArgs e)
{
Bitmap source = pictureBox1.Image as Bitmap;
int [,,] array3d = ImageDataConverter.ToInteger3d(source);
int[,] red = ArrayTools<int>.Split(array3d, 0);
int[,] green = ArrayTools<int>.Split(array3d, 1);
int[,] blue = ArrayTools<int>.Split(array3d, 2);
Complex [,] cpxRed = ImageDataConverter.ToComplex(red);
Complex [,] cpxGreen = ImageDataConverter.ToComplex(green);
Complex [,] cpxBlue = ImageDataConverter.ToComplex(blue);
Complex[,] fftCpxRed = FourierTransform.ForwardFFT(cpxRed);
Complex[,] fftCpxGreen = FourierTransform.ForwardFFT(cpxGreen);
Complex[,] fftCpxBlue = FourierTransform.ForwardFFT(cpxBlue);
Complex[,] shiftedFftCpxRed = FourierShifter.ShiftFft(fftCpxRed);
Complex[,] shiftedFftCpxGreen = FourierShifter.ShiftFft(fftCpxGreen);
Complex[,] shiftedFftCpxBlue = FourierShifter.ShiftFft(fftCpxBlue);
int[,] fftRed = ImageDataConverter.ToIntegerMagnitude(shiftedFftCpxRed);
int[,] fftGreen = ImageDataConverter.ToIntegerMagnitude(shiftedFftCpxGreen);
int[,] fftBlue = ImageDataConverter.ToIntegerMagnitude(shiftedFftCpxBlue);
int [,,] dest = ArrayTools<int>.Merge(fftRed, fftGreen, fftBlue);
Bitmap mag = ImageDataConverter.ToBitmap3d(dest, PixelFormat.Format8bppIndexed);
Grayscale.SetPalette(mag);
pictureBox3.Image = mag;
}
Output
In the first case, the outcome is very good, and as expected. In the second case, the output is totally black.
One more test: if I take only one channel, again the output is cool:
... ... ...
Complex[,] shiftedFftCpxRed = FourierShifter.ShiftFft(fftCpxRed);
Complex[,] shiftedFftCpxGreen = FourierShifter.ShiftFft(fftCpxGreen);
Complex[,] shiftedFftCpxBlue = FourierShifter.ShiftFft(fftCpxBlue);
Bitmap mag = FourierPlot.FftMagnitudePlot(shiftedFftCpxRed, PixelFormat.Format8bppIndexed);
Bitmap phase = FourierPlot.FftPhasePlot(shiftedFftCpxRed, PixelFormat.Format8bppIndexed);
pictureBox2.Image = ImageDataConverter.ToBitmap2d(red, PixelFormat.Format8bppIndexed);
pictureBox3.Image = mag;
pictureBox4.Image = phase;
... ... ...
I think there is a problem in
public static int[,] ToIntegerMagnitude(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;
}
This is only taking the magnitude part and hence losing data in the process.
Any suggestions?
.
Relevant Source Code
public static class FourierPlot
{
public static Bitmap FftMagnitudePlot(Complex[,] fftImage, PixelFormat pixelFormat)
{
int[,] FourierMagnitudeNormalizedInteger = FourierNormalizer.Normalize(fftImage, NormalizeType.Magnitude);
Bitmap color = ImageDataConverter.ToBitmap2d(FourierMagnitudeNormalizedInteger, pixelFormat);
Grayscale.SetPalette(color);
return color;
}
public static Bitmap FftPhasePlot(Complex[,] fftImage, PixelFormat pixelFormat)
{
int[,] FourierPhaseNormalizedInteger = FourierNormalizer.Normalize(fftImage, NormalizeType.Phase);
Bitmap color = ImageDataConverter.ToBitmap2d(FourierPhaseNormalizedInteger, pixelFormat);
Grayscale.SetPalette(color);
return color;
}
}
public partial class FourierNormalizer
{
public static int[,] Normalize(Complex[,] Output, NormalizeType normalizeType)
{
int Width = Output.GetLength(0);
int Height = Output.GetLength(1);
double[,] FourierDouble = new double[Width, Height];
double[,] FourierLogDouble = new double[Width, Height];
int[,] FourierNormalizedInteger = new int[Width, Height];
double max = 0;
if (normalizeType == NormalizeType.Magnitude)
{
for (int i = 0; i <= Width - 1; i++)
{
for (int j = 0; j <= Height - 1; j++)
{
FourierDouble[i, j] = Output[i, j].Magnitude;
FourierLogDouble[i, j] = (double)Math.Log(1 + FourierDouble[i, j]);
}
}
max = FourierLogDouble[0, 0];
}
else
{
for (int i = 0; i <= Width - 1; i++)
{
for (int j = 0; j <= Height - 1; j++)
{
FourierDouble[i, j] = Output[i, j].Phase;
FourierLogDouble[i, j] = (double)Math.Log(1 + Math.Abs(FourierDouble[i, j]));
}
}
FourierLogDouble[0, 0] = 0;
max = FourierLogDouble[1, 1];
}
for (int i = 0; i <= Width - 1; i++)
{
for (int j = 0; j <= Height - 1; j++)
{
if (FourierLogDouble[i, j] > max)
{
max = FourierLogDouble[i, j];
}
}
}
for (int i = 0; i <= Width - 1; i++)
{
for (int j = 0; j <= Height - 1; j++)
{
FourierLogDouble[i, j] = FourierLogDouble[i, j] / max;
}
}
if (normalizeType == NormalizeType.Magnitude)
{
for (int i = 0; i <= Width - 1; i++)
{
for (int j = 0; j <= Height - 1; j++)
{
FourierNormalizedInteger[i, j] = (int)(2000 * FourierLogDouble[i, j]);
}
}
}
else
{
for (int i = 0; i <= Width - 1; i++)
{
for (int j = 0; j <= Height - 1; j++)
{
FourierNormalizedInteger[i, j] = (int)(255 * FourierLogDouble[i, j]);
}
}
}
return FourierNormalizedInteger;
}
}
public static Bitmap ToBitmap3d(int[, ,] image, PixelFormat pixelFormat)
{
int Width = image.GetLength(1);
int Height = image.GetLength(2);
Bitmap bmp = new Bitmap(Width, Height, pixelFormat);
BitmapLocker locker = new BitmapLocker(bmp);
locker.Lock();
int [,] red = ArrayTools<int>.Split(image, 0);
int [,] green = ArrayTools<int>.Split(image, 1);
int [,] blue = ArrayTools<int>.Split(image, 2);
for (int y = 0; y < Height; y++)
{
for (int x = 0; x < Width; x++)
{
int r = red[x,y];
int g = green[x,y];
int b = blue[x,y];
Color clr = Color.FromArgb(r,g,b);
locker.SetPixel(x, y, clr);
}
}
locker.Unlock();
return bmp;
}
This comment solved my problem.
private void button2_Click(object sender, EventArgs e)
{
Bitmap source = (Bitmap)(pictureBox1.Image as Bitmap).Clone();
int[, ,] array3d = ImageDataConverter.ToInteger3d(source);
int[,] red = ArrayTools<int>.Split(array3d, 0);
int[,] green = ArrayTools<int>.Split(array3d, 1);
int[,] blue = ArrayTools<int>.Split(array3d, 2);
Complex[,] cpxRed = ImageDataConverter.ToComplex(red);
Complex[,] cpxGreen = ImageDataConverter.ToComplex(green);
Complex[,] cpxBlue = ImageDataConverter.ToComplex(blue);
Complex[,] fftCpxRed = FourierTransform.ForwardFFT(cpxRed);
Complex[,] fftCpxGreen = FourierTransform.ForwardFFT(cpxGreen);
Complex[,] fftCpxBlue = FourierTransform.ForwardFFT(cpxBlue);
Complex[,] shiftedFftCpxRed = FourierShifter.ShiftFft(fftCpxRed);
Complex[,] shiftedFftCpxGreen = FourierShifter.ShiftFft(fftCpxGreen);
Complex[,] shiftedFftCpxBlue = FourierShifter.ShiftFft(fftCpxBlue);
int[,] normRed = FourierNormalizer.Normalize(shiftedFftCpxRed, NormalizeType.Magnitude);
int[,] normGreen = FourierNormalizer.Normalize(shiftedFftCpxGreen, NormalizeType.Magnitude);
int[,] normBlue = FourierNormalizer.Normalize(shiftedFftCpxBlue, NormalizeType.Magnitude);
Bitmap mag = ImageDataConverter.ToBitmap3d(normRed, normGreen, normBlue, PixelFormat.Format8bppIndexed);
//Grayscale.SetPalette(mag);
//Bitmap mag = FourierPlot.FftMagnitudePlot(shiftedFftCpxRed, PixelFormat.Format8bppIndexed);
Bitmap phase = FourierPlot.FftPhasePlot(shiftedFftCpxRed, PixelFormat.Format8bppIndexed);
pictureBox2.Image = mag;
pictureBox3.Image = mag;
pictureBox4.Image = phase;
}
Related
I have this part of code which converts a bitmap with 32bppArgb pixel format to an 1d byte[] array:
using (var bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb))
{
var boundsRect = new Rectangle(0, 0, width, height);
// Copy pixels from screen capture Texture to GDI bitmap
var mapDest = bitmap.LockBits(boundsRect, ImageLockMode.ReadOnly, bitmap.PixelFormat);
var sourcePtr = mapSource.DataPointer;
var destPtr = mapDest.Scan0;
for (int y = 0; y < height; y++)
{
// Copy a single line
Utilities.CopyMemory(destPtr, sourcePtr, width * 4);
// Advance pointers
sourcePtr = IntPtr.Add(sourcePtr, mapSource.RowPitch);
destPtr = IntPtr.Add(destPtr, mapDest.Stride);
}
// Release source and dest locks
bitmap.UnlockBits(mapDest);
device.ImmediateContext.UnmapSubresource(screenTexture, 0);
using (var ms = new MemoryStream())
{
bitmap.Save(ms, ImageFormat.Bmp);
ScreenRefreshed?.Invoke(this, ms.ToArray());
_init = true;
}
}
I call my function ReplacePixels() to read and replace rgba values like this:
data = ReplacePixels(data);
data is byte[] array received from code above.
The example function which i use but without success:
private byte[] ReplacePixels (byte[] data)
{
int width = Screen.PrimaryScreen.Bounds.Width;
int height = Screen.PrimaryScreen.Bounds.Height;
Int32 curRowOffs = 0;
Int32 stride = 4 * (width * 4 + 31) / 32;
try
{
for (uint y = 0; y < height; y++)
{
// Set offset to start of current row
Int32 curOffs = curRowOffs;
for (uint x = 0; x < width; x++)
{
// ARGB = bytes [B,G,R,A]
var b = data[curOffs];
var g = data[curOffs + 1];
var r = data[curOffs + 2];
var a = data[curOffs + 3];
//bgra changes here..
//apply bgra values
data[offset] = Convert.ToByte(b);
data[offset + 1] = Convert.ToByte(g);
data[offset + 2] = Convert.ToByte(r);
data[offset + 3] = Convert.ToByte(a);
// Increase offset to next colour
curOffs += 4;
}
// Increase row offset
curRowOffs += stride;
}
}
catch (System.Exception e)
{
Debug.WriteLine(e);
}
return data;
}
The question is: how can i read and replace the argb values from this array?
Edit: this is the solution that i found
public byte[] ReplacePixels(byte[] data)
{
int width = Screen.PrimaryScreen.Bounds.Width;
int height = Screen.PrimaryScreen.Bounds.Height;
Int32 stride = width * 4;
Int32 curRowOffs = (((width * height * 4) + 54) - 1) - stride;
for (uint y = 0; y < height; y++)
{
uint index = (uint)curRowOffs;
for (uint x = 0; x < width; x++)
{
// ARGB = bytes [B,G,R,A]
if (index >= 0)
{
//var rgba = GetRGB(data, index);
var b = data[index];
var g = data[index + 1];
var r = data[index + 2];
var a = data[index + 3];
//bgra changes here...
data[index] = b;
data[index + 1] = g;
data[index + 2] = r;
data[index + 3] = a;
}
index += 4;
}
curRowOffs -= stride;
}
return data;
}
I am trying to get color from specific area in an Image.
Assume that , this is image , and I want to get color inside image.(the result should be red of the above image) This color may be different position in image. Because I don't know exact position of color where it starting, so I can't get exact result.
Until now, I cropped image giving manually position of x and y, and then cropped image and I got average color of cropped image. But I know , this is not exact color.
What I tried :
private RgbDto GetRGBvalueCroppedImage(Image croppedImage)
{
var avgRgb = new RgbDto();
var bm = new Bitmap(croppedImage);
BitmapData srcData = bm.LockBits(
new Rectangle(0, 0, bm.Width, bm.Height),
ImageLockMode.ReadOnly,
PixelFormat.Format32bppArgb);
int stride = srcData.Stride;
IntPtr Scan0 = srcData.Scan0;
long[] totals = new long[] { 0, 0, 0 };
int width = bm.Width;
int height = bm.Height;
unsafe
{
byte* p = (byte*)(void*)Scan0;
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
for (int color = 0; color < 3; color++)
{
int idx = (y * stride) + x * 4 + color;
totals[color] += p[idx];
}
}
}
}
avgRgb.avgB = (int)totals[0] / (width * height);
avgRgb.avgG = (int)totals[1] / (width * height);
avgRgb.avgR = (int)totals[2] / (width * height);
return avgRgb;
}
How can I get exact position to crop? May be I can convert image to byte array, then I can find different color and take position of it and then crop. But I have no clue how do this.
You can use something this extension method to get dominant color in a region of an image in case they are not all the same
public static Color GetDominantColor(this Bitmap bitmap, int startX, int startY, int width, int height) {
var maxWidth = bitmap.Width;
var maxHeight = bitmap.Height;
//TODO: validate the region being requested
//Used for tally
int r = 0;
int g = 0;
int b = 0;
int totalPixels = 0;
for (int x = startX; x < (startX + width); x++) {
for (int y = startY; y < (startY + height); y++) {
Color c = bitmap.GetPixel(x, y);
r += Convert.ToInt32(c.R);
g += Convert.ToInt32(c.G);
b += Convert.ToInt32(c.B);
totalPixels++;
}
}
r /= totalPixels;
g /= totalPixels;
b /= totalPixels;
Color color = Color.FromArgb(255, (byte)r, (byte)g, (byte)b);
return color;
}
You can then use it like
Color pixelColor = myBitmap.GetDominantColor(xPixel, yPixel, 5, 5);
there is room for improvement, like using a Point and Size, or even a Rectangle
public static Color GetDominantColor(this Bitmap bitmap, Rectangle area) {
return bitmap.GetDominantColor(area.X, area.Y, area.Width, area.Height);
}
and following this link:
https://www.c-sharpcorner.com/UploadFile/0f68f2/color-detecting-in-an-image-in-C-Sharp/
If you want to get the image colors, you don't need to do any cropping at all. Just loop on image pixels and find the two different colors. (Assuming that you already know the image will have exactly 2 colors, as you said in comments). I've written a small function that will do that. However, I didn't test it in an IDE, so expect some small mistakes:
private static Color[] GetColors(Image image)
{
var bmp = new Bitmap(image);
var colors = new Color[2];
colors[0] = bmp.GetPixel(0, 0);
for (int i = 0; i < bmp.Width; i++)
{
for (int j = 0; j < bmp.Height; j++)
{
Color c = bmp.GetPixel(i, j);
if (c == colors[0]) continue;
colors[1] = c;
return colors;
}
}
return colors;
}
i tried to draw into BMB image and i measure bounding box of each character i want to draw but nothing happen what's the wrong please ?
this is the code which draw the text
private void button2_Click(object sender, EventArgs e)
{
Bitmap bitmap = (Bitmap)Image.FromFile(imagepath);//load the image file
Bitmap newBitmap = new Bitmap(bitmap.Width, bitmap.Height);
PointF GLocation = new PointF(float.Parse(textBox1.Text), float.Parse(textBox2.Text));
/* PointF XLocation = new PointF(float.Parse(textBox3.Text), float.Parse(textBox4.Text));
PointF HLocation = new PointF(float.Parse(textBox5.Text), float.Parse(textBox6.Text));
PointF ZLocation = new PointF(float.Parse(textBox7.Text), float.Parse(textBox8.Text));
PointF YLocation = new PointF(float.Parse(textBox9.Text), float.Parse(textBox10.Text));
PointF KLocation = new PointF(float.Parse(textBox11.Text), float.Parse(textBox12.Text));
PointF FLocation = new PointF(float.Parse(textBox13.Text), float.Parse(textBox14.Text));
PointF ELocation = new PointF(float.Parse(textBox15.Text), float.Parse(textBox16.Text));*/
Graphics grPhoto = Graphics.FromImage(newBitmap);
grPhoto.DrawImage(bitmap, new Rectangle(0, 0, newBitmap.Width, newBitmap.Height), 0, 0, newBitmap.Width, newBitmap.Height, GraphicsUnit.Pixel);
//MessageBox.Show(measureAlphabet('G', arial).ToString());
int x = (int)measureAlphabet('G', arial).Width;
int y = (int)measureAlphabet('G', arial).Height;
Rectangle rec = measureAlphabet('G', arial);
for (int G = int.Parse(textBox1.Text); G <= G + x; G++)
{
for (G = int.Parse(textBox2.Text); G <= G + y; G++)
{
Color pixelcolor = newBitmap.GetPixel(x,y);
if (pixelcolor.R != 255 && pixelcolor.G != 255 && pixelcolor.B != 255)
{
using (Graphics graphics = Graphics.FromImage(newBitmap))
{
using (arial)
{
graphics.DrawString(firstchar, arial, Brushes.Blue, GLocation);
}
}
}
}
}
/* using (Graphics graphics = Graphics.FromImage(newBitmap))
{
using (arial)
{
graphics.DrawString(secondchar, arial, Brushes.Red, XLocation);
graphics.DrawString(thirdchar, arial, Brushes.Brown, HLocation);
graphics.DrawString(fourthchar, arial, Brushes.DarkCyan, ZLocation);
graphics.DrawString(fifthchar, arial, Brushes.DarkGreen, YLocation);
graphics.DrawString(sixthchar, arial, Brushes.Coral, KLocation);
graphics.DrawString(seventhchar, arial, Brushes.Salmon, FLocation);
graphics.DrawString(eighthchar, arial, Brushes.SeaGreen, ELocation);
}
}*/
bitmap.Dispose();
// newBitmap.Dispose();
newBitmap.Save(imagepath);
}
method which measure bounding box
public Rectangle measureAlphabet(char alph, Font font)
{
SizeF size = CreateGraphics().MeasureString(alph.ToString(), font);
Bitmap bmp = new Bitmap((int)size.Width, (int)size.Height);
Graphics grp = Graphics.FromImage(bmp);
grp.FillRectangle(Brushes.White, 0, 0, bmp.Width, bmp.Height);
grp.DrawString(alph.ToString(), font, Brushes.Black, new PointF(0, 0));
Bitmap img = (Bitmap)bmp;
int x = 0, y = 0, width = 0, height = 0;
for (int i = 0; i < img.Width; i++)
for (int j = 0; j < img.Height; j++)
if (img.GetPixel(i, j).B < 2)
{
x = i;
goto jmp1;
}
jmp1:;
for (int i = img.Width - 1; i >= 0; i--)
for (int j = 0; j < img.Height; j++)
if (img.GetPixel(i, j).B < 2)
{
width = i - x;
goto jmp2;
}
jmp2:;
for (int i = 0; i < img.Height; i++)
for (int j = 0; j < img.Width; j++)
if (img.GetPixel(j, i).B < 2)
{
y = i;
goto jmp3;
}
jmp3:;
for (int i = img.Height - 1; i >= 0; i--)
for (int j = 0; j < img.Width; j++)
if (img.GetPixel(j, i).B < 2)
{
height = i - y;
goto jmp4;
}
jmp4:;
Rectangle resultRectangle = new Rectangle(x, y, width, height);
return resultRectangle;
}
Consider the following two routines.
//Tested
///Working fine.
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);
BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, Width, Height),
ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
unsafe
{
byte* address = (byte*)bitmapData.Scan0;
for (i = 0; i < bitmapData.Height; i++)
{
for (j = 0; j < bitmapData.Width; j++)
{
// write the logic implementation here
address[0] = (byte)image[j, i];
address[1] = (byte)image[j, i];
address[2] = (byte)image[j, i];
address[3] = (byte)255;
//4 bytes per pixel
address += 4;
}//end for j
//4 bytes per pixel
address += (bitmapData.Stride - (bitmapData.Width * 4));
}//end for i
}//end unsafe
bitmap.UnlockBits(bitmapData);
return bitmap;// col;
}
//Tested
///Working fine.
public static int[,] ToInteger(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);
unsafe
{
byte* address = (byte*)bitmapData.Scan0;
int paddingOffset = bitmapData.Stride - (bitmap.Width * 4);//4 bytes per pixel
for (int i = 0; i < bitmap.Width; i++)
{
for (int j = 0; j < bitmap.Height; j++)
{
byte[] temp = new byte[4];
temp[0] = address[0];
temp[1] = address[1];
temp[2] = address[2];
temp[3] = address[3];
array2D[j, i] = BitConverter.ToInt32(temp, 0);
//4-bytes per pixel
address += 4;//4-channels
}
address += paddingOffset;
}
}
bitmap.UnlockBits(bitmapData);
return array2D;
}
These two routines work fine for 32bpp images. These routines only work when pixel format is set to PixelFormat.Format32bpp. If I use PixelFormat.Format8bppIndexed, it generates an exception.
In order to avoid that exception (also, I couldn't achieve seamless conversion between byte and int because of address calculation problem), I need to convert that 32 bit Bitmap to gray-scale every time the int[,] is converted back to a Bitmap. I want to get rid of this problem.
Bitmap grayscale = Grayscale.ToGrayscale(InputImage);
//Here, the Bitmap is treated as a 32bit image
//to avoid the exception eventhough it is already
//an 8bpp grayscale image.
int[,] i1 = ImageDataConverter.ToInteger(grayscale);
Complex[,] comp = ImageDataConverter.ToComplex(i1);
int[,] i2 = ImageDataConverter.ToInteger(comp);
Bitmap b2 = ImageDataConverter.ToBitmap(i2);
//It is already a Grayscale image.
//But, the problem is, b2.PixelFormat is set to
//PixelFormat.Formap32bpp because of those routines.
//Hence the unnecessay conversion.
b2 = Grayscale.ToGrayscale(b2);
I need to modify them to operate on 8bpp indexed (grayscale) images only.
How can I achieve that?
If you want to deal with an indexed bitmap, you need to read each byte of the image, and lookup the color from the palette. When you save the image, you'll need to do the reverse logic:
public static Bitmap ToBitmap(int[,] image)
{
int width = image.GetLength(0);
int height = image.GetLength(1);
Bitmap bitmap = new Bitmap(width, height, PixelFormat.Format8bppIndexed);
BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, width, height),
ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
int stride = bitmapData.Stride;
// A dictionary of colors to their index values
Dictionary<int, int> palette = new Dictionary<int, int>();
// A flat list of colors
List<Color> paletteList = new List<Color>();
unsafe
{
byte* address = (byte*)bitmapData.Scan0;
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
// Get the color from the Bitmap
int color = image[x, y];
if (!palette.ContainsKey(color))
{
// This color isn't in the palette, go ahead and add it
palette.Add(color, palette.Count);
paletteList.Add(Color.FromArgb(color));
if (palette.Count >= 256)
{
// The palette is too big. Ideally this function would
// dither some pixels so it could handle this condition
// but that would make this example overly complicated
throw new InvalidOperationException("Too many colors in image");
}
}
// And lookup the index of the color in the palette and
// add it to the BitmapData's memory
address[stride * y + x] = (byte)palette[color];
}
}
}
bitmap.UnlockBits(bitmapData);
// Each time you call Bitmap.Palette it actually returns
// a Clone of the object, so we need to ask for a cloned
// copy here.
var newPalette = bitmap.Palette;
// For each one of our colors, add it to the palette object
for (int i = 0; i < paletteList.Count; i++)
{
newPalette.Entries[i] = paletteList[i];
}
// And since this is a clone, assign it back to the bitmap
// so it'll take effect.
bitmap.Palette = newPalette;
return bitmap;
}
public static int[,] ToInteger(Bitmap bitmap)
{
if (bitmap.Palette.Entries.Length == 0)
{
// This doesn't appear to have a palette, so this operation doesn't
// make sense
throw new InvalidOperationException("bitmap is not an indexed bitmap");
}
int width = bitmap.Width;
int height = bitmap.Height;
int[,] array2D = new int[width, height];
BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, width, height),
ImageLockMode.ReadOnly,
PixelFormat.Format8bppIndexed);
unsafe
{
// Pull out the stride to prevent asking for it many times
int stride = bitmapData.Stride;
byte* address = (byte*)bitmapData.Scan0;
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
// Lookup the color based off the pixel, and set it's value
// to the return array
array2D[x, y] = bitmap.Palette.Entries[address[stride * y + x]].ToArgb();
}
}
}
bitmap.UnlockBits(bitmapData);
return array2D;
}
public static int[,] ToInteger(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.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;
}
I am creating Bitmap object from the same image, but in the end getting different results. It should calculate deviation from the image colors and images are the same so why results are different?
double test1 = GetStdDev("C:\\temp\\images\\file.jpg");
Bitmap img = new Bitmap("C:\\temp\\images\\file.jpg");
double test2 = GetStdDev(img);
public static double GetStdDev(string imageFileName)
{
double total = 0, totalVariance = 0;
int count = 0;
double stdDev = 0;
// First get all the bytes
using (Bitmap b = new Bitmap(imageFileName))
{
BitmapData bmData = b.LockBits(new Rectangle(0, 0, b.Width, b.Height), ImageLockMode.ReadOnly, b.PixelFormat);
int stride = bmData.Stride;
IntPtr Scan0 = bmData.Scan0;
unsafe
{
byte* p = (byte*)(void*)Scan0;
int nOffset = stride - b.Width * 3;
for (int y = 0; y < b.Height; ++y)
{
for (int x = 0; x < b.Width; ++x)
{
count++;
byte blue = p[0];
byte green = p[1];
byte red = p[2];
int pixelValue = Color.FromArgb(0, red, green, blue).ToArgb();
total += pixelValue;
double avg = total / count;
totalVariance += Math.Pow(pixelValue - avg, 2);
stdDev = Math.Sqrt(totalVariance / count);
p += 3;
}
p += nOffset;
}
}
b.UnlockBits(bmData);
}
return stdDev;
}
private static double GetStdDev(Bitmap img)
{
double total = 0, totalVariance = 0;
int count = 0;
double stdDev = 0;
// First get all the bytes
using (Bitmap b = new Bitmap(img))
{
BitmapData bmData = b.LockBits(new Rectangle(0, 0, b.Width, b.Height), ImageLockMode.ReadOnly, b.PixelFormat);
int stride = bmData.Stride;
IntPtr Scan0 = bmData.Scan0;
unsafe
{
byte* p = (byte*)(void*)Scan0;
int nOffset = stride - b.Width * 3;
for (int y = 0; y < b.Height; ++y)
{
for (int x = 0; x < b.Width; ++x)
{
count++;
byte blue = p[0];
byte green = p[1];
byte red = p[2];
int pixelValue = Color.FromArgb(0, red, green, blue).ToArgb();
total += pixelValue;
double avg = total / count;
totalVariance += Math.Pow(pixelValue - avg, 2);
stdDev = Math.Sqrt(totalVariance / count);
p += 3;
}
p += nOffset;
}
}
b.UnlockBits(bmData);
}
return stdDev;
}
Just found solution, it was problem with deep copying bitmap object. instead using new Bitmap(img) use Bitmap img2 = (Bitmap) img.Clone(); don't know it is the right solution, but it does the job.