【问题标题】:find a color in an image in c#在c#中查找图像中的颜色
【发布时间】:2010-09-25 19:38:55
【问题描述】:

我在http://www.youtube.com/watch?v=Ha5LficiSJM 偶然发现了这个 youtube 视频,该视频演示了有人使用 AForge.NET 框架进行颜色检测。我想复制那个作者所做的,但我不确定如何进行一些图像处理。

AForge.NET 框架似乎允许您从视频源中提取位图格式的图像。我的问题是任何人都可以指出我的方向或提供一些关于如何询问位图对象以找到其中特定颜色的指导吗? (例如 - 如果图像中有“红色”或“紫色”持续 X 秒,我想引发一个事件“ColorDetected”左右......)

有人对从哪里开始有任何建议吗?

谢谢,

-R.

编辑:我需要遍历整个 Bitmap 对象并询问每个像素的颜色吗?像这样:http://msdn.microsoft.com/en-us/library/system.drawing.bitmap.getpixel.aspx

【问题讨论】:

    标签: c# image image-processing aforge


    【解决方案1】:

    嗯,你总是可以使用 GDI+ 方法。

    Bitmap b = new Bitmap( "some path" );
    Color x = b.GetPixel( x, y );
    

    但是,GetPixel 实际上很慢。首先尝试这种方式,但如果您需要扫描许多相对较大的图像,它可能不适合您。在这种情况下,使用 LockBits 获取指向连续内存块的指针。然后您可以快速循环浏览图像,但您必须知道如何操作指针,尽管它并不是非常复杂。

    编辑:使用 LockBits 查看每个像素:

    Bitmap b = new Bitmap( "some path" );
    BitmapData data = b.LockBits( new Rectangle( 0, 0, b.Width, b.Height ),
    ImageLockMode.ReadOnly, b.PixelFormat );  // make sure you check the pixel format as you will be looking directly at memory
    
    unsafe
    {         
        // example assumes 24bpp image.  You need to verify your pixel depth
        // loop by row for better data locality
        for( int y = 0; y < data.Height; ++y )
        {
            byte* pRow = (byte*)data.Scan0 + y * data.Stride;
            for( int x = 0; x < data.Width; ++x )
            {
                // windows stores images in BGR pixel order
                byte r = pRow[2];
                byte g = pRow[1];
                byte b = pRow[0];
    
                // next pixel in the row
                pRow += 3;
            }
        }
    }
    
    b.UnlockBits(data);
    

    如果您的图像在末尾被填充,您可以使用 BitmapData.Stride 属性来到达每个新行的开头(否则您将读取一些垃圾内容并且您的偏移量会很糟糕)。

    【讨论】:

    • 感谢您的提示;看起来 LockBits 方法将是要走的路。您还有其他可能有用的指针吗?我使用的网络摄像头能够提供 30fps;所以我显然要对图像检测进行线程化。您是否还有其他建议可以提高速度?
    • 当然,我可以举个例子。但是,从您的帖子中不清楚您将如何使用它。您是要查看每张图像中的每个像素,还是查看一个小区域等?
    • 感谢您的示例!我一定会调查的。
    • 你需要把它包裹在unsafe { }或者在方法/类定义中加上unsafe关键字,然后在项目的属性中启用不安全代码。
    • @Nyerguds:是的,会的
    【解决方案2】:

    除了 Ed Swangren 对LockBits 的回答之外,您还可以避免使用指针。如果您正在使用 WPF(或有权访问),您可以执行以下操作:

    var bitmap = new BitmapImage(uri);
    
    //Pixel array
    byte[] pixels = new byte[width * height * 4]; //account for stride if necessary
    
    bitmap.CopyPixels(..size, pixels, fullStride, 0); 
    

    现在您可以使用pixels 进行常规数组扫描,无需指针。这个 sn-p 已经有几年历史了,并且来自我开发自己的 AmbiLight 解决方案的项目,因此它可以非常快。同样,这是几年前的,所以像WriteableBitmap 等新类可能会更好,并且避免数组复制。在我最初的解决方案中,我使用了指针,但当我发现没有必要时,我切换了。

    【讨论】:

    • 是的,我同意。从最简单的方法开始,做一些时序测试。如果可行,那就太好了,如果不行,请换一种方法。
    • 同意我应该先测量,看看什么效果最好。感谢你们俩的提示。
    • 不客气 :) 我只是稍微简化了代码,BitmapImage 也有 .CopyPixels()...
    • 嗨 Lasse,我们可以为 EPS 图像格式处理这种方法吗?
    • @NachiappanR 这个答案已经过时了。我相信现在有更好的方法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-01-10
    • 2017-04-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多