potrace論文解讀

原文地址:http://linxinboy.blogbus.com
這是一個非常古老的算法 源於2003年,作者 Peter Selinger。
它的作用是輸入一張二值圖(不是黑就是白),輸出此圖的矢量化結果,也就是將位圖輪廓矢量化。
下面是譯文部分, 所有註釋會放在文章最下方。 
 

預覽

csdn看不了在線預覽,http://linxinboy.blogbus.com裏面有。
由於算法只能輸入純黑白圖像 所以我把輸入圖像二值化了一下。

代碼:這裏

 

1 介紹
二值圖可以被以位圖形式或者矢量的形式進行呈現。位圖是將圖像當做一個個不是黑就是白的像素格子。矢量圖則將一張圖像通過代數描述其輪廓來呈現,比如貝塞爾曲線。將一張圖像以矢量方式進行呈現的好處是他可以被縮放至任意大小而沒有品質上的降低。圖像輪廓對於任何特殊的輸出設備都是獨立的。他們在字體這種必須在不同尺寸可重複使用的東西里非常流行。矢量輪廓的字體有PostScript Type 1, TrueType,和Metafont。另外一方面,大多數輸入輸出設備,比如掃描儀,顯示器,打印機最終都產生或者使用位圖。將矢量輪廓轉爲位圖的過程叫做呈現(rendering).將位圖轉爲矢量輪廓的過程叫做描繪(tracing).

很明顯沒有矢量化算法能在任意場合表現完美,因爲同一張位圖一般可以引起多種可能的矢量輪廓。輪廓矢量化不能用於產生還沒有呈現的信息。另一方面,由於多種可能的輪廓可以產生同一張位圖,但明顯有一些比其他的更加合理和美觀。比如,一個在高分辨率下顯示位圖的一般方法,是去繪製每個黑色像素在精確的方形格子裏,這樣會導致鋸齒。很明顯,鋸齒既不好看也不合理。形成好的矢量化算法可能沒有絕對的標準,但明顯有些算法的結果要好於其他。

 

在這片論文裏,我們描述了一種簡單,高效併產生極好結果的輪廓矢量化算法。這個算法被稱作Potrace,表示多邊形繪圖。然而這個算法的輸出並不是一個多邊形,而是一個由貝塞爾曲線構成的光滑輪廓。算法的名字來源於他使用多邊形來當做中間層呈現圖像的事實。

 

Potrace算法被設計爲在高分辨率圖像上工作良好。所以,一個典型的用途是產生某公司或者大學的大分辨率logo矢量化結果。另一個可能的用途是將位圖字體轉爲矢量字體在源位圖有高分辨率的情況下。沒有矢量化算法可以在非常小的圖像上工作良好(注1),比如把10像素的字體以75像素顯示。然而,算法在相對還好的分辨率下的非精確圖形上比如掃描的手寫或卡通繪畫上工作良好。

 

每一個矢量化算法都得有幾個步驟。其中兩個是找到最合理地近似輪廓的曲線,並檢測轉角。在這兩個目標裏有一個權衡。如果檢測出太多轉角,結果會看起來像多邊形而不再光滑。如果檢測出太少轉角,結果會看起來光滑但太圓滑。圖1顯示了一個例子。

矢量化算法的另一個重要功能是決定位圖在掃描或呈現階段哪些特徵是有關的,那些特徵是無關的。那些可以被看做無關的特徵必須完全過濾掉,因爲即使留下一點點這樣的特徵在輸出上都會導致可見的缺陷。比如一個非常短的正向的斜的直線。當以位圖進行呈現,這樣一條線將導致鋸齒,個別像素會偏離得很遠。不論像素離得有多遠,結果應該是一條直線,否則結果會看起來讓人厭。這個例子也顯示了矢量化算法一般不是局部運算,即他不能僅僅只看某點的周圍固定範圍的像素。

 

Potrace算法非常高效,它比其他算法產生更好的輸出。比如,圖2比較了標準設置下的Potrace 1.0和AutoTrace 0.31.1,另一個矢量化算法。(參見http://autotrace.sourceforge.net/).除了它優秀的輸出結果,Potrace也在速度和文件大小方面超出AutoTrace:圖2花費了Potrace0.27秒,Autotrace花費了1.69秒。Potrace產生了一個15790字節的EPS文件,AutoTrace是39788 字節。

 

2 Potrace算法描述

 

Protrace算法將位圖轉爲矢量輪廓有幾個步驟。第一,位圖被分解爲一些路徑,他們構成了黑白區域之間的邊界。第二,每條路徑都被近似爲一個最優多邊形。第三,每個多邊形都轉化爲光滑的輪廓。一個可選的步驟,結果曲線通過鏈接連續的貝塞爾曲線片段來進行優化。最後產生需要的格式輸出。下面的章節將對每個步驟進行詳細描述。

 

2.1 路徑

 

2.1.1 路徑分解

 

我們假定我們的位圖放置於一個座標系每個像素的轉角都有整型座標。讓我們進一步假定背景爲白色,前景爲黑色。按照慣例,超出位圖邊界的區域被假定爲白色填充。

 

我們現在構造一個有向圖如下。p是一個整型座標的點,這樣的一個點與4個像素相鄰(注2)。如果4個像素都不是同一種顏色這個點被稱作頂點。如果v和w是頂點,如果v和w的歐幾里得距離爲1我們說這裏有一條從v到w的邊,並且如果這條直線片段將v和w分爲一個黑像素和一個白像素,當從v移向w使黑像素在它的左邊白像素在它的右邊。讓我們將這個結果有向圖稱爲G。

 

一個路徑是一系列頂點{v0, . . . ,vn},對所有i = 0, . . . ,n−1都有一條邊從vi到vi+1,這些邊都非常清晰。一條路徑被稱爲封閉如果vn=v0。路徑的長度爲邊的個數即路徑分解的目標是將圖G分解爲封閉路徑。即找到一個封閉路徑的集合使G的每條邊都只出現一次。

 

Potrace使用如下的簡單方法去分解一個位圖到路徑。從一對有不同顏色的相鄰像素開始。可以這樣完成,比如通過選擇某一行最左邊的黑像素。兩個被選擇的像素在一條邊上相遇,我們改變這條邊的朝向來使黑色像素在邊的左邊白色像素在右邊。邊被定義爲長度爲1的路徑。我們繼續擴張這條路徑使新的邊都有一個黑色像素在它的左邊一個白色像素在右邊,相對於路徑的方向。換句話,我們在像素間沿着邊移動,每次遇到一個轉角的時候,我們要直走或轉左轉右,根據像素周圍的顏色來決定如圖3所示。我們繼續下去直到我們返回到我們開始的那個點,即那個我們定義了一個封閉圖的點。

 

每次我們找到一個封閉圖,我們通過反轉它所有像素的顏色來從圖中移除。這定義了一個新的位圖,我們在這張圖繼續遞歸應用這個算法直到沒有黑色像素餘留。最終結果是將用於Potrace算法下個階段的封閉路徑的集合。後面Potrace的階段將單獨着眼於每個路徑。

 

2.1.2 轉向方針

 

在圖3(d)的情況下,我們要選擇是往左還是右轉。這個選擇對路徑分解算法的成功失敗沒有影響,不論以哪種方式我們都是以封閉路徑的集合結束。然而,這個選擇會對封閉路徑的形狀有影響。

 

在Potrace算法裏,往左還是往右由一個轉向方針決定,它可以通過 turnpolicy在命令行選項定義。可能的轉向方針有:左,一直會往左轉。右,一直會往右轉。黑,更傾向於鏈接黑色單元。白,更傾向於鏈接白色單元。少數派,更傾向於鏈接在當前點給定範圍內出現的最少的顏色。多數派,更傾向於鏈接出現的更多的顏色。隨機,隨機轉向。默認規則是少數派。

黑色和白色從右和左的轉向方針有區別的原因是某些像素可能在路徑分解的過程中顏色被翻轉。黑白方針查看源像素顏色來決定轉向的方向。(此段話不是很理解)

 

2.1.3 去雜點

去雜點可以通過去除所有路徑內部像素少於t個像素的路徑。t爲一個給定的值,可以通過turdsize命令行選項來設置。路徑內部的面積可以通過下面的公式高效計算:

 

2.2 多邊形

Potrace算法的第二個階段以章節2.1定義的封閉路徑爲輸入。輸出時一個近似這條路徑的最優多邊形。我們由精確定義什麼是"最優"和"近似"來開始。

 

2.2.1 直線路徑

給定兩個點z0(x0, y0) 和 z1(x1, y1)在座標系平面,不用必須整型座標,我們定義他們的最大距離爲d(z0, z1) = max{|x1 − x0|, |y1 −y0|}。因此,離點(1/2, 1/2)最大距離爲最多 1/2 的點的集合爲那些以(1/2, 1/2)爲中心的點(注3)。

對座標平面的任兩點a,b,令ab表示鏈接a和b直線的直線片段。這裏a和b並不必須在整型座標。

給定一組非封閉的路徑p = {v0, . . . ,vn}如在章節2.1,我們說線片段ab近似這條路徑如果d(v0,a) ≤ 1/2,d(vn,b) ≤ 1/2,並且對於每一個i = 1, . . . ,n−1,存在點ci使得d(vn,b) ≤ 1/2。對於一條路徑p = {v0, . . . ,vn},我們說在索引i上的方向爲vi+1 - vi,i = 0, . . . ,n−1。這裏有4中可能的方向:(0,1), (1,0), (0,−1), 和(−1,0)。一條路徑被稱作直的如果它可以被一

些線片段近似而且4種方向沒有都出現。

 

 

圖4顯示了一些直和非直的路徑。注意圖中,那些點表示源位圖坐落於轉角而非中心的頂點。顯示的正方形不是像素,而是路徑點周圍像素。(注2)

 

圖4(e)顯示了一個非直路徑的例子,雖然它被一些線片段近似,但是4種方向都在路徑中出現了。

 

非常明顯如果一條路徑是直的,那麼它所有的子路徑也是直的。爲了計算一條路徑是否是直的,我們使用一個更強的事實,在隨後的部分平直度是一個3元組屬性。假設路徑p = {v0, . . . ,vn} 沒有出現所有4中方向。那麼p是直的當且僅當對於所有索引的3元組(i, j, k)使0≤ i < i < j < k ≤ n,在這條直線上通過vi 和 vk存在一個點w使d(vj, w) ≤ 1。這產生了一個簡單的平直測試算法,最壞的情況下爲3次方複雜度。它簡單對所有3元組(i, j, k)進行測試。

 

在Potrace的實現中,我們使用一種優化來允許我們最壞情況下在時間O(n^2)內找到一個給定長度n的封閉路徑所有直的子路徑。簡單說,訣竅是計算,對每對(i, j),約束所有將來的vk的位置。如果i是固定的而j是增長的,只要檢查一次每個j的約束就可以。而且,一個約束由最多兩個不等式構成並且可以在固定的時間內被更新和檢查。

 

2.2.2 多邊形
 

現在考慮一個封閉路徑p = {v0, . . . ,vn}。回想vn = v0,所以路徑的長度爲n。任一對索引 i, j∈ {0, . . . ,n−1} 定義了一個子路徑Pi,j ,其中路徑爲vi, . . . ,vj如果 i ≤ j 或者爲vi, . . . ,vn−1,v0, . . . ,vj如果j < i。讓我們記做j Θ i (Θ原符號不會打)對i和j之間的環形差異,j Θ i  = j - i如果 i ≤ j 而 j Θ i = j - i + n如果 j < i。因此,子路徑Pi,j的長度被精確爲j Θ i 。在下面的討論中,我們假定加法和減法都對n取模(注4)。

 

我們現在想從封閉路徑p中構建一個多變形。我們說這裏存在一個可能的從i到j的片段如果j Θ i ≤ n - 3並且子路徑Pi-1,j+1是如前面的定義那樣是直的。換句話說,一個子路徑對應於一個可能的片段如果它可以在兩邊的方向上都擴張1像素並且保持直的。這個某條直的路徑兩邊端點特殊的"剪裁"對於整個Potrace算法的輸出非常重要;沒有它,會在轉角處導致奇怪的現象。

注意根據章節2.2.1的定義任何長度3的路徑爲直的,因此它被保證總有一個可能的片段從i 到 i+1。

 

 

爲了這個算法的此階段的目的,一個多邊形是一序列索引i0 ≤ i1 ≤ . . . ≤ im−1 如此這裏有一個可能的片段從ik 到 ik+1對於每個k = 0, . . . ,m−2,和從im-1到i0。(注5)圖5顯示了一個路徑兩個可能的多邊形。

注意圖5中的多邊形片段沒有真正的必須近似他們對應的子路徑從圖4的紅線片段來說。他們簡單呈現了一個近似線片段存在的事實。

 

2.2.3 懲罰(注6)

 

已找到所有可能的多邊形,現在我們想要找到一個最優的。我們對最佳性的主要標準是片段的數量:一個擁有更少片段的多邊形被認爲是比更多片段多邊形更優的。在圖5中,左邊多邊形有14個片段,而右邊的有17個片段。因此左邊的比右邊的更優

在片段數相同的多邊形當中,有一些仍然比其它的更好。我們賦予每個片段一個懲罰。給定一個從 i 到 j 的片段,記直線片段ViVj(如圖5藍線)。賦予這個片段的懲罰等於ViVj的歐幾里得長度乘以路徑上每個點到ViVj歐幾里得距離的標準偏差。即公式如下:

 

dist(a,bc)表示某點距離一條直線的歐幾里得距離,且易理解的從 i 到 j 的累計數量在一個循環方式中。簡而言之,這些點偏離片段越遠,受到的懲罰越大

Pi,j的公式這樣是因爲他可以高效計算;即令(x,y) = vj −vi , (x,y) = (vi+vj)/2(注)。然後我們有

其中

 

是 Xk的平方的期望值,k =i, . . . , j,其他的E(x)類似。

注意這些累加可以提前計算,通過制定一個的累加值的表,爲每一個數量總計qk的值。建表後,這使花費的時間和空間呈線性,以上Pi,j的公式可以在一個固定時間內計算對每個給定的i,j。


2.2.4 優化多邊形

 

我們可以將給定的封閉路徑p = {v0, . . . ,vn}視爲一個有着頂點0, . . . ,n−1的有向圖,其中從 i 到 j 的箭頭如果從 i  至 j其中有可能的片段。對於序列 i0 → i1 → . . . → ik ,我們可以賦予一個懲罰,(k, P), 其中k是箭頭的數量,P是他們的懲罰的和如章節2.2.3中討論的那樣。(k, P)比(k′,P′)更好如果 k < k′, 或者 k = k′且P < P′。

 

這樣,找到一個最優多邊形被降爲在一個有向圖中找到一個最優環形。我們使用一個標準的圖論算法的變量來尋找有向圖中的最優環形來高效解決這個問題。一旦圖被計算了,一個最優環形可以在時間O(nm)內找到,其中n是輸入路徑的大小,m是最長的可能的片段長度。
 

我們注意到是這個優化讓我們的算法非局部,因爲一次必須考慮整個路徑;優化多邊形的每部分可能取決於其他部分。在前面計算一個位圖路徑的階段,和接下來把多邊形轉爲矢量輪廓的階段,都是局部的,即他們每次只查看很少的相鄰的點。

 

2.3 從多邊形到矢量輪廓

 

算法最後的階段是將前面獲得的多邊形轉爲光滑的矢量輪廓。在準備階段,我們調整多邊形頂點的位置來使它儘量符合源位圖。在主要步驟,我們計算轉角和曲線根據臨近的線片段的長度和他們間的夾角。

 

2.3.1 頂點調整

 

算法前一階段的輸出時一個多邊形{i0, . . . , im−1}關聯一個封閉路徑{v0, . . . ,vn}。我們指的是索引i0, . . . , im−1,以及他們關聯的作爲多邊形頂點的點vi0 , . . . ,vim−1。因爲我們的多邊形爲環形,所以按照慣例把索引取模m。

 

爲了計算懲罰,我們將多邊形的頂點 i 精確地放置於對應路徑的點vi,即在座標系有整型座標的點。(即坐落於源位圖4個像素的交叉點)。這樣放置頂點允許我們高效地計算懲罰,這在優化範圍內並不是必要的。我們現在關聯每個頂點ik 一個點 ak在座標系,不需要一定是整型,這樣ak離Vik很近, 而且對於多邊形任意兩個連續頂點 ik 和 ik+1,結果線片段akak+1是合理接近於源子路徑vik , . . . ,vik+1 。

我們使用下述算法來放置點Ak:對每個連續的頂點Ik 和 Ik+1,計算最佳近似點vik , . . . ,vik+1 的直線Lk,k+1,就這而言它最小化了它們離直線的歐幾里得距離。如果Ik-1,Ik,和Ik+1是連續的頂點,那麼我們最想把Ak放置在Lk-1,k 和 Lk,k+1的交叉處。然而,我們並不想讓Ak太過遠離原頂點Vik。因此,我們讓Ak成爲單位平方形裏的最大距離d(Ak, Vik) ≤ 1/2的點,這樣從Ak 到 Lk-1,k 和 Lk,k+1的歐幾里得距離的平方和爲最小。尤其如果Lk-1,k和Lk,k+1的交點在這個單位平方形裏;否則,我們將它放置在離Vik很近的點即離交叉點"很近"。

 

計算ak 很容易,它只是簡單總計去在一個正方形內最小化一個二次函數。並且,通過使用一個標準方法"best fit"很容易計算從點vik , . . . , vik+1 到直線Lk,k+1 :這條線通過重心(E(xk),E(yk))即 k = ik,...,ik+1,並且它的斜率由下面矩陣更大特徵值的特徵向量給出。
矩陣
[a b
b c] ,
其中

 

2.3.2 一種貝塞爾曲線

 

此章節的目的是做一個簡單,有用的貝塞爾曲線觀測。回想貝塞爾曲線由4個控制點z0, z1, z2, z3, 和 參數方程z= (1−t)3z0+3t(1−t)2z1+3t2(1−t)z2+t3z3 給定。爲了分析,我們限制通過z0z1和z3z2的直線交叉於點o(即他們不是平行的)。然後,我們限制曲線是凸的且改變方向小於180度;這意味着z1位於z0和o之間,z2位於z3和o之間。這種情況如圖6所示。通過一個座標系的線性轉化,我們假定z0 =(−1,0), z3 =(1,0), o=(0,1)。任何這種特殊的貝塞爾曲線都由兩個參數決定,a,b ∈ [0,1],z1 = (−1+a,a),z2 =(1−b,b)。圖7給出了在這種情況下的a和b的值每次乘以0.2的貝塞爾曲線預覽。在圖中,控制點z1和z2顯示爲紅點。我們可以馬上從圖中發現貝塞爾曲線在任何特殊水平行上視覺上都幾乎無法區分,除了大概a或者b非常接近於0的情況。我們將看到我們的算方法從不產生a,b很小的貝塞爾曲線,這樣我們可以避免後面的可能性。於是我們如果我們限制a = b則不會漏掉任何有趣的曲線。這消除了一個角度從我們需要考慮的可能的貝塞爾曲線中,而且這樣簡化了我們找最優曲線的工作。

我們沒有強調我們要求所有的貝塞爾曲線都想圖7中顯示的那樣。不如說這是在線性變化的情況。因此,如果給定z0和z3,這裏有兩個在o位置的自由度,且一個額外的自由度是a的選擇。通過設置a = b,第四個自由度被消除了。

一個有趣的事實是被貝塞爾曲線和x軸包圍的面積等於3/10*(2a+2b−ab) 或 3/10 * (4−(2−a)(2−b))。由圖7我們得出兩個曲線看起來很相似如果他們包圍的面積相同。因此,我們可以用相等參數近似任何參數a和b的曲線。

 

另一個貝塞爾曲線有趣的測量是他的最高點。當a = b,最高點會在t = 1/2的時候達到,而他的y座標爲 3a/4;(這裏的a b 是上

圖裏面的阿爾法 貝塔)

 

2.3.3 平滑化和轉角分析

 

算法的最後階段的輸入是從章節2.3.1調整後的多邊形。假定這個多邊形的頂點爲a0, . . . ,ak−1。令b0, . . . ,bk−1爲多邊形邊的中點,即bi = (ai+ai+1)/2。對於每個i,我們現在考慮轉角bi−1..ai..bi,且我們通過一個光滑曲線來決定是否近似它,如圖8(d)所示。
 

我們如下繼續。首先,我們在點ai上畫一個單位方形。然後,我們找到平行於bi−1bi的線Li,並在ai的周圍接觸到方形,且它儘可能地接近直線bi−1bi。令c爲Li和 bi−1ai的交點,並令g爲bi−1c的長度和bi−1ai的商。令 a = 4g/3 並 考慮貝塞爾曲線(章節

2.3.2所考慮的那種)鏈接bi−1 和bi 用參數a。這條曲線切線於bi−1ai, Li, aibi 這3條線。

 

我們使用剛剛計算的參數a來進行轉角檢測盒決定最終從bi−1 到 bi的曲線。這裏有兩種情況。 如果 a ≤ 1,然後我們繪製一條光滑的貝斯阿爾曲線在這個頂點,如圖8(a)-(c),如果 a > 1,這裏沒有凸的貝塞爾曲線來鏈接bi−1 和 b 並切線於Li。在這種情況下,我們檢測了一個轉角且我們通過兩條相交於點ai的直線片段鏈接bi−1 和 bi ,如圖8(d)所示。

 

轉角檢測可以通過轉角閥值參數amax來定義,通過--alphamax命令行選項來設置。如果這個參數有被設置,那麼頂點將爲圓角 如果 a< amax, 如果a > amax則是一個轉角 。因此,更小的amax會導致更多的轉角,如圖1(b)所示,更大的值則會導致更多圓角,如圖1(c)所示。默認的amax = 1。 如果amax = 0,沒有平滑化會執行Potrace的輸出爲一個多邊形。如果amax > 4/3,將會完全沒有轉角,輸出全都是光滑曲線。

 

檢測完轉角以後,a的值被調整爲0.55 和 1 之間。a > 0.55 是爲了阻止曲線太"平"。讓 a < 0.55常導致奇怪的圖像。a < 1是爲了保證結果貝塞爾曲線是凸的。

a = 0.55被選擇是因爲它會導致圓形物的良好近似在輸出時一個正常多邊形的情況下。它被選擇是因爲理論值
a0 =4/3(√2−1) ≈ 0.552285

 

它通過一條貝塞爾曲線對1/4圓有着最好的近似。更精確地講,這條貝塞爾曲線有着坐落於半徑爲1.00027253單位圓中的控制點z0 = (1,0), z1 = (1,a0), z2 =(a0,1), 和 z3 = (0,1)。因此,這條曲線偏離一個真正的圓(1/4圓)不到0.01363%。雖然貝塞爾曲線片段對1/4圓的近似衆人皆知,但準確地範圍很難在文獻中找到;比如,Faux 和 Pratt 錯誤地給出了0.13%的值,這應該

是顯然的印刷錯誤,反之Knuth給出它只"比0.06%要小"。

 

注意我們的轉角檢測算法有如下屬性:尖銳的角度和長片段更有利轉角。因此,我們檢測一個轉角如果兩個短片段相交於一個很小的角度,或者兩個很長的片段相交於一個輕微的角度。

 

2.4 曲線優化

前一個階段在轉角檢測和光滑化之後,輸出地是由貝塞爾曲線片段和直線片段構成的。結果曲線非常接近Potrace的最終結果。但是,這裏算法仍然有一個最後的優化,曲線優化階段,即嘗試通過連接臨近的貝塞爾曲線來優化。曲線優化僅僅對最終曲線產生非常小的改變;小到一般看不出區別。但是,結果曲線會由更少的片段構成,所以程序輸出會以更緊密的方式顯示。如果曲線優化是不需要的,可以通過--longcurve命令行選項來設置。

 

曲線優化基於幾個簡單的想法。首先,我們僅僅嘗試去連接臨近的曲線片段,絕不連接直線片段或者轉角。第二步,我們只連接角度凸的曲線片段,即他們都向右或者向左彎曲。三,我們連接總的方向改變少於179度的曲線片段。(我們沒有允許180度是爲了避免在下面計算不受控制)。這使我們要考慮如圖9藍色顯示的片段序列。

問題是我們是否能找到一條單個貝塞爾曲線來近似給定的一組更短的貝塞爾曲線。假定這裏有這樣的一條曲線C。明顯,C將切線於b0a1和anbn。我們可以找到b0a1和anbn的交點O。根據我們在章節2.3.2中討論的那樣,這只留下一個自由度在需要考慮的曲線中,即參數α。如果我們強行讓被曲線C包圍的面積和原曲線片段包圍的面積相等,然後這決定了參數α。回想章節2.3.2這個面積是很容易計算的。這留給我們一條特殊的近似那些給定的片段的曲線C.如圖9紅色所示。

 

接下來我們需要檢查C是否真正地可以去近似給定的曲線片段,且如果是的,給它一個數值的懲罰。我們用一個簡單的相切來檢查。對於每個i = 1,...,n−1,我們找到點zi在C上的切線並平行於aiai+1.我們另di爲zi到線片段aiai+1的歐幾里得距離。再,對於每個i = 1,...,n,我們找到在C上的點z′i 切線於C並平行於bi-1bi。我們另di′ 爲z′i 到章節2.3.3定義的線片段Li的歐幾里得距離,記爲正的如果z′i 和Li和ai一樣的一邊,否則負的。(as是何意)

 

我們說這個近似是可接受的如果di≤ε,di′ ≥ −ε,且zi在線aiai+1上的正交投影位於ai和ai+1之間。這裏值ε 是一個常量值叫做曲線優化算法的容忍;它預先定義爲0.2,他可以用--opttolerance命令來更改。

爲了一個可接受的曲線,我們定義它的懲罰爲所有di和di’的平方的和。最後,我們使用一個標準的圖形理論算法用最短路徑來分解給定的曲線片段至可接受的近似,優化片段數量,然後總的懲罰。

2.5 結果

2.5.1 縮放和旋轉

 

Potrace算法已產生了一組曲線,每個都由貝塞爾曲線和直線片段構成。這些片段的結束點和控制點是座標平面內的任意點。依據選擇的後端和參數,Potrace現在執行一個線性的變化(縮放圖像至需要的尺寸,並可以旋轉它).

 

2.5.2 冗餘編碼

 

當使用PostScript後端,Potrace使用一個非常緊密的數值格式在輸出中去呈現貝塞爾曲線。這樣做利用了曲線參數裏的冗餘。原則上,需要6個參數去描述每個貝塞爾曲線片段(1個結束點2個控制點)。然而,通過消除多餘的參數,Potrace可以將每個片段僅編碼爲3至4個真正的數字。一個自由度可以被消除是因爲我們只使用 α = β的曲線,見章節2.3.2。另一個自由度可以被消除是因爲點bi常常位於線片段aiai+1上,見章節2.3.3。第3個自由度可以經常被消除是因爲bi實際上在ai和ai+1的半途中對那些沒有被章節2.4的曲線優化步驟影響的曲線片段。(註釋7)

 

這個貝塞爾曲線的冗餘編碼僅僅在PostScript後端執行,因爲它利用了PostScript語言的巨量的性能。冗餘編碼可以用--longcoding選項關閉,用於更長但更易讀的輸出。

 

2.5.3 數字化

 

對於大多數後端,最終的座標,即真正的數字,是量子化的,它意味着他們被四捨五入至最接近1/10像素(注4)。因此,數字的小數部分需要呈現的每個座標是通過在一個很好的網格中高效放置所有控制點來簡化的。這些點的座標可以待會輸出爲整形。默認的量子化常量爲1/10可得到很好的記過。然而,它可用-urable -unit命令行選項來設置。

3 一個完整的例子

圖10顯示了Potrace的一個完整的例子。a部分顯示了源位圖,在b部分,記錄了默認的“少數派”轉向方針是怎樣保持黑色輪廓沿着連着的圖形,同時保持白色輪廓在圖形內也相連。同樣記錄了圖形內大小爲1斑點被移除。b部分顯示了優化過得多邊形。c部分顯示了調整過後的多邊形頂點,相對於源位圖,即用灰色顯示的。每個頂點都圍繞在單元方形周圍。同樣,章節2.3.3的線片段Li也顯示了,參數α被寫在每個頂點的單元方形內;這可以在Acrobat Reader中以一個很大的縮放來觀看。(....這些小方塊裏面真的有數字,諸位同學可以到原版英文pdf裏面觀看)。轉角分析也再這一步執行,注意這張特殊的位圖,僅僅很少的轉角被檢測到。通常,轉角分析在更高分辨率上工作得更好。光滑化下一個被執行;結果貝塞爾曲線片段和線片段在圖中以藍色顯示。d部分顯示了曲線優化的結果;原曲線以藍色顯示,優化過得曲線以紅色顯示。紅點表示新的片段邊界。注意片段的數量由112減少到68,接近40%。最終的結果如部分e所示。
 

調試結果以圖10(b)-(d)那樣顯示可以用命令行選項-d1 -d3來設置。

參考文獻 
[1]  I. D. Faux and M. J. Pratt. Computational Geometry for Design and Manufacture. Ellis Horwood Series in Mathematics and its Applications, Editor: G. M. Bell. Ellis Horwood, New York, NY, USA, 1979.
[2]  D. E. Knuth. The METAFONTbook, volume C of Computers and Typesetting. Addison-Wesley, Reading, MA, USA, 1986.


註釋(1):實際上已經有專門的用於非常小的位圖矢量化算法,07年的Depixelizing Pixel Art

註釋(2):這裏的四個點應該是包括自己的4個點

註釋(3):比如以(0,0)點爲中心,最大距離爲0.5的點的集合就以(0,0)爲中心,邊長爲1的正方形區域點的集合

註釋(4):實際上不是Θ這個字符 原字符打不出來

註釋(5):i0之類的符號 0是下標 im-1 之類也是im-1 具體可看原文

註釋(6):懲罰Penalties,我們在圖形算法裏經常可以看到這個單詞,它指的是當數值偏離最優解付出的代價,我們需要求的是懲罰總和最小的情況即爲最優解,比如懲罰的公式是x的4次方,當x取0的時候值最小,當x>1的時候將會付出巨大的懲罰來限制x儘量<1。一般一個值的改變也會影響其他的值改變,所以是要求總的懲罰最小。

註釋(7):自由度:自由度(degree of freedom, df)在數學中能夠自由取值的變量個數,如有3個變量x、y、z,但x+y+z=18,因此其自由度等於2。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章