Блендинг изображений — различия между версиями

Материал из Викиконспекты
Перейти к: навигация, поиск
(Не дискрестный Пуассон)
(Метки: правка с мобильного устройства, правка из мобильной версии)
м (rollbackEdits.php mass rollback)
 
(не показаны 44 промежуточные версии 3 участников)
Строка 1: Строка 1:
 +
Копирование элемента одного изображения и его вставка на другое изображение {{---}} один из наиболее используемых методов для создания  графического контента. Простая вставка, как правило, бросается в глаза и делает результат похожим на коллаж, во многих случаях этот эффект является нежелательным.
 
{{Определение
 
{{Определение
 
|definition =
 
|definition =
'''Гармонизация изображений''' (англ. ''image harmonization'') {{---}} метод, позволяющий наложить часть одного изображения поверх другого таким образом, чтобы композиция изображений выглядела естественно, без швов на границах вставки и с соответсвующими цветами и текстурами <ref name='ZWS20'>[https://openaccess.thecvf.com/content_WACV_2020/papers/Zhang_Deep_Image_Blending_WACV_2020_paper.pdf Deep Image Blending] Lingzhi Zhang, Tarmily Wen, Jianbo Shi (2020)</ref>.}}
+
'''Блендинг изображений''' (англ. ''image blending'') {{---}} метод, позволяющий вставить часть одного изображения в другое таким образом, чтобы композиция изображений выглядела естественно, без швов на границах вставки. }}
 
+
Основная трудность задачи заключается в том, что естественность результата зависит не только от бесшовности наложения, но и от схожести цветов и текстуры вставляемого и фонового изображений.
{{Определение
 
|definition =
 
'''Блендинг изображений''' (англ. ''image blending'') {{---}} метод, позволяющий вставить часть одного изображения в другое таким образом, чтобы композиция изображений выглядела естественно, без швов на границах вставки и соответсвующими цветами и текстурами. В отличие от гармонизации, блендинг сам определяет какие пиксели фонового изображения нужно заменить.<ref name='ZWS20'/>}}
 
  
 +
{|
 +
! Вставляемое изображение
 +
! Фоновое изображение
 +
! Простая вставка
 +
! Желаемый результат
 +
|-
 +
| [[Файл:Diver bl diver.png|180px]]
 +
| [[Файл:Diver bl sea.png|180px]]
 +
| [[Файл:Diver bl2.png|180px]]
 +
| [[Файл:Diver bl3.png|180px]]
 +
|}
  
 
==Блендинг Пуассона==
 
==Блендинг Пуассона==
[[Файл:Poisson int1.png|thumb|right|300px|Рис. $1.1$. Пример перепада яркости при простой вставке]]
+
[[Файл:Poisson int1.png|thumb|right|250px|Рисунок $1.1$: Пример перепада яркости при простой вставке<ref name='ZWS20'/>]]
[[Файл:Poisson int2.png|thumb|right|300px|Рис. $1.2$. Результат применения блендинга Пуассона]]
+
[[Файл:Poisson int2.png|thumb|right|250px|Рисунок $1.2$: Результат применения блендинга Пуассона<ref name='ZWS20'/>]]
  
Блендинг Пуассона на самом деле является гармонизацией, так как требует маску заменяемых пикселей. Почему-то в статьях его называют блендингом (Poisson blending), хотя оригинальная статья называлась Poisson Image Editing<ref name="PGB03">[https://www.cs.jhu.edu/~misha/Fall07/Papers/Perez03.pdf Poisson Image Editing] Patrick Perez, Michel Gangnet, Andrew Blake (2003)</ref>
+
Простая вставка одного изображения поверх другого нередко влечет заметный перепад яркости на границе вставки (рисунок $1.1$). Метод Пуассона заключается в сглаживании этого перепада (рисунок $1.2$) с целью сделать дефект менее заметным, используя градиент вставляемого изображения и значения пикселей фонового изображения на границе вставки.
 
 
Простая вставка одного изображения поверх другого нередко влечет заметный перепад яркости на границе вставки (рис. $1.1$). Метод Пуассона заключается в сглаживании этого перепада (рис. $1.2$) с целью сделать дефект менее заметным, используя градиент вставляемого изображения и значения пикселей фонового изображения на границе вставки.
 
  
 
'''Замечание:''' Для RGB изображений задача минимизации решается для каждого цветового канала отдельно.
 
'''Замечание:''' Для RGB изображений задача минимизации решается для каждого цветового канала отдельно.
Строка 25: Строка 32:
 
! Маска $M$
 
! Маска $M$
 
|-
 
|-
| [[Файл:Poisson_cat.jpg|200px]]
+
| [[Файл:Poisson_cat.jpg|155px]]
| [[Файл:Poisson_cherry.jpg|200px]]
+
| [[Файл:Poisson_cherry.jpg|155px]]
| [[Файл:Poisson_cherry_mask.png|200px]]
+
| [[Файл:Poisson_cherry_mask.png|155px]]
 
|}
 
|}
  
===  TODO заголовок ===
+
===  Идея подхода ===
 
Пусть замкнутое множество $P \subset \mathbb{R}^2$ {{---}} область, на которой определено изображение $S$, а замкнутое множество $\Omega \subset P$ с границей $\partial\Omega$ и внутренностью $int(\Omega)$ {{---}} область вставки изображения $I$.
 
Пусть замкнутое множество $P \subset \mathbb{R}^2$ {{---}} область, на которой определено изображение $S$, а замкнутое множество $\Omega \subset P$ с границей $\partial\Omega$ и внутренностью $int(\Omega)$ {{---}} область вставки изображения $I$.
  
 
Пусть $f_S$ {{---}} скалярная функция, определенная на $P \setminus int(\Omega)$, задает фоновое изображение $S$; $f$ {{---}} неизвестная скалярная функция, определенная на $int(\Omega)$, задает, каким образом должно выглядеть результат блендинга в области вставки.  
 
Пусть $f_S$ {{---}} скалярная функция, определенная на $P \setminus int(\Omega)$, задает фоновое изображение $S$; $f$ {{---}} неизвестная скалярная функция, определенная на $int(\Omega)$, задает, каким образом должно выглядеть результат блендинга в области вставки.  
  
$v_I$ {{---}} векторное поле, определенное на $\Omega$. В качестве $v_i$ возьмем градиент вставляемого изображения $I$: $v_i = \nabla f_I$
+
$v_I$ {{---}} векторное поле, определенное на $\Omega$. В качестве $v_I$ возьмем градиент вставляемого изображения $I$: $v_I = \nabla f_I$.
  
 
Нашей задачей является поиск такой функции $f$, чтобы блендинговое изображение выглядело реалистично. Для этого минимизируем разность градиента функции $f$ и векторного поля $v_I$, считая, что $f = f_S$ на границе $\Omega$.
 
Нашей задачей является поиск такой функции $f$, чтобы блендинговое изображение выглядело реалистично. Для этого минимизируем разность градиента функции $f$ и векторного поля $v_I$, считая, что $f = f_S$ на границе $\Omega$.
 
$$
 
$$
\underset{f}{\mathrm{min}} \int\int_{\Omega} |\nabla f - v_I|^2, \text{где } f|_{\partial \Omega} = f_S|_{\partial \Omega}
+
\underset{f}{\mathrm{min}} \underset{\Omega}{\iint} |\nabla f - v_I|^2, \text{где } f|_{\partial \Omega} = f_S|_{\partial \Omega}.
 
$$
 
$$
 
Решение задачи минимизации является единственным решением уравнения Пуассона для граничных условий Дирихле.
 
Решение задачи минимизации является единственным решением уравнения Пуассона для граничных условий Дирихле.
Строка 45: Строка 52:
  
 
=== Дискретный случай ===
 
=== Дискретный случай ===
Пусть $p$ {{---}} координаты $(x, y)$ пикселя двухмерного изображения. За $Img_p$ обозначим значение пикселя с координатами $p$ изображения $Img$. Пусть $\Omega = \{ p\;|\;M_p = 1 \}$. Тогда $\partial \Omega$ {{---}} координаты границы вставляемой области, а $int(\Omega)$ {{---}} внутренность области.
+
Пусть $p$ {{---}} координаты $(x, y)$ пикселя двухмерного изображения. За $Img_p$ обозначим значение пикселя с координатами $p$ изображения $Img$. Пусть $\Omega = \left\{ p\;|\;M_p = 1 \right\}$ {{---}} область, заданная маской $M$. Тогда $\partial \Omega$ {{---}} координаты границы вставляемой области, а $int(\Omega)$ {{---}} внутренность области.
  
Пусть $N_p$ {{---}} множество соседей $p$ (максимум четыре пикселя, имеющих общую границу с $p$, т.е. пиксели со следующими координатами: $(x + 1, y), (x - 1, y), (x, y + 1), (x, y - 1)$). Для всех пар $(p, q)$ таких, что $q \in N_p$, введем $v_{pq} = I_p - I_q$
+
Пусть $N_p$ {{---}} множество соседей $p$ (максимум четыре пикселя, имеющих общую границу с $p$, т.е. пиксели со следующими координатами: $(x + 1, y), (x - 1, y), (x, y + 1), (x, y - 1)$). Для всех пар $(p, q)$ таких, что $q \in N_p$, введем $v_{pq} = I_p - I_q$.
  
Введем переменные $O_p, p \in \Omega$. Так как мы хотим сделать результат бесшовным, пиксели $O_p, p \in \partial\Omega$, сделаем равными $S_p$. Для $p, q \in int(\Omega),\; q \in N_p$ постараемся найти такие значения $O_p, O_q$, чтобы их разность была близка к $v_{pq}$. Для этого решим задачу минимизации:
+
Введем переменные $O_p, p \in \Omega$. Так как мы хотим сделать результат бесшовным, пиксели $O_p, p \in \partial\Omega$, сделаем равными $S_p$. Для $p, q \in int(\Omega),\; q \in N_p$ постараемся найти такое $O$, чтобы разность $O_p$ и $O_q$ была близка к $v_{pq}$. Для этого решим задачу минимизации:
  
 
$$
 
$$
\underset{f_p,\; p \in \Omega}{\mathrm{min}}\; \underset{p, q \in \Omega}{\sum}\; (O_p - O_q - v_{pq})^2, \text{где } O_p = S_p, p \in \partial \Omega
+
\underset{O_p,\; p \in \Omega}{\mathrm{min}}\; \underset{p, q \in \Omega}{\sum}\; \left(O_p - O_q - v_{pq}\right)^2, \text{где } O_p = S_p, p \in \partial \Omega.
 
$$
 
$$
  
 
Заметим, что функция, которую мы хотим минимизировать, квадратична относительно переменных $O_p, p \in int(\Omega)$. Для решения задачи минимизации вычислим частные производные по этим переменным и найдем значения переменных, при которых частные производные будут равны нулю.  
 
Заметим, что функция, которую мы хотим минимизировать, квадратична относительно переменных $O_p, p \in int(\Omega)$. Для решения задачи минимизации вычислим частные производные по этим переменным и найдем значения переменных, при которых частные производные будут равны нулю.  
$$\frac{\partial{\underset{p, q \in \Omega}{\sum}\; (O_p - O_q - v_{pq})^2}}{\partial O_p} = \underset{q \in N_p}{\sum} 2 (O_p - O_q - v_{pq}) - \underset{q \in N_p}{\sum} 2 (O_q - O_p - v_{qp}) = 2 \underset{q \in N_p}{\sum} 2 (O_p - O_q - v_{pq})$$.
+
$$\frac{\partial{\underset{p, q \in \Omega}{\sum}\; \left(O_p - O_q - v_{pq}\right)^2}}{\partial O_p} = \underset{q \in N_p}{\sum} 2 \left(O_p - O_q - v_{pq}\right) - \underset{q \in N_p}{\sum} 2 \left(O_q - O_p - v_{qp}\right) = 2 \underset{q \in N_p}{\sum} 2 \left(O_p - O_q - v_{pq}\right).$$
  
 
Приравнивая к нулю, получаем: $|N_p| O_p - \underset{q \in N_p}{\sum} O_q = \underset{q \in N_p}{\sum} v_{pq}$.
 
Приравнивая к нулю, получаем: $|N_p| O_p - \underset{q \in N_p}{\sum} O_q = \underset{q \in N_p}{\sum} v_{pq}$.
  
Для точек, граничащих с $\partial \Omega$:  $\;|N_p| O_p - \underset{q \in N_p \cap \Omega}{\sum} O_q = \underset{q \in N_p \cap \partial \Omega}{\sum} S_q + \underset{q \in N_p}{\sum} v_{pq}$.
+
Добавим условие $O_p = S_p, p \in \partial \Omega$:  $\;|N_p| O_p - \underset{q \in N_p \cap int(\Omega)}{\sum} O_q = \underset{q \in N_p \cap \partial \Omega}{\sum} S_q + \underset{q \in N_p}{\sum} v_{pq}$.
  
Для решения систем уравнений такого вида могут быть использованы итеративные алгоритмы Gauss-Seidel и V-cycle multigrid<ref name="PGB03"/>.
+
Для решения систем уравнений такого вида могут быть использованы итеративные алгоритмы Gauss-Seidel и V-cycle multigrid<ref name="PGB03">[https://www.cs.jhu.edu/~misha/Fall07/Papers/Perez03.pdf Poisson Image Editing] Patrick Perez, Michel Gangnet, Andrew Blake (2003)</ref>.
  
 
Получаем значения пикселей $O_p$, $p \in int(\Omega)$. Тогда результат $B$ блендинга Пуассона будет следующим:  
 
Получаем значения пикселей $O_p$, $p \in int(\Omega)$. Тогда результат $B$ блендинга Пуассона будет следующим:  
Строка 70: Строка 77:
 
O_p,\; \text{если } p \in int(\Omega) \\
 
O_p,\; \text{если } p \in int(\Omega) \\
 
S_p,\; \text{иначе }  
 
S_p,\; \text{иначе }  
\end{cases}
+
\end{cases}.
 
$$
 
$$
  
 
Mетод Пуассона сдвигает цвета накладываемого изображения, сохраняя свойства градиента (т.е. если пиксель $I_{p1}$ был меньше $I_{p2}$, то после преобразования $I_{p1}$ не станет больше $I_{p2}$), однако само значение градиета может получиться другим.<ref name='clear_poisson'>https://erkaman.github.io/posts/poisson_blending.html Poisson blending для самых маленьких</ref>
 
Mетод Пуассона сдвигает цвета накладываемого изображения, сохраняя свойства градиента (т.е. если пиксель $I_{p1}$ был меньше $I_{p2}$, то после преобразования $I_{p1}$ не станет больше $I_{p2}$), однако само значение градиета может получиться другим.<ref name='clear_poisson'>https://erkaman.github.io/posts/poisson_blending.html Poisson blending для самых маленьких</ref>
  
==Трансфер стиля==
+
==Нейронный перенос стиля==
 +
{{main|Neural Style Transfer}}
 +
Прежде чем переходить к гармонизации картин, рассмотрим задачу нейронного переноса стиля с изображения $S$ на изображение $I$. Для этого используются выходы скрытых слоёв [[Сверточные нейронные сети | свёрточной нейронной сети]] VGG-19<ref name="SZ14">[https://arxiv.org/pdf/1409.1556.pdf Very Deep Convolutional Networks for Large-Scale Image Recognition] Karen Simonyan, Andrew Zisserman (2014)</ref> (конкретные слои указаны ниже в деталях реализации).
  
Прежде чем переходить к гармонизации картин, рассмотрим задачу трансфера стиля с изображения $S$ на изображение $I$. Для этого используются выходы скрытых слоёв [[Сверточные нейронные сети | свёрточной нейронной сети]] VGG-19<ref name="SZ14">[https://arxiv.org/pdf/1409.1556.pdf Very Deep Convolutional Networks for Large-Scale Image Recognition] Karen Simonyan, Andrew Zisserman (2014)</ref>.
+
Основная идея генерации изображения {{---}} решение оптимизационной задачи $\mathcal{L}(I, S, O) \xrightarrow[O]{} min$, где $O$ {{---}} итоговое изображение, $\mathcal{L}(I, S, O)$ {{---}} [[Функция потерь и эмпирический риск | функция потерь]]. Такую задачу можно решать градиентным спуском в пространстве изображений используя [[обратное распространение ошибки | метод обратного распространения ошибки]].
 
 
Основная идея генерации изображения {{---}} решение оптимизационной задачи $\mathcal{L}(O, I, S) \xrightarrow[O]{} min$, где $O$ {{---}} итоговое изображение, $\mathcal{L}(O, I, S)$ {{---}} [[Функция потерь и эмпирический риск | функция потерь]]. Такую задачу можно решать градиентным спуском в пространстве изображений используя [[обратное распространение ошибки | метод обратного распространения ошибки]].
 
 
{{Определение
 
{{Определение
 
|definition =
 
|definition =
Пусть $F^l\left[I\right] \in \mathcal{R}^{N_l \times M_l}$ {{---}} выход $l$-го слоя сети на изображении $I$. Представим его как матрицу $N_l \times M_l$,  
+
Пусть $F^l\left[I\right] \in \mathcal{R}^{N_l \times M_l}$ {{---}} матрица значений выхода $l$-го слоя сети на изображении $I$. Выход $l$-го слоя сети имеет размерность $N_l \times W_l \times H_l$. Представим его как матрицу $N_l \times M_l$, где $N_l$ {{---}} количество фильтров в $l$-ом слое, $M_l$ {{---}} количество признаков ($M_l = W_l H_l$). Тогда $F^l_{ij}\left[I\right]$ {{---}} $j$-ый признак $i$-го фильтра в $l$-ом слое. Столбец матрицы $F^l\left[I\right]$ размера $N_l$ назовём '''вектором активации'''.}}
где $N_l$ {{---}} количество фильтров в $l$-ом слое,  
 
$M_l$ {{---}} количество признаков (высота, умноженная на ширину). Тогда $F^l_{ij}\left[I\right]$ {{---}} $j$-ый признак $i$-го фильтра в $l$-ом слое.}}
 
 
{{Определение
 
{{Определение
 
|definition =
 
|definition =
'''Матрица Грама''' (англ. ''Gram matrix'') {{---}} матрица попарных скалярных произведений. В нашем случае матрица отражает корреляцию между выходами фильтров. $G^l\left[I\right] \in \mathcal{R}^{N_l \times N_l} = F^l\left[I\right]F^l\left[I\right]^T$.}}
+
'''Матрица Грама''' (англ. ''Gram matrix'') {{---}} матрица попарных скалярных произведений.  
 +
$$G^l\left[S\right] \in \mathcal{R}^{N_l \times N_l},$$
 +
$$G^l\left[S\right] = F^l\left[S\right]F^l\left[S\right]^T.$$}}
 +
 
 +
Далее рассмотренны функции потерь, которые мы будем использовать.
 +
 
 +
===Content loss===
  
===[https://rn-unison.github.io/articulos/style_transfer.pdf Image Style Transfer Using Convolutional Neural Networks]<ref name="GEB16">[https://rn-unison.github.io/articulos/style_transfer.pdf Image Style Transfer Using Convolutional Neural Networks] Leon A. Gatys, Alexander S. Ecker, Matthias Bethge (2016)</ref>.===
+
$F^l\left[I\right]$ отражает содержание изображения. Мы хотим чтобы содержание результата было как можно ближе к исходной картинке. Введём для этого такую функцию потерь:
 +
$$\mathcal{L}_{content}(I, O) = \displaystyle\sum_l \frac{\alpha_l}{2 N_l M_l}\displaystyle\sum_{i, j} \left(F^l_{ij}\left[I\right] - F^l_{ij}\left[O\right]\right)^2,$$
 +
где $\alpha_l$ {{---}} вклад $l$-го слоя в функцию потерь.
  
{{Определение
+
===Style loss===
|id=content_loss_def
 
|definition =
 
$\mathcal{L}^{\alpha}_{content}(I, O) = \displaystyle\sum_l \frac{\alpha_l}{2 N_l M_l}\displaystyle\sum_{i, j} (F^l_{ij}\left[I\right] - F^l_{ij}\left[O\right])^2$ {{---}} функция потерь содержания, где
 
$\alpha_l$ {{---}} вклад $l$-го слоя в функцию потерь<ref name="NotOriginalDef">Здесь используется определение функции потерь, которое отличается от статьи Гатиса, но используется в таком виде в статье про гармонизацию.</ref>.}}
 
{{Определение
 
|id=style_loss_def
 
|definition =
 
$\mathcal{L}^{\beta}_{style}(I, O) = \displaystyle\sum_l \frac{\beta_l}{2N_l^2} \displaystyle\sum_{i, j} (G^l_{ij}\left[I\right] - G^l_{ij}\left[O\right])^2$ {{---}} функция потерь стиля, где
 
$\beta_l$ {{---}} вклад $l$-го слоя в функцию потерь<ref name="NotOriginalDef"/>.}}
 
  
Итоговой функцией потерь будет $\mathcal{L}_{Gatys} = \mathcal{L}^{\alpha}_{content}(I, O) + w_{style}\mathcal{L}^{\beta}_{style}(I, O)$<ref name="NotOriginalDef"/>. Вес $w_{style}$, векторы $\alpha$ и $\beta$ являются, в некотором смысле, гиперпараметрами алгоритма, которые нужно подбирать.
+
$G^l\left[S\right]$ отражает статистику выходов фильтров независимо от их расположения, что, в свою очередь, отражает стиль изображения. Чтобы стиль результата был похож на стилевое изображение, введём следующую функцию потерь:
 +
$$\mathcal{L}_{style}(S, O) = \displaystyle\sum_l \frac{\beta_l}{2N_l^2} \displaystyle\sum_{i, j} \left(G^l_{ij}\left[S\right] - G^l_{ij}\left[O\right]\right)^2,$$
 +
где $\beta_l$ {{---}} вклад $l$-го слоя в функцию потерь.
  
Авторы статьи показывают, что в качестве начальной инициализации можно брать изображение $I$, изображение $S$ или белый шум {{---}} алгоритм даёт похожие результаты в этих случаях.
+
===Gatys' loss===
  
[[Файл:GEB16_Figure_6.png|1000px|thumb|center|Начальная инициализация: '''A)''' $O_0 = I$; '''B)''' $O_0 = S$; '''C)''' $O_0 = random$, $4$ примера инициализированы различными белыми шумами ]]
+
Скомбинируем $\mathcal{L}_{content}$ и $\mathcal{L}_{style}$ и получим функцию потерь, которая была использована в алгоритме Гатиса<ref name="GEB16">[https://rn-unison.github.io/articulos/style_transfer.pdf Image Style Transfer Using Convolutional Neural Networks] Leon A. Gatys, Alexander S. Ecker, Matthias Bethge (2016)</ref>:
 +
$$\mathcal{L}_{Gatys}(I, S, O) = \mathcal{L}_{content}(I, O) + w_{style}\mathcal{L}_{style}(S, O).$$
 +
Вес $w_{style}$, векторы $\alpha$ и $\beta$ являются, в некотором смысле, гиперпараметрами алгоритма, которые мы выберем позднее.
  
 
===Histogram Loss===
 
===Histogram Loss===
  
Авторы другой статьи<ref name="WRB17">[https://arxiv.org/pdf/1701.08893.pdf Stable and Controllable Neural Texture Synthesis and Style Transfer Using Histogram Losses] Eric Risser, Pierre Wilmot, Connelly Barnes (2017)</ref> показывают, что результаты, полученные с помощью $\mathcal{L}_{Gatys}$ нестабильны и предложили другую функцию потерь, основанную на ''сопоставлении гистограмм''.
+
Авторы другой статьи<ref name="WRB17">[https://arxiv.org/pdf/1701.08893.pdf Stable and Controllable Neural Texture Synthesis and Style Transfer Using Histogram Losses] Eric Risser, Pierre Wilmot, Connelly Barnes (2017)</ref> показывают, что результаты, полученные с помощью $\mathcal{L}_{Gatys}$ нестабильны и предложили учитывать ещё одну функцию потерь, основанную на '''сопоставлении гистограмм'''.
 
{{Определение
 
{{Определение
 
|definition =
 
|definition =
 
'''Сопоставление гистограмм''' (англ. ''Histogram matching'') {{---}} метод обработки изображения, после которого гистограмма изображения совпадает с целевой гистограммой<ref name="HistMatch">https://en.wikipedia.org/wiki/Histogram_matching</ref>.}}
 
'''Сопоставление гистограмм''' (англ. ''Histogram matching'') {{---}} метод обработки изображения, после которого гистограмма изображения совпадает с целевой гистограммой<ref name="HistMatch">https://en.wikipedia.org/wiki/Histogram_matching</ref>.}}
{{Определение
+
Пусть $R = histmatch(S, O)$ {{---}} отображение пикселей такое, что гистограмма $S$ совпадает с гистограммой $R(O)$, тогда Histogram loss будет выглядеть так:
|definition =
+
$$\mathcal{L}_{hist}(S, O) = \displaystyle\sum_l \gamma_l \displaystyle\sum_{i, j} \left(F^l_{ij}\left[O\right] - R\left(F^l_{ij}\left[O\right]\right)\right)^2,$$
Пусть $R = histmatch(S, O)$ {{---}} отображение пикселей такое, что гистограмма $S$ совпадает с гистограммой $R(O)$.}}
+
где $\gamma_l$ {{---}} вклад $l$-го слоя в функцию потерь.
{{Определение
 
|id=hist_loss_def
 
|definition =
 
$\mathcal{L}^{\gamma}_{hist}(S, O) = \displaystyle\sum_l \gamma_l \displaystyle\sum_{i, j} (F^l_{ij}\left[O\right] - R(F^l_{ij}\left[O\right]))^2$ {{---}} функция потерь гистограмм, где
 
$\gamma_l$ {{---}} вклад $l$-го слоя в функцию потерь}}
 
  
'''Замечание:''' Если в случае остальных функций потерь нетрудно посчитать производную, то здесь могут возникнуть проблемы. Но поскольку $\displaystyle\frac{\partial \mathcal{L}_{hist}}{\partial F^l_{ij}\left[O\right]}$ является нулём почти везде, авторы предлагают при подсчёте производной считать $R(F^l_{ij}\left[O\right])$ константой, которая не зависит от $O$.
+
'''Замечание:''' Если в случае остальных функций потерь нетрудно посчитать производную, то здесь могут возникнуть проблемы. Но поскольку $\displaystyle\frac{\partial \mathcal{L}_{hist}}{\partial F^l_{ij}\left[O\right]}$ является нулём почти везде, авторы предлагают при подсчёте производной считать $R\left(F^l_{ij}\left[O\right]\right)$ константой, которая не зависит от $O$.
  
 
===Total variation loss===
 
===Total variation loss===
  
Также добавим ещё одну функцию потерь, которая удаляет шумы, при этом сохраняя важные детали изображения<ref name="MV15">[https://arxiv.org/pdf/1412.0035.pdf Understanding Deep Image Representations by Inverting Them] Aravindh Mahendran, Andrea Vedaldi (2015)</ref><ref name="JAFF16">[https://arxiv.org/pdf/1603.08155.pdf Perceptual Losses for Real-Time Style Transfer and Super-Resolution] Justin Johnson, Alexandre Alahi, Li Fei-Fei (2016)</ref>.
+
Также добавим ещё одну функцию потерь, которая удаляет шумы, при этом сохраняя важные детали изображения<ref name="MV15">[https://arxiv.org/pdf/1412.0035.pdf Understanding Deep Image Representations by Inverting Them] Aravindh Mahendran, Andrea Vedaldi (2015)</ref><ref name="JAFF16">[https://arxiv.org/pdf/1603.08155.pdf Perceptual Losses for Real-Time Style Transfer and Super-Resolution] Justin Johnson, Alexandre Alahi, Li Fei-Fei (2016)</ref>:
{{Определение
+
 
|id=tv_loss_def
+
$$\mathcal{L}_{tv}(O) = \displaystyle\sum_{i, j} \left(O^l_{i, j} - O^l_{i-1, j}\right)^2 + \left(O^l_{i, j} - O^l_{i, j-1}\right)^2.$$
|definition =
 
$\mathcal{L}_{tv}(O) = \displaystyle\sum_{i, j} (O^l_{i, j} - O^l_{i-1, j}))^2 + (O^l_{i, j} - O^l_{i, j-1}))^2$ {{---}} общая вариационная потеря (англ. ''Total variation loss'').}}
 
  
==Глубокая гармонизация картин<ref name="LPSB18">https://arxiv.org/pdf/1804.03189.pdf Fujun Luan, Sylvain Paris, Eli Shechtman, Kavita Bala (2018)</ref>==
+
==Глубокая гармонизация картин==
  
Для того чтобы вставить изображение в картину или рисунок нужно не только сделать бесшовный переход и изменить цвета, но ещё и изменить текстуру вставляемого изображения, например сымитировать мазки кистью. Используем для этого комбинацию подходов из других статей<ref name="GEB16"/><ref name="JAFF16"/><ref name="WRB17"/>.
+
Для того чтобы вставить изображение в картину или рисунок нужно не только сделать бесшовный переход и изменить цвета, но ещё и изменить текстуру вставляемого изображения, например, сымитировать мазки кистью (рисунок $2$). Используем для этого комбинацию подходов из других статей<ref name="GEB16"/><ref name="JAFF16"/><ref name="WRB17"/>.
  
[[Файл:LPSB18_Figure_1.png|1000px|thumb|center|Пример работы алгоритма ''Deep Image Analogy''<ref name="LYY*17">[https://arxiv.org/pdf/1705.01088.pdf Visual Attribute Transfer through Deep Image Analogy] Jing Liao, Yuan Yao, Lu Yuan, Gang Hua, Sing Bing Kang (2017)</ref> (3 картинка) и ''Deep Painterly Harmonization''<ref name="LPSB18"/> (4 картинка)]]
+
<div class="oo-ui-panelLayout-scrollable" style="display: block; vertical-align:middle; height: auto; max-width: auto; float: center">[[Файл:LPSB18_Figure_1.png|750px|thumb|center|Рисунок $2$: Пример работы алгоритма ''Deep Image Analogy''<ref name="LYY*17">[https://arxiv.org/pdf/1705.01088.pdf Visual Attribute Transfer through Deep Image Analogy] Jing Liao, Yuan Yao, Lu Yuan, Gang Hua, Sing Bing Kang (2017)</ref> ($3$ картинка) и ''Deep Painterly Harmonization''<ref name="LPSB18"/> ($4$ картинка)]]</div>
Алгоритм будет состоять из двух проходов. Первый проход будет делать грубую гармонизацию, а второй {{---}} более тщательную. Отличаться они будут '''стилевым маппингом''' и функциями потерь.
+
Алгоритм состоит из двух проходов. Первый проход делает грубую гармонизацию, а второй {{---}} более тщательную. Отличаются они '''стилевым маппингом''' и функциями потерь<ref name="LPSB18">https://arxiv.org/pdf/1804.03189.pdf Fujun Luan, Sylvain Paris, Eli Shechtman, Kavita Bala (2018)</ref>.
  
 
{{Определение
 
{{Определение
 
|definition =
 
|definition =
'''Стилевым маппингом''' мы будем называть отображение $P : \mathcal{R}^{N_l \times M_l} \rightarrow \mathcal{R}^{N_l \times M_l}$, которое некоторым образом переставляет столбцы матрицы (не обязательно обратимо, то есть столбцы могут теряться и копироваться). Более формально, пусть $p(j)$ {{---}} новая позиция столбца $j$, тогда $P(Q)_{i, p(j)} = Q_{ij}$.}}
+
'''Стилевым маппингом''' назовём отображение $P : \mathcal{R}^{N_l \times M_l} \rightarrow \mathcal{R}^{N_l \times M_l}$, которое некоторым образом переставляет столбцы матрицы (не обязательно обратимо, то есть столбцы могут теряться и копироваться). Более формально, пусть $p(j)$ {{---}} новая позиция столбца $j$, тогда $P(Q)_{i, p(j)} = Q_{ij}$.}}
  
Один проход будет состоять из $3$ частей:
+
Один проход состоит из $3$ частей:
 
# Входное $I$ и стилевое $S$ изображения подаются на вход нейронной сети VGG-19, так мы получаем $F^l_{ij}\left[I\right]$ и $F^l_{ij}\left[S\right]$.
 
# Входное $I$ и стилевое $S$ изображения подаются на вход нейронной сети VGG-19, так мы получаем $F^l_{ij}\left[I\right]$ и $F^l_{ij}\left[S\right]$.
# Для каждого слоя $l$ некоторым алгоритмом cтроится стилевой маппинг $P_l$, который сопоставляет столбцам из $F_l[I]$ столбцы из $F_l[S]$.
+
# Для каждого слоя $l$ некоторым алгоритмом $\pi$ cтроится стилевой маппинг $P_l$, который сопоставляет столбцам из $F_l[I]$ столбцы из $F_l[S]$.
# Изображение $O$ восстанавливается градиентным спуском по пространству изображений, используя некоторую функцию потерь.
+
# Изображение $O$ восстанавливается градиентным спуском по пространству изображений с использованием функции потерь $\mathcal{L}$.
 
<font size="3em">
 
<font size="3em">
 
   '''fun''' $SinglePassHarmonization$(
 
   '''fun''' $SinglePassHarmonization$(
     $I$, <font color="green"> // Входное изображение </font>
+
     <span style="display: inline-block; width: 3em">$I$,</span><font color="green">// Входное изображение </font>
     $M$, <font color="green"> // Маска </font>
+
     <span style="display: inline-block; width: 3em">$M$,</span><font color="green">// Маска </font>
     $S$, <font color="green"> // Стилевое изображение </font>
+
     <span style="display: inline-block; width: 3em">$S$,</span><font color="green">// Стилевое изображение </font>
     $\pi$, <font color="green"> // Алгоритм построения стилевого маппинга </font>
+
     <span style="display: inline-block; width: 3em">$\pi$,</span><font color="green">// Алгоритм построения стилевого маппинга </font>
     $\mathcal{L}$ <font color="green"> // Функция потерь </font>
+
     <span style="display: inline-block; width: 3em">$\mathcal{L}$</span><font color="green">// Функция потерь </font>
 
   ):
 
   ):
 
     <font color="green">// Строим матрицы $F[I]$ и $F[S]$ с помощью свёрточной сети VGG-19 </font>
 
     <font color="green">// Строим матрицы $F[I]$ и $F[S]$ с помощью свёрточной сети VGG-19 </font>
Строка 163: Строка 164:
 
     <font color="green">// Градиентным спуском ищем изображение $O$, которое минимизирует $\mathcal{L}$ </font>
 
     <font color="green">// Градиентным спуском ищем изображение $O$, которое минимизирует $\mathcal{L}$ </font>
 
     $O \leftarrow Reconstruct(I, M, S, P, \mathcal{L})$
 
     $O \leftarrow Reconstruct(I, M, S, P, \mathcal{L})$
 
 
     '''return''' $O$
 
     '''return''' $O$
 
</font>
 
</font>
Строка 171: Строка 171:
 
{{Определение
 
{{Определение
 
|definition =
 
|definition =
'''Вектор активации''' (англ. ''activation vector'') {{---}} это вектор значений функции активации для каждого фильтра свёрточного слоя. Заметим, что столбцы $F_l$ являются векторами активации.}}
+
'''Патчем''' (англ. ''patch'') для столбца $j$ будем называть тензор $3 \times 3 \times N_l$, который состоит из соседних векторов активации в тензоре выхода свёрточного слоя, с центром в $(x, y)$, где $j = y W_l + x$.}}
  
{{Определение
 
|definition =
 
'''Патчем''' (англ. ''patch'') для столбца $j$ будем называть тензор $3 \times 3 \times N_l$, который состоит из соседних векторов активации в тензоре свёрточного слоя, с центром в столбце $j$}}
 
  
[[Файл:LPSB18_Figure_2b.png|250px|thumb|right|Результаты после первого прохода]]
+
<div class="tright" style="clear:none">[[Файл:LPSB18_Figure_2c.png|250px|thumb|none|Рисунок $3.2$: Результаты после второго прохода<ref name="WRB17"/>]]</div>
 +
<div class="tright" style="clear:none">[[Файл:LPSB18_Figure_2b.png|250px|thumb|none|Рисунок $3.1$: Результаты после первого прохода<ref name="WRB17"/>]]</div>
  
Первый проход делает грубую гармонизацию, но при этом он хорошо работает с любыми стилями. Здесь используется алгоритм <code>IndependentMapping</code> для построения стилевого маппинга. Этот алгоритм для каждого столбца $j$ в $F_l[I]$ ищет столбец $p(j)$ в $F_l[S]$, такой что евклидово расстояние между патчем $F_l[I]$ с центром $j$ и патчем $F_l[S]$ с центром $p(j)$ минимально (метод ближайшего соседа).
+
Первый проход делает грубую гармонизацию, но при этом он хорошо работает с любыми стилями (рисунок $3.1$). Здесь используется алгоритм $IndependentMapping$ для построения стилевого маппинга. Этот алгоритм для каждого столбца $j$ в $F_l[I]$ ищет столбец $p(j)$ в $F_l[S]$, такой что евклидово расстояние между патчем $F_l[I]$ с центром $j$ и патчем $F_l[S]$ с центром $p(j)$ минимально (метод ближайшего соседа).
  
 
<font size="3em">   
 
<font size="3em">   
 
   '''fun''' $IndependentMapping$(
 
   '''fun''' $IndependentMapping$(
     $F[I]$, <font color="green"> // Выходы слоёв после входного изображения </font>
+
     <span style="display: inline-block; width: 5em">$F[I]$,</span><font color="green">// Выходы слоёв после входного изображения </font>
     $Mask$, <font color="green"> // Маска </font>
+
     <span style="display: inline-block; width: 5em">$Mask$,</span><font color="green">// Маска </font>
     $F[S]$ <font color="green"> // Выходы слоёв после стилевого изображения </font>
+
     <span style="display: inline-block; width: 5em">$F[S]$</span><font color="green">// Выходы слоёв после стилевого изображения </font>
 
   ):
 
   ):
     '''for''' $l \in [1 : L]$: <font color="green"> // L = количество слоёв сети </font>
+
    <font color="green">// Для всех слоёв от $1$ до $L$ </font>
 +
     '''for''' $l \in [1 : L]$:  
 +
      <font color="green">// Для всех столбцов от $1$ до $M_l$ </font>
 
       '''for''' $j \in [1 : M_l]$:
 
       '''for''' $j \in [1 : M_l]$:
         '''if''' $j \in Resize(Mask, l)$: <font color="green"> // рассматриваем патчи только внутри маски, которую нужно масштабировать в соответсвии с размером слоя $l$ </font>
+
        <font color="green">// Рассматриваем патчи только внутри маски, которую нужно масштабировать в соответсвии с размером слоя $l$ </font>
 +
         '''if''' $j \in Resize(Mask, l)$:
 +
          <font color="green">// Берём самый похожий стилевой патч и записываем его в маппинг. </font>  
 
           $P_l(j) \leftarrow NearestNeighborIndex(F[I], j, F[S])$
 
           $P_l(j) \leftarrow NearestNeighborIndex(F[I], j, F[S])$
 
     '''return''' $P$
 
     '''return''' $P$
 
</font>
 
</font>
  
В первом проходе используется модифицированная функция потерь $\mathcal{L}_{Gatys}$, с тем лишь отличием, что к $F_l[S]$ применяется стилевой маппинг $P_l$.
+
В первом проходе используется модифицированная функция потерь $\mathcal{L}_{Gatys}$, с тем лишь отличием, что в $\mathcal{L}_{style}$ к $F_l[S]$ применяется стилевой маппинг $P_l$:
{{Определение
+
 
|definition =
+
$$\mathcal{L}_1(I, S, O, P) = \mathcal{L}_{content}(I, O) + w_{style}\mathcal{L}_{style}(S, O, P).$$
$\mathcal{L}_1(I, S, O, P) = \mathcal{L}^{\alpha}_{content}(I, O) + w_{style}\mathcal{L}^{\beta}_{style}(S, O, P)$, где $w_{style}$ {{---}} вес стилевой функции потерь}}
+
 
 +
'''Замечание:''' при посчёте градиента $\mathcal{L}_{content}$ используются только пиксели внутри маски<ref>https://github.com/luanfujun/deep-painterly-harmonization/blob/a33a9a70366b6baff1cc0291f857b5895b271fc1/neural_gram.lua#L349</ref>.
  
 
===Второй проход===
 
===Второй проход===
  
[[Файл:LPSB18_Figure_2c.png|250px|thumb|right|Результаты после второго прохода]]
+
[[Файл:LPSB18_Figure_5c.png|thumb|right|250px|Рисунок $4.1$: Только первый проход<ref name="WRB17"/>]]
 +
[[Файл:LPSB18_Figure_5d.png|thumb|right|250px|Рисунок $4.2$: Только второй проход<ref name="WRB17"/>]]
 +
[[Файл:LPSB18_Figure_5f.png|thumb|right|250px|Рисунок $4.3$: Результат с $\mathcal{L}_{style}$ вместо $\mathcal{L}_{s1}$<ref name="WRB17"/>]]
 +
[[Файл:LPSB18_Figure_5g.png|thumb|right|250px|Рисунок $4.4$: Оба прохода<ref name="WRB17"/>]]
 +
[[Файл:LPSB18_Figure_5h.png|thumb|right|250px|Рисунок $4.5$: Финальный результат<ref name="WRB17"/>]]
  
Второй проход делает более качественную гармонизацию после первого прохода. Здесь мы будем использовать более сложный алгоритм <code>ConsistentMapping</code> построения стилевого маппинга и более сложную функцию потерь. Суть этого алгоритма в том, чтобы найти стилевой мапинг на некотором слое $l_{ref}$ и перенести этот маппинг на остальные слои. Также, мы будем предпочитать маппинги, в которых смежные патчи в $F_l[S]$ остаются смежными после мапинга, чтобы обеспечить пространсвенную согласованность (видимо таким образом мы хотим переносить сложные текстуры более качественно, например мазки кистью).
+
Второй проход делает более качественную гармонизацию после первого прохода (рисунок $3.2$). Здесь мы будем использовать более сложный алгоритм $ConsistentMapping$ построения стилевого маппинга и более сложную функцию потерь. Суть этого алгоритма в том, чтобы найти стилевой мапинг на некотором слое $l_{ref}$ и перенести этот маппинг на остальные слои. Также, мы будем предпочитать маппинги, в которых смежные патчи в $F_l[S]$ остаются смежными после мапинга, чтобы обеспечить пространсвенную согласованность (таким образом мы хотим переносить сложные текстуры более качественно, например, мазки кистью). Если применять второй проход сразу, то результаты получаются хуже (рисунок $4.2$).
  
 
<font size="3em">
 
<font size="3em">
   '''fun''' ConsistentMapping(
+
   '''fun''' $ConsistentMapping$(
     $F[I]$, <font color="green"> // Выходы слоёв после входного изображения </font>
+
     <span style="display: inline-block; width: 5em">$F[I]$,</span><font color="green">// Выходы слоёв после входного изображения </font>
     $Mask$, <font color="green"> // Маска </font>
+
     <span style="display: inline-block; width: 5em">$Mask$,</span><font color="green">// Маска </font>
     $F[S]$ <font color="green"> // Выходы слоёв после стилевого изображения </font>
+
     <span style="display: inline-block; width: 5em">$F[S]$</span><font color="green">// Выходы слоёв после стилевого изображения </font>
 
   ):
 
   ):
 
     <font color="green">// Сначала посчитаем маппинг как в IndependentMapping только для слоя $l_{ref}$ </font>
 
     <font color="green">// Сначала посчитаем маппинг как в IndependentMapping только для слоя $l_{ref}$ </font>
Строка 223: Строка 230:
 
         $CSet \leftarrow \{q\}$
 
         $CSet \leftarrow \{q\}$
 
         <font color="green">// Перебираем все смежные патчи </font>
 
         <font color="green">// Перебираем все смежные патчи </font>
         '''for''' $o \in {N, NE, E, SE, S, SW, W, NW}$:  
+
         '''for''' $o \in \left\{N, NE, E, SE, S, SW, W, NW\right\}$:  
 
           <font color="green">// Добавляем в кандидаты патч, сосед которого является маппингом для нашего соседа в соответсвующем направлении </font>
 
           <font color="green">// Добавляем в кандидаты патч, сосед которого является маппингом для нашего соседа в соответсвующем направлении </font>
           $CSet \leftarrow CSet \cup \{P_0(j + o) - o\}$
+
           $CSet \leftarrow CSet \cup \left\{P_0(j + o) - o\right\}$
 
         <font color="green">// Среди всех кандидатов выбираем тот, который ближе всего к маппингам наших соседей </font>
 
         <font color="green">// Среди всех кандидатов выбираем тот, который ближе всего к маппингам наших соседей </font>
         $P_{l_{ref}}(j) \leftarrow argmin_{c \in CSet}\displaystyle\sum_o \|(F_{l_{ref}}[S]_c - F_{l_{ref}}[S]_{P_0(j + o)}\|^2$
+
         $P_{l_{ref}}(j) \leftarrow \underset{c \in CSet}{\mathrm{argmin}}\displaystyle\sum_o \left\|(F_{l_{ref}}[S]_c - F_{l_{ref}}[S]_{P_0(j + o)}\right\|^2$
 
    
 
    
 
     <font color="green">// Теперь нужно перенести маппинг для $l_{ref}$ на остальные слои </font>
 
     <font color="green">// Теперь нужно перенести маппинг для $l_{ref}$ на остальные слои </font>
Строка 239: Строка 246:
 
           <font color="green">// Переносим позицию $q$ обратно на слой $l$</font>
 
           <font color="green">// Переносим позицию $q$ обратно на слой $l$</font>
 
           $P_l(j) \leftarrow ChangeResolution(l_{ref}, l, q)$
 
           $P_l(j) \leftarrow ChangeResolution(l_{ref}, l, q)$
     '''return''' P
+
     '''return''' $P$
 
</font>
 
</font>
  
При вычислении стилевого маппинга появляется очень много дублирующихся векторов, что даёт не очень хорошие результаты. Поэтому при вычислении матрицы Грама выкинем повторяющиеся векторы. Назовём эту функцию потерь $\mathcal{L}_{s1}$.
+
При вычислении стилевого маппинга появляется очень много дублирующихся векторов, что даёт не очень хорошие результаты (рисунок $4.3$). Поэтому при вычислении матрицы Грама выкинем повторяющиеся векторы. Назовём функцию потерь с такой модификацией $\mathcal{L}_{s1}$.
  
{{Определение
+
$$\mathcal{L}_2(I, S, O, P) = \mathcal{L}_{content}(I, O) + w_{style}\mathcal{L}_{s1}(S, O, P) + w_{hist}\mathcal{L}_{hist}(S, O) + w_{tv}\mathcal{L}_{tv}(O),$$  
|definition =
+
где $w_{style}, w_{hist}, w_{tv}$ {{---}} веса соответсвующих функций потерь.
$\mathcal{L}_2(I, S, O, P) = \mathcal{L}^{\alpha}_{content}(I, O) + w_{style}\mathcal{L}^{\beta}_{s1}(S, O, P) + w_{hist}\mathcal{L}^{\gamma}_{hist}(S, O) + w_{tv}\mathcal{L}_{tv}(O)$, где $w_{style}$, $w_{hist}$, $w_{tv}$ {{---}} веса соответсвующих функций потерь}}
 
  
{|
+
<!--
| [[Файл:LPSB18_Figure_5c.png|250px|thumb|none|Только второй проход]]
+
{| class="wikitable" style="background-color:#FFF; text-align:center"
| [[Файл:LPSB18_Figure_5d.png|250px|thumb|none|Только первый проход]]
+
|-
| [[Файл:LPSB18_Figure_5f.png|250px|thumb|none|Результат с $\mathcal{L}_{style}$ вместо $\mathcal{L}_{s1}$]]
+
| Рисунок $4.1$: Только первый проход<ref name="WRB17"/>
 +
| Рисунок $4.2$: Только второй проход<ref name="WRB17"/>
 +
| Рисунок $4.3$: Результат с $\mathcal{L}_{style}$ вместо $\mathcal{L}_{s1}$<ref name="WRB17"/>
 +
| Рисунок $4.4$: Оба прохода<ref name="WRB17"/>
 +
| Рисунок $4.5$: Финальный результат<ref name="WRB17"/>
 +
|-
 +
| [[Файл:LPSB18_Figure_5c.png|250px]]
 +
| [[Файл:LPSB18_Figure_5d.png|250px]]
 +
| [[Файл:LPSB18_Figure_5f.png|250px]]
 +
| [[Файл:LPSB18_Figure_5g.png|250px]]
 +
| [[Файл:LPSB18_Figure_5h.png|250px]]
 
|}
 
|}
 +
-->
  
 
===Итоговый алгоритм===
 
===Итоговый алгоритм===
  
Теперь осталось запустить две стадии  
+
Теперь осталось запустить две стадии:
  
 
<font size="3em">
 
<font size="3em">
 
   '''fun''' $Harmonization$(
 
   '''fun''' $Harmonization$(
     $I$, <font color="green"> // Входное изображение </font>
+
     <span style="display: inline-block; width: 5em">$I$,</span><font color="green">// Входное изображение </font>
     $Mask$, <font color="green"> // Маска </font>
+
     <span style="display: inline-block; width: 5em">$Mask$,</span><font color="green">// Маска </font>
     $S$ <font color="green"> // Стилевое изображение </font>
+
     <span style="display: inline-block; width: 5em">$S$</span><font color="green">// Стилевое изображение </font>
 
   ):
 
   ):
 
     <font color="green">// Грубый проход алгоритма. Каждый слой рассматривается отдельно при построении стилевого маппинга. </font>
 
     <font color="green">// Грубый проход алгоритма. Каждый слой рассматривается отдельно при построении стилевого маппинга. </font>
Строка 273: Строка 290:
 
===Постобработка===
 
===Постобработка===
  
[[Файл:LPSB18_Figure_6abc.png|400px|thumb|right|Результат постобработки (без постобработки , после первой стадии, после второй стадии)]]
+
[[Файл:LPSB18_Figure_6abc.png|400px|thumb|right|Рисунок $5$: Результат постобработки (без постобработки, после первой стадии, после второй стадии)<ref name="WRB17"/>]]
  
Описанный алгоритм даёт хорошие результаты в целом, но при ближайшем рассмотрении могут быть артефакты. Поэтому сделаем двухступенчатую постобработку (подробное описание есть в оригинальной статье<ref name="LPSB18"/>):
+
Описанный алгоритм даёт хорошие результаты в целом, но при ближайшем рассмотрении могут быть артефакты (рисунок $5$). Поэтому сделаем двухступенчатую постобработку (подробное описание есть в оригинальной статье<ref name="LPSB18"/>):
# Переведём изображение в [https://en.wikipedia.org/wiki/CIELAB_color_space CIELAB] и применим [https://en.wikipedia.org/wiki/Guided_filter Guided filter] для a и b каналов.
+
# Переведём изображение в цветовое пространство [https://en.wikipedia.org/wiki/CIELAB_color_space $L*\alpha*\beta$] и применим [https://en.wikipedia.org/wiki/Guided_filter Guided filter] для a и b каналов.
# С помощью алгоритма PatchMatch<ref name="BSFG09">https://www.researchgate.net/profile/Eli_Shechtman/publication/220184392_PatchMatch_A_Randomized_Correspondence_Algorithm_for_Structural_Image_Editing/links/02e7e520897b12bf0f000000.pdf Connelly Barnes, Eli Shechtman, Adam Finkelstein, Dan B Goldman (2009)</ref> и того же Guided filter делаем так чтобы все патчи выходного изображения присутсвовали в стилевом (чтобы не было новых объектов или структур)
+
# С помощью алгоритма PatchMatch<ref name="BSFG09">https://www.researchgate.net/profile/Eli_Shechtman/publication/220184392_PatchMatch_A_Randomized_Correspondence_Algorithm_for_Structural_Image_Editing/links/02e7e520897b12bf0f000000.pdf Connelly Barnes, Eli Shechtman, Adam Finkelstein, Dan B Goldman (2009)</ref> и того же Guided filter делаем так, чтобы все патчи выходного изображения присутсвовали в стилевом (чтобы не было новых объектов или структур).
  
===Подбор гиперпараметров===
+
===Детали реализации===
  
[[Файл:LPSB18_Figure_4.png|400px|thumb|none|Влияние $l_{ref}$ на результат]]
+
[[Файл:LPSB18_Figure_4.png|400px|thumb|right|Рисунок $6$: Влияние $l_{ref}$ на результат<ref name="WRB17"/>]]
  
Возьмём $l_{ref}$ = conv4_1.
+
Возьмём $l_{ref}$ = conv4_1 (что будет если использовать другие слои видно на рисунке $6$).
 
Выберем следующие веса для слоёв:
 
Выберем следующие веса для слоёв:
  
Строка 343: Строка 360:
 
|}
 
|}
  
Введём гиперпараметр $\tau$ и возьмём $w_{style} = w_{hist} = \tau$, $w_{tv} = \tau\frac{10}{1 + \exp(10^4 * noise(S) - 25)}$, где $noise(S) = med_{i,j}\left\{(O^l_{i, j} - O^l_{i-1, j}))^2 + (O^l_{i, j} - O^l_{i, j-1}))^2\right\}$<ref>[https://github.com/luanfujun/deep-painterly-harmonization/blob/a33a9a70366b6baff1cc0291f857b5895b271fc1/neural_paint.lua#L470 код функции $noise$</ref>
+
<!--
 +
{| class="wikitable"
 +
|+ Веса функций потерь
 +
|-
 +
! $w_{style}$
 +
! $w_{hist}$
 +
! $w_{tv}$
 +
|-
 +
| $\tau$
 +
| $\tau$
 +
| $\tau\frac{10}{1 + \exp(10^4 * noise(S) - 25)}$
 +
|}
 +
-->
 +
Введём гиперпараметр $\tau$ и возьмём $w_{style} = w_{hist} = \tau$, $w_{tv} = \tau\frac{10}{1 + \exp(10^4 * noise(S) - 25)}$, где $noise(S) = \underset{i,j}{\mathrm{med}}\left\{\left(O^l_{i, j} - O^l_{i-1, j}\right)^2 + \left(O^l_{i, j} - O^l_{i, j-1}\right)^2\right\}$<ref>[https://github.com/luanfujun/deep-painterly-harmonization/blob/a33a9a70366b6baff1cc0291f857b5895b271fc1/neural_paint.lua#L470 код функции $noise$.</ref>.
  
Для того чтобы подбирать $\tau$ авторы статьи использовали классификатор стилей изображений. Они взяли VGG-19, обучили её классифицировать 18 различных стилей. Эти стили были разделены на 3 категории с разными $\tau$. Используя Softmax можно интерполировать необходимый $\tau$ по следующей таблице:
+
Для того чтобы подбирать $\tau$ авторы статьи использовали классификатор стилей изображений. Они взяли VGG-19, обучили её классифицировать $18$ различных стилей. Эти стили были разделены на $3$ категории с разными $\tau$. Используя $Softmax$ можно интерполировать необходимый $\tau$ по следующей таблице:
  
 
{| class="wikitable"
 
{| class="wikitable"
Строка 365: Строка 395:
 
| $10$
 
| $10$
 
|}
 
|}
 +
 +
На рисунке $4.4$ результат алгоритма без подбора гиперпараметров. Видно, что самолёт ярче, чем остальное изображение. С подбором параметров получается более естественный результат (рисунок $4.5$).
  
 
===Примеры===
 
===Примеры===
 +
Примеры взяты с [https://github.com/luanfujun/deep-painterly-harmonization/tree/master/results Github авторов].
  
 
{|
 
{|
Строка 374: Строка 407:
 
! Постобработка
 
! Постобработка
 
|-
 
|-
| [[Файл:5_target.jpg|300px]]
+
| [[Файл:5_target.jpg|180px]]
| [[Файл:5_naive.jpg|300px]]
+
| [[Файл:5_naive.jpg|180px]]
| [[Файл:5_final_res.png|300px]]
+
| [[Файл:5_final_res.png|180px]]
| [[Файл:5_final_res2.png|300px]]
+
| [[Файл:5_final_res2.png|180px]]
 
|-
 
|-
| [[Файл:6_target.jpg|300px]]
+
| [[Файл:6_target.jpg|180px]]
| [[Файл:6_naive.jpg|300px]]
+
| [[Файл:6_naive.jpg|180px]]
| [[Файл:6_final_res.png|300px]]
+
| [[Файл:6_final_res.png|180px]]
| [[Файл:6_final_res2.png|300px]]
+
| [[Файл:6_final_res2.png|180px]]
 
|-
 
|-
| [[Файл:10_target.jpg|300px]]
+
| [[Файл:10_target.jpg|180px]]
| [[Файл:10_naive.jpg|300px]]
+
| [[Файл:10_naive.jpg|180px]]
| [[Файл:10_final_res.png|300px]]
+
| [[Файл:10_final_res.png|180px]]
| [[Файл:10_final_res2.png|300px]]
+
| [[Файл:10_final_res2.png|180px]]
 
|}
 
|}
 +
 +
===Более новые подходы===
 +
 +
* [https://arxiv.org/pdf/2006.00809.pdf Foreground-aware Semantic Representations for Image Harmonization]
 +
* [https://arxiv.org/pdf/2009.09169.pdf BargainNet: Background-Guided Domain Translation for Image Harmonization]
  
 
==Глубокий блендинг==
 
==Глубокий блендинг==
 +
 +
<!-- Настя лапочка :3 -->
  
 
Алгоритм глубокого блендинга состоит из двух этапов. На первом этапе на стилевое изображения $S$ бесшовно накладывается входное изображение $I$, получается подготовительное блендинг-изображение $B$. На втором этапе $B$ модифицируется таким образом, чтобы результат по стилю был похож на $S$.
 
Алгоритм глубокого блендинга состоит из двух этапов. На первом этапе на стилевое изображения $S$ бесшовно накладывается входное изображение $I$, получается подготовительное блендинг-изображение $B$. На втором этапе $B$ модифицируется таким образом, чтобы результат по стилю был похож на $S$.
  
 
Будем считать, что на вход подаются изображения, прошедшие предварительную обработку:
 
Будем считать, что на вход подаются изображения, прошедшие предварительную обработку:
* Используемая для вставки часть $I$ вырезана с помощью маски  
+
* Используемая для вставки часть $I$ вырезана с помощью маски.
* $M$ и $I$ выровнены относительно $S$
+
* $M$ и $I$ выровнены относительно $S$.
* Размеры матриц, задающих $M, S, I$ совпадают
+
* Размеры матриц, задающих $M, S, I$, совпадают.
  
 
'''Примеры входных данных:'''
 
'''Примеры входных данных:'''
 
{| class="wikitable" style="background-color:#FFF; text-align:center"
 
{| class="wikitable" style="background-color:#FFF; text-align:center"
|-
+
! '''Стилевое <br/> изображение $S$'''<ref name='ZWS20'/>
! '''Стилевое <br/> изображение $S$'''
 
 
| [[Файл:Deep bl s1.png|150px]]
 
| [[Файл:Deep bl s1.png|150px]]
 
| [[Файл:Deep bl s2.png|150px]]
 
| [[Файл:Deep bl s2.png|150px]]
 
| [[Файл:Deep bl s3.png|150px]]
 
| [[Файл:Deep bl s3.png|150px]]
 
|-
 
|-
! '''Накладываемое <br/> изображение $I$'''
+
! '''Накладываемое <br/> изображение $I$'''<ref name='ZWS20'/>
 
| [[Файл:Deep bl i1.png|150px]]
 
| [[Файл:Deep bl i1.png|150px]]
 
| [[Файл:Deep bl i2.png|150px]]
 
| [[Файл:Deep bl i2.png|150px]]
 
| [[Файл:Deep bl i3.png|150px]]
 
| [[Файл:Deep bl i3.png|150px]]
 
|}
 
|}
 
На обоих этапах алгоритм минимизирует взвешенную сумму следующих функций потерь:
 
* [[Блендинг_изображений#content_loss_def|Функция потерь содержания]] $\mathcal{L}_{cont}$ для сохранения содержания накладываемого изображения $I$
 
* [[Блендинг_изображений#style_loss_def|Функция потерь стиля]] $\mathcal{L}_{style}$ для переноса стиля изображения $S$ на $I$
 
* [[Блендинг_изображений#hist_loss_def|Гистограмная функция потерь]] $\mathcal{L}_{hist}$ для стабилизации переноса стиля
 
* [[Блендинг_изображений#tv_loss_def|Функция потерь полного отклонения]] $\mathcal{L}_{tv}$ для удаления шумов
 
* [[Блендинг_изображений#grad_loss_def|Градиентная функция потерь]] $\mathcal{L}_{grad}$ для бесшовности наложения
 
 
Для подсчета $\mathcal{L}_{style}$ и $\mathcal{L}_{content}$ авторами статьи<ref name='ZWS20'/> использовалась сеть VGG-19<ref name="SZ14"/>, обученная на ImageNet<ref name="ImageNet">https://image-net.org/papers/imagenet_cvpr09.pdf J. Deng, W. Dong, R. Socher, L.-J. Li, K. Li, and L. FeiFei. Imagenet: A large-scale hierarchical image database</ref>.
 
  
 
{{Определение
 
{{Определение
Строка 428: Строка 458:
  
 
{{Определение
 
{{Определение
|id=grad_loss_def
 
 
|definition =
 
|definition =
$\mathcal{L}_{grad}(S, I, M, O) = \displaystyle\frac{1}{2HW}\displaystyle\sum_{m=1}^H \displaystyle\sum_{n=1}^W [\,\nabla^2 f(B) - (\nabla^2 f(S) + \nabla^2 f(I)) ]\,^2_{mn}$ {{---}} градиентная функция потерь (англ. ''Possion gradient loss''). $\nabla^2$ {{---}} оператор Лапласа. $H, W$ {{---}} высота и ширина изображений. $B = CAP(M, S, O)$ {{---}} блендинговое изображение, оптимизируемое относительно $O$. }}
+
'''Дискретный оператор Лапласа''' (фильтр Лапласа) $\mathbf{D}^2$ {{---}} аналог непрерывного оператора Лапласа $\nabla^2$, который позволяет выделять контуры изображения (рисунки $7.1$ и $7.2$).
 +
$$\mathbf{D}^2=\begin{bmatrix}0 & 1 & 0\\1 & -4 & 1\\0 & 1 & 0\end{bmatrix}.$$ }}
 +
{| class="wikitable" style="float:right; clear:right;"
 +
!Рисунок $7.1$:<br>Исходное изображение<ref>https://en.wikipedia.org/wiki/Lenna#/media/File:Lenna_(test_image).png</ref>
 +
!Рисунок $7.2$:<br>Применение фильтра Лапласа
 +
|-
 +
| [[Файл:Lenna.png|220px]]
 +
| [[Файл:Lenna_Laplacian_Neg.png|220px]]
 +
|}
  
 +
Для сохранения контуров изображений $S$ и $I$ в области вставки воспользуемся идеей из [[Блендинг изображений#Блендинг Пуассона|метода Пуассона]] и введём следующую функцию потерь<ref name='ZWS20'/>:
 +
$$\mathcal{L}_{grad}(S, I, M, O) = \displaystyle\frac{1}{2HW}\displaystyle\sum_{m=1}^H \displaystyle\sum_{n=1}^W \left[ \mathbf{D}^2 B - \left(\mathbf{D}^2 S + \mathbf{D}^2 I\right) \right]^2_{mn},$$
 +
где $H, W$ {{---}} высота и ширина изображений. $B = CAP(M, S, O)$ {{---}} блендинговое изображение, оптимизируемое относительно $O$.
 +
 +
Рассмотрим область $\overline{\Omega} = \{\;p \;| \;M_p = 0\; \}$. Заметим, что градиент $I$ в $\overline{\Omega}$ равен нулю. Тогда градиенты $S$ и $B$ совпадают, и задача минимизации $\mathcal{L}_{grad}$ решается только в области вставки. 
 +
 +
На обоих этапах алгоритм минимизирует взвешенную сумму следующих функций потерь:
 +
* $\mathcal{L}_{content}$ для сохранения содержания накладываемого изображения $I$.
 +
* $\mathcal{L}_{style}$ для переноса стиля изображения $S$ на $I$.
 +
* $\mathcal{L}_{hist}$ для стабилизации переноса стиля.
 +
* $\mathcal{L}_{tv}$ для удаления шумов.
 +
* $\mathcal{L}_{grad}$ для сохранения контуров фона и изображения.
 +
 +
<!-- 0JAg0LXRidGRINCd0LDRgdGC0Y8g0L7Rh9C10L3RjCDQvNC40LvQsNGPIQ== -->
 +
Для подсчета $\mathcal{L}_{style}$ и $\mathcal{L}_{content}$ авторами статьи<ref name='ZWS20'>[https://openaccess.thecvf.com/content_WACV_2020/papers/Zhang_Deep_Image_Blending_WACV_2020_paper.pdf Deep Image Blending] Lingzhi Zhang, Tarmily Wen, Jianbo Shi (2020)</ref> использовалась сеть VGG-19<ref name="SZ14"/>, обученная на ImageNet<ref name="ImageNet">https://image-net.org/papers/imagenet_cvpr09.pdf J. Deng, W. Dong, R. Socher, L.-J. Li, K. Li, and L. FeiFei. Imagenet: A large-scale hierarchical image database</ref>.
  
 
=== Первый этап ===
 
=== Первый этап ===
[[Файл:Deep bl 1stage.png|thumb|right|200px|Результат первого этапа]]
 
 
На первом этапе изображение $I$ накладывается на фоновое изображение $S$ таким образом, чтобы были незаметны швы.  
 
На первом этапе изображение $I$ накладывается на фоновое изображение $S$ таким образом, чтобы были незаметны швы.  
 
Построение начинается с белого шума $Z$, который оптимизируется в области вставки путем минимизации суммарной функции потерь $\mathcal{L}_{total}$, представленной взвешенной суммой всех функций потерь, описанных выше:
 
Построение начинается с белого шума $Z$, который оптимизируется в области вставки путем минимизации суммарной функции потерь $\mathcal{L}_{total}$, представленной взвешенной суммой всех функций потерь, описанных выше:
$$ \mathcal{L}_{total}(Z) = w_{grad}\mathcal{L}_{grad}(I, S, B) + w_{cont}\mathcal{L}_{cont}(I, M, Z) + w_{style}\mathcal{L}_{style}(S, B) + w_{tv}\mathcal{L}_{tv}(B) + w_{hist}\mathcal{L}_{hist}(S, B) $$
+
$$ \mathcal{L}_{total}(Z) = w_{grad}\mathcal{L}_{grad}(I, S, B) + w_{content}\mathcal{L}_{content}(I, M, Z) + w_{style}\mathcal{L}_{style}(S, B) + w_{tv}\mathcal{L}_{tv}(B) + w_{hist}\mathcal{L}_{hist}(S, B).$$
Отметим, что $\mathcal{L}_{cont}$ зависит от маски и отвечает за сохранение содержания $I$ в области вставки.
+
Для решения задачи минимизации авторы статьи<ref name='ZWS20' /> используют алгоритм L-BFGS<ref name="LBFGS">https://en.wikipedia.org/wiki/Limited-memory_BFGS Limited-memory BFGS - Wikipedia</ref>.
  
Отличительной чертой этого этапа является использование функции потерь $\mathcal{L}_{grad}$, приближающей градиент результата к градиенту $I$ в области наложения, за счет чего достигается бесшовность. Для вычисления производных второго порядка используется фильтр Лапласа.
+
Отметим, что $\mathcal{L}_{content}$ зависит от маски и отвечает за сохранение содержания $I$ в области вставки.
  
В результате получается подготовительное блендинг-изображение $B$:
+
Отличительной чертой этого этапа является использование функции потерь $\mathcal{L}_{grad}$, приближающей градиент результата к градиенту $I$ в области наложения, за счет чего достигается бесшовность.
$$
+
 
B_p =
+
В результате получается подготовительное блендинг-изображение $B$.
\begin{cases}
 
Z_p,\; \text{если } M_p = 1 \\
 
S_p,\; \text{иначе }
 
\end{cases}
 
$$
 
  
 
<font size="3em">
 
<font size="3em">
 
   '''fun''' $SeamlessBlending$(
 
   '''fun''' $SeamlessBlending$(
     $I$, <font color="green">  // Входное изображение </font>
+
     <span style="display: inline-block; width: 3em">$I$,</span> <font color="green">  // Входное изображение </font>
     $M$, <font color="green">  // Маска </font>
+
     <span style="display: inline-block; width: 3em">$M$,</span> <font color="green">  // Маска </font>
     $S$ <font color="green">  // Стилевое изображение </font>
+
     <span style="display: inline-block; width: 3em">$S$ </span> <font color="green">  // Стилевое изображение </font>
 
   ):
 
   ):
 
     <font color="green">// Инициализируем первое приближение белым шумом </font>
 
     <font color="green">// Инициализируем первое приближение белым шумом </font>
Строка 461: Строка 507:
 
     $B \leftarrow CAP(M, S, Z)$
 
     $B \leftarrow CAP(M, S, Z)$
 
     <font color="green">// Определим суммарную функцию потерь с весами слагаемых $w$</font>
 
     <font color="green">// Определим суммарную функцию потерь с весами слагаемых $w$</font>
     $\mathcal{L}_{total}(Z) \leftarrow w_{grad}\mathcal{L}_{grad}(I, S, B) + w_{cont}\mathcal{L}_{cont}(I, M, Z) + w_{style}\mathcal{L}_{style}(S, B) + w_{tv}\mathcal{L}_{tv}(B) + w_{hist}\mathcal{L}_{hist}(S, B)$
+
     $\mathcal{L}_{total}(Z) \leftarrow w_{grad}\mathcal{L}_{grad}(I, S, B) + w_{content}\mathcal{L}_{content}(I, M, Z) + w_{style}\mathcal{L}_{style}(S, B) + w_{tv}\mathcal{L}_{tv}(B) + w_{hist}\mathcal{L}_{hist}(S, B)$
 
     <font color="green">// С помощью алгоритма L-BFGS ищем изображение $Z$, которое минимизирует $\mathcal{L}_{total}$ </font>
 
     <font color="green">// С помощью алгоритма L-BFGS ищем изображение $Z$, которое минимизирует $\mathcal{L}_{total}$ </font>
 
     $Z \leftarrow Reconstruct(\mathcal{L}_{total}, Z)$
 
     $Z \leftarrow Reconstruct(\mathcal{L}_{total}, Z)$
Строка 468: Строка 514:
  
 
=== Второй этап ===
 
=== Второй этап ===
[[Файл:Deep bl 2stage.png|thumb|right|200px|Результат после обоих этапов]]
+
 
 
Второй этап алгоритма представляет собой модификацию полученного на первом этапе блендинг-изображения $B$ таким образом, чтобы стиль изображения был наиболее близок к стилю $S$.  
 
Второй этап алгоритма представляет собой модификацию полученного на первом этапе блендинг-изображения $B$ таким образом, чтобы стиль изображения был наиболее близок к стилю $S$.  
  
 
В отличие от предыдущего этапа, функция потерь не включает в себя $\mathcal{L}_{grad}$:
 
В отличие от предыдущего этапа, функция потерь не включает в себя $\mathcal{L}_{grad}$:
$$\mathcal{L}_{total}(O) = w_{cont}\mathcal{L}_{cont}(B, O) + w_{style}\mathcal{L}_{style}(S, O) + w_{tv}\mathcal{L}_{tv}(O) + w_{hist}\mathcal{L}_{hist}(S, O)$$
+
$$\mathcal{L}_{total}(O) = w_{content}\mathcal{L}_{content}(B, O) + w_{style}\mathcal{L}_{style}(S, O) + w_{tv}\mathcal{L}_{tv}(O) + w_{hist}\mathcal{L}_{hist}(S, O).$$
  
Минимизация происходит относительно результата алгоритма $O$, которой инициализируется изображением $B$.
+
Минимизация происходит относительно результата алгоритма $O$, который инициализируется изображением $B$.
  
 
<font size="3em">
 
<font size="3em">
 
   '''fun''' $StyleRefinement$(
 
   '''fun''' $StyleRefinement$(
    $B$, <font color="green">  // Подготовительное блендинг-изображение, результат первого этапа </font>
+
    <span style="display: inline-block; width: 3em">$B$,</span> <font color="green">  // Подготовительное блендинг-изображение, результат первого этапа </font>
    $M$, <font color="green">  // Маска </font>
+
    <span style="display: inline-block; width: 3em">$M$,</span> <font color="green">  // Маска </font>
    $S$ <font color="green">  // Стилевое изображение </font>
+
    <span style="display: inline-block; width: 3em">$S$ </span> <font color="green">  // Стилевое изображение </font>
 
   ):
 
   ):
 
     $O \leftarrow B$
 
     $O \leftarrow B$
 
     <font color="green">// Определим суммарную функцию потерь с весами слагаемых $w$</font>
 
     <font color="green">// Определим суммарную функцию потерь с весами слагаемых $w$</font>
     $\mathcal{L}_{total}(O) \leftarrow w_{cont}\mathcal{L}_{cont}(B, O) + w_{style}\mathcal{L}_{style}(S, O) + w_{tv}\mathcal{L}_{tv}(O) + w_{hist}\mathcal{L}_{hist}(S, O)$
+
     $\mathcal{L}_{total}(O) \leftarrow w_{cont}\mathcal{L}_{content}(B, O) + w_{style}\mathcal{L}_{style}(S, O) + w_{tv}\mathcal{L}_{tv}(O) + w_{hist}\mathcal{L}_{hist}(S, O)$
 
     <font color="green">// С помощью алгоритма L-BFGS ищем изображение $O$, которое минимизирует $\mathcal{L}_{total}$ </font>
 
     <font color="green">// С помощью алгоритма L-BFGS ищем изображение $O$, которое минимизирует $\mathcal{L}_{total}$ </font>
 
     $O \leftarrow Reconstruct(\mathcal{L}_{total}, O)$
 
     $O \leftarrow Reconstruct(\mathcal{L}_{total}, O)$
 
     '''return''' $O$
 
     '''return''' $O$
 
</font>
 
</font>
 +
 +
Примеры с [https://github.com/owenzlz/DeepImageBlending/tree/master/results Github авторов]:
 +
 +
{|
 +
! После первого этапа
 +
! После обоих этапов
 +
|-
 +
| [[Файл:1_first_pass.png|300px]]
 +
| [[Файл:1_second_pass.png|300px]]
 +
|-
 +
| [[Файл:3_first_pass.png|300px]]
 +
| [[Файл:3_second_pass.png|300px]]
 +
|-
 +
| [[Файл:5_first_pass.png|300px]]
 +
| [[Файл:5_second_pass.png|300px]]
 +
|}
 +
 +
===Детали реализации===
 +
В статье использовались следующие значения коэффициентов:
 +
 +
{| class="wikitable"
 +
|+ Веса функций потерь
 +
|-
 +
! Этап
 +
! $w_{grad}$
 +
! $w_{content}$
 +
! $w_{style}$
 +
! $w_{hist}$
 +
! $w_{tv}$
 +
|-
 +
! $1$
 +
| $10^5$
 +
| $1$
 +
| $10^5$
 +
| $1$
 +
| $10^{-6}$
 +
|-
 +
! $2$
 +
| $0$
 +
| $1$
 +
| $10^7$
 +
| $1$
 +
| $10^{-6}$
 +
|}
 +
<!--Для подсчета $\mathcal{L}_{style}$ используются слои conv1_2, conv2_2, conv3_3, conv4_3 VGG-19, для $\mathcal{L}_{content}$ {{---}} conv2_2.-->
 +
{| class="wikitable"
 +
|+ Коэффициенты $\alpha$ и $\beta$
 +
|-
 +
! Параметр
 +
! conv1_2
 +
! conv2_2
 +
! conv3_3
 +
! conv4_3
 +
|-
 +
! $\alpha$
 +
| $0$
 +
| $1$
 +
| $0$
 +
| $0$
 +
|-
 +
! $\beta$
 +
| $1/4$
 +
| $1/4$
 +
| $1/4$
 +
| $1/4$
 +
|}
 +
 +
На обоих этапах максимальное количество итераций алгоритма L-BFGS {{---}} $1000$.
  
 
=== Примеры ===
 
=== Примеры ===
[[Файл:МЛ блендинг пример.png|1000px]]
+
Примеры с [https://github.com/owenzlz/DeepImageBlending/tree/master/results Github авторов]:
  
==Ссылки==
+
[[Файл:МЛ блендинг пример.png|800px]]
  
[https://en.wikipedia.org/wiki/Gramian_matrix Матрица Грама (англ.)]
+
==См. также==
 +
* [[Neural_Style_Transfer|Neural Style Transfer]]
 +
* [[Сверточные_нейронные_сети | Свёрточная нейронная сеть]]
 +
 
 +
==Источники информации==
 +
* [https://en.wikipedia.org/wiki/Histogram_matching Histogram matching]
 +
* Patrick Perez, Michel Gangnet, Andrew Blake (2003), [https://www.cs.jhu.edu/~misha/Fall07/Papers/Perez03.pdf Poisson Image Editing].
 +
<!--* Karen Simonyan, Andrew Zisserman (2014), [https://arxiv.org/pdf/1409.1556.pdf Very Deep Convolutional Networks for Large-Scale Image Recognition]-->
 +
* Leon A. Gatys, Alexander S. Ecker, Matthias Bethge (2016), [https://rn-unison.github.io/articulos/style_transfer.pdf Image Style Transfer Using Convolutional Neural Networks]
 +
<!--* Eric Risser, Pierre Wilmot, Connelly Barnes (2017), [https://arxiv.org/pdf/1701.08893.pdf Stable and Controllable Neural Texture Synthesis and Style Transfer Using Histogram Losses]-->
 +
<!--* Aravindh Mahendran, Andrea Vedaldi (2015), [https://arxiv.org/pdf/1412.0035.pdf Understanding Deep Image Representations by Inverting Them]-->
 +
<!--* Justin Johnson, Alexandre Alahi, Li Fei-Fei (2016), [https://arxiv.org/pdf/1603.08155.pdf Perceptual Losses for Real-Time Style Transfer and Super-Resolution]-->
 +
<!--* Jing Liao, Yuan Yao, Lu Yuan, Gang Hua, Sing Bing Kang (2017), [https://arxiv.org/pdf/1705.01088.pdf Visual Attribute Transfer through Deep Image Analogy]-->
 +
* Fujun Luan, Sylvain Paris, Eli Shechtman, Kavita Bala (2018), [https://arxiv.org/pdf/1804.03189.pdf Deep Painterly Harmonization]
 +
* Lingzhi Zhang, Tarmily Wen, Jianbo Shi (2020), [https://openaccess.thecvf.com/content_WACV_2020/papers/Zhang_Deep_Image_Blending_WACV_2020_paper.pdf Deep Image Blending]
  
 
==Примечания==
 
==Примечания==
 +
 +
[[Категория: Машинное обучение]]
 +
[[Категория: Нейронные сети]]
 +
[[Категория: Сверточные нейронные сети]]

Текущая версия на 19:44, 4 сентября 2022

Копирование элемента одного изображения и его вставка на другое изображение — один из наиболее используемых методов для создания графического контента. Простая вставка, как правило, бросается в глаза и делает результат похожим на коллаж, во многих случаях этот эффект является нежелательным.

Определение:
Блендинг изображений (англ. image blending) — метод, позволяющий вставить часть одного изображения в другое таким образом, чтобы композиция изображений выглядела естественно, без швов на границах вставки.

Основная трудность задачи заключается в том, что естественность результата зависит не только от бесшовности наложения, но и от схожести цветов и текстуры вставляемого и фонового изображений.

Вставляемое изображение Фоновое изображение Простая вставка Желаемый результат
Diver bl diver.png Diver bl sea.png Diver bl2.png Diver bl3.png

Блендинг Пуассона

Рисунок $1.1$: Пример перепада яркости при простой вставке[1]
Рисунок $1.2$: Результат применения блендинга Пуассона[1]

Простая вставка одного изображения поверх другого нередко влечет заметный перепад яркости на границе вставки (рисунок $1.1$). Метод Пуассона заключается в сглаживании этого перепада (рисунок $1.2$) с целью сделать дефект менее заметным, используя градиент вставляемого изображения и значения пикселей фонового изображения на границе вставки.

Замечание: Для RGB изображений задача минимизации решается для каждого цветового канала отдельно.

Давайте обозначим за $S$ изображение, которое служит фоном, а за $I$ — изображение, вставляемое поверх $S$. Область вставки будем задавать двоичной маской $M$, содержащей единицы в области наложения. Например:

Фоновое
изображение $S$
Накладываемое
изображение $I$
Маска $M$
Poisson cat.jpg Poisson cherry.jpg Poisson cherry mask.png

Идея подхода

Пусть замкнутое множество $P \subset \mathbb{R}^2$ — область, на которой определено изображение $S$, а замкнутое множество $\Omega \subset P$ с границей $\partial\Omega$ и внутренностью $int(\Omega)$ — область вставки изображения $I$.

Пусть $f_S$ — скалярная функция, определенная на $P \setminus int(\Omega)$, задает фоновое изображение $S$; $f$ — неизвестная скалярная функция, определенная на $int(\Omega)$, задает, каким образом должно выглядеть результат блендинга в области вставки.

$v_I$ — векторное поле, определенное на $\Omega$. В качестве $v_I$ возьмем градиент вставляемого изображения $I$: $v_I = \nabla f_I$.

Нашей задачей является поиск такой функции $f$, чтобы блендинговое изображение выглядело реалистично. Для этого минимизируем разность градиента функции $f$ и векторного поля $v_I$, считая, что $f = f_S$ на границе $\Omega$. $$ \underset{f}{\mathrm{min}} \underset{\Omega}{\iint} |\nabla f - v_I|^2, \text{где } f|_{\partial \Omega} = f_S|_{\partial \Omega}. $$ Решение задачи минимизации является единственным решением уравнения Пуассона для граничных условий Дирихле. $$\nabla^2 f = \nabla^2 f_I \text{ на } \Omega, f|_{\partial \Omega} = f_S|_{\partial \Omega}, \text{где } \nabla^2 \text{— оператор Лапласа.}$$

Дискретный случай

Пусть $p$ — координаты $(x, y)$ пикселя двухмерного изображения. За $Img_p$ обозначим значение пикселя с координатами $p$ изображения $Img$. Пусть $\Omega = \left\{ p\;|\;M_p = 1 \right\}$ — область, заданная маской $M$. Тогда $\partial \Omega$ — координаты границы вставляемой области, а $int(\Omega)$ — внутренность области.

Пусть $N_p$ — множество соседей $p$ (максимум четыре пикселя, имеющих общую границу с $p$, т.е. пиксели со следующими координатами: $(x + 1, y), (x - 1, y), (x, y + 1), (x, y - 1)$). Для всех пар $(p, q)$ таких, что $q \in N_p$, введем $v_{pq} = I_p - I_q$.

Введем переменные $O_p, p \in \Omega$. Так как мы хотим сделать результат бесшовным, пиксели $O_p, p \in \partial\Omega$, сделаем равными $S_p$. Для $p, q \in int(\Omega),\; q \in N_p$ постараемся найти такое $O$, чтобы разность $O_p$ и $O_q$ была близка к $v_{pq}$. Для этого решим задачу минимизации:

$$ \underset{O_p,\; p \in \Omega}{\mathrm{min}}\; \underset{p, q \in \Omega}{\sum}\; \left(O_p - O_q - v_{pq}\right)^2, \text{где } O_p = S_p, p \in \partial \Omega. $$

Заметим, что функция, которую мы хотим минимизировать, квадратична относительно переменных $O_p, p \in int(\Omega)$. Для решения задачи минимизации вычислим частные производные по этим переменным и найдем значения переменных, при которых частные производные будут равны нулю. $$\frac{\partial{\underset{p, q \in \Omega}{\sum}\; \left(O_p - O_q - v_{pq}\right)^2}}{\partial O_p} = \underset{q \in N_p}{\sum} 2 \left(O_p - O_q - v_{pq}\right) - \underset{q \in N_p}{\sum} 2 \left(O_q - O_p - v_{qp}\right) = 2 \underset{q \in N_p}{\sum} 2 \left(O_p - O_q - v_{pq}\right).$$

Приравнивая к нулю, получаем: $|N_p| O_p - \underset{q \in N_p}{\sum} O_q = \underset{q \in N_p}{\sum} v_{pq}$.

Добавим условие $O_p = S_p, p \in \partial \Omega$: $\;|N_p| O_p - \underset{q \in N_p \cap int(\Omega)}{\sum} O_q = \underset{q \in N_p \cap \partial \Omega}{\sum} S_q + \underset{q \in N_p}{\sum} v_{pq}$.

Для решения систем уравнений такого вида могут быть использованы итеративные алгоритмы Gauss-Seidel и V-cycle multigrid[2].

Получаем значения пикселей $O_p$, $p \in int(\Omega)$. Тогда результат $B$ блендинга Пуассона будет следующим: $$ B_p = \begin{cases} O_p,\; \text{если } p \in int(\Omega) \\ S_p,\; \text{иначе } \end{cases}. $$

Mетод Пуассона сдвигает цвета накладываемого изображения, сохраняя свойства градиента (т.е. если пиксель $I_{p1}$ был меньше $I_{p2}$, то после преобразования $I_{p1}$ не станет больше $I_{p2}$), однако само значение градиета может получиться другим.[3]

Нейронный перенос стиля

Основная статья: Neural Style Transfer

Прежде чем переходить к гармонизации картин, рассмотрим задачу нейронного переноса стиля с изображения $S$ на изображение $I$. Для этого используются выходы скрытых слоёв свёрточной нейронной сети VGG-19[4] (конкретные слои указаны ниже в деталях реализации).

Основная идея генерации изображения — решение оптимизационной задачи $\mathcal{L}(I, S, O) \xrightarrow[O]{} min$, где $O$ — итоговое изображение, $\mathcal{L}(I, S, O)$ — функция потерь. Такую задачу можно решать градиентным спуском в пространстве изображений используя метод обратного распространения ошибки.

Определение:
Пусть $F^l\left[I\right] \in \mathcal{R}^{N_l \times M_l}$ — матрица значений выхода $l$-го слоя сети на изображении $I$. Выход $l$-го слоя сети имеет размерность $N_l \times W_l \times H_l$. Представим его как матрицу $N_l \times M_l$, где $N_l$ — количество фильтров в $l$-ом слое, $M_l$ — количество признаков ($M_l = W_l H_l$). Тогда $F^l_{ij}\left[I\right]$ — $j$-ый признак $i$-го фильтра в $l$-ом слое. Столбец матрицы $F^l\left[I\right]$ размера $N_l$ назовём вектором активации.


Определение:
Матрица Грама (англ. Gram matrix) — матрица попарных скалярных произведений.

$$G^l\left[S\right] \in \mathcal{R}^{N_l \times N_l},$$

$$G^l\left[S\right] = F^l\left[S\right]F^l\left[S\right]^T.$$


Далее рассмотренны функции потерь, которые мы будем использовать.

Content loss

$F^l\left[I\right]$ отражает содержание изображения. Мы хотим чтобы содержание результата было как можно ближе к исходной картинке. Введём для этого такую функцию потерь: $$\mathcal{L}_{content}(I, O) = \displaystyle\sum_l \frac{\alpha_l}{2 N_l M_l}\displaystyle\sum_{i, j} \left(F^l_{ij}\left[I\right] - F^l_{ij}\left[O\right]\right)^2,$$ где $\alpha_l$ — вклад $l$-го слоя в функцию потерь.

Style loss

$G^l\left[S\right]$ отражает статистику выходов фильтров независимо от их расположения, что, в свою очередь, отражает стиль изображения. Чтобы стиль результата был похож на стилевое изображение, введём следующую функцию потерь: $$\mathcal{L}_{style}(S, O) = \displaystyle\sum_l \frac{\beta_l}{2N_l^2} \displaystyle\sum_{i, j} \left(G^l_{ij}\left[S\right] - G^l_{ij}\left[O\right]\right)^2,$$ где $\beta_l$ — вклад $l$-го слоя в функцию потерь.

Gatys' loss

Скомбинируем $\mathcal{L}_{content}$ и $\mathcal{L}_{style}$ и получим функцию потерь, которая была использована в алгоритме Гатиса[5]: $$\mathcal{L}_{Gatys}(I, S, O) = \mathcal{L}_{content}(I, O) + w_{style}\mathcal{L}_{style}(S, O).$$ Вес $w_{style}$, векторы $\alpha$ и $\beta$ являются, в некотором смысле, гиперпараметрами алгоритма, которые мы выберем позднее.

Histogram Loss

Авторы другой статьи[6] показывают, что результаты, полученные с помощью $\mathcal{L}_{Gatys}$ нестабильны и предложили учитывать ещё одну функцию потерь, основанную на сопоставлении гистограмм.

Определение:
Сопоставление гистограмм (англ. Histogram matching) — метод обработки изображения, после которого гистограмма изображения совпадает с целевой гистограммой[7].

Пусть $R = histmatch(S, O)$ — отображение пикселей такое, что гистограмма $S$ совпадает с гистограммой $R(O)$, тогда Histogram loss будет выглядеть так: $$\mathcal{L}_{hist}(S, O) = \displaystyle\sum_l \gamma_l \displaystyle\sum_{i, j} \left(F^l_{ij}\left[O\right] - R\left(F^l_{ij}\left[O\right]\right)\right)^2,$$ где $\gamma_l$ — вклад $l$-го слоя в функцию потерь.

Замечание: Если в случае остальных функций потерь нетрудно посчитать производную, то здесь могут возникнуть проблемы. Но поскольку $\displaystyle\frac{\partial \mathcal{L}_{hist}}{\partial F^l_{ij}\left[O\right]}$ является нулём почти везде, авторы предлагают при подсчёте производной считать $R\left(F^l_{ij}\left[O\right]\right)$ константой, которая не зависит от $O$.

Total variation loss

Также добавим ещё одну функцию потерь, которая удаляет шумы, при этом сохраняя важные детали изображения[8][9]:

$$\mathcal{L}_{tv}(O) = \displaystyle\sum_{i, j} \left(O^l_{i, j} - O^l_{i-1, j}\right)^2 + \left(O^l_{i, j} - O^l_{i, j-1}\right)^2.$$

Глубокая гармонизация картин

Для того чтобы вставить изображение в картину или рисунок нужно не только сделать бесшовный переход и изменить цвета, но ещё и изменить текстуру вставляемого изображения, например, сымитировать мазки кистью (рисунок $2$). Используем для этого комбинацию подходов из других статей[5][9][6].

Рисунок $2$: Пример работы алгоритма Deep Image Analogy[10] ($3$ картинка) и Deep Painterly Harmonization[11] ($4$ картинка)

Алгоритм состоит из двух проходов. Первый проход делает грубую гармонизацию, а второй — более тщательную. Отличаются они стилевым маппингом и функциями потерь[11].


Определение:
Стилевым маппингом назовём отображение $P : \mathcal{R}^{N_l \times M_l} \rightarrow \mathcal{R}^{N_l \times M_l}$, которое некоторым образом переставляет столбцы матрицы (не обязательно обратимо, то есть столбцы могут теряться и копироваться). Более формально, пусть $p(j)$ — новая позиция столбца $j$, тогда $P(Q)_{i, p(j)} = Q_{ij}$.


Один проход состоит из $3$ частей:

  1. Входное $I$ и стилевое $S$ изображения подаются на вход нейронной сети VGG-19, так мы получаем $F^l_{ij}\left[I\right]$ и $F^l_{ij}\left[S\right]$.
  2. Для каждого слоя $l$ некоторым алгоритмом $\pi$ cтроится стилевой маппинг $P_l$, который сопоставляет столбцам из $F_l[I]$ столбцы из $F_l[S]$.
  3. Изображение $O$ восстанавливается градиентным спуском по пространству изображений с использованием функции потерь $\mathcal{L}$.

 fun $SinglePassHarmonization$(
   $I$,// Входное изображение 
   $M$,// Маска 
   $S$,// Стилевое изображение 
   $\pi$,// Алгоритм построения стилевого маппинга 
   $\mathcal{L}$// Функция потерь 
 ):
   // Строим матрицы $F[I]$ и $F[S]$ с помощью свёрточной сети VGG-19 
   $F[I] \leftarrow ComputeNeuralActivations(I)$
   $F[S] \leftarrow ComputeNeuralActivations(S)$
   // Строим стилевой маппинг 
   $P \leftarrow \pi(F[I], M, F[S])$
   // Градиентным спуском ищем изображение $O$, которое минимизирует $\mathcal{L}$ 
   $O \leftarrow Reconstruct(I, M, S, P, \mathcal{L})$
   return $O$

Первый проход

Определение:
Патчем (англ. patch) для столбца $j$ будем называть тензор $3 \times 3 \times N_l$, который состоит из соседних векторов активации в тензоре выхода свёрточного слоя, с центром в $(x, y)$, где $j = y W_l + x$.


Рисунок $3.2$: Результаты после второго прохода[6]
Рисунок $3.1$: Результаты после первого прохода[6]

Первый проход делает грубую гармонизацию, но при этом он хорошо работает с любыми стилями (рисунок $3.1$). Здесь используется алгоритм $IndependentMapping$ для построения стилевого маппинга. Этот алгоритм для каждого столбца $j$ в $F_l[I]$ ищет столбец $p(j)$ в $F_l[S]$, такой что евклидово расстояние между патчем $F_l[I]$ с центром $j$ и патчем $F_l[S]$ с центром $p(j)$ минимально (метод ближайшего соседа).

 fun $IndependentMapping$(
   $F[I]$,// Выходы слоёв после входного изображения 
   $Mask$,// Маска 
   $F[S]$// Выходы слоёв после стилевого изображения 
 ):
   // Для всех слоёв от $1$ до $L$ 
   for $l \in [1 : L]$: 
     // Для всех столбцов от $1$ до $M_l$ 
     for $j \in [1 : M_l]$:
       // Рассматриваем патчи только внутри маски, которую нужно масштабировать в соответсвии с размером слоя $l$ 
       if $j \in Resize(Mask, l)$:
         // Берём самый похожий стилевой патч и записываем его в маппинг.  
         $P_l(j) \leftarrow NearestNeighborIndex(F[I], j, F[S])$
   return $P$

В первом проходе используется модифицированная функция потерь $\mathcal{L}_{Gatys}$, с тем лишь отличием, что в $\mathcal{L}_{style}$ к $F_l[S]$ применяется стилевой маппинг $P_l$:

$$\mathcal{L}_1(I, S, O, P) = \mathcal{L}_{content}(I, O) + w_{style}\mathcal{L}_{style}(S, O, P).$$

Замечание: при посчёте градиента $\mathcal{L}_{content}$ используются только пиксели внутри маски[12].

Второй проход

Рисунок $4.1$: Только первый проход[6]
Рисунок $4.2$: Только второй проход[6]
Рисунок $4.3$: Результат с $\mathcal{L}_{style}$ вместо $\mathcal{L}_{s1}$[6]
Рисунок $4.4$: Оба прохода[6]
Рисунок $4.5$: Финальный результат[6]

Второй проход делает более качественную гармонизацию после первого прохода (рисунок $3.2$). Здесь мы будем использовать более сложный алгоритм $ConsistentMapping$ построения стилевого маппинга и более сложную функцию потерь. Суть этого алгоритма в том, чтобы найти стилевой мапинг на некотором слое $l_{ref}$ и перенести этот маппинг на остальные слои. Также, мы будем предпочитать маппинги, в которых смежные патчи в $F_l[S]$ остаются смежными после мапинга, чтобы обеспечить пространсвенную согласованность (таким образом мы хотим переносить сложные текстуры более качественно, например, мазки кистью). Если применять второй проход сразу, то результаты получаются хуже (рисунок $4.2$).

 fun $ConsistentMapping$(
   $F[I]$,// Выходы слоёв после входного изображения 
   $Mask$,// Маска 
   $F[S]$// Выходы слоёв после стилевого изображения 
 ):
   // Сначала посчитаем маппинг как в IndependentMapping только для слоя $l_{ref}$ 
   for $j \in [1 : M_{l_{ref}}]$:
     if $j \in Resize(Mask, l_{ref})$:
       $P_0(j) \leftarrow NearestNeighborIndex(F[I], j, F[S])$
 
   // Далее обеспечиваем пространсвенную согласованность 
   for $j \in [1 : M_{l_{ref}}]$:
     if $j \in Resize(Mask, l_{ref})$:
       $q \leftarrow P_0(j)$
       // Инициализируем множество кандидатов на новый маппинг 
       $CSet \leftarrow \{q\}$
       // Перебираем все смежные патчи 
       for $o \in \left\{N, NE, E, SE, S, SW, W, NW\right\}$: 
         // Добавляем в кандидаты патч, сосед которого является маппингом для нашего соседа в соответсвующем направлении 
         $CSet \leftarrow CSet \cup \left\{P_0(j + o) - o\right\}$
       // Среди всех кандидатов выбираем тот, который ближе всего к маппингам наших соседей 
       $P_{l_{ref}}(j) \leftarrow \underset{c \in CSet}{\mathrm{argmin}}\displaystyle\sum_o \left\|(F_{l_{ref}}[S]_c - F_{l_{ref}}[S]_{P_0(j + o)}\right\|^2$
 
   // Теперь нужно перенести маппинг для $l_{ref}$ на остальные слои 
   for $l \in [1 : L] \setminus \{l_{ref}\}$:
     for $j \in [1 : M_l]$:
       if $j \in Resize(Mask, l)$:
         // Вычисляем позицию $j'$ на слое $l_{ref}$ соответствующую позиции $j$ на слое $l$
         $j' \leftarrow ChangeResolution(l, l_{ref}, j)$
         // Берём маппинг для позиции $j'$
         $q \leftarrow P_{l_{ref}}(j')$
         // Переносим позицию $q$ обратно на слой $l$
         $P_l(j) \leftarrow ChangeResolution(l_{ref}, l, q)$
   return $P$

При вычислении стилевого маппинга появляется очень много дублирующихся векторов, что даёт не очень хорошие результаты (рисунок $4.3$). Поэтому при вычислении матрицы Грама выкинем повторяющиеся векторы. Назовём функцию потерь с такой модификацией $\mathcal{L}_{s1}$.

$$\mathcal{L}_2(I, S, O, P) = \mathcal{L}_{content}(I, O) + w_{style}\mathcal{L}_{s1}(S, O, P) + w_{hist}\mathcal{L}_{hist}(S, O) + w_{tv}\mathcal{L}_{tv}(O),$$ где $w_{style}, w_{hist}, w_{tv}$ — веса соответсвующих функций потерь.


Итоговый алгоритм

Теперь осталось запустить две стадии:

 fun $Harmonization$(
   $I$,// Входное изображение 
   $Mask$,// Маска 
   $S$// Стилевое изображение 
 ):
   // Грубый проход алгоритма. Каждый слой рассматривается отдельно при построении стилевого маппинга. 
   $I' \leftarrow SinglePassHarmonization(I, Mask, S, IndependentMapping, \mathcal{L}_1)$
   // Улучшение результата. Стилевой маппинг строится консистентно для всех слоёв. 
   $O  \leftarrow SinglePassHarmonization(I', Mask, S, ConsistentMapping, \mathcal{L}_2)$
   return $O$

Постобработка

Рисунок $5$: Результат постобработки (без постобработки, после первой стадии, после второй стадии)[6]

Описанный алгоритм даёт хорошие результаты в целом, но при ближайшем рассмотрении могут быть артефакты (рисунок $5$). Поэтому сделаем двухступенчатую постобработку (подробное описание есть в оригинальной статье[11]):

  1. Переведём изображение в цветовое пространство $L*\alpha*\beta$ и применим Guided filter для a и b каналов.
  2. С помощью алгоритма PatchMatch[13] и того же Guided filter делаем так, чтобы все патчи выходного изображения присутсвовали в стилевом (чтобы не было новых объектов или структур).

Детали реализации

Рисунок $6$: Влияние $l_{ref}$ на результат[6]

Возьмём $l_{ref}$ = conv4_1 (что будет если использовать другие слои видно на рисунке $6$). Выберем следующие веса для слоёв:

Первый проход
Параметр conv1_1 conv2_1 conv3_1 conv4_1 conv5_1
$\alpha$ $0$ $0$ $0$ $1$ $0$
$\beta$ $0$ $0$ $1/3$ $1/3$ $1/3$
Второй проход
Параметр conv1_1 conv2_1 conv3_1 conv4_1 conv5_1
$\alpha$ $0$ $0$ $0$ $1$ $0$
$\beta$ $1/4$ $1/4$ $1/4$ $1/4$ $0$
$\gamma$ $1/2$ $0$ $0$ $1/2$ $0$

Введём гиперпараметр $\tau$ и возьмём $w_{style} = w_{hist} = \tau$, $w_{tv} = \tau\frac{10}{1 + \exp(10^4 * noise(S) - 25)}$, где $noise(S) = \underset{i,j}{\mathrm{med}}\left\{\left(O^l_{i, j} - O^l_{i-1, j}\right)^2 + \left(O^l_{i, j} - O^l_{i, j-1}\right)^2\right\}$[14].

Для того чтобы подбирать $\tau$ авторы статьи использовали классификатор стилей изображений. Они взяли VGG-19, обучили её классифицировать $18$ различных стилей. Эти стили были разделены на $3$ категории с разными $\tau$. Используя $Softmax$ можно интерполировать необходимый $\tau$ по следующей таблице:

Категория стиля Примеры стилей $\tau$
Слабый Барокко, Высокое Возрождение $1$
Средний Абстрактное Искусство, Постимпрессионизм $5$
Сильный Кубизм, Экспрессионизм $10$

На рисунке $4.4$ результат алгоритма без подбора гиперпараметров. Видно, что самолёт ярче, чем остальное изображение. С подбором параметров получается более естественный результат (рисунок $4.5$).

Примеры

Примеры взяты с Github авторов.

Исходное изображение Простая вставка Результат Постобработка
5 target.jpg 5 naive.jpg 5 final res.png 5 final res2.png
6 target.jpg 6 naive.jpg 6 final res.png 6 final res2.png
10 target.jpg 10 naive.jpg 10 final res.png 10 final res2.png

Более новые подходы

Глубокий блендинг

Алгоритм глубокого блендинга состоит из двух этапов. На первом этапе на стилевое изображения $S$ бесшовно накладывается входное изображение $I$, получается подготовительное блендинг-изображение $B$. На втором этапе $B$ модифицируется таким образом, чтобы результат по стилю был похож на $S$.

Будем считать, что на вход подаются изображения, прошедшие предварительную обработку:

  • Используемая для вставки часть $I$ вырезана с помощью маски.
  • $M$ и $I$ выровнены относительно $S$.
  • Размеры матриц, задающих $M, S, I$, совпадают.

Примеры входных данных:

Стилевое
изображение $S$
[1]
Deep bl s1.png Deep bl s2.png Deep bl s3.png
Накладываемое
изображение $I$
[1]
Deep bl i1.png Deep bl i2.png Deep bl i3.png


Определение:
Простой вставкой (англ. copy and paste) $CAP(M, S, I)$ будем назвать изображение, полученное наложением части изображения $I$, заданной маской $M$, на изображение $S$. $CAP(M, S, I) = I \odot M + S \odot (1 - M)$, где $\odot$ — покомпонентное умножение.


Определение:
Дискретный оператор Лапласа (фильтр Лапласа) $\mathbf{D}^2$ — аналог непрерывного оператора Лапласа $\nabla^2$, который позволяет выделять контуры изображения (рисунки $7.1$ и $7.2$). $$\mathbf{D}^2=\begin{bmatrix}0 & 1 & 0\\1 & -4 & 1\\0 & 1 & 0\end{bmatrix}.$$
Рисунок $7.1$:
Исходное изображение[15]
Рисунок $7.2$:
Применение фильтра Лапласа
Lenna.png Lenna Laplacian Neg.png

Для сохранения контуров изображений $S$ и $I$ в области вставки воспользуемся идеей из метода Пуассона и введём следующую функцию потерь[1]: $$\mathcal{L}_{grad}(S, I, M, O) = \displaystyle\frac{1}{2HW}\displaystyle\sum_{m=1}^H \displaystyle\sum_{n=1}^W \left[ \mathbf{D}^2 B - \left(\mathbf{D}^2 S + \mathbf{D}^2 I\right) \right]^2_{mn},$$ где $H, W$ — высота и ширина изображений. $B = CAP(M, S, O)$ — блендинговое изображение, оптимизируемое относительно $O$.

Рассмотрим область $\overline{\Omega} = \{\;p \;| \;M_p = 0\; \}$. Заметим, что градиент $I$ в $\overline{\Omega}$ равен нулю. Тогда градиенты $S$ и $B$ совпадают, и задача минимизации $\mathcal{L}_{grad}$ решается только в области вставки.

На обоих этапах алгоритм минимизирует взвешенную сумму следующих функций потерь:

  • $\mathcal{L}_{content}$ для сохранения содержания накладываемого изображения $I$.
  • $\mathcal{L}_{style}$ для переноса стиля изображения $S$ на $I$.
  • $\mathcal{L}_{hist}$ для стабилизации переноса стиля.
  • $\mathcal{L}_{tv}$ для удаления шумов.
  • $\mathcal{L}_{grad}$ для сохранения контуров фона и изображения.

Для подсчета $\mathcal{L}_{style}$ и $\mathcal{L}_{content}$ авторами статьи[1] использовалась сеть VGG-19[4], обученная на ImageNet[16].

Первый этап

На первом этапе изображение $I$ накладывается на фоновое изображение $S$ таким образом, чтобы были незаметны швы. Построение начинается с белого шума $Z$, который оптимизируется в области вставки путем минимизации суммарной функции потерь $\mathcal{L}_{total}$, представленной взвешенной суммой всех функций потерь, описанных выше: $$ \mathcal{L}_{total}(Z) = w_{grad}\mathcal{L}_{grad}(I, S, B) + w_{content}\mathcal{L}_{content}(I, M, Z) + w_{style}\mathcal{L}_{style}(S, B) + w_{tv}\mathcal{L}_{tv}(B) + w_{hist}\mathcal{L}_{hist}(S, B).$$ Для решения задачи минимизации авторы статьи[1] используют алгоритм L-BFGS[17].

Отметим, что $\mathcal{L}_{content}$ зависит от маски и отвечает за сохранение содержания $I$ в области вставки.

Отличительной чертой этого этапа является использование функции потерь $\mathcal{L}_{grad}$, приближающей градиент результата к градиенту $I$ в области наложения, за счет чего достигается бесшовность.

В результате получается подготовительное блендинг-изображение $B$.

 fun $SeamlessBlending$(
   $I$,   // Входное изображение 
   $M$,   // Маска 
   $S$    // Стилевое изображение 
 ):
   // Инициализируем первое приближение белым шумом 
   $Z \leftarrow RandomNoise() $
   $B \leftarrow CAP(M, S, Z)$
   // Определим суммарную функцию потерь с весами слагаемых $w$
   $\mathcal{L}_{total}(Z) \leftarrow w_{grad}\mathcal{L}_{grad}(I, S, B) + w_{content}\mathcal{L}_{content}(I, M, Z) + w_{style}\mathcal{L}_{style}(S, B) + w_{tv}\mathcal{L}_{tv}(B) + w_{hist}\mathcal{L}_{hist}(S, B)$
   // С помощью алгоритма L-BFGS ищем изображение $Z$, которое минимизирует $\mathcal{L}_{total}$ 
   $Z \leftarrow Reconstruct(\mathcal{L}_{total}, Z)$
   return $CAP(M, S, Z)$

Второй этап

Второй этап алгоритма представляет собой модификацию полученного на первом этапе блендинг-изображения $B$ таким образом, чтобы стиль изображения был наиболее близок к стилю $S$.

В отличие от предыдущего этапа, функция потерь не включает в себя $\mathcal{L}_{grad}$: $$\mathcal{L}_{total}(O) = w_{content}\mathcal{L}_{content}(B, O) + w_{style}\mathcal{L}_{style}(S, O) + w_{tv}\mathcal{L}_{tv}(O) + w_{hist}\mathcal{L}_{hist}(S, O).$$

Минимизация происходит относительно результата алгоритма $O$, который инициализируется изображением $B$.

 fun $StyleRefinement$(
    $B$,   // Подготовительное блендинг-изображение, результат первого этапа 
    $M$,   // Маска 
    $S$    // Стилевое изображение 
 ):
   $O \leftarrow B$
   // Определим суммарную функцию потерь с весами слагаемых $w$
   $\mathcal{L}_{total}(O) \leftarrow w_{cont}\mathcal{L}_{content}(B, O) + w_{style}\mathcal{L}_{style}(S, O) + w_{tv}\mathcal{L}_{tv}(O) + w_{hist}\mathcal{L}_{hist}(S, O)$
   // С помощью алгоритма L-BFGS ищем изображение $O$, которое минимизирует $\mathcal{L}_{total}$ 
   $O \leftarrow Reconstruct(\mathcal{L}_{total}, O)$
   return $O$

Примеры с Github авторов:

После первого этапа После обоих этапов
1 first pass.png 1 second pass.png
3 first pass.png 3 second pass.png
5 first pass.png 5 second pass.png

Детали реализации

В статье использовались следующие значения коэффициентов:

Веса функций потерь
Этап $w_{grad}$ $w_{content}$ $w_{style}$ $w_{hist}$ $w_{tv}$
$1$ $10^5$ $1$ $10^5$ $1$ $10^{-6}$
$2$ $0$ $1$ $10^7$ $1$ $10^{-6}$
Коэффициенты $\alpha$ и $\beta$
Параметр conv1_2 conv2_2 conv3_3 conv4_3
$\alpha$ $0$ $1$ $0$ $0$
$\beta$ $1/4$ $1/4$ $1/4$ $1/4$

На обоих этапах максимальное количество итераций алгоритма L-BFGS — $1000$.

Примеры

Примеры с Github авторов:

МЛ блендинг пример.png

См. также

Источники информации

Примечания

  1. Перейти к: 1,0 1,1 1,2 1,3 1,4 1,5 1,6 Deep Image Blending Lingzhi Zhang, Tarmily Wen, Jianbo Shi (2020)
  2. Перейти Poisson Image Editing Patrick Perez, Michel Gangnet, Andrew Blake (2003)
  3. Перейти https://erkaman.github.io/posts/poisson_blending.html Poisson blending для самых маленьких
  4. Перейти к: 4,0 4,1 Very Deep Convolutional Networks for Large-Scale Image Recognition Karen Simonyan, Andrew Zisserman (2014)
  5. Перейти к: 5,0 5,1 Image Style Transfer Using Convolutional Neural Networks Leon A. Gatys, Alexander S. Ecker, Matthias Bethge (2016)
  6. Перейти к: 6,00 6,01 6,02 6,03 6,04 6,05 6,06 6,07 6,08 6,09 6,10 Stable and Controllable Neural Texture Synthesis and Style Transfer Using Histogram Losses Eric Risser, Pierre Wilmot, Connelly Barnes (2017)
  7. Перейти https://en.wikipedia.org/wiki/Histogram_matching
  8. Перейти Understanding Deep Image Representations by Inverting Them Aravindh Mahendran, Andrea Vedaldi (2015)
  9. Перейти к: 9,0 9,1 Perceptual Losses for Real-Time Style Transfer and Super-Resolution Justin Johnson, Alexandre Alahi, Li Fei-Fei (2016)
  10. Перейти Visual Attribute Transfer through Deep Image Analogy Jing Liao, Yuan Yao, Lu Yuan, Gang Hua, Sing Bing Kang (2017)
  11. Перейти к: 11,0 11,1 11,2 https://arxiv.org/pdf/1804.03189.pdf Fujun Luan, Sylvain Paris, Eli Shechtman, Kavita Bala (2018)
  12. Перейти https://github.com/luanfujun/deep-painterly-harmonization/blob/a33a9a70366b6baff1cc0291f857b5895b271fc1/neural_gram.lua#L349
  13. Перейти https://www.researchgate.net/profile/Eli_Shechtman/publication/220184392_PatchMatch_A_Randomized_Correspondence_Algorithm_for_Structural_Image_Editing/links/02e7e520897b12bf0f000000.pdf Connelly Barnes, Eli Shechtman, Adam Finkelstein, Dan B Goldman (2009)
  14. Перейти [https://github.com/luanfujun/deep-painterly-harmonization/blob/a33a9a70366b6baff1cc0291f857b5895b271fc1/neural_paint.lua#L470 код функции $noise$.
  15. Перейти https://en.wikipedia.org/wiki/Lenna#/media/File:Lenna_(test_image).png
  16. Перейти https://image-net.org/papers/imagenet_cvpr09.pdf J. Deng, W. Dong, R. Socher, L.-J. Li, K. Li, and L. FeiFei. Imagenet: A large-scale hierarchical image database
  17. Перейти https://en.wikipedia.org/wiki/Limited-memory_BFGS Limited-memory BFGS - Wikipedia