将grey8(8bit)图像转换为rgb888(24位)图像

时间:2016-03-10 14:37:45

标签: c# image .net-4.5

我的问题是何时拍摄8位灰度图像并将其转换为24位rgb24bpp我的图像会放大并且色阶会混淆(请参阅3)。 我的计划是通过客户端 - 服务器实现在我的程序中显示GigE-Cam。因此,由于日期问题,我需要将图片变得灰度化,但我只能得到这个错误尺寸和相应的图片。只有当我将它们转换为myImage / myImageFormat时才会发生这种情况。我的问题是我之后需要测量图片。

我用来转换图像的代码如下:

public myImage(Bitmap bmp, myImageFormat format)
    {
        if (bmp == null)
        {
            throw new ArgumentNullException("bmp");
        }

        this.Height = bmp.Height;
        this.Width = bmp.Width;
        this.Format = format;

        // copy bmp matrix without padding to rgb or grey array     
        Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
        //if (format == myImageFormat.Grey8)
        //{ return; }
        //else
        //{
            int factor = 3;
            if (format == myImageFormat.Grey8)
            {
                factor = 1;

                // save grey scale palette
                m_colorPaletteColorData = new Color[bmp.Palette.Entries.Length];
                for (int i = 0; i < bmp.Palette.Entries.Length; i++)
                {
                    m_colorPaletteColorData[i] = bmp.Palette.Entries[i];
                }
                //return;
            }
            else if (format == myImageFormat.Rgb888
                && bmp.PixelFormat == PixelFormat.Format8bppIndexed)
            {
                // convert all type of bitmaps to 24-Bit bitmaps by using GDI+
                Bitmap bmp24 = new Bitmap(bmp.Width, bmp.Height, PixelFormat.Format24bppRgb);
                bmp24.SetResolution(bmp.HorizontalResolution, bmp.VerticalResolution); // prevent resolution conversion
                using (Graphics g = Graphics.FromImage(bmp24))
                {
                    g.PageUnit = GraphicsUnit.Pixel; // prevent DPI conversion
                    g.DrawImageUnscaled(bmp, 0, 0, bmp.Width, bmp.Height);
                }
                bmp = bmp24;
            }

            BitmapData bmpData = bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadOnly, bmp.PixelFormat); // LOCKED

            int bytes = bmp.Height * bmp.Width * factor;
            int byteIndex = 0;
            m_imageData = new byte[bytes];
            unsafe
            {
                for (int y = 0; y < bmpData.Height; y++)
                {
                    byte* row = (byte*)bmpData.Scan0 + (y * bmpData.Stride);
                    for (int x = 0; x < bmpData.Width; x++)
                    {
                        m_imageData[byteIndex] = row[x * factor];
                        byteIndex++;

                        if (format == myImageFormat.Rgb888)
                        {
                            m_imageData[byteIndex] = row[x * factor + 1];
                            byteIndex++;
                            m_imageData[byteIndex] = row[x * factor + 2];
                            byteIndex++;
                        }
                    }
                }
            }

            bmp.UnlockBits(bmpData); // UNLOCKED
        //}
    }

    /// <summary>
    /// returns a 8bppGrey or 24bppRgb Bitmap
    /// </summary>
    public Bitmap ToBitmap()
    {
        if (m_imageData == null)
        {
            throw new InvalidOperationException("Internal image data does not exist!");
        }

        PixelFormat pixelFormat;
        int factor = 3;
        if (this.Format == myImageFormat.Grey8)
        {
            pixelFormat = PixelFormat.Format8bppIndexed;
            factor = 1;
        }
        else
        {
            pixelFormat = PixelFormat.Format24bppRgb;
        }

        m_bmp = new Bitmap(this.Width, this.Height, pixelFormat);
        Rectangle rect = new Rectangle(0, 0, this.Width, this.Height);
        BitmapData bmpData = m_bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.WriteOnly, pixelFormat); // LOCKED

        int counter = 0;
        unsafe
        {
            for (int y = 0; y < bmpData.Height; y++)
            {
                byte* row = (byte*)bmpData.Scan0 + (y * bmpData.Stride);
                for (int x = 0; x < bmpData.Width; x++)
                {
                    byte color = m_imageData[counter];

                    row[x * factor] = color;
                    counter++;

                    if (this.Format == myImageFormat.Rgb888)
                    {
                        row[x * factor + 1] = m_imageData[counter];
                        counter++;
                        row[x * factor + 2] = m_imageData[counter];
                        counter++;
                    }
                }
            }
        }

        // copy original grayscale color palette, otherwise it will be a 8bit RGB bitmap
        if (this.Format == myImageFormat.Grey8)
        {
            ColorPalette palette = m_bmp.Palette;
            Color[] entries = palette.Entries;
            if (m_colorPaletteColorData.Length >= entries.Length)
            {
                for (int i = 0; i < entries.Length; i++)
                {
                    entries[i] = m_colorPaletteColorData[i];
                }
            }
            m_bmp.Palette = palette;
        }

        m_bmp.UnlockBits(bmpData); // UNLOCKED            
        return m_bmp;
    }

任何人都可以帮我解决这个问题吗?

The Grey8 image converted into an RGB24

1 个答案:

答案 0 :(得分:0)

如果传入24位位图以转换为8位灰色,则无法复制有效的源调色板,因为24位格式未编入索引。因此,当您将调色板从24位源图像(在构造函数中)保存到m_colorPaletteColorData[]然后将其设置在8位灰度图像(在ToBitmap()中)时,该调色板实际包含什么?在构造函数中,当源是24位(因此没有有效的调色板)时,您需要创建一个新的灰度调色板,而不是尝试将其从非索引图像中复制出来。

另一个小点,当在两个方向(8到24,24到8)进行转换时,您可以直接将一个图像的字节分配给另一个图像;因此,如果一个是打算调色的8位图像,另一个是24位图像,则指定一个调色板索引作为颜色分量的每个R,G和B值,或指定一个color component作为索引。

如果调色板保证是线性渐变,其中每个索引与灰度阴影相匹配,但是基于调色板的图像很少使用完美组织的调色板,所以这是一个危险的假设。为了使其正常工作,您应该在分配到24位图像之前将8位索引值转换为调色板中的颜色值,并在分配时从24位值中查找调色板中最接近的匹配项到8位灰度图像。