實現SLIC算法生成像素畫

前言

像素風最先出如今8bit的電子遊戲中,受制於電腦內存大小以及顯示色彩單一, 只能使用少許像素來呈現內容,卻成就了很多經典的像素遊戲。隨着內存容量與屏幕分辨率的提高,內存與顯示媒介的限制再也不是問題,而像素風也慢慢演變成一種獨特的創做風格。html

像素畫的通常的繪製流程包括了勾線、填色等,而逐個像素的繪製須要大量時間。一些流行的藝術方式,好比線描與繪畫領域,都逐漸出現了自動化或半自動化生成的方法。本文將從零開始實現SLIC[1]算法,並實現一款生成像素畫工具。前端

什麼是SLIC算法

像素畫的繪製之因此不簡單,是由於直接的下采樣並不能準確的捕獲關鍵像素,且容易致使丟失邊緣信息,生成的像素畫每每不盡人意。手工的勾線、填色,都是爲了選取合適的像素點。由此,咱們的問題變成了如何選取合適的像素點進行填色。git

首先,引入一個概念——超像素。超像素是 2003 年 Xiaofeng Ren 提出和發展起來的圖像分割技術,是指具備類似紋理、顏色、亮度等特徵的相鄰像素構成的有必定視覺意義的不規則像素塊[1]。github

經過將圖片分割爲超像素,能夠獲得類似的像素簇,類似的像素使用同一個顏色進行填充,獲得的像素畫會更合理。算法

超像素點分割的方法包括了提取輪廓、聚類、梯度上升等多種。論文[1]提出的SLIC超像素點分割算法(簡單線性迭代聚類,simple linear iterative clustering)就是其中一種,它基於K-means聚類算法,根據像素的顏色和距離特徵進行聚類來實現良好的分割結果,與若干種超像素點分割算法相比,SLIC具備簡單靈活、效果好、處理速度快等優點。
SLICide

如何實現SLIC算法

SLIC的基本流程以下:函數

  1. 圖像預處理。工具

    將圖像從RGB顏色空間轉換到CIE-Lab顏色空間,Lab顏色空間更符合人類對顏色的視覺感知。這個空間裏的距離能反映人感受到的顏色差異,相關計算更爲準確。優化

    Lab顏色空間一樣具備三個通道,分別是lab,其中l表明亮度,數值範圍爲[0,100]a表示從綠色到紅色的份量,數值範圍爲[-128,127]b表示藍色到黃色的份量,數值範圍爲[-128,127]ui

    RGBLAB之間沒有直接的轉換公式,須要將RGB轉爲XYZ顏色空間再轉爲LAB,代碼見文末完整代碼。

  2. 初始化聚類中心。

    根據參數肯定超像素的數目,也就是須要劃分爲多少個區域。假設圖片有N個像素點,預計分割爲K個超像素,每一個超像素大小爲N/K,相鄰中心距離爲S=Sqr(N/K),獲得K個聚類座標。

  3. 優化初始聚類中心。在聚類中心的3*3鄰域內選擇梯度最小的像素點做爲新的聚類中心。

    把圖像當作二維離散函數,梯度也就是這個函數的求導,當相鄰像素值有變化就會存在梯度,而在邊緣上的像素點的梯度最大。將聚類中心挪到梯度最小的地方能夠避免其落到邊緣輪廓上,影響聚類效果。

    離散梯度的梯度計算這裏不作詳細推導了,因爲其中包含了若干平方與開方,計算量較大,通常會簡化爲用絕對值來近似平方和平方根的操做。簡化後的計算座標爲(i,j)的像素點的梯度公式爲:

    其中(i+1,j)(i,j+1)爲像素右側點與像素下方點的座標。l(a,b)(a,b)座標上像素的亮度通道值l

  4. 計算像素點與聚類中心的距離。

    在聚類中心距離S的區域內 2S*2S的鄰域內計算像素點與每一個聚類中心的距離。

    這裏的距離使用的是歐式距離,總距離Ddc顏色距離與ds空間距離兩部分組成。公式以下:

    若是直接將labxy拼接成一個矢量計算距離,當超像素的大小變化時,xy的值能夠取到很是大 ,好比若是一張圖1000*1000,空間距離能夠達到1000*Sqr(2),而顏色距離最大僅10*Sqr(2),致使最終計算獲得的距離值中,空間距離ds權重佔比過大。

    因此須要進行歸一化,除以最大值即超像素點的初始寬度S,將值映射到[0,1]

    而顏色空間距離也會給到一個固定的值m來調節顏色距離與空間距離的影響權重,m取值範圍爲[1,40]

    距離公式即變成了

    205.png

    m越大,顏色空間除以m後的值越小,即空間距離的權重越大,生成的像素會更爲形狀規則,當m越小,顏色距離權重更大,超像素會在邊緣更爲緊湊,而形狀大小較爲不規則。

  5. 像素點分類。

    標記每一個像素點的類別爲距離其最小的聚類中心的類別。

  6. 從新計算聚類中心。

    計算屬於同一個聚類的全部像素點的平均向量值,從新獲得聚類中心 。

  7. 迭代4~6的過程。

    直到舊聚類中心與新聚類中心的距離小於必定閾值或者達到必定迭代次數,通常來講,當迭代次數到達10,算法可以達到收斂。

  8. 聚類優化。

    迭代到最後,可能會出現與聚類中心不屬於同一連通域的孤立像素點,可使用到連通算法將其分配到最近的聚類標籤。

    論文中並未給出具體的實現算法。而本文的應用場景是生成像素畫,會對像素進行下取樣,並不會細化到每一個像素,由此,本文不作聚類優化處理。

小小總結一下,SLIC算法流程大致與K-means是一致的,不斷迭代計算距離最小的聚類簇,不一樣的是隻對聚類中心的S距離內像素點進行計算,減小了很多的計算量。

生成像素畫

基於SLIC算法,咱們已經能夠把一張圖劃分爲N個超像素點。每一個超像素中像素都是相近的。也就是說,每一個像素都被歸類爲一個超像素,有一個聚類中心。那麼將像素的顏色賦值爲其聚類中心的顏色即獲得咱們想要的效果。

設定必定步長stride,使用Canvas,每隔stride個像素,將像素賦值爲其聚類中心的顏色,即獲得最終的像素化結果。

而每一個人對於像素畫的主觀感覺是不一致的,爲了讓用戶有更多的選擇,獲得本身滿意的結果。能夠暴露更多的人工干預參數,好比取消聚類優化的終止條件,改成由用戶來設置迭代次數,以及最終取像素值的步長。人工設定的參數包括了

  • 超像素點大小blocksizeblocksize越小,超像素點分割越細膩。
  • 迭代次數itersiters越大,分割結果更精準,計算時間越長。
  • 顏色空間權重weightweight越大,顏色對於分割結果的影響越大。
  • 取像素點步長stridestride越小,生成的像素圖越接近超像素點,也就越細膩。

實現用戶交互界面

做爲一個工具,天然須要用戶交互界面,前端界面基於HTML/Javascript/CSS搭建,使用Canvas API繪製圖像內容,而用戶交互面板選擇的是dat.gui [3] 庫。dat.gui是一個輕量級的圖像化界面庫,很是適用於參數的修改,經常使用做可視化 Demo 的演示。支持的參數類型包括了NumberStringBoolean、自定義函數等。能夠爲不一樣的屬性綁定相應的響應事件,當屬性值改變時自動觸發事件。

爲生成像素化工具添加如下屬性與事件:

  • iters、stride、blockSize、weight(顏色空間權重m)參數變化時從新進行SLIC算法的計算,並從新繪製計算結果;
  • 添加Upload imageExport image按鈕,支持用戶上傳圖片與下載像素化後的圖片;

在繪製圖像的Canvas畫布層上疊加一層Canvas畫布,對算法的結果進行可視化,添加如下功能

  • grid開關控制是否繪製像素網格;
  • Centers開關控制是否顯示聚類中心;
  • Contours開關控制是否顯示聚類邊緣輪廓;

其中聚類中心點Centers的繪製直接使用ctx.fillRect 傳入中心點座標便可。

超像素輪廓Contours的繪製則須要先計算獲得輪廓點。

能夠對每一個像素點與周圍的8個像素點進行比較,若是聚類中心不一樣的像素點個數大於2,則表明着這個像素點周圍有兩個以上不一樣類別的點,則這個點爲輪廓。效果以下:

最後,就獲得一個簡單的生成像素畫工具了。

體驗地址

完整版代碼地址(JS版)

參考文獻

[1] Achanta R, Shaji A, Smith K, Lucchi A, Fua P, Su ̈sstrunk S. SLIC superpixels. Technical Report. IVRG CVLAB; 2010.

[2] Gerstner T , Decarlo D , Alexa M , et al. Pixelated image abstraction with integrated user constraints[J]. Computers & graphics, 2013.

[3] https://github.com/dataarts/d...

歡迎關注凹凸實驗室博客:aotu.io

或者關注凹凸實驗室公衆號(AOTULabs),不定時推送文章。

相關文章
相關標籤/搜索