So here is my problem
I've used a scanner to scan an object in greyscale and convert it into a JPEG format to be analyzed by a C# program. The image's pixelformat is 8BppIndexed.
When I import this image into C# and draw a histogram of it, I only see 16 grayscale values, like this:
All the values in between these peaks are 0.
This is what the normal histogram should look like (don't mind the colors, this histogram is made with another tool):
The first histogram (int[]) is formed with this code:
public static int[] GetHistogram(Bitmap b)
{
int[] myHistogram = new int[256];
for (int i = 0; i < myHistogram.Length; i++)
myHistogram[i] = 0;
BitmapData bmData = null;
try
{
//Lock it fixed with 32bpp
bmData = b.LockBits(new Rectangle(0, 0, b.Width, b.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
int scanline = bmData.Stride;
System.IntPtr Scan0 = bmData.Scan0;
unsafe
{
byte* p = (byte*)(void*)Scan0;
int nWidth = b.Width;
int nHeight = b.Height;
for (int y = 0; y < nHeight; y++)
{
for (int x = 0; x < nWidth; x++)
{
long Temp = 0;
Temp += p[0]; // p[0] - blue, p[1] - green , p[2]-red
Temp += p[1];
Temp += p[2];
Temp = (int)Temp / 3;
myHistogram[Temp]++;
//we do not need to use any offset, we always can increment by pixelsize when
//locking in 32bppArgb - mode
p += 4;
}
}
}
b.UnlockBits(bmData);
}
catch
{
try
{
b.UnlockBits(bmData);
}
catch
{
}
}
return myHistogram;
}
To be sure this code is not the problem, I've tried using the AForge.Math.Histogram way and even a for - in - for loop to iterate through all pixels. Each time I get the same result.
Now here is the funny part(s):
- When I draw the histogram with any other tool (used 3 others), I get a normal histogram. This tells me that the information is within the image, but my code just can't get it out.
- When I scan the exact same object and set the settings to export the image into a .bmp file, c# is able to draw a normal histogram
- With another random .jpg image I found on my computer, c# is able to draw a normal histogram.
These points tell me that there is probably something wrong with the way that I import the image into my code, so I tried different ways to import the image:
Bitmap bmp = (Bitmap)Bitmap.FromFile(path);
or
Bitmap bmp = AForge.Imaging.Image.FromFile(path);
or
Stream imageStreamSource = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read);
System.Windows.Media.Imaging.JpegBitmapDecoder decoder = new System.Windows.Media.Imaging.JpegBitmapDecoder(imageStreamSource, System.Windows.Media.Imaging.BitmapCreateOptions.PreservePixelFormat, System.Windows.Media.Imaging.BitmapCacheOption.Default);
System.Windows.Media.Imaging.BitmapSource bitmapSource = decoder.Frames[0];
System.Windows.Controls.Image image = new System.Windows.Controls.Image();
image.Source = bitmapSource;
image.Stretch = System.Windows.Media.Stretch.None;
MemoryStream ms = new MemoryStream();
var encoder = new System.Windows.Media.Imaging.BmpBitmapEncoder();
encoder.Frames.Add(System.Windows.Media.Imaging.BitmapFrame.Create(image.Source as System.Windows.Media.Imaging.BitmapSource));
encoder.Save(ms);
ms.Flush();
System.Drawing.Image myImage = System.Drawing.Image.FromStream(ms);
Bitmap bmp = (Bitmap)Bitmap.FromStream(ms);
None of which gave a different histogram than the one with just 16 results.
I can not use the .bmp extension in my scanner, because I need to make a great many images and one .bmp image is around 200mb (yea, the images need a high resolution), while the .jpg is only around 30mb. Plus I've already made many .jpg images that can not be remade because the objects that have been scanned no longer exist.
NOTE: I know that using the .jpg extension is a lossy way to compress the images. That is not the current issue.
This is what a histogram, created with the exact same code as the first one, looks like with another random .jpg image from my computer:
Does this sound familiar to anyone? I feel like I've tried everything. Is there another way to solve this problem that I have not yet found?
EDIT
I thought I had found an extremely dirty way to fix my problem, but it does change the histogram:
Bitmap temp = (Bitmap)Bitmap.FromFile(m_sourceImageFileName);
if (temp.PixelFormat == PixelFormat.Format8bppIndexed ||
temp.PixelFormat == PixelFormat.Format4bppIndexed ||
temp.PixelFormat == PixelFormat.Format1bppIndexed ||
temp.PixelFormat == PixelFormat.Indexed)
{
//Change pixelformat to a format that AForge can work with
Bitmap tmp = temp.Clone(new Rectangle(0, 0, temp.Width, temp.Height), PixelFormat.Format24bppRgb);
//This is a super dirty way to make sure the histogram shows more than 16 grey values.
for (int i = 0; true; i++)
{
if (!File.Exists(m_sourceImageFileName + i + ".jpg"))
{
tmp.Save(m_sourceImageFileName + i + ".jpg");
tmp.Dispose();
temp = AForge.Imaging.Image.FromFile(m_sourceImageFileName + i + ".jpg");
File.Delete(m_sourceImageFileName + i + ".jpg");
break;
}
}
}
Bitmap properImage = temp;
This is the new histogram:
As you can see, it's not the same as what the histogram should look like. I found out that the problem might be because the image is an 8bppIndexed jpeg image, and jpeg only supports 24bppRgb images. Any solutions?