【问题标题】:Get all pixels of specified color from PictureBox从 PictureBox 中获取指定颜色的所有像素
【发布时间】:2014-11-14 11:25:54
【问题描述】:

我想在 C# 中获取指定颜色的所有像素(来自 ARGB 或来自 Color 类的任何像素)。我的第一个想法是将图片框内容绘制成Bitmap,然后使用for 循环,使用b.GetPixel(x, y); 遍历像素。但是,我使用的 PictureBox 很大,因此需要几百万/几千万次迭代来检查它,这对性能来说太不友好了。有没有人有比这更好的解决方案?谢谢

【问题讨论】:

  • 您正在寻找Bitmap.Lockbits
  • 我几乎看不出如何在不检查每个像素的情况下验证每个像素并选择所需的像素。看起来你被 O(n) 困住了,除非你当然使用会降低准确性的启发式算法(比如预测周围的像素)。这就像试图在不遍历每个元素的情况下计算一个数组,你被限制为 O(n),这是不可能的。无论如何,您可能会发现的替代方案可能都依赖于在内部逐个查看每个像素。
  • 您要处理的图像有多大?也许使用前面评论中提到的Lockbits() 并将其与不安全的图像处理代码结合起来,尽管检查了每个像素,但您可以获得可接受的性能。
  • 使用 LockBits 非常快;不过,我希望你不是实时进行的..!
  • 我刚刚编写了一个示例代码来逐个像素地检查颜色,并使用Lockbits()unsafe 像素数据访问来计算匹配像素的数量,在我的机器上它花了大约 90 毫秒处理 1920x1080 图像(2073600 像素要检查)。您可以在此处找到一些不安全的像素数据访问示例:ithoughthecamewithyou.com/post/…。如果您在实施过程中需要帮助,请告诉我。

标签: c# winforms picturebox


【解决方案1】:

我为 System.Drawing.Image 编写了扩展方法,它遍历图像中的每个像素并返回一个包含每个 x/y 坐标的列表作为 System.Drawing.Point。
您可以搜索 rgb 值或 rgba 值。
我的方法是使用指针,所以您需要为您的项目启用不安全代码。
与 GetPixel(...) 相比,使用指针迭代位图要快很多倍。
在此博客条目中,据称 GetPixel(...) 比基于指针的解决方案慢 1000 倍以上。
http://davidthomasbernal.com/blog/2008/03/14/c-image-processing-performance-unsafe-vs-safe-code-part-ii/
您应该在使用此代码之前对其进行正确测试,但即使有些地方不正确,所显示的技术也应该可以帮助您入门!

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;

public static class Pixelcounter
{
    private struct PixeldataARGB
    {
        public byte b;
        public byte g;
        public byte r;
        public byte a;
    }

    private struct PixeldataRGB
    {
        public byte b;
        public byte g;
        public byte r;
    }

    public static IEnumerable<Point> CountOccurences(this Image @this, int r, int g, int b)
    {
        if (r < 0 || g < 0 || b < 0)
            throw new ArgumentException("color values must not be negative");
        if (r > 255 || g > 255 || b > 255)
            throw new ArgumentException("color values must be below 256");

        return CountOccurences(@this, (byte)r, (byte)g, (byte)b);
    }

    public static unsafe IEnumerable<Point> CountOccurences(this Image @this, byte r, byte g, byte b)
    {
        Bitmap bitmap = new Bitmap(@this);
        BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
        PixeldataRGB* pointer = (PixeldataRGB*)bitmapData.Scan0;

        List<Point> pointList = new List<Point>();

        for (int y = 0; y < bitmap.Height; y++)
        {
            for (int x = 0; x < bitmap.Width; x++)
            {
                PixeldataRGB current = *pointer;
                if (current.r == r && current.g == g && current.b == b)
                    pointList.Add(new Point(x, y));
                pointer++;
            }
        }

        bitmap.Dispose();

        return pointList;
    }

    public static IEnumerable<Point> CountOccurences(this Image @this, int r, int g, int b, int a)
    {
        if (r < 0 || g < 0 || b < 0 || a < 0)
            throw new ArgumentException("color and alpha values must not be negative");
        if (r > 255 || g > 255 || b > 255 || a > 255)
            throw new ArgumentException("color and alpha values must be below 256");

        return CountOccurences(@this, (byte)r, (byte)g, (byte)b, (byte)a);
    }

    public static unsafe IEnumerable<Point> CountOccurences(this Image @this, byte r, byte g, byte b, byte a)
    {
        Bitmap bitmap = new Bitmap(@this);
        BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
        PixeldataARGB* pointer = (PixeldataARGB*)bitmapData.Scan0;

        List<Point> pointList = new List<Point>();

        for (int y = 0; y < bitmap.Height; y++)
        {
            for (int x = 0; x < bitmap.Width; x++)
            {
                PixeldataARGB current = *pointer;
                if (current.r == r && current.g == g && current.b == b && current.a == a)
                    pointList.Add(new Point(x, y));
                pointer++;
            }
        }

        bitmap.Dispose();

        return pointList;
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-07-05
    • 1970-01-01
    • 2013-07-21
    • 2019-07-27
    • 2014-08-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多