圖像素描風格生成

前言

論文連接:Combining Sketch and Tone for Pencil Drawing Productionjava

Matlab版本的代碼,目前找到有兩個:python

一、https://github.com/fumin/pencilgit

二、https://github.com/candycat1992/PencilDrawing github

效果看起來第二個要好,並且寫的代碼很是簡潔。api

我實現了Scala的版本(有一小部分用到了python),基於第一個Matlab版本的代碼:框架

https://github.com/Ldpe2G/Pencil-Drawing-Scala學習

實際上是差很少實現完了才發現了第二個版本的matlab代碼,後面會看看可否做些改進。spa

正文

首先看看從論文中截取的素描風格生成框架圖.net

 

 

 

 

 

 

 

 

 

 

主要是兩大步組成,模擬畫家畫素描畫的兩個步驟scala

1,Line Drawing,先畫線,描輪廓;

2,Tone Drawing 再加上色調,好比陰影。

下面詳細介紹兩個步驟。

1. Line Drawing

首先來看看一幅圖:

左邊是畫家畫的一幅素描畫,右邊是放大細節部分。經過觀察咱們能夠發現,畫家在畫

邊的時候,都是用一段一段的線段組合起一幅畫的。基於這個事實,文章提出了一種模擬

素描畫邊的方法。主要也是分兩步走。

 

1.1 Classification

首先將輸入圖片轉爲灰度圖,而後經過前向差分,分別計算x,y方向的梯度,再根據如下公式

計算大小:

公式中的   表示輸入圖片的灰度圖,實現上我是用Prewitt’s operator來計算梯度的,也試過

Sobel operator,效果差很少。

在模擬素描畫線的難點在於估計每一個像素點的畫線方向,比較簡單的方法是根據梯度方向,

可是會很容易受噪聲的影響,而在文章中則提出了一個更加魯棒的策略。

首先生成8個方向的線段(卷積核),

                       

而後分別和G做卷積:

而後經過獲得的相應圖Gi來分類像素點,i (1~8):

p表明原圖像素點的索引。根據公式3,咱們能夠知道

文章中聲稱以上的方法能對抗各類的噪聲。

 

1.2 Line Shaping

得到Ci以後,首先和對應的線段卷積核做卷積,而後再加起來:

經過卷積操做能夠彙集附近同一個方向的像素點,這樣就能夠把邊原圖上邊上的像素點連起

來。最後的結果就是把S‘的像素值反轉,而後再映射到 [0, 1] 區間。就獲得結果了。

用scala代碼跑的結果做演示:

  

2. Tone Drawing

這一步這要就是模擬畫家用鉛筆上色的過程,這須要利用道原始灰度圖的信息。

咱們首先來看一張圖:

左邊是天然場景圖片和對應的像素值直方圖,右邊是素描畫和對應的直方圖。

能夠看到直方圖的分佈是很不同的。所以原圖像的色調是不能直接用在色調生成上的。

而後文章中提出了一種參數化模型來解決這個問題。

2.1 Model-based Tone Transfer

文中提出了一個模型來表示色調分佈:

v 表示色調值,而後 p(v)表示這個像素是用色調值v來表示的機率。Z是正則化因子。

三個 pi(v) 分別表明在素描畫中的三個不一樣的色調層,ω 表明權值,形象的理解能夠看做是

對應的色調的像素值的個數。再來看一幅圖:

(a)是一幅素描畫,而後 (b),是把像素值分紅三類的結果,綠,橙,藍分別表明 深,中,淺

三種色調。(c)對應的三種色調的直方圖。分析結果就是,天然圖像和素描畫的最大的區別

就是素描畫空白的區域更大,亮度更高。

而後三中色調對應三個公式來表示:

而後就是如何求解公式中的參數了。

2.2 Parameter Learning

權值 ω 由每一個色調層的像素個數決定。而後對每層的參數採用最大似然估計的方式來求解。

每層的像素值的均值和標準差表示爲m和s。參數能夠近似的表示爲:

    

xi表明像素值,N表示每層像素值的個數。

而後學習到的參數以下:

可是其實在matlab代碼的實現上,對於權值 ω的設定和三個公式的實現,並非徹底呀按照

論文中的定義來實現的,我作了很多實驗來調節參數而後看結果,發現仍是得按照matlab

代碼的設定才能最大程度復現論文的結果,因此應該還有有哪裏一些細節沒處理好。

而後學習到參數以後,對於每一張新的輸入圖像,經過直方圖匹配的方法來修正灰度圖的

像素值,也就是用輸入圖像的灰度圖的直方圖去匹配素描畫的直方圖。

2.3 Pencil Texture Rendering

作完直方圖匹配以後,原圖的像素值分配就比較接近素描畫的了,可是還不能直接就用這個

修正的灰度圖和上一步生成的描邊直接組合,還須要模擬一下素描畫的紋理。如何生成

這個紋理是一個很難解決的問題。

文章中生成他們收集了20張左右的素描紋理圖來作實驗,matlab的代碼中提供了3張:

    

每一個輸入圖片只須要一張便可。在畫家做畫的時候,色調的生成就是在某處重複的畫。

模擬的方法直觀的理解就是,經過將紋理圖做乘法。。這個  就是咱們要

求解的。越大則獲得的獲得色調越深。經過求解如下公式能夠獲得

其實怎麼在代碼上去實現求解我是想不到的,可是好在matlab的代碼實現了求解,

最後實際上是在求解一個很是大的線性方程組,不過矩陣都是很是稀疏的。至於怎麼能那麼

實現,到目前爲止我仍是沒看懂,不過直接把matlab的代碼移植到scala仍是沒問題的。個

人感受復現過程當中最難的部分也就是這裏了,我嘗試了不少java/scala的矩陣庫

(la4j, mtj, colt等等),速度上都不滿意,最終發現 breeze是速度上最接近matlab的,

可是在求解稀疏矩陣相關的線性方程組的時候,breeze還不支持,最後實在沒辦法了,

只能把這部分求解的實現放到python中去作,用scipy這個庫來解決,由此能夠看到,

scala在作科學計算上仍是,比不上python。最後用了一種比較low的方法,在代碼中調用

python的腳本,而後再把腳本的結果讀取上來。

 

ok,回到正題,獲得以後,模擬素描畫色調紋理的圖就能夠獲得了:

    

最終的結果就是把色調和輪廓結合起來,用一個矩陣的點乘操做便可:

 

3 Color Pencil Drawing

而後文章還作了一些拓展,好比如何給素描畫上色,就是好比把RGB轉換到YUV空間,

而後把Y通道拿出來,通過以前的步驟來生成素描畫,再把它放回到Y通道上,最後再

從新轉換成RGB便可。

而後文章剩下的部分就是一些結果展現和對比試驗結果,想深刻了解的話能夠去看看paper。

4 復現結果展現

最後展現一下用scala代碼生成的一些素描圖,只能說勉強復現了論文的方法。

展現格式,左上角原圖,左下角素描輪廓圖,右下角,素描圖或彩色素描圖。

       

  

 

 

 

 

5 參考資料

[1] http://stackoverflow.com/questions/12636896/how-to-solve-a-linear-system-of-matrices-in-scala-breeze

[2] http://statr.me/2015/09/an-overview-of-linear-algebra-libraries-in-scala-java/

[3] http://stackoverflow.com/questions/7086820/convert-rgb-to-ycbcr-c-codehttps://en.wikipedia.org/wiki/Edge_detection

[4] https://en.wikipedia.org/wiki/Edge_detection

[5] http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.301.927&rep=rep1&type=pdf

相關文章
相關標籤/搜索