for (int x = 0; x < blockCountX; x++)
{
for (int y = 0; y < blockCountY; y++)
{
//get blocks from image to new image and send to threaded processor
imageBlocks[x, y] = image.Clone(clipRectangle, System.Drawing.Imaging.PixelFormat.Format8bppIndexed);
System.Threading.Thread t = new System.Threading.Thread(new System.Threading.ParameterizedThreadStart(ThreadedFromHeightMap));
t.Start(imageBlocks[x,y]);
clipRectangle.Offset(0, IMAGEBLOCKSIZE);
}
clipRectangle.Offset(IMAGEBLOCKSIZE, clipRectangle.Location.Y * -1);
}
break;
}
}
private void ThreadedFromHeightMap(object Image)
{
Bitmap image = (Bitmap)Image;
int width = image.Width;
int height = image.Height;
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
map.Hexes.Add(new Point(x, y), new Hex(image.GetPixel(x, y).B));
//tempHexes.Enqueue(new Hex(image.GetPixel(x, y).B));
}
}
}
我正在尝试从2048 x 2048 8bpp灰度高度图中获取像素数据,并构建具有相应高度值的十六进制地图。我将hexes存储在Dictionary集合中。总而言之,该系列中有大约400万个咒语。
为了有效地执行此操作,我将图像分成256 x 256个块并将该图像传递给另一个将解析它并将其添加到集合中的线程。这一切都是乱七八糟的。我现在有64个图像块,它们的左上角有(0,0),而不是一个图像的左上角为(0,0)。但是我使用像素位置作为字典的索引。当第二个线程尝试使用索引(0,0)添加另一个值时,这会崩溃。
如何缓解此问题?我已经考虑构建一个只有一个图像成员和一个块编号成员的类,并将其传递给线程,这样我就可以根据线程处理的块来调整像素位置,但这似乎不是最佳的。
(我意识到我使用的词典不是线程安全的。我已经解决了这个问题。)
答案 0 :(得分:3)
我可以推荐几件事吗?
忘掉image.GetPixel(),它非常慢;直接使用位图数据,算法的性能将提高很多,您不需要运行并行线程来提高效率。请参阅MSDN:http://msdn.microsoft.com/en-us/library/system.drawing.imaging.bitmapdata.aspx
如果你坚持使用并行线程,请使用线程池,而不是产生64个线程。 (参见MSDN:http://msdn.microsoft.com/en-us/library/3dasc8as(v=vs.80).aspx)
如果您坚持产生许多线程,请不要产生比CPU核心更多的线程。我不认为你的机器上有64个核心,对吗?
如果您坚持产生许多线程,您当然需要将每个图块的位置传递给线程,以便在重建整个图片时准确知道该图块的放置位置。这不是最优的,这是必要的。
答案 1 :(得分:2)
为什么你认为将大图像拆分成更小的块会更有效?大图像是否太大而无法放入系统内存? 400万像素x 8bpp(每像素1个字节)= 4兆字节。这是20年前的大量记忆。今天它发生了变化。
创建多个256x256子图像将需要将像素数据复制到内存中的新图像,以及每个新图像的图像头/描述符开销,以及每个扫描线的对齐填充。您的内存使用量将增加一倍以上,这可能会导致性能问题(虚拟交换)本身。
您还要为每个图像块启动一个新线程。分配线程非常昂贵,并且可能比您希望线程完成的工作花费更多时间。考虑至少使用ThreadPool.QueueUserWorkItem
来使用已经可用的系统工作线程。使用.NET 4.0的Task
类会更好,IMO。
忘记.GetPixel()。它比像素存储器访问慢一千倍。
如果要在多个CPU内核之间分配处理图像像素,请考虑将每个扫描线或一组扫描线处理到不同的任务或工作线程。
答案 2 :(得分:0)
image.Scan0
获取像素指针。Parallel.ForEach
进行此类使用。如果您无法使用它,则可以使用线程池。我猜你的电脑没有(2048 x 2048)/(256 x 256)= 64核CPU。