在 C# 中从图像中获取 RGB 数组

发布于 2024-10-13 04:08:43 字数 197 浏览 5 评论 0原文

我目前正在编写一个用 Java 编写的小程序的 C# 实现。

我在 Java 应用程序中使用了 BufferedImage.getRGB(int startX, int startY, int w, int h, int[] rgbArray, int offset, int scansize) 函数。但我在 C# 中找不到这个版本,而且我不知道如何手动编写它。

I'm currently writing a C# implementation of a little program which I have written in Java.

I had used BufferedImage.getRGB(int startX, int startY, int w, int h, int[] rgbArray, int offset, int scansize) function in my Java app. But I couldn't exactly find a version of this in C# and I am not sure how to write it manually.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

物价感观 2024-10-20 04:08:43

.NET Framework 中没有与此方法直接等效的方法。但是,如果您的图像是 System.Drawing.Bitmap,则可以调用 LockBits 方法,这将返回包含第一条扫描线的地址的 BitmapData 结构。然后,您可以使用它来创建与 API 兼容的包装器。我假设您使用的是 C# 3.5 或更高版本,因此我使用的是扩展方法 - 如果您使用的是旧版本,请通过从位图参数中删除“this”将其更改为常规方法

    public static void getRGB(this Bitmap image, int startX, int startY, int w, int h, int[] rgbArray, int offset, int scansize)
    {
        const int PixelWidth = 3;
        const PixelFormat PixelFormat = PixelFormat.Format24bppRgb;

        // En garde!
        if (image == null) throw new ArgumentNullException("image");
        if (rgbArray == null) throw new ArgumentNullException("rgbArray");
        if (startX < 0 || startX + w > image.Width) throw new ArgumentOutOfRangeException("startX");
        if (startY < 0 || startY + h > image.Height) throw new ArgumentOutOfRangeException("startY");
        if (w < 0 || w > scansize || w > image.Width) throw new ArgumentOutOfRangeException("w");
        if (h < 0 || (rgbArray.Length < offset + h * scansize) || h > image.Height) throw new ArgumentOutOfRangeException("h");

        BitmapData data = image.LockBits(new Rectangle(startX, startY, w, h), System.Drawing.Imaging.ImageLockMode.ReadOnly, PixelFormat);
        try
        {
            byte[] pixelData = new Byte[data.Stride];
            for (int scanline = 0; scanline < data.Height; scanline++)
            {
                Marshal.Copy(data.Scan0 + (scanline * data.Stride), pixelData, 0, data.Stride);
                for (int pixeloffset = 0; pixeloffset < data.Width; pixeloffset++)
                {
                    // PixelFormat.Format32bppRgb means the data is stored
                    // in memory as BGR. We want RGB, so we must do some 
                    // bit-shuffling.
                    rgbArray[offset + (scanline * scansize) + pixeloffset] = 
                        (pixelData[pixeloffset * PixelWidth + 2] << 16) +   // R 
                        (pixelData[pixeloffset * PixelWidth + 1] << 8) +    // G
                        pixelData[pixeloffset * PixelWidth];                // B
                }
            }
        }
        finally
        {
            image.UnlockBits(data);
        }
    }

:现在可以这样调用:

        Bitmap foo = Bitmap.FromFile(@"somefile.jpg") as Bitmap;
        int[] rgbArray = new int[100];
        foo.getRGB(1, 1, 10, 10, rgbArray, 0, 10);

希望这有帮助,欢迎使用 .NET!

There's not a direct equivalent in the .NET Framework to this method. However, if your image is a System.Drawing.Bitmap, you can call the LockBits method, and this will return a BitmapData structure that contains the address of the first scanline. You can then use it to create what should be an API-compatible wrapper. I'm assuming you're using C# 3.5 or greater, so I'm using an extension method - if you're using an older flavor, change this to a regular method by dropping the 'this' from the Bitmap argument:

    public static void getRGB(this Bitmap image, int startX, int startY, int w, int h, int[] rgbArray, int offset, int scansize)
    {
        const int PixelWidth = 3;
        const PixelFormat PixelFormat = PixelFormat.Format24bppRgb;

        // En garde!
        if (image == null) throw new ArgumentNullException("image");
        if (rgbArray == null) throw new ArgumentNullException("rgbArray");
        if (startX < 0 || startX + w > image.Width) throw new ArgumentOutOfRangeException("startX");
        if (startY < 0 || startY + h > image.Height) throw new ArgumentOutOfRangeException("startY");
        if (w < 0 || w > scansize || w > image.Width) throw new ArgumentOutOfRangeException("w");
        if (h < 0 || (rgbArray.Length < offset + h * scansize) || h > image.Height) throw new ArgumentOutOfRangeException("h");

        BitmapData data = image.LockBits(new Rectangle(startX, startY, w, h), System.Drawing.Imaging.ImageLockMode.ReadOnly, PixelFormat);
        try
        {
            byte[] pixelData = new Byte[data.Stride];
            for (int scanline = 0; scanline < data.Height; scanline++)
            {
                Marshal.Copy(data.Scan0 + (scanline * data.Stride), pixelData, 0, data.Stride);
                for (int pixeloffset = 0; pixeloffset < data.Width; pixeloffset++)
                {
                    // PixelFormat.Format32bppRgb means the data is stored
                    // in memory as BGR. We want RGB, so we must do some 
                    // bit-shuffling.
                    rgbArray[offset + (scanline * scansize) + pixeloffset] = 
                        (pixelData[pixeloffset * PixelWidth + 2] << 16) +   // R 
                        (pixelData[pixeloffset * PixelWidth + 1] << 8) +    // G
                        pixelData[pixeloffset * PixelWidth];                // B
                }
            }
        }
        finally
        {
            image.UnlockBits(data);
        }
    }

This wrapper can now be called like this:

        Bitmap foo = Bitmap.FromFile(@"somefile.jpg") as Bitmap;
        int[] rgbArray = new int[100];
        foo.getRGB(1, 1, 10, 10, rgbArray, 0, 10);

Hope this helps, and welcome to .NET!

自演自醉 2024-10-20 04:08:43

您可以使用 Bitmap.LockBits 直接访问位图中的像素。这是一个示例实现,它从传递的位图中返回一条扫描线作为 int[]:

    int[] getRGB(Bitmap bmp, int line) {
        var data = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height),
            System.Drawing.Imaging.ImageLockMode.ReadOnly,
            System.Drawing.Imaging.PixelFormat.Format32bppRgb);
        try {
            var ptr = (IntPtr)((long)data.Scan0 + data.Stride * (bmp.Height - line - 1));
            var ret = new int[bmp.Width];
            System.Runtime.InteropServices.Marshal.Copy(ptr, ret, 0, ret.Length * 4);
            return ret;
        }
        finally {
            bmp.UnlockBits(data);
        }
    }

You'd use Bitmap.LockBits to get direct access to the pixels in a bitmap. Here's a sample implementation, it returns one scanline from the passed bitmap as an int[]:

    int[] getRGB(Bitmap bmp, int line) {
        var data = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height),
            System.Drawing.Imaging.ImageLockMode.ReadOnly,
            System.Drawing.Imaging.PixelFormat.Format32bppRgb);
        try {
            var ptr = (IntPtr)((long)data.Scan0 + data.Stride * (bmp.Height - line - 1));
            var ret = new int[bmp.Width];
            System.Runtime.InteropServices.Marshal.Copy(ptr, ret, 0, ret.Length * 4);
            return ret;
        }
        finally {
            bmp.UnlockBits(data);
        }
    }
想挽留 2024-10-20 04:08:43

我认为最接近的是 Bitmap.GetPixel(x,y) ,它在某个点返回单个像素颜色。
为了模拟java函数,您需要编写一些帮助程序。

I think the closest one is Bitmap.GetPixel(x,y) that return a single pixel color at a point.
In order to simulate the java function, you will need to write some helper.

梦晓ヶ微光ヅ倾城 2024-10-20 04:08:43

您可能需要检查

另请检查 < a href="https://stackoverflow.com/questions/392324/converting-an-array-of-pixels-to-an-image-in-c">在 C# 中将像素数组转换为图像。

夏至、离别 2024-10-20 04:08:43

这取决于你需要多快地完成它。

BitmapGetPixel() 方法,可以很好地处理像素。

如果您需要进行快速图像处理,则需要使用LockBits,您可以在此处找到示例。

Bitmap img = (Bitmap) Image.FromFile(imageFileName);
BitmapData data = img.LockBits(new Rectangle(0,0,img.Width, img.Height), ImageLockMode.ReadWrite, img.PixelFormat);
byte* ptr = (byte*) data.Scan0;
for (int j = 0; j < data.Height; j++)
{
    byte* scanPtr = ptr + (j * data.Stride);
    for (int i = 0; i < data.width; i++, scanPtr+=NO_OF_CHANNELS)
    {
        for (int m = 0; m < NO_OF_CHANNELS; m++)
            Console.WriteLine(*scanPtr); // value of each channel
    }
}

img.UnlockBits(data);

It depends how fast you need to do it.

Bitmap has GetPixel() method which works fine for a pixel.

If you need to do fast image processing you need to use LockBits which you can find a sample here.

Bitmap img = (Bitmap) Image.FromFile(imageFileName);
BitmapData data = img.LockBits(new Rectangle(0,0,img.Width, img.Height), ImageLockMode.ReadWrite, img.PixelFormat);
byte* ptr = (byte*) data.Scan0;
for (int j = 0; j < data.Height; j++)
{
    byte* scanPtr = ptr + (j * data.Stride);
    for (int i = 0; i < data.width; i++, scanPtr+=NO_OF_CHANNELS)
    {
        for (int m = 0; m < NO_OF_CHANNELS; m++)
            Console.WriteLine(*scanPtr); // value of each channel
    }
}

img.UnlockBits(data);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文