【问题标题】:Render 16 bits image in picturebox在图片框中渲染 16 位图像
【发布时间】:2017-09-30 16:06:19
【问题描述】:

我有一个数组,它包含从 Dicom 图像中提取的 PixelData。

代码如下:

        byte[] bytes = img.PixelData.GetFrame(0).Data; // img is the Dicom Image
        int count = bytes.Length / 2;
        ushort[] words = new ushort[count];
        for (int i = 0, p = 0; i < count; i++, p += 2)
        {
            words[i] = BitConverter.ToUInt16(bytes, p);
        }
        pixels16 = words.ToList(); //pixels16 contains now the PixelData for the Grayscale image

现在,我的问题是,如何将它渲染到 Picturebox 中??

【问题讨论】:

    标签: c# picturebox pixel


    【解决方案1】:

    我将位图从 Format16bppGrayScale 转换为 Format8bppIndexed 格式的代码。 PictureBox 可以轻松展示这种格式。 (如果你愿意,你可以使用不同的调色板)。

    public Bitmap Gray16To8bppIndexed(Bitmap BmpIn)
    {
        if (BmpIn.PixelFormat != PixelFormat.Format16bppGrayScale)
            throw new BadImageFormatException();
    
        byte[] ImageData = new byte[BmpIn.Width * BmpIn.Height * 2];
        Rectangle Re = new Rectangle(0, 0, BmpIn.Width, BmpIn.Height);
    
        BitmapData BmpData = BmpIn.LockBits(Re, ImageLockMode.ReadOnly, BmpIn.PixelFormat);
        Marshal.Copy(BmpData.Scan0, ImageData, 0, ImageData.Length);
        BmpIn.UnlockBits(BmpData);
    
        byte[] ImageData2 = new byte[BmpIn.Width * BmpIn.Height];
        for (long i = 0; i < ImageData2.LongLength; i++)
            ImageData2[i] = ImageData[i * 2 + 1];
        ImageData = null;
    
        Bitmap BmpOut = new Bitmap(BmpIn.Width, BmpIn.Height, PixelFormat.Format8bppIndexed);
        BmpData = BmpOut.LockBits(Re, ImageLockMode.WriteOnly, BmpOut.PixelFormat);
        Marshal.Copy(ImageData2, 0, BmpData.Scan0, ImageData2.Length);
        BmpOut.UnlockBits(BmpData);
        ImageData2 = null;
        BmpData = null;
    
        ColorPalette GrayPalette = BmpOut.Palette;
        Color[] GrayColors = GrayPalette.Entries;
        for (int i = 0; i < GrayColors.Length; i++)
            GrayColors[GrayColors.Length - 1 - i] = Color.FromArgb(i, i, i);
        BmpOut.Palette = GrayPalette;
    
        return BmpOut;
    }
    

    【讨论】:

    • 我不得不更改“ImageData2[i] = ImageData[i * 2 + 1];”这一行通过删除“+ 1”,所以我猜在我的情况下,由于某种原因,字节顺序是相反的。但现在您的解决方案效果很好!
    【解决方案2】:

    好吧,我不知道具体细节,因为这取决于您真正想要如何去做(如果性能很重要,您需要创建自己的 Bitmap 子类,否则,Bitmap.SetPixel 可以正常工作)。

    但本质上,您需要将这些像素推入位图,然后将图片框的图像设置为该位图,例如:

    Bitmap bitmap = new Bitmap(width, height);
    
    for(int y = 0;y < height;y++)
       for(int x = 0;x < width;x++)
           bitmap.SetPixel(x,y, Color.fromRGB(/* unpack your R,G,B channel of your pixel here */);
    
    pictureBox.Image = bitmap;
    

    【讨论】:

    • 我会试一试的。我也试过这个:MemoryStream ms = new MemoryStream(bytes);Image returnImage = Image.FromStream(ms); 但我得到一个错误
    • 只有当 'bytes' 包含与 JPG 或 PNG 中相同类型的打包图像数据时,它才会起作用。它会自动找出您传递给它的图像类型并像文件一样读取它。但是,您的 img 是已加载的未打包图像,因此我怀疑 Image.FromStream 方法是否适合您。
    • 所以如果我把像素塞进位图中,我会不会因为 bmp 通常是 24bpp 或 32bpp 而失去 16bpp 格式?这背后的整个想法是稍后当用户单击图片框中的一个点时获得正确的像素值。如果我使用 bmp,我基本上会给出 24bpp 值而不是 16bpp 值,对吗?
    • 嗯,Bitmap 实际上有许多不同的方式来存储图像数据。您可以在创建位图时指定像素的格式,因此您可以根据需要选择保持 16bpp。我认为 Bitmap 有一种构造方法,它采用宽度、高度和 PixelFormat。实际上,来自下面的 boli:System.Drawing.Bitmap bitmapImage = new System.Drawing.Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format16bppGrayScale);
    • 但除此之外,您也可以只显示一个 24bpp 的图像,然后,当用户单击一个像素时,您可以从原始图像中采样以获取确切的颜色。我想这取决于你在做什么。
    【解决方案3】:

    您可以利用 AForge .NET Framework,这是一个用于图像处理的出色 .NET 库。内置的 .NET Picturebox 无法使用 System.Drawing.Imaging.PixelFormat.Format16bppGrayScale 显示图像,但 AForge 库有自己的Picturebox 控件,请查看此。它expects 一个 .NET 映像。

    您可以使用 NuGet 轻松地将 AForge 包含到您的项目中:

    Install-Package AForge.Controls
    Install-Package AForge.Imaging
    

    或者只是

    Install-Package AForge

    示例代码如下:

    //SOME BYTES
    //Load here the DICOM image
    int width=640, height=480;
    int numberOfPixels = width*height;
    byte[] source = new byte[2*numberOfPixels];
    
    //With AFORGE
    var image = AForge.Imaging.UnmanagedImage.Create(width, height, System.Drawing.Imaging.PixelFormat.Format16bppGrayScale);
    IntPtr ptrToImage = image.ImageData;
    //Copies the bytes from source to the image
    //System.Runtime.InteropServices
    Marshal.Copy(source, 0, ptrToImage,numberOfPixels);
    
    //WITH .NET
    System.Drawing.Bitmap bitmapImage = new System.Drawing.Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format16bppGrayScale);
    var imageData = bitmapImage.LockBits(new System.Drawing.Rectangle(0, 0, width, height), System.Drawing.Imaging.ImageLockMode.ReadWrite, System.Drawing.Imaging.PixelFormat.Format16bppGrayScale);
    Marshal.Copy(source, 0, imageData.Scan0, numberOfPixels);
    bitmapImage.UnlockBits(imageData);   
    

    【讨论】:

    • 谢谢,您在上面使用 .NET 编写的代码实际上适用于 16bpp 图像?
    • 我以前用过 Marshal.Copy,但不是在 16 bpp 图像上。我认为它应该可以工作,但不要忘记使用 AForge 的 Picturebox。将 16 位像素值缩放为 8 位像素值也可以。
    • 我尝试了 .net 代码但没有用(我在图片框的位置看到一个红十字)我所做的是:picbox_mpr.Image = imageData; 在最后一行之后
    • 好的,我尝试了 Aforge 并且工作正常,但是您如何将图像分配给 aforge 图片框?
    • picbox_mpr.Image = imageData;不会工作。 imageData 变量保存有关托管位图的信息(内存中的位置,...)。当您调用 LockBits 时,Bitmap 将被固定在内存中,这就是您可以轻松使用它的原因,没有任何风险。你应该试试 picbox_mpr.Image = bitmapImage;我也认为,而不是 Marshal.Copy(source, 0, imageData.Scan0, ​​numberOfPixels);试试 Marshal.Copy(source, 0, imageData.Scan0, ​​2*numberOfPixels);,因为源(即 byte[])也有 2*numberOfPixels 个元素。 msdn.microsoft.com/en-us/library/ms146625.aspx
    【解决方案4】:

    从朋友那里得到这个想法。 inputImage.ImageSource 属性是一个具有灰度像素值的二维数组。

    Bitmap grayscaleImage = new Bitmap(inputImage.ImageSource);
                for (int x = 0; x < grayscaleImage.Width; x++)
                {
                    for (int y = 0; y < grayscaleImage.Height; y++)
                    {
                        byte[,] tempMatrix = inputImage.ImageGrayscale;
                        byte temp = tempMatrix[x, y];
                        Color tempColor = Color.FromArgb(255, temp, temp, temp);
                        grayscaleImage.SetPixel(x, y, tempColor);
                    }
                }
                picboxDisplay.Image = grayscaleImage;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-02-03
      • 2016-07-13
      • 1970-01-01
      • 2015-09-04
      • 2021-02-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多