导入JPEG 8Bpp索引图像仅显示16个灰度值C#

时间:2014-08-01 08:11:19

标签: c# image-processing

所以这是我的问题

我使用扫描仪扫描灰度对象并将其转换为JPEG格式,以便通过C#程序进行分析。图像的像素格式为8BppIndexed。

当我将这个图像导入C#并绘制它的直方图时,我只看到16个灰度值,如下所示:

enter image description here

这些峰值之间的所有值均为0.

这是正常的直方图应该是这样的(不要介意颜色,这个直方图是用另一个工具制作的):

enter image description here

第一个直方图(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循环迭代所有像素。每次我得到相同的结果。

现在这里是有趣的部分:

  1. 当我用任何其他工具(使用其他3个)绘制直方图时,我得到了 正常的直方图。这告诉我信息在图像中,但我的代码无法解决。
  2. 当我扫描完全相同的对象并设置设置以将图像导出为.bmp文件时,c#能够绘制正常的直方图
  3. 使用我在计算机上找到的另一个随机.jpg图像,c#能够绘制正常图像 直方图。
  4. 这些要点告诉我,将图像导入代码的方式可能有问题,所以我尝试了不同的方法来导入图像:

    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图像一样:

    enter image description here

    这听起来对任何人都很熟悉吗?我觉得我已经尝试了一切。还有另一种方法可以解决我尚未找到的问题吗?

    修改

    我以为我找到了一种非常脏的方法来解决我的问题,但确实改变了直方图:

    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图像。任何解决方案?

2 个答案:

答案 0 :(得分:1)

我认为线索属于&#34;索引&#34;在你的第二行。查找表中可能只有16种颜色。您可以发布原始扫描图像,以便我们可以查看其中是否有更多阴影?如果没有,请尝试使用ImageMagick计算颜色

像这样得到直方图:

convert yourimage.jpg -format %c histogram:info:-

convert yourimage.jpg -colorspace rgb -colors 256 -depth 8 -format "%c" histogram:info:

或者计算这样的独特颜色:

identify -verbose yourimage.jpg | grep -i colors:

或者像这样转储所有像素:

convert yourimage.jpg -colorspace rgb -colors 256 -depth 8 txt:

答案 1 :(得分:0)

好吧,我通过打开JPEG并用java中的ImageJ库将其保存为bmp来解决它。我从代码中创建了一个.jar文件,并使用此代码将bmp放入我的c#代码中:

string extension = m_sourceImageFileName.Substring(m_sourceImageFileName.LastIndexOf("."), m_sourceImageFileName.Length - m_sourceImageFileName.LastIndexOf("."));
int exitcode;
ProcessStartInfo ProcessInfo;
Process process;

ProcessInfo = new ProcessStartInfo("java.exe", @"-jar ""C:\Users\stevenh\Documents\Visual Studio 2010\Projects\BlackSpotDetection V2.0\ConvertToBmp\dist\ConvertToBmp.jar"" " + extension + " " + m_sourceImageFileName + " " + m_addedImageName);

ProcessInfo.CreateNoWindow = true;
ProcessInfo.UseShellExecute = false;
// redirecting standard output and error
ProcessInfo.RedirectStandardError = true;
ProcessInfo.RedirectStandardOutput = true;

process = Process.Start(ProcessInfo);

process.WaitForExit();

//Reading output and error
string output = process.StandardOutput.ReadToEnd();
string error = process.StandardError.ReadToEnd();

exitcode = process.ExitCode;
if (exitcode != 0)
{
    statusLabel.Text = output;
    MessageBox.Show("Error in external process: converting image to bmp.\n" + error);
    //Exit code '0' denotes success and '1' denotes failure
    return;
}
else
    statusLabel.Text = "Awesomeness";
process.Close();

Bitmap realImage = AForge.Imaging.Image.FromFile(m_addedImageName);
File.Delete(m_addedImageName);

jar将接收扩展名m_sourceImageFileName和m_addedImageFileName。它将打开sourceImage并以m_addedImageFileName的名称保存它 我正在使用AForge库来打开图像,因为这个库在打开时不会锁定图像,这使我能够删除“自制”图像。