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%.

Оставить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *