從泊松方程的解法,聊到泊松圖像融合
雷鋒網 AI 科技評論按,本文作者成指導,位元組跳動演算法工程師,本文首發於知乎,雷鋒網 AI 科技評論獲其授權轉載,正文內容如下:
2004 年 SIGGRAPH 上,Microsoft Research UK 有篇經典的圖像融合文章《Poisson Image Editing》。先看看其驚人的融合結果(非論文配圖,本人實驗結果):
這篇文章的實現,無關目前演算法領域大火的神經網路,而是基於泊松方程推導得出。
泊松方程是什麼?
很多朋友比較熟悉概率論裡面的泊松分布。泊松方程,也是同一個數學家泊松發明的。但卻和泊松分布沒有什麼關係,是泊松物理學領域提出的一個偏微分方程。
這裡
表示的是拉普拉斯運算元,
和
(
在泊松方程中是已知量)可以是實數或複數值方程,特殊情況當
時被稱為拉普拉斯方程。當處於歐幾里得空間時,拉普拉斯運算元通常表示為
。
學習圖像處理的朋友對於
和
比較熟悉,分別表示二階微分(直角坐標系下的散度)、一階微分(直角坐標系下的梯度)。
微分與卷積
連續空間中的微分計算,就是大學裡微積分那一套公式。但是在計算機的世界裡,數據都是在離散空間中進行表示,對於圖像而言,基本的計算單元就是像素點。讓我們從最簡單的情形,一維數組的微分說起:
表示位置 x 一階微分計算(一階中心導):
表示位置 x 二階微分計算(二階中心導):
隨著
,上面的微分算式的結果會逐漸逼近真實的微分值。對於圖像而言,這裡 h 最小可分割單元是像素,也就表示像素間的間距,可視為 1。再看看,二階微分的公式,是不是可以看成
的卷積核
在一維數組上進行卷積計算的結果(卷積中心在 x 上)。
至此,不難理解,離散數據(例如圖像)上的微分操作完全可以轉換為卷積操作。
當數組維度更高,變成二維數組呢?也就是處理圖像的拉普拉斯運算元:
此時,卷積核尺寸應該是
,具體數值為
,稱為拉普拉斯卷積核。
記住拉普拉斯卷積核,我們後面會用到。
泊松方程求解
這個時候,想想我們學會了什麼?泊松方程的形式,以及拉普拉斯卷積核。
再想想,在圖像場景下,什麼是泊松方程的核心問題?
已知圖像點二階微分值(直角坐標系下即散度 div)的情況下,求解各個圖像點的像素值。
一個簡單的例子,假設有一張
的圖像
,
表示各個位置上的圖像像素值,共 16 個未知參數需要被求解。
應用拉普拉斯卷積核後,得到 4 個方程式:
4 個方程式求解出 16 個未知參數?這是不可能的。
因此,我們需要另加入至少 12 個更多的方程式,也就是說,需要把剩餘 12 個邊界點的值確定,即需要確定邊界條件。邊界一般符合 2 種常見的邊界條件:
Neumann 邊界,譯為紐曼邊界或黎曼邊界,給出函數在邊界處的二階導數值;
Dirichlet 邊界,狄利克雷邊界,給出邊界處函數在邊界處的實際值。
但給定邊界條件之後,就可以有 16 個方程式組成的方程組了,矩陣化表示此方程組之後,得到形式為
。
看到
,大家就應該放鬆了,不就是解方程嘛,用雅可比迭代法或者高斯賽德爾迭代法來求解就 OK 了。
Poisson Image Editing
背景知識儲備好了後,讓我們把目光拉回到論文《Poisson Image Editing》上。
在圖像融合任務中,前景放置在背景上時,需要保證兩點:
前景本身主要內容相比於背景而言,盡量平滑;
邊界處無縫,即前景、背景在邊界點位置上的像素值,需要保持邊界一致。
重點關注兩個詞:內容平滑、邊界一致。平滑是什麼?可以理解成圖像前景、背景梯度相同。邊界一致是指什麼?可以理解成在邊界上像素值相同。再用一張圖來說明:
上圖中 u 表示需要被合成的前景圖片,V 是 u 的梯度場。S 是背景圖片,
是合併後目標圖像中被前景所覆蓋的區域,則
是
的邊界。設合併後圖像在
內的像素表示函數是 f,在
外的像素值表示函數是
。
此時,平滑可表示為:
;保持邊界一致可表示為:
。
這裡如果接觸過泛函的朋友會比較開心,沒接觸過的朋友可以先看看歐拉-拉格朗日方程。
令
,
代入歐拉-拉格朗日方程後則有:
注意:F 是
f 的函數,不是對 f 的,因此
怎麼樣,看起來是不是一個泊松方程呢?當然,還差兩步:
因為需要平滑,div v 取值需要同時參考前景圖片和背景圖片,可以直接等於前景像素的散度,也可以在前景和背景在同一點像素的散度進行某種組合得到(論文中在 Selection cloning 和 Selection editing 章節有討論各自合適的場景,但個人以為這裡採取學習的方法應該更魯棒,而不是用固定的策略來區分)。anyway,div v 是可以計算的已知量;
因為需要保持邊界一致,邊界條件上像素值等於背景圖片即可。當然也可以做一些策略,但同樣也可以計算得到的已知量。
現在很輕鬆了,邊界條件已知、散度已知,在離散空間中求解泊松方程中的 f,參考上一節的求解過程即可。
代碼實現
函數代碼已經收錄在了 OpenCV 的官方函數 seamlessClone 里:github source code
使用的時候,需要三張圖片:前景圖、背景圖、mask 圖(指明前景圖中需要融合的區域,最簡單的就是直接等於前景圖大小的 mask,待融合區域是白色,其餘位置黑色)。
下面我們使用 OpenCV 的 Python 介面來動手試試,用到以下兩張圖以及一段代碼:
foreground.jpg
background.jpg
import cv2
import numpy as np
# Read images : src image will be cloned into dst
dst = cv2.imread("background.jpg")
obj= cv2.imread("foreground.jpg")
# Create an all white mask
mask = 255 * np.ones(obj.shape, obj.dtype)
# The location of the center of the src in the dst
width, height, channels = im.shape
center = (height/2, width/2)
# Seamlessly clone src into dst and put the results in output
normal_clone = cv2.seamlessClone(obj, dst, mask, center, cv2.NORMAL_CLONE)
mixed_clone = cv2.seamlessClone(obj, dst, mask, center, cv2.MIXED_CLONE)
# Write results
cv2.imwrite("images/opencv-normal-clone-example.jpg", normal_clone)
cv2.imwrite("images/opencv-mixed-clone-example.jpg", mixed_clone)
最終效果如下:
※OPPO 小米公布屏下攝像頭方案:這就是未來手機該有的樣子
※英特爾以數據為中心的競爭優勢是什麼?BATJ有個共同的觀點
TAG:雷鋒網 |