Chroma Key с использованием dlib

Эффект Chroma Key (“цветовой ключ”) заключается в сегментации изображения с тем, чтобы отделить объект переднего плана от фона. При этом цвет фона должен быть сплошным и равномерным – как правило, выбирают либо зеленый, либо синий, в зависимости от того, какой цвет отсутствует на объекте. Отделенное изображение затем накладывается на другой фон – например, на фотографию или рендер виртуальной сцены.

Существуют различные алгоритмы подобной сегментации, мы рассмотрим один из самых простых. Несмотря на простоту, он достаточно эффективен. Метод основан на нахождении евклидового расстояния в пространстве RGB – между цветом исходного пикселя и цветом фона. Если рассматривать цвета как точки в трехмерном пространстве, то пиксели, например, зеленого фона будут представлять собой облако точек, сосредоточенное вокруг “абсолютно зеленой” точки – (0, 1, 0). Чтобы получить значение альфа-канала (0 – пиксель принадлежит фону, 1 – не принадлежит), мы просто нормируем расстояние в заранее выбранном диапазоне.

import dlib.math.vector;
import dlib.math.utils;
import dlib.image.image;
import dlib.image.color;

SuperImage chromaKey(
SuperImage img,
Color4f keyColor,
float minDist,
float maxDist)
{
auto res = new ImageRGBA8(img.width, img.height);

foreach(y; img.col)
foreach(x; img.row)
{
Color4f col = img[x, y];

Color4f delta = col - keyColor;
float distSqr = dot(delta, delta);
col.a = clamp(
(distSqr - minDist) / (maxDist - minDist),
0.0f, 1.0f);
res[x, y] = col;
}

return res;
}

Вот пример использования этой функции:

import dlib.image.io.io;

auto img = load("input.png");
auto res = img.chromaKey(Color4f(0, 1, 0), 0.3f, 0.7f);
res.save("output.png");

Как нетрудно заметить, результат не идеален – если наложить изображение на фон, вокруг актера наблюдается зеленоватый контур. От него можно избавиться путем эрозии альфа-канала: изображение пропускается через дискретный оконный фильтр 3х3, который присваивает пикселю наименьшее значение в окне. В результате, непрозрачная область “теряет” несколько пикселей контура, и зеленый ореол практически исчезает.

SuperImage erodeAlpha(SuperImage img)
{
uint kw = 3, kh = 3;

auto res = img.dup;

foreach(y; img.col)
foreach(x; img.row)
{
auto c = img[x, y];

foreach(ky; 0..kh)
foreach(kx; 0..kw)
{
int iy = y + (ky - kh/2);
int ix = x + (kx - kw/2);

if (ix < 0) ix = 0;
if (ix >= img.width) ix = img.width - 1;
if (iy < 0) iy = 0;
if (iy >= img.height) iy = img.height - 1;

float a = img[ix, iy].a;

if (a < c.a)
c.a = a;
}

res[x, y] = c;
}

return res;
}

Винтажные фильтры – обновление

Обновилась коллекция винтажных фильтров для GIMP: добавлены три новых фильтра (Amaro, Brannan, Toaster), а также поддержка виньетирования. Все фильтры теперь объединены в один: при запуске скрипта выводится диалоговое окно с выбором фильтра и другими опциями.

Скачать можно здесь.

Обновление dlib.image

В dlib.image появилась возможность отслеживать прогресс во время работы фильтров. Для этого используется многопоточность – необходимо создать класс-враппер, наследующий от FilteringThread. Прогресс (от 0 до 1) считывается из свойства progress для SuperImage. В данном примере показано, как использовать эту функциональность для вывода прогресса свертки в консоль:

import std.stdio;
import dlib.image.image;
import dlib.image.io.png;
import dlib.image.filters.convolution;
import dlib.image.fthread;

class ConvolutionThread: FilteringThread
{
float[] kernel;

this(SuperImage img, float[] k)
{
super(img);
kernel = k;
}

override void run()
{
output = image.convolve(kernel);
}

override void onRunning()
{
writef("Convolving %s%%", cast(uint)(image.progress * 100));
write("r");
stdout.flush();
}

override void onFinished()
{
writeln();
}
}

void main()
{
auto img = loadPNG("test.png");
img = (new ConvolutionThread(img, Kernel.Emboss)).filtered;
img.savePNG("output.png");
}

dlib 0.1.2

Коллекция библиотек dlib обновилась до версии 0.1.2. Были внесены несколько значительных нвовведений:

  • В dlib.image.color типы ColorRGBA и ColorRGBAf были переименованы в Color4 и Color4f соответственно. Для обеспечения обратной совместимости, старые имена сохранены в виде псевдонимов, но новый код рекомендуется писать с использованием новых имен;
  • Добавлена поддержка свертки изображений (dlib.image.filters.convolution), которая позволяет реализовать на ее основе множество различных фильтров. Есть несколько встроенных ядер 3×3: Identity, BoxBlur, GaussianBlur, Sharpen, Emboss, EdgeEmboss, EdgeDetect, Laplace;
  • Добавлена поддержка цветового пространства HSV. На его основе реализованы эффекты Chroma Key (“зеленый фон”) и Color Pass (выборочное обесцвечивание).
  • Исправлены баги, связанные со сборкой при помощи DUB.

Страница проекта:
https://github.com/gecko0307/dlib

Скачать dlib 0.1.2:
https://github.com/gecko0307/dlib/releases/tag/v0.1.2