我正在开发一个图形应用程序,用户可以在画布上绘制任意数量的线条(从A点到B点有一些厚度),矩形或椭圆形。
完成后,我有一组形状数据,表明每个形状和线条的位置,我需要确定它们作为研究项目的一部分着色了多少个独特像素。
我的天真算法是实现bool形状。包含每个形状的(x,y),并为图像中每个像素的每个绘制形状调用它,以确定该像素是否由线条,矩形或椭圆绘制。 / p>
以另一种方式工作,我可以创建void shape.SetPixels(bool [,] canvas)并将每个形状设置为true,它包含每个像素。这是我实际实现的,对于大型数据集,它的速度非常慢。
我感觉有一种更直接的方法可以从原始形状数据转换到我需要的输出,而无需检查每个像素。所以我的问题是,给定一组形状数据,是否存在O(n)函数bool [,] IsColored(int x,int y){},它可以比任何一个更直接地为彩色像素生成真/假的矩阵我已经给出了什么想法?
答案 0 :(得分:2)
避免使用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。
答案 1 :(得分:1)
您所谈论的两种方法通常是您的两个主要选择。根据需要检查每个像素,或者预先构建某种数据结构以便快速查找。
如果你有一个大画布,但只有几个形状(因此,相对较少的“开”像素),那么最好只记录任何形状所击中的每个像素,例如哈希。 / p>
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 :(得分:0)
如果你没有使用图形库,请做!
如果它是一个图形应用程序,大概你已经在绘制用户输入的内容了。你能不能查询一下?您总是可以绘制2个不同的目标,一个用于漂亮的用户版本,另一个用于查询(每个对象都是唯一的颜色)。
你想如何处理重叠?
我们说的数据集有多大?渲染应该是“免费的”,因为当用户在应用程序中绘制时可以构建位图。
如果您所做的事情非常缓慢,您可以考虑使用GPU绘制和查询(可能使用花哨的着色器)。