API dlib.image позволяет создавать фильтры, которые легко распараллеливать на несколько процессоров. Изображение условно разбивается на несколько блоков заданного размера, которые затем обрабатываются фильтром через std.parallelism.
import std.parallelism;
import dlib.functional.range;
import dlib.image.image;
struct Block
{
uint x1, y1;
uint x2, y2;
}
alias Range!uint PixRange;
void parallelFilter(
SuperImage img,
void delegate(PixRange blockRow, PixRange blockCol) ffunc,
uint bw = 100,
uint bh = 100)
{
if (bw > img.width)
bw = img.width;
if (bh > img.height)
bh = img.height;
uint numBlocksX = img.width / bw + ((img.width % bw) > 0);
uint numBlocksY = img.height / bh + ((img.height % bh) > 0);
Block[] blocks = new Block[numBlocksX * numBlocksY];
foreach(x; 0..numBlocksX)
foreach(y; 0..numBlocksY)
{
uint bx = x * bw;
uint by = y * bh;
uint bw1 = bw;
uint bh1 = bh;
if ((img.width - bx) < bw)
bw1 = img.width - bx;
if ((img.height - by) < bh)
bh1 = img.height - by;
blocks[y * numBlocksX + x] = Block(bx, by, bx + bw1, by + bh1);
}
foreach(i, ref b; taskPool.parallel(blocks))
{
ffunc(range!uint(b.x1, b.x2),
range!uint(b.y1, b.y2));
}
}
Пример (закрашивание сплошным цветом):
SuperImage filterTestMultithreaded(SuperImage img)
{
auto res = img.dup;
img.parallelFilter((PixRange row, PixRange col)
{
foreach(x; row)
foreach(y; col)
{
res[x, y] = hsv(180.0f, 1.0f, 0.5f);
}
});
return res;
}
Для сравнения – однопоточный вариант:
SuperImage filterTestSinglethreaded(SuperImage img)
{
auto res = img.dup;
foreach(x; img.row)
foreach(y; img.col)
{
res[x, y] = hsv(180.0f, 1.0f, 0.5f);
}
return res;
}
На двухъядерном Intel Dual Core T2390 (1.86 ГГц) многопоточный вариант показывает прирост производительности на 70%.