【发布时间】:2014-08-20 15:47:56
【问题描述】:
这是我的问题
我使用扫描仪以灰度扫描对象并将其转换为 JPEG 格式以供 C# 程序分析。图片的像素格式为 8BppIndexed。
当我将此图像导入 C# 并绘制它的直方图时,我只看到 16 个灰度值,如下所示:
这些峰值之间的所有值都是 0。
这是正常直方图的样子(不要介意颜色,这个直方图是用其他工具制作的):
第一个直方图 (int[]) 由以下代码构成:
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;
}
为了确保这段代码不是问题,我尝试使用 AForge.Math.Histogram 方式,甚至使用 for - in - for 循环来遍历所有像素。每次我得到相同的结果。
现在是有趣的部分:
- 当我使用任何其他工具(使用其他 3 个工具)绘制直方图时,我得到 一个正常的直方图。这告诉我信息在图像中,但我的代码无法将其取出。
- 当我扫描完全相同的对象并设置设置以将图像导出为 .bmp 文件时,c# 能够绘制正常的直方图
- 使用我在计算机上找到的另一个随机 .jpg 图像,c# 能够绘制正常的 直方图。
这些点告诉我,我将图像导入代码的方式可能有问题,因此我尝试了不同的方式来导入图像:
Bitmap bmp = (Bitmap)Bitmap.FromFile(path);
或
Bitmap bmp = AForge.Imaging.Image.FromFile(path);
或
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);
没有一个给出的直方图与只有 16 个结果的直方图不同。
我不能在我的扫描仪中使用 .bmp 扩展名,因为我需要制作大量图像,而一张 .bmp 图像大约是 200mb(是的,图像需要高分辨率),而 .jpg 只是大约30mb。另外,我已经制作了很多无法重新制作的 .jpg 图片,因为已扫描的对象已不存在。
注意:我知道使用 .jpg 扩展名是压缩图像的一种有损方式。这不是当前的问题。
这是使用与第一个完全相同的代码创建的直方图,与我计算机中另一个随机 .jpg 图像的样子:
这听起来对任何人来说都很熟悉吗?我觉得我什么都试过了。有没有其他方法可以解决这个我还没有找到的问题?
编辑
我以为我找到了一种非常肮脏的方法来解决我的问题,但它确实改变了直方图:
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;
这是新的直方图:
如您所见,它与直方图的外观不同。 我发现问题可能是因为图像是 8bppIndexed jpeg 图像,而 jpeg 仅支持 24bppRgb 图像。有什么解决办法吗?
【问题讨论】:
标签: c# image-processing