我正在编写一款软件,需要对许多(可能很大的)图像进行许多图像操作/合成。多线程可以显著提高速度,但QT不允许同时在同一图像上使用多个QPainter。因此,我必须在每个线程中对复制品进行图像操作/合成,然后再将其复制回来,这会大大降低性能(根据用例而定)。
所以我想到了一个看起来可行但感觉极其hacky的方法。我获取目标图像数据(QImage::bits)指针,并将其提供给工作线程。在工作线程中,我从所提供的指针重新创建一个新的QImage。这意味着没有复制和blitting。只要确保每个像素/块在一个线程中被处理且不分离目标图像,它似乎运行得很好。
我的问题是:这样做是否安全,并且是否存在其他可能出现的问题?
示例代码:
所以我想到了一个看起来可行但感觉极其hacky的方法。我获取目标图像数据(QImage::bits)指针,并将其提供给工作线程。在工作线程中,我从所提供的指针重新创建一个新的QImage。这意味着没有复制和blitting。只要确保每个像素/块在一个线程中被处理且不分离目标图像,它似乎运行得很好。
我的问题是:这样做是否安全,并且是否存在其他可能出现的问题?
示例代码:
QImage source = ...;
QImage target = ...;
QPainter::CompositionMode compositionMode = QPainter::CompositionMode_SourceOver;
// calculate tiles
QList<QRect> tiles;
for(int y = rect.top(); y < rect.top() + rect.height(); y += tileSize){
for(int x = rect.left(); x < rect.left() + rect.width(); x += tileSize){
QRect tile(
x, y,
x + tileSize > rect.left() + rect.width() ? rect.left() + rect.width() - x : tileSize,
y + tileSize > rect.top() + rect.height() ? rect.top() + rect.height() - y : tileSize
);
tiles.append(tile);
}
}
// Get target pixel pointer and do threaded operation on each tile
uchar *targetPix = target.bits();
auto target_size = target.size();
auto targetFormat = target.format();
QList<int> lol = QtConcurrent::blockingMapped(tiles, [&target_size, &targetFormat, &source, targetPix, &compositionMode](const QRect &r){
QImage tile_target(targetPix, target_size.width(), target_size.height(), targetFormat);
QPainter p(&tile_target);
p.setCompositionMode(compositionMode);
// do you image operations here. For now we just do a simple draw
p.drawImage(r.topLeft(), source, r);
return 1; // In reallity this would return sensible data ;)
});
(顺便说一句,这个例子在我的测试中将速度提高了约4.6倍。当然,取决于操作和系统。)