0

我需要对任意图像进行分析。我想从最简单的例子开始 - 只需将图像复制到图片框。

Bitmap foreImg = new Bitmap("input.jpg");
//output image
Bitmap resImg = new Bitmap(foreImg.Width, foreImg.Height);
unsafe
{
    BitmapData oneBits = foreImg.LockBits(new Rectangle(0, 0, foreImg.Width, foreImg.Height), ImageLockMode.ReadOnly, foreImg.PixelFormat);
    BitmapData thrBits = resImg.LockBits(new Rectangle(0, 0, resImg.Width, resImg.Height), ImageLockMode.WriteOnly, resImg.PixelFormat);

    System.Threading.Tasks.Parallel.For(0, foreImg.Width * foreImg.Height, j =>
    {
        Pixel* pxOne = (Pixel*)((byte*)oneBits.Scan0 + j * sizeof(Pixel));
        Pixel* pxRes = (Pixel*)((byte*)thrBits.Scan0 + j * sizeof(Pixel));
        pxRes->Green = pxOne->Green;
        pxRes->Red = pxOne->Red;
        pxRes->Blue = pxOne->Blue;

     });

    foreImg.UnlockBits(oneBits);
    resImg.UnlockBits(thrBits);
}

在我的程序的结果中,图像被扭曲 Original: original_image After: after_image。我究竟做错了什么?

4

2 回答 2

1

谢谢!问题是输入图像的 PixelFormat 与我的 struct Pixel 不匹配。确实,我没有添加 alpha 字节,在这种情况下,我应该使用Format24bppRgb

于 2017-11-01T13:39:16.977 回答
0

由于假设对于复制的特定图像不正确,您的图像复制代码有几个错误。首先假设我们,当您为复制操作创建新目标图像时,它将具有与源图像完全相同的像素表示,这有时可能是正确的,但在许多情况下不会:

Bitmap resImg = new Bitmap(foreImg.Width, foreImg.Height);

应该改为:

Bitmap resImg = new Bitmap(foreImg.Width, foreImg.Height, foreImg.PixelFormat);

根据图像可能会或可能不会出错的下一个假设是一个隐含的假设,即源图像PixelFormat的大小正好是 3 个字节并且对应于PixelFormat.Format24bppRgb格式(或 3 个字节的倍数,因为我不知道红色、绿色的大小是多少或像素结构中的蓝色通道,它可能是PixelFormat.Format48bppRgb格式),因此基于此假设将字节从源图像复制到目标图像。

要执行精确复制,必须将完全相同数量的字节从源图像复制到目标图像,并且不需要使用底层Pixel结构,而是可以基于整数复制。最后但并非最不重要的一点是,如果目标是复制图像而不是逐像素分析其内容,最快的方法是使用专门的内存复制功能:

System.Buffer.MemoryCopy((void*)oneBits.Scan0, (void*)thrBits.Scan0, byteLength, byteLength);

下面有一个代码清单,其中包含使用ulongas复制图像的代码carrier。我添加了以字节为单位返回Pixel大小的函数,用于计算以字节为单位的图像大小并执行精确复制。然而,它可以用来选择匹配Pixel结构,然后可以用来分析图像数据。例如,如果图像具有PixelFormat.Format24bppRgb格式,则可以使用Pixel3 字节大小和 RGB 颜色的结构。对于其他格式,有必要定义Pixel直接复制图像Pixel格式的其他结构。

using System;
using System.Drawing;
using System.Drawing.Imaging;

namespace DrawingImagingOperations
{
    class Program
    {
        static void Main(string[] args)
        {
            Bitmap foreImg = new Bitmap(@"..\..\YaHI9.jpg");
            //output image
            Bitmap resImg = new Bitmap(foreImg.Width, foreImg.Height, foreImg.PixelFormat);
            unsafe
            {
                BitmapData oneBits = foreImg.LockBits(new Rectangle(0, 0, foreImg.Width, foreImg.Height), ImageLockMode.ReadOnly, foreImg.PixelFormat);
                BitmapData thrBits = resImg.LockBits(new Rectangle(0, 0, resImg.Width, resImg.Height), ImageLockMode.WriteOnly, resImg.PixelFormat);
                int pixelSize = GetPixelSize(foreImg.PixelFormat);

                var byteLength = foreImg.Width * foreImg.Height * pixelSize;
                var length = byteLength / sizeof(UInt64);
                var reminder = byteLength % sizeof(UInt64);


                System.Threading.Tasks.Parallel.For(0, length, j =>
                {
                    ulong* pxOne = (ulong*)((byte*)oneBits.Scan0 + j * sizeof(UInt64));
                    ulong* pxRes = (ulong*)((byte*)thrBits.Scan0 + j * sizeof(UInt64));
                    *pxRes = *pxOne;
                });

                if (reminder > 0)
                {
                    byte* pSrc = (byte*)oneBits.Scan0 + (pixelSize * length);
                    byte* pDst = (byte*)thrBits.Scan0 + (pixelSize * length);
                    for (int j = length; j < byteLength; j++)
                        *pDst++ = *pSrc++;

                }

                foreImg.UnlockBits(oneBits);
                resImg.UnlockBits(thrBits);
            }

            resImg.Save(@"..\..\imgCopy.jpg");
        }

        internal static int GetPixelSize(PixelFormat data)
        {
            switch (data)
            {
                case PixelFormat.Format8bppIndexed:
                    return 1;
                case PixelFormat.Format16bppGrayScale:
                case PixelFormat.Format16bppRgb555:
                case PixelFormat.Format16bppRgb565:
                case PixelFormat.Format16bppArgb1555:
                    return 2;
                case PixelFormat.Format24bppRgb:
                    return 3;
                case PixelFormat.Canonical:
                case PixelFormat.Format32bppArgb:
                case PixelFormat.Format32bppPArgb:
                case PixelFormat.Format32bppRgb:
                    return 4;
                case PixelFormat.Format48bppRgb:
                    return 6;
                case PixelFormat.Format64bppArgb:
                case PixelFormat.Format64bppPArgb:
                    return 8;
            }

            throw new FormatException("Unsupported image format: " + data);
        }
    }
}
于 2017-11-01T13:53:03.057 回答