对绘制的形状图像中的唯一像素进行计数

本文关键字:像素 唯一 绘制 图像 | 更新日期: 2023-09-27 18:11:03

我正在开发一个图形应用程序,用户可以在画布上绘制任意数量的直线(从a点到B点具有一定的厚度)、矩形或椭圆。

在他们完成后,我有一组形状数据,表明每个形状和绘制的线的位置,我需要确定他们已经为多少个独特的像素上色,作为研究项目的一部分。

我的原始算法是为每个形状实现bool shape. contains (x,y),并为图像中的每个像素的每个绘制形状调用它,以确定该像素是由直线,矩形还是椭圆绘制的。

用另一种方法,我可以创建void形状。SetPixels(bool[,] canvas)并将每个形状设置为true,它包含的每个像素。这是我实际实现的,对于大型数据集,它非常慢。

我有一种感觉,有一种更直接的方法可以从原始形状数据到我需要的输出,而无需检查每个像素。所以我的问题是,给定一组形状数据,是否有一个O(n)函数bool[,] IsColored(int x, int y){},可以比我给出的任何一个想法更直接地生成彩色像素的真/假矩阵?

对绘制的形状图像中的唯一像素进行计数

避免使用Bitmap.GetPixel方法。它非常非常慢。如果可能的话,您可以使用LockBits或类似的技术对位图数据进行低级访问。

在我的一个项目中,我使用:

public void LoadFromBitmap(Bitmap bmp)
    {
        if (bmp.Width != Width || bmp.Height != Height)
            throw new ArgumentException("Size missmatch");
        unsafe
        {
            BitmapData bmpData = null;
            try
            {
                bmpData = bmp.LockBits(new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
                for (int y = 0; y < bmpData.Height; y++)
                {
                    uint* p = (uint*)((byte*)bmpData.Scan0 + y * bmpData.Stride);
                    for (int x = 0; x < bmpData.Width; x++)
                    {
                        this[x, y] = RawColor.FromARGB(*p);
                        p++;
                    }
                }
            }
            finally
            {
                if (bmpData != null)
                    bmp.UnlockBits(bmpData);
            }
        }
    }
https://github.com/CodesInChaos/ChaosUtil/blob/master/Chaos.Image/Pixels.cs

另一个优化是为包含像素的数组实现一个池。根据我的经验,频繁地在大对象堆上分配对象会对gc造成很大的压力。

您正在谈论的两个方法通常是您的两个主要选择。根据需要检查每个像素,或者预先构建某种数据结构以便快速查找。

如果你有一个大的画布,但只有几个形状(因此,相对较少的"打开"像素),那么最好只是记录任何形状击中的每个像素,例如在散列中。

HashSet<KeyValuePair<int,int>> listOfPixelsHitByAnyShape = new HashSet()
foreach(Shape s in allShapes)
{
    s.Draw(listOfPixelsHitByAnyShape); // will update listOfPixelsHitByAnyShape
}
// Now we can easily query if a pixel is set
bool isSet = listOfPixelsHitByAnyShape.Contains(new KeyValuePair(10,99))

这应该可以快速查找,但要消耗内存和构建HashSet的时间。

但是它不会像你的SetPixels(bool[,] canvas)版本那么快,也不会使用那么多的内存(在我们正在谈论的稀疏情况下)。

如果您没有使用图形库,请使用!


如果它是一个图形应用程序,你可能已经绘制了用户输入的内容。你就不能质疑一下吗?你可以总是画到2个不同的目标,一个用于漂亮的用户版本,另一个用于查询(每个对象都有一个独特的颜色)。

你想如何处理重叠?


我们谈论的数据集有多大?渲染应该是"自由的",因为位图可以在用户在应用程序中绘制时构建。

如果你所做的真的很慢,你可以考虑使用GPU来绘制和查询(可能使用花哨的着色器)。