ImageMagick 範例 --
形狀形態學

索引
ImageMagick 範例前言與索引
形態學簡介
基本形態學方法
差異形態學方法
使用低階形態學方法
擊中與未擊中(HMT)模式匹配
距離形態學方法
條件或約束形態學
從形狀產生骨架。 建構中
形態學基於周圍像素的“鄰域”,以各種方式修改圖像。這反過來可以提供廣泛的效果,形狀擴展和收縮(膨脹/腐蝕),到邊緣的距離,細化到骨架或中線軸。即使是更古老的“卷積”技術(下一節),提供模糊和銳化技術,在某種程度上也是一種形態學方法。本質上,形態學是用於修改、確定和發現圖像中發現的物體形狀的。

形態學簡介

形態學最初是作為一種方法而開發的,通過這種方法可以清理和研究圖像中形狀的結構。它的工作原理是以各種方式將圖像中的每個像素与其鄰居進行比較,以便添加或刪除、變亮或變暗該像素。應用於整個圖像,可能是重複地,可以找到和/或刪除和修改特定的形狀。例如,如果一個像素是白色的,並且完全被其他白色像素包圍,那麼該像素顯然不在圖像的邊緣。然後,您可能希望將該像素設為黑色,以便僅保留邊緣像素處於開啟狀態。一種稱為“內邊緣”的方法(見下文)。整個過程實際上取決於“結構元素”或“內核”的定義,它定義了對於每個特定的形態學方法,哪些像素將被歸類為“鄰居”。這個“鄰域”的確切大小和形狀通常取決於您想要達到的目標,或者您在圖像中具體尋找的內容。以下是一些已轉換為圖像的各種內核示例(使用特殊腳本“kernel2image”),顯示了中心像素“原點”周圍的一些“鄰域”。
[IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output]
這些圖像已經過縮放,以突顯「核」的個別元素,您可以看到典型的核通常非常小。事實上,上面顯示的「圓盤」核實際上是「[原始圓盤核圖像]」,而這是上面顯示的最大核之一。然而,「核」並不是真正的圖像。只是一個浮點數值的陣列,其中一個元素被指定為核的「原點」。這個特殊元素是將被定義鄰域「影響」的像素位置,通常(但不總是)是對稱核的中心像素。請注意,這些只是一些可能的鄰域示例。某些核可以做得更大,通常是通過增加特定於該核的「半徑」參數,而其他用於特殊目的的核則具有固定大小。對於簡單的核,例如前兩個,可以重複(迭代)形態學方法以增加核的有效「大小」,以便影響距離「原點」(如標記所示)更遠的像素。然而,這並不總是有效,並且可能會產生意外結果,但有時它比直接使用更大的核更快,但同樣,這並不總是如此。在形態學研究論文中,「結構元素」或「SE」(即核的術語)的最終大小和形狀很重要,它是定位和增強或刪除大於或小於此形狀的圖像元素的一種方法。這就是形態學作為一種區分圖像中各種元素的極其強大的方法的原因。然而,核越大,形態學方法所需的時間就越長,因此最好保持核較小。除最後一個外,所有顯示的核實際上都是有形狀的。透明的部分*不是*核定義「鄰域」的一部分。也就是說,它們將沒有任何有效值,也不會參與任何形態學計算。請注意倒數第二個核「Corner #0」不僅具有「開啟」值,還具有「關閉」值,作為其「形狀」的一部分。這兩個值以及那些透明的(不屬於形狀的一部分)值對於擊中與錯過和相關方法(見下文)都很重要。這個特定的核只是一系列核中的第一個,用於定位圖像中二進制形狀的「角」像素。上面顯示的最後一個「核」是在一個大的矩形(正方形)區域上完全定義的。此外,與其他僅使用 1(白色)、0(黑色)或特殊「未定義」值的核不同,此核的值實際上從邊緣的接近零(幾乎黑色)到中心的最高(純白色)值不等。然而,此類核也可以使用負值,甚至是遠遠超出其他核正常範圍的非常大的值。請記住,核實際上只是一個值的陣列,這些值可以是任何值,而不僅僅是 0 到 1 的範圍。這種類型的核在「卷積運算」中尤其重要,這是一種比形態學本身存在時間长得多的特殊方法。因此,IM 具有大量的此類內置或「命名」核。這一點將在 IM 示例的下一部分圖像卷積中詳細介紹。現在,正如我已經提到的,核並不是真正的圖像。它們只是一個浮點數值的陣列。我們將在後面查看這些實際值(已轉換為圖像以供查看,如上所示)。

形態學運算子

-morphology」運算符非常複雜,因為它為用戶提供了許多对其操作的控制。

  -morphology {method}[:{iterations}]   {kernel}[:[k_args}]
請注意,您需要提供至少兩個項目,「method」形態學,告訴運算符您想要應用於圖像的操作類型,以及一個「kernel」指定哪些「相鄰」像素會影響最終結果。兩者同樣重要,並且兩者都可以產生深遠的影響。您可以使用「-list morphology」獲取可用方法的列表。可以使用「-list kernel」查看我們包含在 IM 中的內建核心列表。稍後我們將詳細介紹各種方法,以及這些方法可能會使用的核心。
-morphology」運算符(基本方法)和初始核心集是由我自己在 ImageMagick 6.5.9-0 版本中添加的,當時我正在中國度假。2009 年 12 月至 2010 年 1 月。

但是,可以使用較舊且密切相關的「-convolve」方法執行簡化的「方形」核心形態學。請參閱下面的替代基本形態學技術

基本的內建形狀核心

由於核心對於所有形態學方法都是通用的,並且各種方法的結果在很大程度上取決於所選的實際核心,因此我們首先將了解如何定義或選擇要使用的核心。我們已經為您預先定義了一系列優質的核心,而且通常您只需要查看這些核心即可。您可以使用「-list kernel」獲取預先定義的內建核心列表。所有核心都有一個特定的大小,通常是一個正方形,每邊的像素數為奇數,其中心是核心的「原點」。但是,正如您將看到的,「-morphology」運算符並不局限於此限制。用於內建核心的最常見k_argument,通常是給出的第一個參數是「radius」(半徑)。這定義了核心典型的奇數大小方形鄰域的大小。最終核心大小通常是半徑的兩倍加一(對於中心像素)。也就是說,「radius」為「2」將創建一個 5×5 像素的正方形核心。雖然「radius」通常定義最終核心的大小,從而定義形態學操作在圖像上的整體速度,但它可能不是最重要的因素,尤其是對於卷積核心,其中值對結果的影響大於核心大小。如果將「radius」設置為 0 或未定義,「radius」將自動默認為某些合理或最常用的值,具體取決於所涉及的核心。 [IM Output]

Unity(單位)

這是一個特殊的核心,專門用於需要「無操作」核心的情況。大多數使用此核心的形態學方法將重新生成原始圖像或生成空白結果。核心沒有參數。可以使用「Disk:0.5」生成完全相同的單元素核心,這也允許您在核心生成過程中指定縮放參數。[IM 輸出]

Diamond(菱形)

最小的核心(雖然可能不是最簡單的)是「Diamond」內建核心。查看基本核心的一種簡單方法是在包含黑色背景上的單個白色像素的圖像上使用膨脹形態學方法。這基本上將單個像素擴展為核心鄰域的「形狀」。這是使用「Dilate」和最小的「Diamond」內建核心,並將結果放大以使其更清晰可見的結果。

  magick xc: -bordercolor black -border 5x5 pixel.gif
  magick pixel.gif -scale 800% pixel_mag.gif
  magick pixel.gif -morphology Dilate Diamond \
                    -scale 800% k_diamond.gif
[IM Output] ==> [IM Output]
請記住,在 IM 範例的這個區域中,所有核心影像結果都已放大,以便您能看到個別像素。實際上,我們所展示的所有核心和結果都非常小,這才是它們應有的樣子。在這個例子中,被膨脹的影像只有 11×11 像素大小,並且已經被縮放了 8 倍以供顯示。
這實際上是一個相當適合形態學運算的核心,並且基本上定義了最小的實用鄰域:原始像素加上直接接觸的四個像素。這種類型的核心也稱為「Z4」結構元素。它看起來很像一個小小的「加」號。只有當半徑增加時,菱形才會變得明顯。這個核心的可選 k_arg 可以採用兩個值,如下所示...

     Diamond[:{radius}[,{scale}]]
對於所有形狀核心而言,最重要的參數是 radius,如前所述,它是一個整數,表示從中心「原點」到最近邊緣的距離。因此,最終的「Diamond」(菱形)核心是一個正方形(2 乘以 radius 加 1),其中包含菱形形狀。以下是使用較大的 radius 生成大型核心的結果。

  for r in 1 2 3 4; do
    magick pixel.gif -morphology Dilate Diamond:$r -scale 800% k_diamond:$r.gif
  done
[IM Output]
Diamond:1(菱形:1)
(預設值)
[IM Output]
Diamond:2(菱形:2)
[IM Output]
Diamond:3(菱形:3)
[IM Output]
Diamond:4(菱形:4)
另一個 k_argumentscale,預設值為 1.0。通常,這用於更改核心用於形成形狀的實際值。這通常只對特殊方法很重要,例如 卷積灰度形態學[IM 輸出]

Square(正方形)

Square」(正方形)核心是形態學中最常用的核心,因為它最容易使用其他替代技術來應用。但是,它不是最小的核心(請參閱上面的「Diamond」(菱形))。
根據預設,「Square」(正方形)核心使用「中心」周圍的 3x3 像素鄰域。

  magick pixel.gif  -morphology Dilate Square -scale 800% k_square.gif
[IM Output]
基本上,這意味著原始像素的所有 8 個鄰居都將被歸類為該像素鄰域的一部分。因此,它是一個很好的核心,用於對像素進行平均,或將某些形狀擴展/縮小一個像素。與所有形狀核心一樣,它採用與上面針對 菱形核心 所示的相同的 k_arguments,其中第一個參數 radius 最重要。

  for r in 1 2 3 4; do
    magick pixel.gif  -morphology Dilate Square:$r -scale 800% k_square:$r.gif
  done
[IM Output]
Square:1(正方形:1)
(預設值)
[IM Output]
Square:2(正方形:2)
[IM Output]
Square:3(正方形:3)
[IM Output]
Square:4(正方形:4)
如前所述,此核心的預設值(radius=1)是一個 3×3 正方形,通常稱為「Z8」結構元素(用於所涉及的相鄰鄰居的數量)。[IM 輸出]

Octagon(八邊形)

Octagon」(八邊形)核心是一個 8 邊形狀的核心。它專為匹配「八邊形距離度量」而設計。不要將兩者混淆,因為它們是非常不同的核心。以下是針對小半徑產生的核心...
[IM Output] [IM Output] [IM Output] [IM Output] [IM Output]
請注意,在半徑為 1 時,您將獲得與「菱形」核心相同的核心。因此,預設的八邊形大小為半徑「2」。
從現在開始,我將使用一個特殊的 kernel2image 腳本來生成核心的影像,因為它們比使用原始的「膨脹縮放」方法(如上所示)清晰得多。但是請記住,核心通常非常小,儘管八邊形和圓盤核心(請參閱下文)對於特定用途可能會變得非常大。

Octagon」(八邊形)核心是在 IM v6.6.9-4 中添加的,同時還添加了「八邊形」距離核心。
[IM Output]

Disk(圓盤)

顧名思義,「Disk」(圓盤)核心是圓形的。當需要非常大的形態學核心時,通常會使用它。但是請注意,它是一個別名化的布林圓。但是,圓盤的 radius 參數可以是浮點數,這使您可以使用小半徑來產生相當多的形狀。
[IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output]
[IM Output] [IM Output] [IM Output] [IM Output] [IM Output]
Disk:4.3」 核心是預設值,我認為這是第一個真正的圓盤形狀。這個大小或更大的圓盤特別適合用於圖像形狀的圓角化和平滑化。包含圓盤的核心的最終大小是「半徑」值向下取整,乘以 2 再加 1。因此,默認的「Disk:4.3」核心具有 4 的核心大小半徑,使得最終核心大小為 4 乘以 2 加 1,並生成一個 9×9 的核心來容納圓盤形狀。請注意,小於 1(但不為零)的值始終會產生單像素核心,儘管這不是很有用。之後,核心往往主要產生也可以使用先前核心類型生成的內核。只有當半徑變大時,真正的圓盤形核心才會開始出現。需要注意的最重要一點是,具有分數半徑的圓盤比使用整數半徑的效果要好得多。通常建議添加大約 0.3 到 0.5 的分數,以避免在圓盤的側面生成難看的單個像素。[IM 輸出]

加號

Plus」核心實際上與其他形態形狀核心略有不同,因為它旨在表示特定的「形狀」,而不是像素周圍的簡單「鄰域」。對此核心使用更大的「半徑」不會簡單地增加核心的大小,而是會延長所得加號的臂長。然而,臂的厚度不會增加。
[IM Output] [IM Output] [IM Output] [IM Output]
Plus」核心的默認大小為 2 的半徑,在中心「原點」周圍產生 2 個像素的「臂」。「Plus:1」核心恰好與默認的「Diamond」核心相同。請注意,「Plus」核心通常不用於正常的形態學方法,並且應避免將其用於此類目的。但是,如果您想查找並突出顯示圖像中的單個點,這將非常有用,就像我稍後為顯示骨架信息 所做的那樣。基本上,它提供了一種繪製符號的方法,而無需確切知道各個「點」在圖像中的位置。 [IM Output]

十字

Cross」核心與「Plus」完全相同,但旋轉了 45 度。它也是一種特殊的核心形狀,適用於擴展像素以標記各個點的位置
[IM Output] [IM Output] [IM Output] [IM Output]
[IM Output]

環形

與「Plus」核心一樣,「Ring」核心也被設計為一種特殊的「形狀」核心,用於標記像素並在圖像上生成圖案。但是,它不僅採用一個半徑,還可以採用兩個半徑,並且其定義方式與圓盤核心 相同...

     Ring[:{radius1}[,{radius2}[,{scale}]]]
它的作用是「開啟」落在兩個半徑之間的任何像素,而不管給定的兩個半徑的順序如何。如果沒有給出半徑,則默認為「2.5」和「3.5」的半徑,產生一個「Ring:2.5,3.5」,看起來像一個空心的八邊形環,非常適合於圈出一個像素。通過改變兩個半徑,您可以創建任何大小和厚度的「環」。對半徑的小幅更改將在邊緣添加和移除極少數的像素,從而可以精細控制環的外觀。如果兩個半徑在彼此的 1 個像素以內,您還可以生成一個由稀疏分佈的點組成的環,這可以用作特殊用途的鄰域。小半徑也會生成類似於盒子的核心,這也可能很有用。如果沒有給出第二個半徑,它將默認為「0.5」的值,這實際上定義了一個完整的圓盤,但沒有中心「原點」像素。換句話說,一個圓盤核心,但不包括「原點」像素。以下是可以生成的許多「Ring」核心的示例...
[IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output]
您可以看到,通過仔細調整兩個半徑,您有很多可能性,並提供了一種在圖像中顯示感興趣位置的好方法。[IM 輸出]

矩形

Rectangle」內核與上面的「Square」內核密切相關,並且默認情況下會產生相同的 3x3 正方形內核。但您可以給出一個「幾何」參數來指定所需的矩形內核的確切大小,而不是一個簡單的半徑參數。以下是一些規格及其產生的內核圖像。
[IM Output] [IM Output] [IM Output] [IM Output]
[IM Output] [IM Output] [IM Output] [IM Output]
默認情況下,內核會嘗試將鄰域的「原點」設置為內核的確切「中心」。但是對於偶數大小的矩形,它會根據需要選擇中心正上方和/或左側的點。但是,您也可以指定偏離中心的原點。這個特殊的內核還擅長定義長水平線和垂直線,允許您在圖像中搜索此類對象。稍後會詳細介紹。目前,您不能為矩形提供比例因子。它的所有內核值都將僅設置為 1.0。

用戶自定義的 DIY 內核

您不僅限於使用內置內核,還可以指定您自己的內核,並指定您希望內核使用的確切值...

   "[{geometry}:] {value}, {value}, {value},....."
幾何」規範基本上與之前「Rectangle」內核的參數完全相同。它給出了內核的大小,以及可選的鄰域「原點」的「偏移量」。如果只提供一個數字,則假定它是正方形內核的維度。
請記住,幾何值不是「半徑」參數,而是整個內核大小。
如果沒有指定「幾何」或「:」,則您使用的是「舊」樣式規範。將生成一個足以容納所有給定值的奇數大小的正方形內核。不推薦這樣做,僅為了向後兼容舊版本的 ImageMagick。在「:」(在「幾何」規範之後是必需的)之後,您提供由逗號和/或空格分隔的寬度 × 高度浮點值。可以使用特殊值「NaN」(表示「非數字」)或單獨的「-」來指定內核中的此點不是形態鄰域的一部分。
例如,以下是寬度為 3 的方形內核的規範,可用於單像素圖像的卷積模糊。

  magick pixel.gif   -morphology Convolve \
            "3:  0.3,0.6,0.3   0.6,1.0,0.6   0.3,0.6,0.3" \
                                         -scale 800%  k_user_3.gif
[IM Output]
對於單個像素,Convolve 的工作方式幾乎與 Dilate 相同,但是 Convolve 使用內核值,將相鄰值擴展並加在一起。Dilate 通常使用開/關(布爾)形狀和所有鄰居的最大值。但是,當應用於具有布爾形狀的單個孤立像素時,您會得到相同的結果。請注意,您可以如何在輸入字符串中添加額外的空格(甚至換行符),以便分隔矩形內核定義的各個行。
在這裡,我定義了一個 5×3 的矩形區域,但使用特殊的「nan」(非數字)值來切斷角落以形成橢圓形內核...

  magick pixel.gif   -morphology Dilate \
            "5x3: nan,1,1,1,nan   1,1,1,1,1   nan,1,1,1,nan " \
                                    -scale 800%   k_user_5x3.gif
[IM Output]
最後,這裡是一個指定矩形鄰域的示例,該鄰域在「原點」周圍形成「L」形。我使用「-」而不是「nan」來指定不屬於內核的部分。請注意,此內核的原點甚至不屬於它自己的鄰域,它可以位於內核矩形邊界內的任何位置。

  magick pixel.gif   -morphology Dilate \
            "2x3+1+1:   1,-   1,-   1,1   "  -scale 800% k_lman.gif
[IM Output]
如您所見,使用者核心規格非常靈活,允許您指定幾乎任何類型的核心,無論是具有許多分數的捲積核心,還是具有「非鄰域的一部分」元素的形狀核心,用於形態學方法。

將圖像轉換為使用者核心

為了更容易生成 DIY 核心,您可以使用「image2kernel」腳本創建核心。例如,在這裡,我將一個小旗標(  )變成一個使用者核心數據文件(「flag_kernel.dat」),然後使用它用幾個像素擴展圖像。

  magick -size 80x80 xc:black -fill white \
          -draw 'point 20,15 point 55,30 point 40,60'  points_pixels.gif
  image2kernel -qgm flag.gif flag_kernel.dat

  magick points_pixels.gif \
             -morphology Dilate @flag_kernel.dat \
           flagged_points.gif
[IM Output] - [IM Output] ==> [IM Output]
另請參閱下面的生成核心的圖像,它可以生成核心的圖像(或生成放大的漂亮版本)。繪製符號的替代方法中也討論了這種技術。

迭代(重複)形態學運算

如您所見,您可以生成更大的核心,以便在更大的鄰域上應用形態學。然而,在大多數情況下,使用更大核心的更快替代方法是簡單地多次重複(迭代或循環)形態學運算符。這意味著該運算符的效果將進一步發揮,與使用更大核心具有相同的基本效果,但沒有使用更大核心的額外計算成本。
例如,這裡是使用“Diamond:3”核心的單個像素的膨脹...

  magick pixel.gif  -morphology Dilate Diamond:3 -scale 800% k_diamond_x3.gif
[IM Output]
但是您也可以通過三次使用較小的“Diamond”核心(半徑 1)來獲得相同的結果...

  magick pixel.gif  -morphology Dilate Diamond \
                     -morphology Dilate Diamond \
                     -morphology Dilate Diamond  -scale 800% k_diamond_x3.gif
[IM Output]
您仍然只使用一個非常小的 3x3 核心,但重複基本形態學操作三次,以產生與使用更大核心相同的效果。事實上,像這樣重複小核心實際上比使用更大的核心快得多。
一個大的“Diamond:3”核心在圖像中每個像素有 81 個元素要處理。但是重複一個較小的“Diamond”核心 3 次在圖像中每個像素有 3×9 或 27 個核心元素要處理。在這種情況下,它快了 3 倍。

在這種情況下,速度提升並不多,但隨著核心尺寸的增加,節省會更大。
因為重複形態學操作非常普遍,所以您可以要求 IM 循環或迭代該操作多次,而不是重複該操作多次。

  magick pixel.gif   -morphology Dilate:3 Diamond -scale 800%  k_diamond_3.gif
[IM Output]
請注意這與第一個示例之間的區別。發生的所有事情是我們將“:3”從“Diamond”核心的半徑移到了“Dilate”方法的使用次數。使用“迭代”來擴大有效鄰域,適用於大多數“圓形”或“凸形”核心,例如“Square”和“Diamond”。但並非所有核心類型都適用。例如,對於非凸核心,例如“Plus”(它不是“凹”形),將產生非常不尋常的結果。
例如,這與從“Plus”(半徑 2)到雙倍大小的“Plus:4”核心不同...

  magick pixel.gif   -morphology Dilate:2 Plus  -scale 800%  k_plus_2.gif
[IM Output]
請注意,如果您使用 '迭代' 計數 '0',則形態學運算將不執行任何操作。當您不希望運算符執行任何操作,但又不想將其從命令列中刪除時,這是一種「關閉」運算符的有效方法。有關零迭代計數的另一個用途,請參閱下面的 詳細輸出顯示。使用特殊值 '-1' 將重複該操作,直到影像中看不到更多變化為止。也就是說,影像達到「收斂」點。然而,這很危險,因為在某些情況下可能會導致運算時間非常長。例如,對於 'Dilate' 之類的運算,它只會重複膨脹,直到整個影像完全填充為白色。基本上產生一種失控的「填充」(請參閱下面的下一個範例)。也不建議迭代 'Disk' 核心以產生更大的鄰域效應。這是因為隨著半徑變大,'Disk' 核心會變成更準確的圓盤形狀,而迭代圓盤不僅會放大形狀,還會放大核心的誤差(非圓盤形狀)。因此,您最好使用更大的半徑(速度較慢),而不是迭代操作(會產生更扭曲的圓盤)。但是,當 'Disk' 半徑變得非常大時,半徑和多次迭代的組合可能會產生更快但仍然可以接受的結果。可能需要謹慎和一些針對您的特定情況進行的實驗。

變化的詳細輸出

如果您想查看迭代(重複)形態學運算的結果,可以設定 "-define debug=True" 選項,這將開啟 詳細操作控制。當形態學運算符迭代時,它會報告迭代計數的遞增,以及每次迭代步驟更改了影像中的多少像素。輸出到標準錯誤,以便您仍然可以管道傳輸影像結果。例如,讓我們使用更大的 'Octagon' 核心 'Dilate' 單像素影像,直到整個影像都被白色填充並且無法對影像進行更多更改。請記住,迭代限制 '-1' 表示永遠迭代,或者直到看不到更多變化為止。

  MAGICK_THREAD_LIMIT=1 \
    magick pixel.gif -define debug=true -morphology Dilate:-1 Octagon \
            -scale 800% iterate_infinite.gif
[IM Output]
[IM Text]
請注意每次迭代中所做的更改次數。最初有 20 個像素從黑色轉換為白色。然後在下一次迭代中再增加 48 個,依此類推。這個數字通常隨著結果形狀的邊緣變大而增長,但隨著形狀碰到影像邊界而開始再次縮小。在第四次膨脹時,最後 4 個像素(在影像的角落)被填充。在最後一次膨脹(迭代 5)時,影像已經完全填充,因此沒有對任何像素執行更多更改。由於沒有進行任何更改,因此形態學會自動中止,並提供此階段操作的最終更改次數。使用 '-1' 的無限迭代確實有一個內部限制。目前設定為影像的最大寬度或高度。這樣做是為了防止 ImageMagick 進入永無止境的迴圈。然而,通常操作會在達到該內部限制之前很久完成。一些形態學方法實際上是根據更簡單、更原始的方法來定義的。例如,'Smooth' 方法就是這樣一種複合方法。使用此方法時產生的 "-define" 輸出顯示了構成其處理的多個內部步驟。

  MAGICK_THREAD_LIMIT=1 \
    magick man.gif -define debug=true -morphology Smooth:2 Diamond null:
[IM Text]
如果您仔細觀察,您會發現 'Smooth' 實際上迭代了 4 種更原始的方法,因此在內部處理影像 8 次以執行請求的操作。每一行都包含..
平滑處理:i.s
這顯示套用至影像的高階形態學方法,以及 IM 正在處理的迭代計數「i」和基本「階段」「s」。對於「Smooth」方法,第一個數字始終為「1」,因為使用者給定的「迭代計數」套用於低階基本方法。在其他方法中,使用者給定的迭代可以套用於此較高階而不是較低階。第二個「階段」編號是正在套用的基本「階段」計數。「Smooth」本身由四個這樣的階段組成,因為它實現了「Open」和「Close」複合方法。
擴張*:i.k
這是正在套用的基本方法。第一個數字「i」同樣是使用者給定的迭代計數(如果它在這裡套用)。第二個數字「k」是由基本形態學方法套用的核心。由於只有一個核心,所以在這種情況下它始終為零。(請參閱下面的多核心處理)「*」表示核心在被形態學基元套用之前被反射(或圍繞原點旋轉 180 度)。這對於某些複合形態學方法是必需的,在這種情況下,「Close」方法在其對「Dilate」和「Erode」基本方法的使用中始終使用反射核心。
#6 => 已變更 311 個,總計 637 個
這是將形態學基元套用於影像的結果報告。「雜湊」編號是影像通過基元傳遞次數的增量計數。這讓您很好地了解複合形態學運算符的計算密集程度。然後,您將獲得在該次通過期間以某種方式實際更改的像素數。如果這是此特定基元和核心多次迭代中的最後一次,則還會輸出像素修改的總數。然而,這並不反映從頭到尾更改的像素總數,而僅反映由特定基元、核心操作的低階迭代引起的更改。某些像素可能會被某些形態學基元更改多次。
從上面您可以看到,在內部,IM 可能有四個處理循環被套用於完全處理給定的形態學方法。然而,通常這些循環中的大多數只套用一次。
警告:在現代多核心機器上運行程式多線程環境的機器上,更改的像素數可能不正確!只有在單線程環境中執行時才能保證準確。我將其歸類為錯誤,但不是致命錯誤。

如果這是一個問題,則請確保將環境變數「MAGICK_THREAD_LIMIT」設置為值「1」以用於 ImageMagick 的特定運行,就像我在上面最後兩個示例中所做的那樣。

從 IM v6.8.4 開始,您不再需要「MAGICK_THREAD_LIMIT」環境設置,因為計數在多線程環境中得到正確處理。

顯示生成的核心(用於調試目的)

如果您想實際查看用於定義生成的特定核心的值,則可以定義一個特殊設置...

    -define morphology:showkernel=1    
    -define convolve:showkernel=1    
上述任何定義都會導致 IM 在核心經過完全處理以準備使用後,將有關生成核心的所有信息輸出(到「標準錯誤」)。(請參閱卷積核心縮放)。例如,以下是內置「Disk」核心的實際值...

  magick xc: -define morphology:showkernel=1 -morphology Dilate:0 Disk null:
[IM Text]
請注意,因為我只想顯示內核,所以我根本不關心圖像處理。因此,我將形態學「迭代」設置為「0」(不做任何事情),並且還使用 null: 輸出文件格式丟棄任何圖像結果。上面浮點值「nan」的特殊含義與輸入 用戶定義內核 時的含義相同。它表示「非數字」,並標記內核中不屬於鄰域的部分。所有形態學操作都忽略這些值。以下是另一個示例。這次是「Comet」卷積內核。

  magick xc: -define morphology:showkernel=1 -morphology Dilate:0 Comet:0x2  null:
[IM Text]
這實際上是 1 維高斯曲線的一半(sigma 為 1.0),並且可以提供從 ImageMagick 中提取此類曲線的好方法。另請注意,此特定內核的「原點」(它影響的像素)不在中心(位於 +0+0),這並不常見。輸出中值的尺寸和間距可以使用特殊的 精度操作控制 來控制。這是在形態學運算符出現的同時添加到 IM 中的。例如,以下是上一個示例的重複,但使用「-precision」將有效位數從默認值 6 位限制為 3 位。

  magick xc: -define morphology:showkernel=1 -precision 3 \
          -morphology Dilate:0 Comet:0x2  null:
[IM Text]
-precision」選項是在形態學開發週期中添加到 ImageMagick 6.5.9-1 版本中的。因此,如果形態學可用,則精度也可以被視為可用。

生成內核圖像

為了更容易看到內核,而不是在單個像素圖像上使用 膨脹卷積 來查看它產生的結果,我創建了一個名為「kernel2image」的特殊腳本。此腳本提取確切的 顯示內核 輸出,並將其轉換為內核的圖像。「kernel2image」腳本有很多選項,從輸出內核的原始圖像(默認)到指定縮放量、像素間間隙、蒙太奇、標記,甚至生成的「內核圖像」的顏色。該腳本使查看和理解各種內核變得更加容易,並廣泛用於生成這些示例頁面中顯示的內核圖像。
例如,以下是我如何生成「八邊形」內核圖像。

  kernel2image -10.1  -m "Octagon"  kernel_octagon.gif
[IM Output]
特殊選項「-10.1」表示將所有像素縮放到 10 像素大小,但也包括這些像素之間的 1 像素間隙。如果內核縮放得足夠大,則內核的「原點」將使用一些繪製的圓圈進行標記。然後,「-m」指定我要為圖像創建一個帶有提取的「八邊形」內核的識別標籤和陰影效果的 蒙太奇
在這裡,我生成上面使用的「L」形用戶定義內核的「內核圖像」。

  kernel2image -20.2 -ml 'L-Shape'  "3: 1,-,-  1,-,-  1,1,- " kernel_lman.gif
[IM Output]
如果要從現有圖像創建內核,可以使用腳本「image2kernel」從圖像創建內核數據文件。此腳本通常採用灰度圖像,但如果給定多色圖像,則圖像的每個通道都將轉換為單獨的內核數據文件。
在這裡,我從一個小旗標圖像(  )創建 用戶內核數據,然後使用「kernel2image」將該數據轉換回放大的「內核圖像」以進行顯示。

   image2kernel -qgm flag.gif  flag_kernel.dat
   kernel2image -6.1 -m  -ml "Flag"  @flag_kernel.dat  kernel_flag.gif
[IM Output]
順便一提:我本可以使用類似的腳本「enlarge_image」更直接地生成小圖像的「放大」版本,但这將顯示圖像,而不是內核數據「flag_kernel.dat」。

多個核心列表處理

生成多個內核

從 IM v6.6.2-0 版本開始,您可以指定多個內核,這些內核將依次應用於圖像。要指定多個內核,您只需將每個內核定義附加在一起,並以分號「;」分隔。結尾處的最後一個分號是可選的。例如,我在此定義了一個特殊的內核列表,其中包含一個可用於「模式匹配」角像素的列表。

     3: 0,0,- 0,1,1 -,1,-  ;      
     3: -,0,0 1,1,1 -,1,-  ;
     3: -,1,- 1,1,0 -,0,0  ;
     3: -,1,- 0,1,1 0,0,-  ;
額外的分號(「;」)無關緊要,只要在內核規範之間至少提供一個即可。內核規範中的額外空格(包括換行符)也無關緊要。這是此定義的顯示內核輸出

  magick xc: -define morphology:showkernel=1 -morphology Dilate:0 \
             " 3: 0,0,- 0,1,1 -,1,-  ;
               3: -,1,- 1,1,0 -,0,0  ;
               3: -,0,0 1,1,1 -,1,-  ;
               3: -,1,- 0,1,1 0,0,-  ; " null:
[IM Text]
這是使用特殊「kernel2image」腳本生成的這四個內核的內核圖像

   kernel2image -20.2 -ml '' -mt x1 \
             " 3: 0,0,- 0,1,1 -,1,-  ;
               3: -,1,- 1,1,0 -,0,0  ;
               3: -,0,0 1,1,0 -,1,-  ;
               3: -,1,- 0,1,1 0,0,-  ; "  kernel_multi.gif
[IM Text]
現在,此定義實際上只包含一個內核,該內核已擴展為一組 4 個內核,每個內核旋轉 90 度。順帶一提:此定義幾乎等效於特殊的「Corners」模式匹配內核(見下文),只是它將自身限制為實際形狀的角,而不僅僅是任何角、背景或前景。

擴展到旋轉核心列表

從 IM v6.2.2-0 版本開始,您可以要求 IM 通過在命名或自定義內核中使用三個特殊標誌之一,將單個內核展開為旋轉內核列表。這三個特殊標誌是...
@」    以 45 度增量循環旋轉 3x3 內核,生成最多 8 個旋轉內核的列表。(助記符:「@」是圓形的)
'>' 以 90 度增量旋轉(僅限方形或線性內核)。(助記符:「>」是直角)。
'<' 也產生 90 度旋轉,但採用「鏡像」順序(旋轉角度為 0、180、-90、+90)。這種特殊形式的旋轉展開更適合形態學方法,例如「Thinning」。(助記符:「<」是直角的鏡像)。
例如,可以使用以下更簡單的方式指定上面相同的內核...

    ' 3>:  0,0,-  0,1,1  -,1,- '
這定義了一個內核,「>」標誌告訴 IM 將其展開為 90 度旋轉列表。這是生成的 multi-kernel 列表的圖像

   kernel2image -20.2 -ml '' -mt x1 \
                '3>: 0,0,- 0,1,1 -,1,- '  kernel_rotated_list.gif
[IM Text]
我在此以「循環」45 度旋轉旋轉 3x3 內核,將其展開為 8 個內核的列表。

   kernel2image -20.2 -ml '' -mt x1 \
                '3@: -,1,- -,0,- 1,1,1 '  kernel_rotated_list2.gif
[IM Text]
您也可以對任何「單個」內置命名內核 IM 執行相同的操作,方法是在這些內核的參數部分中使用相同的標誌。例如,我在此使用「>」標誌將對稱的「Blur」內核展開為 90 度旋轉列表。

   kernel2image -12.1 -n -ml ''   "Blur:0x1>"  blur_kernels.gif
[IM Text]
請注意,只生成了 2 個內核,因為第三個內核只會完全複製第一個內核。發現這一點後,旋轉內核的生成就會停止。但是,如果「原點」偏離中心,則會生成完整的 4 個旋轉內核序列,因為雖然內核「形狀」匹配,但原點位置不同。許多內置內核定義會自動生成 multi-kernel 列表,因此您無需為此目的指定任何標誌。也就是說,旋轉展開也「內置」到特定的內核定義中。此類內核通常還提供原始單個內核定義的「子類型」,以便您可以為特定目的挑選和選擇特定的內核。

多內核結果合併:重複或組合

當您定義了多個內核時,形態學方法還需要知道如何合併多個內核生成的結果。這可以通過使用全局Define來控制...

    -define morphology:compose={compose_method}    
多數形態學方法的預設設定都是 'None'。這表示在使用指定形態學方法套用每個核心之後,產生的圖像應該被用作下一個核心的來源。也就是說,簡單地'重複迭代'或重複使用套用一個核心後產生的圖像,用於下一個核心。例如,如果我使用 2 個旋轉 90 度的 '模糊' 核心進行 卷積,我們會得到以下結果。

  magick pixel.gif  -morphology Convolve "Blur:0x1>" \
          -auto-level  blur_re-iterate.gif
[IM Output] * [IM Output] , [IM Output] ==> [IM Output]
如您所見,兩個核心都依次套用到了圖像上,因此每個核心都使用前一個核心的結果。也就是說,它'重複迭代'一個核心的結果與下一個核心,依此類推。這等同於執行以下兩個步驟。

  magick pixel.gif -morphology Convolve "Blur:0x1" -auto-level blur_1.gif
  magick blur_1.gif -morphology Convolve "Blur:0x1+90" \
          -auto-level blur_re-iterate.gif
[IM Output] * [IM Output] ==> [IM Output] * [IM Output] ==> [IM Output]
實際上,這就是 模糊運算子 的真正工作原理,以更快地產生圖像模糊。請參閱 高斯與模糊核心,其中更全面地演示了這種用法。
通過將 '{compose_method}' 設定為 'None' 以外的任何方法,操作將不會重複迭代。相反,每個核心將套用到原始圖像,然後使用指定的 '{compose_method}' 方法將產生的圖像 合成 在一起。例如,如果我使用 '加亮' 形態學方法來產生單獨結果的 聯集,我們將得到..

  magick pixel.gif -define morphology:compose=Lighten \
                     -morphology Convolve "Blur:0x1>" \
          -auto-level blur_union.gif
[IM Output] * [IM Output] , [IM Output] ==> [IM Output]
這相當於做...

  magick pixel.gif -morphology Convolve "Blur:0x1"  -auto-level blur_1.gif
  magick pixel.gif -morphology Convolve "Blur:0x1+90" -auto-level blur_2.gif
  magick blur_1.gif blur_2.gif -compose Lighten -composite \
          -auto-level blur_union.gif
[IM Output] * [IM Output] ==> [IM Output]
[IM Output] * [IM Output] ==> [IM Output]
[IM Output] U [IM Output] ==> [IM Output]
如果您不確定 IM 在形態學過程中實際在做什麼,請開啟 變化的詳細輸出。例如,這裡是使用每個核心重複迭代的詳細輸出...

  magick pixel.gif -define morphology:compose=None \
         -define debug=true -morphology Convolve "Blur:0x1>" null:
[IM Text]
這裡是每個核心結果的 聯集 (加亮合成) 的詳細輸出....

  magick pixel.gif -define morphology:compose=Lighten \
         -define debug=true -morphology Convolve "Blur:0x1>" null:
[IM Text]
兩者都清楚地顯示了 ImageMagick 為生成最終圖像所做的工作。小數點後的數字表示在每個步驟中套用的核心編號。最後是根據 'morphology:compose' 設定如何將圖像合成在一起。許多 數學合成方法 及其等效的 集合論 類型操作,也可以用於合併將每個核心套用到原始圖像的結果。總之,此設定定義了如何將多核心列表的單個核心套用到給定圖像。預設值是組合值 'None',表示簡單地'重複迭代'結果,否則它將根據給定的組合方法合併所有結果。

基本形態學方法

形態學方法是一種圖像處理技術,用於查找和分析圖像中物體的形狀。擴展、縮小、定位特定形狀等等。它最初是為二進制(純黑白)圖像而開發的,因此它最常套用於包含簡單黑白形狀的 閾值化 圖像。按照慣例,二進制圖像中的白色表示前景,而黑色表示背景。因此,方法名稱是根據此慣例描述的。也就是說,並不是說運算符不能用於灰度圖像,或者在某些情況下用於彩色圖像,而是它們的最初目的是處理二進制形狀。上面已經看過的基本 形狀核心 是形態學方法中最常用的鄰域定義'形狀'。這樣的核心通常被稱為“結構元素”,因為它們通常用於確定圖像中形狀的結構。

侵蝕  ( )

顧名思義,「侵蝕」方法會從任何背景像素「侵蝕」白色形狀,使其變小。您也可以將其視為擴展圖像的黑色區域。例如,以下是一個使用「八邊形」核心侵蝕後的簡單二元「人形」形狀。

  magick man.gif   -morphology Erode Octagon  erode_man.gif
[IM Output] - [IM Output] ==> [IM Output]
其基本效果是使圖像可能具有的任何突起或尖端變薄或完全移除,但它也會使圖像中存在的任何孔洞(例如由該圖像的「手臂」造成的)變大。一般來說,核心的尺寸決定了要移除多少像素。

膨脹  ( )

膨脹」方法是「侵蝕」的對偶。它會根據指定的內核(和迭代次數)擴展白色形狀,使形狀變大。當然,這也意味著它會「侵蝕」圖像的黑色區域。

  magick man.gif   -morphology Dilate Octagon  dilate_man.gif
[IM Output] + [IM Output] ==> [IM Output]
請注意,形狀不僅變大,而且其輪廓也變得更平滑。 「腿」之間的大凹痕已被填滿,圖像中包含的單個像素小「孔」也是如此。核心的尺寸和形狀決定了在圖像邊緣周圍添加了多少像素。
膨脹」和「侵蝕」是對偶的。也就是說,(至少使用對稱核心)通過在應用形態學方法前後對圖像進行反轉,您實際上將執行另一種形式的運算符。例如,這裡我通過在 反轉圖像 上使用「膨脹」來執行侵蝕。

  magick man.gif -negate \
             -morphology Dilate Octagon   -negate dilate_man_neg.gif
[IM Output]

開運算  ( )

這是「開運算」方法的效果,但這次使用的是更大的「圓盤」核心。

  magick man.gif   -morphology Open Disk  open_man.gif
[IM Output] o [IM Output] ==> [IM Output]
因此,您將看到「開運算」通過圓滑任何尖角來平滑輪廓,並移除任何小於所用形狀的部分。它還將斷開或「打開」任何細橋。但是,它不會移除圖像中可能存在的任何「孔」或間隙。例如在形狀「腿」之間。此外,它不會使形狀的基本「核心」尺寸變大或變小。實際上,它所做的是使用提供的相同核心「侵蝕」圖像,然後再次「膨脹」它。

  magick man.gif         -morphology Erode  Disk  open_erode.gif
  magick open_erode.gif  -morphology Dilate Disk  open_man_2.gif
[IM Output] ==> [IM Output] ==> [IM Output]
請注意,對已經使用相同核心打開的形狀執行「開運算」不會導致形狀進一步改變。例如...

  magick open_man.gif  -morphology Open Disk  open_man_twice.gif
[IM Output] ==> [IM Output] ==> [IM Output]
也就是說,使用相同的核心重複「開運算」操作對結果沒有影響。
因此,提供的任何迭代計數都將應用於單獨的膨脹和侵蝕子方法,而不是應用於整個方法,以便迭代可用於「擴展」有效核心,而不是毫無用處地重複複合操作。也就是說,「Open:2」迭代實際上將應用為對圖像進行「Erode:2」,然後是「Dilate:2」。這具有一般效果,即使由核心定義的有效「鄰域」更大。

  magick man.gif   -morphology Open:2  Disk  open_man_x2.gif
[IM Output]
在這裡您可以看到,由此產生的較大鄰域導致人的「頭部」和「腳部」末端都被移除。形狀的主體基本完好無損,但外觀也更平滑,而腿部間隙保持不變。這與將核心的尺寸加倍具有相同的效果,儘管其確切形狀可能與半徑加倍的核心不完全相同。

閉運算  ( )

閉運算」方法的基本用途是減少或移除核心「結構元素」大小的任何「孔」或「間隙」。也就是「關閉」大約是那個尺寸的背景部分。

  magick man.gif    -morphology Close Disk   close_man.gif
[IM Output] . [IM Output] ==> [IM Output]
此運算子的基本作用是通過填充(閉合)任何孔洞和凹陷來平滑形狀的輪廓。它還將形成連接到其他形狀的「橋樑」,這些形狀足夠接近,以便內核可以同時觸摸到這兩個形狀。但它不會使形狀的基本「核心」尺寸變大或變小。實際上,它的作用是先使用提供的相同內核「膨脹」影像,然後再「侵蝕」它,導致影像先變大,然後變小。這與「開啟」的順序相反。

  magick man.gif           -morphology Dilate Disk  close_dilate.gif
  magick close_dilate.gif  -morphology Erode  Disk  close_man_2.gif
[IM Output] ==> [IM Output] ==> [IM Output]
結果是影像的外部點將保持原樣,但任何「海灣」都將被平滑和加厚,「孔洞」和「間隙」都將被閉合。非常靠近的斷開物件可以連接在一起。與「開啟」一樣,使用相同的內核重複「閉合」方法不會對影像進行任何進一步的更改。但是,使用運算子的「迭代」將會重複內部子方法,以便產生更強的圓潤效果,類似於使用更大的內核。
與「膨脹」和「侵蝕」方法一樣,「開啟」和「閉合」方法也是對偶的。您可以通過在操作前後反轉影像來重現另一種「對偶」方法的效果。

  magick man.gif   -negate -morphology Close Disk -negate   close_man_neg.gif
[IM Output]

平滑

平滑」方法首先應用「開啟」,然後對形狀進行「閉合」,這首先會移除任何「小物件」,然後填充與內核「結構元素」大小相關的「孔洞」或「間隙」。這裡我們使用中等範圍的「八邊形:3」內核來平滑影像。

  magick man.gif  -morphology Smooth  Octagon:3  smooth_man.gif
[IM Output]
如您所見,所有「凹痕」、「間隙」、「孔洞」和「點」都已根據內核的大小和形狀進行了平滑和圓潤處理。「平滑」運算子也經常與緩慢增加大小的結構元素重複使用,以便從影像中慢慢去除雜訊。如果保留移除的部分,您將獲得影像的形態「分解」,可用於進一步研究。請參閱下面的粒度。該方法特別適用於清理掃描文件。請注意,這實際上是對原始影像應用 4 個獨立的「基本」操作。因此,它比簡單的「侵蝕」或「膨脹」慢 4 倍。

平面灰階形態學

雖然本質上所有四種基本形態學方法,以及後來根據這四種方法定義的方法,都是專門為處理二值影像而設計的,但它們可以應用於灰階和彩色影像(儘管彩色影像可能會產生一些奇怪的顏色效果)。需要灰階操作的實際範例。然而,內核本身將始終被視為一個簡單的「開啟」或「關閉」鄰域。任何為「nan」或小於「0.5」的內核值都將被視為在其定義的「鄰域」之外。總之,上述運算子應用「扁平」內核,沒有任何「高度」或「三維」特徵,但仍然可以應用於灰階影像。

真正的灰階或三維形態學

真正的灰階或 3D 形態學(如某個函式庫所稱)實際上會將核心中的值與影像中相鄰像素的值相加或相減,然後再尋找最大值/最小值作為結果。這意味著它將灰階影像視為 3D 形態物件的「高度場」,並將核心的灰階形狀視為調整該高度場的平滑形狀。雖然真正的灰階形態學的實作細節有詳細的記載,但它在實際情況中的應用卻沒有。也就是說,除了關於其在「光度」處理中的應用外,我還沒有找到任何使用真正的灰階形態學(除了「平面核心」之外)的有用範例。因此,我還沒有實作真正的 3D 灰階形態學。但是,如果人們真的需要這種非平面的灰階形態運算子,請告訴我,我會實作適當的運算子。請注意,特殊的「距離」方法(見下文)實際上與真正的灰階形態學的工作原理類似,它會將核心的值加到每個像素值,然後再取最小的「最小值」。但是,此方法與 3D 侵蝕(減去並取最小值)或膨脹(加上並取最大值)形態定義都不符。然而,它與這兩種方法密切相關,並且可能可以使用這兩種方法來實作。

彩色影像的強度變體

由於上述四種方法都是灰階 通道 方法,因此在彩色影像上使用它們會產生偏色效應,其中一個通道被修改,而另一個通道沒有被修改。它們實際上並非設計用於多通道彩色影像,而僅適用於灰階和二值影像。結果是,對於彩色影像,顏色會失真,根據操作的不同而變成更亮或更暗的色調。考慮到這一點,我建立了這些方法的「強度」版本。「ErodeIntensity」、「DilateIntensity」、「OpenIntensity」、「CloseIntensity」。這些方法會比較定義的「鄰域」內的像素,並根據像素強度替換當前像素的顏色。也就是說,複製的是整個彩色像素,而不僅僅是單個通道值。結果是...
強度變體不會在影像中產生任何「新」顏色。
由於其性質,強度方法 將完全忽略當前的「-channel」設定。例如,這裡我在內建的「rose:」影像上使用了「膨脹」形態學(擴展亮區)的二值和強度變體。

  magick rose: -morphology Dilate          Octagon:3  rose_dilate.gif
  magick rose: -morphology DilateIntensity Octagon:3  rose_dilate_intensity.gif
[IM Output] ==> [IM Output] [IM Output]
如您所見,普通的「膨脹」方法會在每個大的膨脹點中產生不同的色調,因為每個通道都是單獨處理的。但是,第二次強度膨脹會保留最亮點的完整顏色,並根據布林核心形狀擴展它們。強度方法還有一個簡短的命名方案,將「Intensity」一詞替換為「I」。因此,這裡我使用了「CloseIntensity」方法,但使用了簡稱「CloseI」。例如,以下是在內建的玫瑰影像上使用四種「強度」變體的結果。

  magick rose: -morphology ErodeI Octagon:3 rose_erode_intensity.gif
[IM Output]


magick rose: -morphology DilateI Octagon:3 rose_dilate_intensity.gif
[IM Output]

  magick rose: -morphology OpenI Octagon:3 rose_open_intensity.gif
[IM Output]

  magick rose: -morphology CloseI Octagon:3 rose_close_intensity.gif
[IM Output]
最後兩個變體可能特別適合作為 繪製運算子 的替代運算子。*這些方法被歸類為實驗性方法*,歡迎對其使用提出意見或問題。如果我沒有收到任何意見,就不會再添加任何內容!

替代基本形態學技術

For people with versions of IM older than v6.5.9-0 you can still implement
some basic morphology methods.

You can generate a kernel that is all ones. For example a 7x7 array of 1's
(radius=3), by use an extremely large sigma and specify the appropriate radius,
using a Gaussian blur.

As such
    -convolve 1,1,1,1,1,.....
for a total of 49 ones is equivalent to
    -gaussian-blur 3x65535

This allows you to generate a simple square kernel for binary morphological
methods.

'Dilate'   for a 3x3 square kernel (radius=1) is thus
    -gaussian-blur 1x65535 -threshold 0
'Erode'  is thus
    -gaussian-blur 1x65535 -threshold 99.999%

As previously shown above
'Open' is a 'Dilate' followed by a 'Erode'
'Close' is a 'Erode' followed by a 'Dilate'
and Smooth is a 'Open' followed by a 'Close'

Larger square kernels can be specified using larger radii.

Unfortunately the other built-in kernel shapes are not available,
without using the convolve operator to manually define their shape.

This also only truly works for binary morphology. To implement a
flat-greyscale morphology, you will need to use a different technique of
generating a separate image for each pixel in the kernel, and rolling
it for the pixels position.

Both the thresholded-convolve and roll-shift composition methods have been
implemented in Fred Weinhaus's script "morphology", which was created long
before the "-morphology" operator was added to ImageMagick.

See and Download Fred's Weinhaus "Morphology" Script from
  http://www.fmwconcepts.com/imagemagick/morphology/index.php

差分形態學方法

形態學方法的下一級別是我稱之為差異形態學的東西。也就是說,這些形態學方法的結果是一個先前的基本形態學方法與原始影像之間的差異,或者與其他形態學方法的差異。本質上,它們返回的是由一種更簡單的方法對原始影像所做的更改,為您提供影像之間的輪廓、添加或減少的部分。它們本質上是影像結果的「差異」或「減去」影像合成。

內邊緣

內邊緣」方法,也稱為「內部梯度」,會尋找侵蝕從原始影像中移除的像素。因此,會返回最靠近邊緣但屬於原始形狀一部分的像素。

  magick man.gif   -morphology EdgeIn Octagon  edgein_man.gif
[IM Output] ==> [IM Output] ==> [IM Output]
產生的邊緣大約是給定核心大小的一半,對於「八邊形」核心來說,這條邊緣相當粗。更常見的情況是,您會使用小得多的「菱形」或「方形」核心,以產生形狀的單像素輪廓。在稀疏顏色作為填充運算子中顯示了使用「內邊緣」和 Alpha 色板來提取邊緣像素的範例。

外邊緣

外邊緣」方法,也稱為「外部梯度」,會尋找透過膨脹影像添加到原始影像的像素。因此,會返回緊鄰形狀的背景像素。

  magick man.gif   -morphology EdgeOut Octagon  edgeout_man.gif
[IM Output] ==> [IM Output] ==> [IM Output]
輪廓或光暈透明度中顯示了使用「外邊緣」和 Alpha 色板的範例。

邊緣或形態學梯度

邊緣」方法會返回「形態學梯度」,可以將其描述為最後兩個「邊緣」方法的相加,或者更具體地說,是侵蝕形狀与其膨脹形狀之間的差異。

  magick man.gif   -morphology Edge Octagon  edge_man.gif
[IM Output] ==> [IM Output] ==> [IM Output] ==> [IM Output]
與之前一樣,核心的尺寸和形狀決定了侵蝕影像的厚度。其厚度基本上等於該核心尺寸減去中心像素。因此,半徑為 3 的核心通常會產生厚度為 6 個像素(核心尺寸為 7 個像素)的「邊緣
例如,這裡是使用最小「菱形」核心的形狀「邊緣」輪廓。

  magick man.gif  -morphology Edge Diamond  man_outline.gif
邊緣有兩個像素厚,因為它包含位於原始形狀實際「像素邊緣」兩側的像素。使此邊緣變細的唯一方法是實際上將整個影像沿對角線偏移半個像素。
[IM Text]
有關以各種方式獲取形狀輪廓的更多詳細資訊,請參閱邊緣偵測一節。未來:使用「對角線」產生邊緣。

頂帽變換

頂帽變換」方法,或者更具體地說是「白頂帽變換」,會返回被形狀的開運算移除的像素,也就是被移除以使點變圓以及連接形狀之間的橋樑的像素。

  magick man.gif   -morphology TopHat Disk  tophat_man.gif
[IM Output] ==> [IM Output] ==> [IM Output]
如您所見,像素通常形成小的、高度不相交的島嶼,沒有任何像素集比使用的核心厚。方法名稱「頂帽」實際上是指在灰階三維形態學(而不是像我們這裡所做的那樣使用二進制影像)中應用該方法時使用的運算子。此運算子更常與灰階影像一起使用。未來:灰階頂帽變換的範例

底帽變換

底帽變換」方法,也稱為「黑頂帽變換」,是形狀的閉運算添加到影像中的像素。也就是說,用於填充「孔洞」、「間隙」和「橋樑」的像素。

  magick man.gif   -morphology BottomHat Disk  bottomhat_man.gif
[IM Output] ==> [IM Output] ==> [IM Output]
同樣地,你可以看到它也會產生高度分離的像素「島嶼」,每個「島嶼」的厚度都不會超過所使用的核心。然而,它們始終是與先前方法完全不同的一組「島嶼」。 未來:灰階底帽範例

使用低階形態學方法

基本形態學與通道

以上所有基本形態學方法都是通道方法,因此它們會根據目前的「-channel」設定套用到影像的個別通道。這表示你可以將這些方法套用到彩色影像,只要你不太在意未定義透明區域的「顏色溢出」。例如,讓我們「侵蝕」原始「人物」影像的 Alpha 通道,而不修改顏色通道。

  magick figure.gif -channel A  -morphology Erode Diamond:3 \
          +channel   figure_erode.gif
[IM Output] - [IM Output] ==> [IM Output]
如你所見,它運作良好。如需其他範例,請參閱稀疏顏色作為填充運算子,使用「EdgeIn」方法尋找影像的邊緣像素。還有輪廓或光暈透明度,使用「EdgeOut」方法以特定顏色擴展影像的邊緣。

搜尋特定形狀

Knowledge about an object depends on the manner in which we probe (observe)
it.                    -- Georges Matheron, The Father of Morphology

Using Erode to locate specific shapes from a large correction of shapes. Taken
to extreme this creates Skeletons, see also Thinning Skeletons.

Restoring objects using Open (smoothed result) or Conditional Dilation.

Needs some sort of Connected Component Analysis, (Segmentation) to properly
count objects found within an image.

形狀集合的粒度

透過在一系列尺寸逐漸增加的結構元素影像中使用一系列的「開啟」操作,並測量產生的區域,你可以快速獲得影像中可以找到的此類形狀數量的總和。透過取得該結果的導數(斜率),你可以獲得構成影像的那些形狀的數量和大小的「頻譜」。此圖表是針對某些特定形狀的影像「粒度」。請參閱粒度分析(形態學),維基百科。從一種尺寸到下一種尺寸的差異還可以讓你根據尺寸分離和計算特定元素,並進一步分離包含不同尺寸和形狀元素的區域。結果是一種紋理分割的方法。 演示如何確定形狀集合的數量和大小。但是,這需要一種「計數」方法(將被添加)才能完全實現。 歷史註記...這種用法實際上是 1960 年代巴黎一家礦業公司最初創造形態學方法背後的驅動力。它允許創建者創建一個自動化系統,用於分析礦物樣品顯微照片的顆粒結構,以確定其是否適合開採。也就是說,定位並計算樣品中礦物的尺寸和數量。例如:兩種礦石可能具有相同數量的所需礦物(通常以岩石中的顆粒或晶體的形式存在),但只有具有較大顆粒的礦石才能有效開採,因為它可以讓你更容易地將大型純礦物與周圍的含礦岩石分開。這是一項非常勞動密集型的任務,而形態學使其變得容易得多。

非對稱核心效應(基本方法測試)

讓我們看看當與非對稱核心一起使用時,這些基本方法是如何工作的。例如,在這裡,我將使用者定義的「L」形狀應用於特殊的形態學測試影像(放大以查看個別像素)。

  for method in  erode dilate open close; do
    magick test_morphology.gif \
             -morphology $method  '2x3+1+1: 1,-  1,-  1,1 '  test_$method.gif
  done
[IM Text]
其結果如下...

[IM Text] 侵蝕 會導致核心的任何精確匹配變成匹配點「原點」處的單個白色像素。它還會將任何單個像素「孔」擴展為相同的形狀,但在「原點」周圍「反射」,就好像核心已旋轉 180 度一樣。

[IM Text] 擴張 正如預期的那樣,會產生相同的結果,但適用於影像或核心的「負片」和「反射」形式。單個白色像素會擴展到核心形狀,而任何匹配的「反射」形狀孔都會縮小為單個像素「孔」。
另請注意,測試圖像正負兩半之間的邊界會因應用上述基本形態方法而移動。也就是說,這是意料之中的。這就引出關於這兩種方法的一個特定觀點。要將“侵蝕”方法轉換為“膨脹”方法,反之亦然,您不僅需要在前後反轉圖像,還需要圍繞原點旋轉或翻轉內核。通常可以忽略第二個方面,因為大多數內核都是“對稱的”。它僅在用戶定義的非對稱內核中變得重要。[IM 文字]如前所述,開啟通常不會移除圖像中的任何“孔洞”,但是完全匹配的形狀將保持不變。較大的形狀(例如測試圖像的負半部分)也可能保留,但可能會略有修改。
[IM 文字]閉合與前一個結果完全相反,但其定義方式不需要翻轉內核(因為它已通過其內部定義翻轉),只需對圖像進行反轉。

擊中與錯失 (HMT) 模式匹配

擊中與錯失  ( )

擊中與錯失”形態方法(在電腦科學文獻中也稱為“HMT”)是一種高階形態方法,專門用於在圖像中查找和定位特定模式。它通過查找“原點”周圍“前景”和“背景”像素的特定配置來實現這一點。
從 IM v6.6.9-4 開始,您可以使用任何方法名稱“HitAndMiss”、“Hit_N_Miss”或僅“HMT”及其變體來指定此形態方法。在此版本之前,只能使用“HitAndMiss”方法名稱。
例如,我們可以查找“前景”像素,其右側緊鄰“背景”像素。

  magick man.gif   -morphology Hit-and-Miss '2x1:1,0'  hmt_right.gif
[IM Output] o [IM Output] ==> [IM Output]
如您所見,這個小的 2 元素內核僅匹配圖像右側的像素。也就是說,該方法僅返回與給定模式匹配的特定像素。使用的“內核”或“結構元素”只能包含 3 種類型的元素模式:“1”值表示“前景”,“0”值表示“背景”,以及第三個元素,可以指定為“Nan”或“-”或值“0.5”,表示“我不在乎”或“任何像素”您為“原點”使用的值非常重要,因為它將定義您是否只想“擊中”前景形狀或背景模式。但是,如果您專門將“原點”值設置為“我不在乎”值,則您可以匹配具有正確周圍鄰域的前景和背景像素。例如,如果我使用如下所示的結構元素...

  magick man.gif   -morphology Hit-and-Miss '3x1:1,-,0'  hmt_right2.gif
[IM Output] o [IM Output] ==> [IM Output]
您將獲得位於內部或外部的任何右邊緣像素。因此,您現在正在標記形狀邊界的兩側,並提取 2 個像素寬的邊緣。但是,並非所有像素都與模式匹配,因此並非每個像素都加倍,但總體而言,這就是您得到的。實際上,對“原點”使用“我不在乎”值非常普遍,尤其是在我們稍後查看加粗細化方法時,這些方法將自身限制為僅添加或移除像素。通過“不在乎”,相同的內核定義可以用於任何一種操作,因為操作本身定義了您感興趣的“擊中”類型。
這是另一個示例,但這次我再次將“擊中”限制在形狀內部但形成西北方向的像素。

  magick man.gif   -morphology HMT "3:0,0,- 0,1,1 -,1,-" hmt_nw_corner.gif
[IM Output] o [IM Output] ==> [IM Output]
透過新增「>」旗標,將單一角落擴展成一組旋轉 90 度的角落,我們就可以找到形狀內出現的所有角落。

  magick man.gif  -morphology HMT "3>:0,0,- 0,1,1 -,1,-" hmt_corners.gif
[IM Output]
[IM Output]
如您所見,「擊中與錯過」方法會找出並返回與提供的任何內核樣式相符的所有像素位置。
如果您要檢查上述「-morphology」操作的詳細輸出,您會發現「擊中與錯過」使用「加亮」合成方法來建立與提供的每個樣式內核相符的所有像素的「聯集」。

遺憾的是,「已變更」的像素計算是指所有被每個內核應用程式關閉的像素。換句話說,就是形狀中的像素數量減去每個內核匹配的像素數量。

出於同樣的原因,對自身的結果重複使用擊中與錯過方法通常是沒有用的,因為圖像會發生很大變化,您之後可能最終會找不到任何匹配項。

您可以(正如您所見)使用結果來修改原始圖像,以便生成稍微不同的圖像。
您可以使用一組內核,這些內核對您特別感興趣的內容更有選擇性。例如,假設您對三條線相交的點感興趣。然後,您可以使用專為此目的設計的「線條交匯點」內核集。

  magick lines.gif -morphology HMT LineJunctions hmt_junctions.gif
[IM Output] ==> [IM Output]
如您所見,只有少數位置與該集合中的任何內核相符。但是,結果可能使得很難實際看到匹配位置在原始圖像中的位置。如果您正在處理灰度圖像,則情況尤其糟糕。一種解決方案是使用「擴張」和一些形狀內核(例如「環形」)來擴展匹配項。舉個例子...

  magick lines.gif \( +clone \
             -morphology HMT LineJunctions \
             -morphology Dilate Ring \
             -background red -alpha shape \
          \) -composite              hmt_junctions_rings.gif
[IM Output]
您現在可以清楚地看到這組特定內核找到 3 條或更多條線的交匯點的位置。「線條交匯點」中的每個內核可能只匹配幾個特定位置,因此這種模式匹配可能很慢。儘管如此,它還是非常精確且效果很好。另一個類似的「擊中與錯過」內核集是「線條端點」內核,可用於查找圖像中所有線條的自由端。

  magick lines.gif \( +clone \
             -morphology HMT LineEnds \
             -morphology Dilate Ring \
             -background red -alpha shape \
          \) -composite                  hmt_lineends_rings.gif
[IM Output]
擊中與錯過 - 僅限前景像素 -> 侵蝕擊中與錯過 - 僅限背景 -> 反轉擴張

使用灰度圖像進行擊中與錯過

當「擊中與錯過」方法應用於灰度圖像時,返回的實際值將是最小「前景」值與最大「背景」值之間的差。如果出現負結果(沒有數學運算),則結果將「裁剪為零」,因為負數沒有實際意義。換句話說,它返回匹配像素集中「最小間隔」的值。對於布林形狀,這將是「0.0」(黑色)或「1.0」(白色)。但對於灰度圖像,這相當於匹配像素的「漸變」。例如,它可以用於識別匹配模式中特定前景和背景之間存在的對比度。如果您真的只想獲得灰度圖像中實際與模式匹配的像素的布林值(開/關),則應在命令後添加「-threshold 0」選項。

加粗 (向形狀添加像素)

加粗」方法將在每個匹配位置向原始形狀添加像素。例如,我在這裡查找距離形狀右邊緣兩個像素的背景像素。

  magick man.gif   -morphology Thicken '3x1+2+0:1,0,0'  thick_right.gif
[IM Output] o [IM Output] ==> [IM Output]
如您所見,您最終得到了一條位於形狀原始邊界外的像素線。您可以迭代此「加粗」方法幾次以繼續該序列。

  magick man.gif   -morphology Thicken:4 '3x1+2+0:1,0,0'  thick_right2.gif
[IM Output]
然而,當新增像素時,圖案匹配內核的原點不應該與前景像素匹配,否則你實際上是在已經存在像素的地方新增像素。在上面的集合中,將原點像素設置為背景圖案,這樣只有背景圖案才會真正匹配。另一種方法是始終將原點設置為「無關緊要」元素值。通過這樣做,你將能夠使用相同的內核模式進行「加粗」操作,並且正如你稍後將看到的,也可以使用相同的內核模式進行「細化」操作。所以更好的規則是將原點設置為「無關緊要」。
生成「加粗」操作的另一種方法是生成此內核與特殊「單位」內核的「擊中與不擊中」結果的聯集,以便在結果中包含原始圖像。

例如...

  magick man.gif -define morphology:compose=Lighten \
                  -morphology HitAndMiss 'Unity ; 3x1+2+0:1,0,0' hmt_thicken.gif
[IM Output] ==> [IM Output]
實際上,上述範例中的多內核組合設置是不需要的,因為當用戶未定義時,「擊中與不擊中」方法預設會特別設置此組合設置。


通常,「加粗」用於放大形狀(例如線條),但不會使線條變長。一組稱為「凸包」內核的特殊內核允許你執行此操作。例如...

  magick -size 80x80 xc:black -fill none -stroke white \
          +antialias   -draw 'line 10,20 70,60'     man_line.gif
  magick man_line.gif   -morphology Thicken ConvexHull  thick_line.gif
[IM Output] ==> [IM Output]

加粗 - 八邊形凸包

實際的「凸包」內核實際上是設計用於處理圖像形狀的,它會將形狀擴展為「*八邊形凸包*」。也就是說,它會嘗試填補極值之間的所有間隙,直到產生「八邊形」的物體。

  magick man.gif -morphology Close Diamond \
                  -morphology Thicken:-1 ConvexHull \
                  -morphology Close Diamond       man_hull_full.gif
[IM Output] ==> [IM Output]
有關更多詳細信息以及為何需要兩種「閉合」方法,請參閱「凸包」內核定義。
你可以通過打開詳細輸出設置來觀察正在執行的迭代。但是,這將顯示上述操作非常非常慢。每次「加粗」迭代實際上只會在每次迭代中向形狀添加幾個像素。因此,在完成完整的「凸包」之前,可能需要很多次迭代。在這個特定情況下,圖像需要 80 次「加粗」迭代,使用 8 個內核的「凸包」。這意味著上述操作實際上需要 640 次基本迭代,外加執行兩種「閉合」方法所需的另外 4 次基本迭代。這可能會花費相當長的時間。基本上,使用擊中與不擊中圖案匹配進行迭代可能會非常非常「*慢*」,如果可以找到替代技術,則應改用替代技術。你也可以通過獲取交集(變暗組合)以及凸包的邊緣和原始形狀來找到導致此八邊形形狀創建的原始圖像點。

  magick man_hull_full.gif \
              -morphology EdgeIn Diamond man_convex_edge.gif
  magick man.gif man_convex_edge.gif \
          -compose Darken -composite man_extremities.gif
[IM Output] n [IM Output] ==> [IM Output]
任何適合凸包內部的連接形狀,但同時也包含上述凸包每條邊緣上至少一個像素的形狀,都將生成相同的八邊形凸包。

使用灰度圖像加粗

處理灰度圖像時,「加粗」會將「擊中與不擊中」的前景和背景分離結果*添加*到原點像素。因此,即使「原點」像素不在「背景」集合中,也可以使用此方法使匹配像素更亮。例如,讓我們重複上面的角點查找示例,但使用形狀的 50% 灰色版本。

  magick man.gif   -evaluate multiply 0.5   man_grey.gif
  magick man_grey.gif  -morphology Thicken Corners  thick_corners.gif
[IM Output] ==> [IM Output]
當您使用「加粗」處理HDRI 版本的 Imagemagick 影像時,最好使用「-clamp」或「-auto-level」來處理結果,以防止其超過影像像素值的範圍限制。

細化 ( )   (從形狀中減去像素)

細化」方法與「加粗」相反。此方法不是添加像素,而是從原始影像中減去像素。例如,讓我們移除右側邊緣 4 個像素內的任何像素。

  magick man.gif   -morphology Thinning '5x1+0+0:1,1,1,1,0' thin_right.gif
[IM Output] [IM Output] ==> [IM Output]
為了讓「細化」正常運作,圖案匹配核心應該有一個包含前景像素的原點,否則該方法就沒有匹配的像素可以從形狀中移除。
產生「細化」操作的另一種方法是使用「擊中與錯過」的結果,對原始影像進行相對互補(使用 MinusSrc 合成)。您可以透過使用「單位」核心,將該影像包含在核心清單的開頭(從中「減去」)。

例如...

  magick man.gif -define morphology:compose=MinusSrc \
          -morphology HMT 'Unity ; 5x1+0+0:1,1,1,1,0' hmt_thinning.gif
[IM Output] ==> [IM Output]
這是一種「交集」風格的細化,可以在單一步驟中移除所有核心中的所有指定像素,而不是「迭代」風格,後者會依序從每個核心移除像素。有關更多資訊,請參閱細化風格

線條連通性

未來:4 連通與 8 連通線條請參閱 IM 論壇中的討論,從 8 連通線條到 4 連通線條

細化邊緣偵測器輸出

細化最常見的用途之一是減少邊緣偵測器(例如 Sobel 卷積)的臨界值輸出,使其成為單一像素厚度的線條,同時保留這些線條的完整長度。使用距離梯度影像的範例

細化到骨架

實際上,「細化」影像比「加粗」更常用,因為它用於將形狀簡化為更易於管理的形式,例如骨架。正如稍後將討論的,骨架是指形狀任意兩個(或多個)邊緣之間的像素中心線。骨架非常重要,因為它提供了對非常複雜形狀的良好描述。例如,處理影像以找出迴圈的數量、線段的數量以及它們的排列方式,將會告訴您很多關於您擁有的形狀的資訊。因此,讓我們透過重複「細化」人型形狀的邊緣,直到只剩下中心線,來產生「細化骨架」。

  magick man.gif  -morphology Thinning:-1 Skeleton  man_raw_thinned.gif
[IM Output] ==> [IM Output]
上述內容的詳細報告顯示,經過 18 次迭代,使用了 8 個核心,總共進行了 144 次基本迭代。這實際上比找到它的凸包(上方)要快得多,因為細化核心會在每次迭代中移除整行和整列的像素,而不僅僅是幾個像素。請注意,「骨架」核心集無法擴展孔洞,因此它沒有找到孔洞和外緣之間的中心線。這是此特定骨架細化核心的嚴重缺陷,這是因為所有核心都至少需要背景像素才能進行任何細化匹配。您可以使用多組骨架細化核心來解決此問題。更簡單的解決方案是稍微侵蝕影像,讓核心有一些東西可以處理。我也只會侵蝕和細化「紅色」和「綠色」通道,以便在藍色通道中保留原始形狀。

  magick man.gif -channel RG -morphology Erode Diamond  man_erode.gif
  magick man_erode.gif -channel RG \
          -morphology Thinning:-1 Skeleton +channel  man_skeleton.gif
[IM Output] ==> [IM Output]
您還可以發現,影像中的任何孔洞現在都已擴展,在其周圍產生了更大的連續像素迴圈。
以下是侵蝕孔洞周圍迴圈的特寫。

  magick man_skeleton.gif -crop 22x22+47+29 +repage \
          -scale 120x120    man_skeleton_zoom.gif
[IM Output]
請注意,它並未在孔和邊緣之間產生精確的中心線。此外,由於形狀已被侵蝕,因此線條不會到達原始形狀的邊緣,而是會停在距離一個像素的位置。也就是說,線條的末端已被稍微「修剪」。也就是說,這是「侵蝕」解決方案的缺點。骨架也被限制為八邊形線條,這意味著它缺少很多細節,但在這種情況下,這種簡化可能是一件好事。請參閱下方關於骨架的部分。這是一個傳統的「骨架」核心,如您所見,它會產生「粗」的對角線,以便骨架的所有部分都是「4 連接」或「鑽石連接」的。還有其他變化的「骨架」核心,它們將在產生的「細化骨架」中產生其他變化。 更細、8 連接的骨架 如前所述,這種「傳統」骨架具有粗對角線。但通常這不夠「細」。在某些情況下,您需要的是稍微更細的骨架。也就是說,您需要一個「8 連接」的骨架,而不是「4 連接」的骨架。
一種解決方案是使用不同的骨架生成變體,例如使用「骨架:2」核心生成的變體(可在HIPR2 圖形教程網站上找到)。舉例來說...

  magick man.gif   -channel RG  -morphology Erode Diamond \
          -morphology Thinning:-1 Skeleton:2 +channel  man_skeleton_hipr.gif
[IM Output]
這裡是循環區域的放大圖,顯示生成的骨架是如何通過更細的對角線進行 8 連接的。

  magick man_skeleton_hipr.gif -crop 22x22+47+29 +repage \
          -scale 120x120    man_skeleton_hipr_zoom.gif
[IM Output]
然而,我發現這種骨架不如「傳統」骨架準確。基本上,在測試案例中,我發現對角線在錯誤的一側被「細化」了。基本上,因為被移除的對角線一側完全由核心集中「角」細化核心的順序控制,而不是由形狀的性質決定的。
另一種方法是採用「傳統」骨架,並將其細化,以便始終將對角線在其端點定義的對角線「外側」細化。特殊的「對角線」細化核心旨在執行此操作,之後使用「」核心進行「完成」。因此,讓我們進一步細化之前的「傳統」骨架。

  magick man_skeleton.gif -channel RG \
          -morphology Thinning:-1 Diagonals \
          -morphology Thinning Corners   man_thin_skeleton.gif
[IM Output] ==> [IM Output]
這種細化傳統 4 連接骨架的技術比直接使用「骨架:2」變體稍微慢一些。額外的細化需要 8 個核心的 8 次細化迭代,或 64 次原始迭代。或者,您可以僅使用「」核心,儘管這只會生成「HIPR」變體,並且只是「隨機」選擇對角線的哪一側被細化。但是,它只需要對所有 4 個核心進行 1 次遍歷,因此比使用「對角線」快得多。無論如何,通過從「傳統」的 4 連接骨架開始,您可以非常輕鬆地生成一個 8 連接的版本(某種類型)。

骨架資訊

當您擁有一個骨架(甚至可能是 4 連接和 8 連接的版本)時,下一步通常是找出有關該骨架的更多信息。例如,存在多少「線條的自由端」、「線條交匯處」和「線條迴路」。線條端點的數量 這裡,我在我們之前生成的骨架上使用命中和未命中搜索來查找「線條端點」(從「紅色」通道中提取)。然後我將這些線條端點膨脹並為它們著色,然後再與原始骨架合併,以使其位置清晰可見。

  magick man_skeleton.gif -channel R -separate +channel \
          -morphology HMT LineEnds man_ends.gif
  magick man_ends.gif -morphology Dilate Ring -background Red -alpha Shape \
          man_skeleton.gif +swap -composite man_ends_marked.gif
[IM Output] ==> [IM Output] ==> [IM Output]
請注意,所有線條彼此相連,或者未找到像素迴路。 僅指示了自由線的端點。 如果您進行像素計數(使用 直方圖輸出),您會看到此骨架生成了 12 個線端點。 線交點的數量您可以使用「LineJunctions」內核和8 連接骨架來粗略計算圖像中線交點的數量,最好是從用於計算線端的原始骨架中細化而來的。 不要混合兩種不同的骨架生成變體。

  magick man_thin_skeleton.gif -channel R -separate +channel \
            -morphology HMT LineJunctions  man_junctions.gif
  magick man_junctions.gif -morphology Dilate Ring \
          -background Red -alpha Shape \
            man_thin_skeleton.gif +swap -composite man_junctions_marked.gif
[IM Output] ==> [IM Output] ==> [IM Output]
如果您嘗試使用傳統的 4 連接骨架直接嘗試此內核,您將獲得一些「T」形連接的多個匹配項,從而使計數非常不準確。 正如您所見,結果是 12 個線交點,對於此特定形狀是正確的。 然而,對於某些連接,「LineJunctions」內核是不準確的。 例如,4 線對角線「X」形連接只會產生 1 個匹配項,而正交「+」形連接會產生 4 個匹配項。 這兩個特殊連接都應該產生 2 個匹配項,以保持線交點計數正確。 因此,要獲得準確的計數,您需要為每個「X」形連接添加 1 個值,並為每個「+」形連接減去 2 個計數。
對於沒有迴路的骨架,連接點的數量應該比線端點的數量少 2。 但是,如果線端點的數量等於線交點的數量,則表示骨架中有一個或多個迴路。 現在這個骨架有 12 個線端點和 12 個連接點。 所以它在圖像中的某個地方包含至少一個連續的像素迴路。 迴路數未來:連接對象標籤

修剪線條

所以你知道這張圖片至少有一個迴路。 假設您想將形狀簡化為僅包含那些迴路。 解決方案是重複「修剪」所有線端點,直到將它們全部刪除。 對於像這樣的 4 連接骨架,您甚至可以使用一組較小的「LineEnds」內核來使處理速度提高大約兩倍。

  magick man_skeleton.gif -channel G \
          -morphology Thinning:-1 'LineEnds:1>' man_loop.gif
[IM Output] ==> [IM Output]
關於此的 詳細 報告表明,這需要使用 4 個內核進行 75 次迭代,從而產生 300 次原始積分以「修剪」圖像中所有具有自由端的線。 也就是說,運算量大約是用於查找骨架的兩倍,這表明此操作的密集程度要高得多。 使用全套「LineEnds」內核(8 個內核)也需要 75 次迭代,但內核數量是其兩倍,因此需要 600 次原始迭代。

快速修剪線條

Fast Complete pruning technique..

  1/  Find line ends, and line junctions.
  2/  Delete the line junctions to completely disconnect all line segments.
  3/  Flood fill, or use contitional dilate to remove 'line end' segments.
  4/  Restore line junctions.
  5/  use that as a map on original image to restore 'loops'.

我們已經涵蓋了第一步...導致...

  magick man_skeleton.gif -channel R -separate +channel \
          -morphology HMT LineEnds man_ends.gif
[IM Output]
要斷開(或分離)所有線段,您可以使用「LineJunctions」內核。 但是,默認內核集不會完全斷開「T」形連接(僅定位它們)。
要正確斷開所有線段,您還需要將正交「T」內核添加到內核集中,並且最好也包含「+」形連接。 例如。

  magick man_skeleton.gif -channel R -separate +channel \
      -morphology HMT 'LineJunctions;LineJunctions:3>;LineJunctions:5' \
      man_disconnect.gif
[IM Output]
使用這些匹配項進行細化實際上會斷開線段,但是您必須一步完成所有這些操作(請參閱 細化樣式),否則它將無法正常工作。

  magick man_skeleton.gif -channel R -separate +channel \
      -define morphology:compose=Darken \
      -morphology Thinning 'LineJunctions;LineJunctions:3>;LineJunctions:5' \
      man_line_segments.gif
[IM Output]
這是顯示斷開線段的“迴路”的放大圖。

  magick man_line_segments.gif -crop 22x22+47+29 +repage \
          -scale 120x120    man_line_segments_zoom.gif
[IM Output]
在這個階段,我們可以移除任何包含先前發現的“線條末端”匹配的線段。這可以通過從那些“種子”點進行“泛洪填充”來刪除它們。然而,這僅適用於 4 連接骨架,這是泛洪填充所假設的。示例或者,我們可以使用條件膨脹同時找到所有點,並將它們移除。示例 - 當條件膨脹或侵蝕可用時。如果您現在恢復線條交匯處,執行一次修剪,並移除任何剩餘的單個像素,您現在將快速移除所有線段。是的,這看起來步驟很多,但相信我,它仍然比必須“修剪線條末端” 300 次才能獲得相同的結果快得多。

細化樣式 - 順序或同時

如果您要對線段的末端進行一次“修剪”,並將其與原始圖像進行比較,您會發現線段通常會被修剪 2 到 4 次,具體取決於線條的確切形狀和方向。例如(結果圖像放大)是默認的線條末端細化

  magick -size 10x10 xc:black -fill white \
          +antialias  -draw 'line 1,7 8,3' line.gif
  magick line.gif -channel GB \
          -morphology Thinning LineEnds  line_seqential.gif
[IM Output] ==> [IM Output]
這是因為,默認情況下,每個“細化”內核都按順序應用於先前內核的結果。也就是說,它會在將下一個內核應用於該結果之前移除一個內核選擇的所有像素,這可能會(並且確實會)從線條的同一端選擇更多像素。換句話說,默認情況下,它會在通過提供的所有內核進行一次完整的“迭代”時多次細化線條的末端。這意味著您不能依靠詳細輸出通過計算此運算符單次迭代移除的像素數來準確了解所有線條的長度。但是,您可以修改“細化”的工作方式,使其僅移除單次“擊中和未擊中”迭代通過所有內核會找到的像素集。換句話說,在交互開始時將所有內核應用於同一圖像,合併它們,然後僅移除那些像素,一次僅針對所有內核。也就是說,同時移除所有 HMT 選擇的像素。基本上,您將多內核組合設置設置為使用“變暗”組合方法,這將完全做到這一點。具體來說,合併所有選定像素以單次移除選定像素。例如...

  magick line.gif -channel GB -define morphology:compose=darken \
          -morphology Thinning LineEnds  line_simultaneous.gif
[IM Output]
這裡發生的事情是,模式匹配內核的每個內核都只會應用於原始圖像。然後將收集與原始圖像匹配的任何像素。也就是說,我們只會通過使用“變暗”組合來移除所有內核針對原始圖像的結果的“交集”。但是,對於通過所有內核的任何一次迭代,移除操作都是一步完成的。結果是,即使多個內核可以匹配該線條末端,線條末端也只會被匹配一次。因此,只會移除末端的單個像素,而不是通過不同的內核移除 2 個或更多像素。總之,添加“變暗多內核組合設置將確保“細化”方法執行“同時細化”(所有內核同時進行),而不是“順序細化”(一次一個內核 - 默認)。
但是,雖然這會使線條末端的修剪表現得更好,但它會使其變慢,並且可以改變細化的總體結果。以通過同時細化左右邊緣來“細化”一些框的情況為例。

  magick -size 10x10 xc:black -fill white -draw 'rectangle 4,1 5,7' rect.gif
  magick rect.gif -channel GB -define morphology:compose=darken \
          -morphology Thinning Edges  rect_simultaneous.gif
[IM Output] ==> [IM Output]
「同步細化」實際上完全刪除了中心矩形!發生這種情況的原因是形狀被細化到兩個像素的厚度,然後「厚」中心矩形的兩側都匹配模式,並且兩側都被「細化」。如果您在細化骨架時執行此操作,也會發生同樣的事情。另一方面,默認的「順序細化」產生了...

  magick rect.gif -channel GB \
          -morphology Thinning Edges rect_seqential.gif
[IM Output]
如您所見,它保留了一個像素(在右側)作為骨架中心線。這是因為一組內核首先將「粗」中心線的一側細化,但後面的內核與這條「較細」的線不匹配,因此沒有將其刪除。本質上,在某些情況下,「順序細化」(默認)比特殊的「同步細化」更好,反之亦然。

模式匹配核心

如前所述,「模式匹配」或「擊中與不擊中」內核可以包含 3 種類型的元素:前景、背景和「無關緊要」。值「1.0」或(白色)匹配前景像素。值「0.0」或(黑色)匹配背景像素。您可以使用值「0.5」或特殊值「Nan」或「-」來表示不屬於鄰域的像素元素,因此您「無關緊要」。「擊中與不擊中」只會匹配最小(最小)前景像素大於最大(最大)背景像素的位置。然後它將返回這兩個值之間的差值,或零。 [IM Output]

峰值

峰值」內核是先前顯示的「環形」內核的擴展。兩個半徑參數將生成一個背景像素的「環」,圍繞中心「原點」處的單個前景像素。以下是一些更有用的「峰值」內核示例...
[IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output]
上述內核可用於在較暗像素的海洋中明確定位單個像素的「峰值」值,或找到完全適合較大環內的任何小形狀。它們對於提高相關模式匹配搜索的對比度特別有用。

邊緣


邊緣」內核集將匹配形狀平坦邊緣上的任何像素。它不匹配銳角九十度角上的像素,儘管它會匹配八邊形形狀上的角像素。
[IM Output]
如您所見,所有 90 度旋轉都被生成,但它們以通常產生更好結果的「正反」鏡像順序排序。通常,此內核用作圖像「細化」內核的一種類型,但是,就目前而言,它無法細化對角線邊緣,或者生成適當的圖像骨架。例如...

  magick man.gif -channel RG \
          -morphology Thinning:-1 Edges   thin_edges.gif
[IM Output] ==> [IM Output]
請參閱下面的「骨架」內核。

」內核定位圖像邊緣周圍的任何對角線角像素。有關其使用示例,請參閱上面的「擊中與不擊中」。
[IM Output]
例如,在這裡,我使用它來嘗試將所有對角線邊緣細化...

  magick man.gif -channel RG \
          -morphology Thinning:-1 Corners  thin_corners.gif
它可以與「邊緣」內核組合以產生一種骨架細化方法。有關此示例,請參閱下面的「骨架」內核。
[IM Output]

對角線

對角線」內核是簡單地使用「」內核將 4 連接對角線細化為 8 連接對角線的替代方法。這可用於通過從角向中心移除外部像素集直到完成來細化 4 連接線。
[IM Output]
請注意,結果應該使用「Corners」內核來完成,以定位和細化 90 度角。請參閱更細的骨架以獲取使用範例。 對角線子類型透過提供「type[,angle]」參數給內核,您可以選擇用於組成上述內核集的特定子類型。
[IM Output] [IM Output]
這將允許您指定自己特定的內核集,以完全按照您想要的方式細化對角線。例如,您可以分別細化四種類型的對角線(使用具有相同「angle」值的上述兩個內核)。透過這樣做,您可以對每種類型的對角線進行一次迭代縮減,一旦所有這些特定對角線都被細化後就中止,從而減少執行的「原始形態步驟」的總數。需要範例按照給定的方式,預設內核集將簡單地嘗試同時重複地細化所有對角線,直到它們都被細化。這意味著將應用所有內核,直到所有對角線都被細化,而不僅僅是需要細化的對角線。這意味著它會執行許多不再需要的「原始形態步驟」,並且大多數內核在每個循環中都不會對圖像進行任何更改。需要完整範例請記住,四個對角線中的每一個都應該使用兩對內核(針對每個特定角度)來執行,以便每個特定對角線的兩端一起細化,例如當對角線是「弧線」的一部分時。在 IM 論壇中有一個關於這種類型的細化/增厚操作的相關討論,從 8 連接線到 4 連接線

線條端點

如上面的修剪線條端點所示,「LineEnds」內核集旨在定位線條的端點。更具體地說,它會找到尖銳點的端點。
[IM Output]
如您所見,它只會匹配至少具有兩個像素的線條,匹配的像素被背景像素「覆蓋」或「包圍」。例如,在這裡我們使用「擊中與錯過」來查找所有線條端點。

  magick lines.gif -morphology HMT LineEnds  hmt_lineends.gif
[IM Output] ==> [IM Output] ==> [IM Output]
是的,這張圖片中有很多線條端點。但您應該注意,以某種「迴圈」結束的線條不會產生匹配。請注意,如果您使用「迭代細化」樣式(預設)使用此內核「細化」圖像,則連續的內核可能會多次匹配線條的相同端點,從而在整個「細化」方法的單次迭代中多次縮短線條。有關更多詳細信息,請參閱細化 - 序列與同步 線條端點子類型您也可以為此內核提供「type[,angle]」參數,這將返回用於生成上述「LineEnds」內核集的單個內核定義之一。
[IM Output] [IM Output] [IM Output] [IM Output]
然後可以根據需要將這些內核展開為旋轉內核列表,或旋轉到特定的「angle」。預設的「LineEnds」集實際上使用內核定義。
LineEnds:1> ; LineEnds:2>
LineEnds:3」是對角線「LineEnds:2」的正交等效項,它只會在遠離任何對角線拐角或交匯處找到線條端點。「LineEnds:4」是一個傳統的線條端點內核,它以循環方式旋轉以產生 8 個內核(例如「LineEnds:4@」)。但是,它將無法定位連接到正交「T」形交匯處的線條的最後一個像素。但是,如上所述,預設的「LineEnds」集確實使用相同數量的內核找到了「T」形交匯處的最後一個像素。

線條交匯處

LineEnds」用於找出線條群組的端點,而「LineJunctions」則會找出由 3 條或更多條線條形成的交點。
[IM Output]
例如,我們在這裡使用「Hit-And-Miss」找出所有線條交點。

  magick lines.gif -morphology HMT LineJunctions hmt_junctions.gif
[IM Output] ==> [IM Output] ==> [IM Output]
LineJunctions」核心通常有兩種用途。
  • 計算影像中的線條交點數量,進而計算骨架中的線段數量。
  • 斷開所有線段之間的連接。
但請注意,在上圖的「T」形和「+」形交點處,「Y」形交點核心匹配的點距離實際交點有一個像素的距離。因此,交點計數可能與預期不完全一致,尤其是在「+」形交點處,找到了四個匹配項,而交點計數只需要兩個。建議謹慎使用。有關這兩個方面的更多詳細資訊,請參閱骨架資訊快速線條修剪。實際上,該核心僅將前景像素定義為前景像素,因此它可以簡單地作為「Erode」方法應用,而不是作為「Hit-and-Miss」方法應用。線條交點子類型該核心還允許透過指定「type[,angle]」參數來存取各種子類型。這可以用於搜尋特定類型的線條交點。
[IM Output] [IM Output] [IM Output] [IM Output] [IM Output]
核心「LineJunctions:2」也可以使用「LineJunctions:3,45」指定,同樣地,「LineJunctions:5」和「LineJunctions:4,45」是等效的。預設的「LineJunctions」核心集僅以下列方式使用前兩個交點定義(「Y」形和對角線「T」形交點)...
LineJunctions:1@ ; LineJunctions:2>
這適用於 8 連接線條交點。如 IM 論壇「LineJunctions 使用的核心」中所述,如果您只想測試 4 連接線條交點,則需要尋找正交「T」形交點和「+」形交點。
LineJunctions:3> ; LineJunctions:5
然而,由於「T」形核心也會命中「+」形,因此您可以將上述內容縮減為...
LineJunctions:3>
如果需要確定線段計數,可以使用僅針對 4 路「+」形交點的單獨影像測試將其與 3 路「T」形交點分開。

脊線

Ridges」核心用於定位脊線和像素細線,例如距離梯度影像。這些核心是實驗性的,可能會有所變更。預設值旨在定位單個像素厚的脊線。
[IM Output]
Ridges:2一種特殊的擴展子類型,旨在尋找兩個像素厚的脊線。其複雜性是由於需要定位和標記這種傾斜線及其鏡像。
[IM Output]
這組核心非常重要,因為「形態骨架」實際上由 1 個像素和 2 個像素厚的線條組成。

凸包

ConvexHull」核心集旨在加厚形狀,以產生形狀的「八邊形凸包」。也就是說,可以包含整個形狀的最小八邊形形狀。
[IM Output]
有兩組旋轉 90 度的核心,一組是另一組的鏡像。由於原點實際上是一個「背景」元素,因此它實際上只能用作「Thicken」模式核心。但是,對於包含水平或垂直「狹縫」的影像(例如「人」形中的狹縫),核心將會失敗。

  magick man.gif -channel R \
          -morphology Thicken:-1 ConvexHull  man_hull.gif
[IM Output] ==> [IM Output]
解決方案是在使用「Close」之前先「ConvexHull」關閉這些間隙(以及中心孔)。

  magick man.gif -morphology Close Diamond \
                  -morphology Thicken:-1 ConvexHull \
                  -morphology Close Diamond       man_hull_full.gif
[IM Output]
請注意,在上面我還重複了在使用「ConvexHull」之後的「Close」。原因是圖像中的任何大「孔」也會通過「Thicken」縮小到單個像素或正交「間隙」。重複「Close」會刪除這些孔,而不會影響最終形狀。
這是另一個範例,其中原始形狀(白色)使用凸包加厚(紅色)進行了擴展。

  magick circles.gif -channel R \
          -morphology Thicken:-1 ConvexHull  circles_hull.gif
[IM Output]
如您所見,結果是一個八邊形,而中心孔被縮小為一個兩像素的間隙,準備好關閉。

骨架

通過細化特定形狀來生成「骨架」並非易事。即使使用相同的內核集,重新排序內核也可以在最終「骨架」上產生不同的變化。因此,我沒有僅實現一個「Skeleton」內核集,而是實現了許多內核集,可以通過給出「類型」參數編號來選擇它們。

骨架:1

第一個也是預設的集合「Skeleton:1」是一種傳統的細化內核,與最初使用的內核相同。這基本上與上面的「Edges」內核完全相同,但以 45 度增量循環旋轉。
[IM Output]

  magick man.gif -channel RG \
          -morphology Thinning:-1 Skeleton   thin_skeleton1.gif
[IM Output]
結果是一個合理的形狀「細化骨架」,儘管對角線在一側往往會保持一點粗。基本上,生成的骨架是 4 連接的,這將允許您使用快速修剪技術。另請注意,此內核集無法正確擴展圖像中的單個像素孔。換句話說,該孔周圍的骨架甚至不靠近孔與圖像其餘部分之間的中心線。有關更多詳細信息,請參閱細化到骨架

骨架:2

Skeleton:2」變體與傳統的「Skeleton:1」版本幾乎完全相同。它是在HIPR2 圖像處理資源文檔中找到的。
[IM Output]

  magick man.gif -channel RG \
          -morphology Thinning:-1 Skeleton:2   thin_skeleton2.gif
[IM Output]
如果將此與之前的集合進行比較,您會注意到角落的內部像素已被移除。然後,這將允許細化操作從對角線中移除額外的加厚。然而,這種對角線細化是不對稱的,並且高度依賴於圖像的形狀以及應用內核的順序。 Skeleton:2」變體與僅使用組合的「Edges;Corners」內核列表非常相關。
[IM Output]

  magick man.gif -channel RG \
          -morphology Thinning:-1 'Edges;Corners' thin_edge-corner.gif
[IM Output]
這與「Skeleton:2」使用的唯一區別是列表中內核的順序。請注意,即使使用了相同的內核集,生成的骨架也有所不同。這表明通過細化生成骨架實際上相當脆弱,因為僅僅是簡單的順序更改就會在連接的骨架中產生不同的結果。

骨架:3

Skeleton:3」是在 Dan S. Bloomberg 於 1991 年發表的研究論文「連接保持形態圖像變換」中對使用細化內核(請參閱下面的ThinSE 內核)進行正式研究時開發的。他開發了許多這樣的骨架,並將研究結果製成表格。以下是 er 能夠想出的最好的方法,它將生成一個 4 連接的骨架。然而,與之前的骨架不同,這需要使用 3 個旋轉內核(總共 12 個)。
[IM Output]

  magick man.gif -channel RG \
          -morphology Thinning:-1 Skeleton:3   thin_skeleton3.gif
[IM Output]
需要注意的是,第一組旋轉內核僅包含一個背景像素。這意味著該骨架能夠打開「人」形狀中存在的單個像素孔,並生成以中心線為導向的骨架。它不會生成太多分支,產生乾淨平滑的線條,並且還會完全變薄。總而言之,這是更好的骨架細化內核之一。

ThinSE

同一篇研究論文,由 Dan S. Bloomberg 所著的「保持連通性的形態學影像轉換」,實際上是從基本原理出發,開發了一整套最小化的 3x3「細化結構元素」,這些元素都旨在保留 4 連通線或 8 連通線。「ThinSE:{type}」核心集是所有這些結構元素的列表,並根據連通性和保留強度進行分組排序。「{type}」是一個基於研究論文中使用的上標(連通性)和下標元素編號的數字。因此,核心「ThinSE:41」是保留 4 連通線元素中的第一個。您也可以在給定的核心定義中添加旋轉角度,或生成一組旋轉或鏡像旋轉的標誌。
[IM Output] [IM Output]
[IM Output] [IM Output]
[IM Output] [IM Output]
最後一個「通用細化核心」,「ThinSE:482」,您可能會認出它與用於定義邊緣檢測核心集合的相同核心。這個通用核心實際上是所有其他上述細化核心發展的核心核心。它是集合的默認核心。請注意,兩個通用核心「ThinSE:481」和「ThinSE:482」是唯一旋轉相關的核心。也就是說,「ThinSE:481x45」等同於「ThinSE:482」。許多其他內建的 HMT 核心集實際上是根據這些核心內部定義的。例如,核心集「ThinSE:41 ; ThinSE:42 ; ThinSE:43」及其旋轉擴展將產生用於創建「Skeleton:3」集的 12 個核心。該骨架在論文中被列為產生良好細化骨架的最佳核心集。其他生成骨架的細化核心也使用上述核心定義。
但請注意,某些核心,例如「ThinSE:44」,雖然旨在保留「連通性」,但實際上並未保留線條端點,因此會導致骨架被修剪到單個點或一組連接環。所有核心都沒有定義中心原點值,這意味著您可以將這些「細化核心」不僅用於「細化形狀」,還可以通過「加粗形狀」來生成 SKIZ(影響區域)。如果您仔細觀察,您可能會注意到每個 4 連通核心實際上也以負數和 180 度旋轉的形式出現在 8 連通集中,反之亦然。例如,「ThinSE:41」和「ThinSE:84」是彼此的負旋轉。原因是 4 連通性和 8 連通性通過細化和加粗形態學方法(使用負片圖像)的對偶性密切相關。從本質上講,保留 4 連通性的「細化核心」用於加粗圖像時,將導致形狀周圍出現 8 連通的背景骨架(未修剪的 SKIZ),反之亦然。因此,通過使用負數形式(因此交換加粗和細化方法),您可以為同一操作生成其他形式的連通性。

距離梯度形態學

Distance」形態學方法是眾多特殊方法中第一個可行的。它的作用是使用一個特殊的內核來測量每個前景像素到形狀「邊緣」的距離。更具體地說,它測量像素到「零」或「黑色」顏色值的距離。然而,它只適用於純二進制(黑底白字)形狀,儘管稍後你會看到你可以修改抗鋸齒形狀以使用距離方法。而且只能使用特別設計的距離內核。距離內核被應用到圖像上,以便為每個像素分配最小的像素值加上該距離的內核值。這將同時應用於整個圖像,使用一種不需要多次迭代的算法,正如我們在之前的形態學方法中看到的那樣。因此,它的速度與單個原始形態學操作一樣快,與細化骨架形態學方法相比,速度快得驚人。由於它是應用於整個圖像的,因此不需要「迭代」參數,因為重複(迭代)相同的內核操作不會導致結果的進一步變化。
在 IM v6.6.9-4 之前,需要一個「-1」迭代計數,因為內核的應用方式類似於普通的侵蝕。現在不再需要這樣做了,任何給定的「迭代」參數(零(無操作)除外)現在都將被忽略。
以下是在我們的「人」形狀上使用「Distance」方法的示例。

  magick man.gif -threshold 50% \
          -morphology Distance Euclidean:4 \
          +depth  distance.png
[IM Output] ==> [IM Output]
這真是太令人興奮了,不對!問題是最終圖像的顏色非常暗。但如果你有一台好的顯示器,並且可以近距離觀察,你可能會在「人」所在的位置看到一個非常暗的「幽靈」狀的形狀。發生的事情是,至少對於這個小圖像來說,所有像素都「靠近」邊緣,因此沒有得到一個非常大的「距離」值。
對於任何使用「Distance」方法的情況,都建議使用 PNG 圖像。這是因為與 GIF 相比,它可以提供更大的輸出值「深度」,而且不會像 JPEG 那樣有任何顏色損失。

這也是為什麼使用深度設定+depth」來確保輸出被重置為 16 位深度(對於我的 Q16 版本的 IM)的原因,即使我讀入的是 8 位的 GIF 源圖像。

對於使用 Q8 版本 IM 的用戶,我建議您閱讀距離內核(如下)中的「縮放」距離內核選項,以調整使用的「縮放值」(請參閱下面的下一節)。不建議將 Q8 版本的 IM 與非整數距離內核(如這個歐幾里得距離內核)一起使用,儘管會產生不太準確的結果。

有關這兩個方面的更好理解,請參閱 IM 示例部分中的品質和深度

默認情況下,內置的距離內核將為每個像素應用「100 × {像素距離}」的顏色值。如果像素比這個值亮,則將其設置為該值,以便分配從像素到任何邊緣的最短距離。結果是,沿著形狀邊緣的像素將被分配比背景顏色多 100 個單位的顏色值。下一個更遠的像素將被賦予 100 個單位的值。將分配多少個單位由所使用的距離內核決定。因此,讓我們看看上面圖像中設置的最大顏色值。

  magick identify -verbose distance.png | grep max:
[IM Text]
也就是說,結果圖像中的最大顏色值是「1616」,這使得圖像中最「亮」的像素成為一個非常暗的 2.5% 灰色,它到最近邊緣的距離是 16.16 個像素。換句話說,我們看到的是一個非常暗,但並不是完全黑色的圖像。
讓我們使用數學上的「-auto-level」來調整得到的顏色值,使最亮或距離邊緣最遠的像素設置為白色。通過這種方式,我們可以實際看到生成的「距離梯度」的全部效果。

  magick distance.png -auto-level  distance_man.gif
因為我們不再關心為此圖像生成的精確「距離」值,而只關心距離的可見效果,所以現在可以使用 GIF 圖像文件格式保存和顯示圖像。
[IM Output]
這就是「Distance」(距離)方法的作用。根據使用的特定距離內核,在給定形狀上生成漸變,定義每個像素到最近邊緣的距離。
讓生成的「距離」圖像更亮的另一種方法是實際使用更大的距離內核「*比例*」值,例如 3000 單位的值(Q8 用戶可能可以使用 20 的值)。

  magick man.gif -threshold 50% +depth \
          -morphology Distance Euclidean:4,3000     distance_scaled.gif
[IM Output]
請注意,距離漸變並沒有從黑色覆蓋到白色,而是在某個灰度值達到峰值。由於我們已經知道峰值的「距離」,因此可以計算出最大峰值為16.16 * 3000 => 48480,約為 74% 的灰色。您也可以使用百分比縮放因子,例如,對每個像素到邊緣的距離使用 8% 的顏色範圍值。

  magick man.gif -threshold 50% +depth \
          -morphology Distance Euclidean:4,8%    distance_scale_percent.gif
[IM Output]
如您所見,這次我們在達到最大距離之前就達到了最大值限制。您可以計算出距離漸變可以覆蓋的最大距離為(最大範圍內的 100%)/(每個像素 8%)=> 12.5 像素距離。當然,如果您使用的是ImageMagick 的 HDRI 版本,則完整的距離值將保留在內存中,至少在您限制其值或將其保存為非浮點圖像文件格式之前。您也可以使用特殊的距離縮放標誌!」直接指定您感興趣的最大像素距離。
因為我們已經知道我們的形狀到邊緣的最大距離為 16.16,所以至少需要 18 個像素的限制。

  magick man.gif -threshold 50% +depth \
          -morphology Distance Euclidean:4,'18!'   distance_range.gif
[IM Output]
!」標誌將縮放距離,以便在達到顏色範圍限制之前給出「n」個灰度值。因此,值為 1 時只會對與圖像邊緣直接相鄰的像素進行「羽化」(或變為灰色)。如您所見,所有縮放方法在很大程度上都取決於您執行「Distance」(距離)方法的形狀的實際大小。如果形狀太小,則距離會非常暗,並且可能無法滿足您的需求。如果形狀太大,則距離可能會被 ImageMagick 的編譯時質量的最大允許顏色值「裁剪」。有關內核中「*比例*」因子的更多詳細信息,請參閱下面的距離內核部分。我想對這些示例中使用的人形「形狀」做最後一點說明。該形狀包含一個單像素「孔」,該「孔」在其周圍形成了一種「漸變井」。這對生成的「距離漸變」圖像的上半部分產生了非常強烈的影響。解決此問題的一種方法是使用「Close」(閉合)刪除該孔,以使形狀「乾淨且平滑」。例如...

  magick man.gif -morphology Close Diamond  man_clean.gif
  magick man_clean.gif   -morphology Distance Euclidean \
                                    -auto-level   distance_clean.gif
[IM Output] ==> [IM Output] ==> [IM Output]
當然,這也會產生「閉合」形狀「腿」之間間隙的效果,這會影響最終結果的下半部分。另一種解決方案是使用Floodfill(填充)方法提取圖像外部,並將其變換為新的蒙版。結果是所有孔都被閉合,但圖像的外部邊界得以保留。例如..

  magick man.gif -gamma 0,1,1 -bordercolor black -border 1x1 \
          -fill red -floodfill +0+0 black -shave 1x1 \
          -channel R -separate +channel -negate  man_floodfill.gif
  magick man_floodfill.gif    -morphology Distance Euclidean \
                                    -auto-level   distance_floodfill.gif
[IM Output] ==> [IM Output] ==> [IM Output]

距離內核

給定的內核非常特殊,因為它用於定義要分配給每個像素的實際距離測量值。例如,以下是內置「距離內核」之一的Show Kernel(顯示內核)輸出。

  magick xc: -define morphology:showkernel=1 -precision 3 \
          -morphology Distance:0 Chebyshev:3     null:
[IM Text]
需要注意的是「原點」(此例中為內核的確切中心)的值為零。這非常重要。該「原點」周圍的值較大,並隨與「原點」距離的增加而線性增加。如果未以這種特定方式定義內核,則可能會導致意外和奇怪的效果。內核中給出的值是將添加到已「知」距離的實際「值」,如果該值小於已分配的值,則將其分配給像素。結果是「白色」像素越靠近邊緣就越暗,而離邊緣越遠則線性越亮(添加到先前分配的值)。所有提供的內建距離內核都可以採用兩個可選的k_arguments...

     {distance_kernel}[:{radius}[,{scale}[%][!]]]
第一個參數與所有形狀內核一樣,是內核的半徑,它定義了生成的內核的大小。默認情況下,內建距離內核的半徑設置為 '1',這會產生一個非常小的 3x3 內核,在大多數情況下都能很好地工作。第二個參數 'scale' 設置用於表示一個像素長度的距離的距離比例。如上例所示,它默認為 '100'。也就是說,最終像素值或灰度值為 '300' 的像素應該距離邊緣正好「3 個像素」。距離縮放如前所述,使用較大的 'scale' 值是為了讓您可以使用「分數」距離進行更「精確」的距離測量。但是,只有提供的 '歐幾里得' 距離內核使用這種「分數」值。在前面的示例中,分配的「最大距離」值為 '1700',這將超出 Q8 版本 ImageMagick 的範圍(請參閱品質,記憶體位元深度)。IM Q8 僅允許顏色值達到最大值 255(2Q => 28 => 256 種顏色值,範圍從 0 到 255)。因此,使用較小的scale,例如 '10' 或 '20',對於使用 IM Q8 編譯時變體的用戶來說效果會更好。儘管在與 '歐幾里得' 內核一起使用時,它的準確性要低得多。因此,建議使用 Q8 版本 IM 的用戶限制自己使用其他「整數」距離內核,比例因子為 '1'。您也可以通過在縮放因子中包含 '%' 來將距離縮放指定為完整顏色範圍的百分比。這意味著,如果您使用顏色值範圍的 '12.5%' 的比例,那麼您將能夠在距離超出您正在使用的 IM 版本的顏色範圍限制之前獲得大約 8 個像素的距離度量。或者,您可以改用 '!',這表示比例是顏色範圍的除數。也就是說,如果您指定比例為 '20!',則距離縮放將設置為距離圖像邊緣 20 個像素處達到顏色範圍限制。但是,即使使用這些「特殊縮放標誌」,在 Q8 版本的 IM 中,您仍然會遇到嚴重的範圍精度限制。它只是沒有許多距離操作所需的數據值範圍。當然,任何scale(包括完整的浮點數)都可以準確地用於HDRI版本的 IM,因為生成的顏色值也存儲為浮點值。在嘗試將此類圖像保存為非浮點圖像文件格式之前,請務必相應地重新調整顏色範圍。
程式提供了許多種不同的距離測量核心,其中一種核心可以用兩種不同的方式使用。每個核心都提供不同的「距離度量」,用於指定像素到邊緣的距離,基本上定義了什麼是「最近的邊緣」。

切比雪夫(西洋棋盤)距離核心

Chebyshev」距離核心是最簡單的,它指定「原點」周圍的所有像素到其鄰居的距離都只有 1 個距離單位。也就是說,所有 8 個鄰居彼此都是「相鄰」的。因此,不僅僅是緊鄰的四個鄰居距離為 1 個單位,對角線上的鄰居也恰好距離 1 個單位。這通常被比作西洋棋盤上「國王」或「皇后」棋子移動的格數,因此通常也被稱為「西洋棋盤」距離度量。但請注意,距離核心預設使用 100 個距離單位作為每個像素距離的「比例」因子。因此,距離每遠離原點一步就增加 100 個單位。這也是上面範例中使用的核心。以下是它產生的實際核心...

  magick xc: -define morphology:showkernel=1  -precision 4 \
          -morphology Distance:0 Chebyshev       null:
[IM Text]
這個核心的名稱來自俄羅斯數學家 Pafnuty Chebyshev,他首先在數學上描述了這種距離測量形式。您可以在 維基百科,切比雪夫距離 上找到更多關於此度量的資訊。使用「Chebyshev」距離度量,像素的最終距離是到最近邊緣的最大 X 或 Y 值。但是,由於對角線距離只有 1 個單位,因此圖像中的最大距離通常比您預期的要小。讓我們使用此核心「度量」生成一個「距離漸層」。但是,為了讓我們能夠看到發生了什麼,讓我們使用一種較慢的「Iterative Distance」(迭代距離)形態學方法,並使用無限迭代次數。

  magick man.gif -threshold 50% +depth \
          -define debug=true -morphology IterativeDistance:-1 Chebyshev \
          chebyshev_gradient.png


magick identify -format 'Maximum Distance = %[max]' chebyshev_gradient.png magick chebyshev_gradient.png -auto-level chebyshev_gradient.gif rm chebyshev_gradient.png
[IM Output]
[IM Text]
[IM Text]
Iterative Distance」形態學方法通過重複應用距離核心來計算距離,直到看不到值發生變化為止。

這比更常見的「Distance」(距離)方法慢得多,「Distance」方法使用兩次遍歷方法來設定整個圖像的距離。但是,「Distance」方法的詳細輸出就沒有那麼有趣了。

我打開了 Verbose(詳細)標誌,以便該命令在每次迭代(遍歷)圖像時輸出操作更改了多少個像素(所有白色像素)。然後我提取生成的「最大」距離(「1400」),然後調整結果(標準化)到一個圖像中,您可以在其中看到生成的漸層。最大距離「1400」是圖像中最亮像素的值(實際上它是 4 個此類像素的群集)。這些信息是這個距離核心(度量)最重要的結果,因為它表示適合這個形狀的最大正方形的大小。特別是半徑為 14 個像素的正方形,或者邊長約為 (R-1)*2+1 => 27 個像素的正方形,以這 4 個最大像素為中心。由於此核心中的所有距離單位始終是「100」的倍數,因此此最終距離值應始終是「100」的倍數,並且永遠不會有任何小數部分。基本上,此核心將產生一個整數距離,並且您可以對此核心使用簡單的「1 個單位」的「比例」,而不會丟失任何距離信息。如果您使用的是 ImageMagick 的 Q8 版本,或者將其應用於非常大的圖像,則建議這樣做。
這是形狀「腿」之間漸層的放大圖,它突出了生成的距離漸層的特徵。

  magick chebyshev_gradient.gif -crop 25x20+39+69 +repage \
          -scale 500% chebyshev_magnify.gif
[IM Output]
如您所見,「切比雪夫」距離核心產生了一個非常類似正方形的漸層。這是這種簡單形式距離度量的特定特徵,並且直接反映了距離核心本身的平方性質。以上還顯示了圖像「腹部」靠近頂部的 4 個最大距離像素。通過以這 4 個點中的任何一個為中心,您可以生成完全包含在圖形中的最大奇數大小的正方形。但是請注意,可能會有許多這樣的「峰值」。

曼哈頓(計程車)距離核心

曼哈頓」距離核心通過將 X 和 Y 值添加到最接近的邊緣來測量距離。它基本上是當您被限制只能進行類似網格的移動時需要移動的距離,例如在紐約曼哈頓等大城市的街道上行駛的計程車。由於這個原因,此度量的其他更常見的名稱是「計程車」或「城市街區」距離度量。您可以在 維基百科,曼哈頓距離 上找到更多資訊。這是它生成的實際核心……

  magick xc: -define morphology:showkernel=1  -precision 4 \
          -morphology Distance:0 Manhattan     null:
[IM Text]
請注意,對角線現在的值為「200」,即距離中心 2 個單位。也就是說,要到達對角線像素,您必須在提到的類似網格的移動中穿過兩個像素。因此,對角線往往比預期的要大,因此最終的距離測量結果也往往更大。讓我們再次使用此「度量」提取最大距離和「距離漸層」圖像。

  magick man.gif -threshold 50% +depth \
          -morphology Distance Manhattan      manhattan_gradient.png


magick identify -format 'Maximum Distance = %[max]' manhattan_gradient.png magick manhattan_gradient.png -auto-level manhattan_gradient.gif rm manhattan_gradient.png
[IM Output]
[IM Text]
這次我沒有使用「迭代距離」,即使我使用了,更改的像素總數也不會準確。只有先前的「切比雪夫」核心會且只會設置一次像素距離。請注意,圖像的最終最大距離要大得多,為「1700」距離單位,這使得形狀內的最大像素距離邊緣 17 個像素。此距離核心也是一個「整數」核心,因此您可以將比例設置為僅「1 個單位」而不會丟失資訊。
這是漸層的放大圖。

  magick manhattan_gradient.gif -crop 25x20+39+69 +repage \
          -scale 500% manhattan_magnify.gif
[IM Output]
如您所見,「曼哈頓」距離核心產生了一個菱形的漸層,這基本上就是這種簡單距離度量的表示,如實際核心值所示。

八邊形距離核心

八邊形」距離核心與其他兩個略有不同。它的創建方法是:首先為最邊緣的像素生成 曼哈頓 距離,然後對距離邊緣 2 個單位的像素使用 切比雪夫 距離。然後,它重複使用 曼哈頓 距離來計算 3 個單位距離的像素,依此類推。結果是使用兩個更簡單的核心所產生的距離的「交織」或「平均」。由於此核心基於兩個整數距離核心的交織,因此它也是一個整數距離核心。因此,可以使用「1 個單位」的比例來產生較小的值,適用於較低品質的 ImageMagick 版本或非常大的距離測量值。距離形狀也是兩個核心的混合,因此產生了相當於「八邊形」形狀核心的形狀。這是它生成的實際核心……

  magick xc: -define morphology:showkernel=1  -precision 4 \
          -morphology Distance:0 Octagonal     null:
[IM Text]
請注意,核心具有最小且默認的半徑 2 大小,形成一個 5x5 像素的核心。需要這個稍大的核心來生成核心的「交織」。總體距離通常會比實際距離略小。在這裡,我們再次計算最大距離……

  magick man.gif -threshold 50% +depth \
          -morphology Distance Octagonal  octagonal_gradient.png


magick identify -format 'Maximum Distance = %[max]' octagonal_gradient.png magick octagonal_gradient.png -auto-level octagonal_gradient.gif rm octagonal_gradient.png
[IM Output]
[IM Text]
1500」的結果是一個「整數」距離,實際上介於太小的切比雪夫距離和太大的曼哈頓距離之間。但是,總的來說,它應該與到形狀中心的實際距離相當接近,同時保持「整數」值。
這是漸層的放大圖。

  magick octagonal_gradient.gif -crop 25x20+39+69 +repage \
          -scale 500% octagonal_magnify.gif
[IM Output]
您可以清楚地看到,在腿部間隙頂部周圍形成了「八邊形」距離。您還可以注意到,對角線是使用粗細對角線交織生成的。

分數八邊形距離內核

尚未提供命名的距離內核。但它在這個階段非常適合我們正在研究的距離內核序列。您可以使用八邊形生成另一種類型的整數距離內核。但是,在這種情況下,整數距離使用的單位值為每個像素 2 個單位,因此實際上需要將生成的距離值減半,從而從生成的較小整數生成分數值。這就是名稱「分數八邊形」的由來。為此,我們在相鄰像素之間使用 2 的整數距離,在對角線方向上使用 3 的整數距離。
'3: 3,2,3
    2,0,2
    3,2,3'
由於可以生成「半整數」,因此可以使用的最小最小刻度為「2 個單位」。雖然它不如「騎士移動」準確,但它也能很好地發揮作用。此內核的八邊形在正交方向上具有「點」,而不是像前一個內核生成的那樣具有「平面」。它與下一個「騎士移動」內核相關,但不完全相同,並且可以被認為是「knights」內核的一種「近整數」形式。如果您想像以前的 IM 距離內核一樣縮放它,可以使用此內核。
'3: 150,100,150
    100, 0 ,100
    150,100,150'
以下是一個示例

  magick man.gif -threshold 50% +depth \
          -morphology Distance '3:3,2,3 2,0,2 3,2,3' \
          fractional_gradient.png


magick identify -format 'Maximum Distance = %[max]' fractional_gradient.png magick fractional_gradient.png -auto-level fractional_gradient.gif rm fractional_gradient.png
[IM Output]
[IM Text]
34」的結果是一個「整數」距離,但需要除以 2 才能產生 17 的實際最大距離結果。然而,雖然這也是一個整數,但它也很容易成為 16.5 的分數距離。距離結果的這種分數方面是大多數內核使用 100 個單位定義的原因,並且隨著我們從純整數距離內核轉移,在後面的內核中將變得更加普遍。
這是漸層的放大圖。

  magick fractional_gradient.gif -crop 25x20+39+69 +repage \
          -scale 500% fractional_magnify.gif
[IM Output]
梯度(如果您仔細研究結果)是一個八邊形。但是很難看到具有共同距離值的像素。為了更清楚地看到形狀,我採用了上面的圖像,並使用相同的顏色值(紅色)為一組像素著色。

  magick fractional_magnify.gif -fill red -opaque gray53 \
          fractional_magnify_shape.gif
[IM Output]
如您所見,具有相同值的像素通常以「騎士移動」模式分隔,但形成生成八邊形的線條。然而,八邊形從八邊形距離內核旋轉了 45 度。正是這種形狀差異導致最終的最大距離更大。從本質上講,以這種方式旋轉的較大八邊形更適合該形狀,因此最大距離結果更大。可以使用的另一個分數距離「整數」內核是這個,儘管距離以 3 個單位而不是 2 個單位表示。也就是說,結果需要除以 3 才能得到以像素大小表示的距離,這並不是一個很好的除數。然而,它是另一種類型的八邊形距離度量。
'3: 4,3,4
    3,0,3
    4,3,4'
下面的歐幾里得(騎士移動)距離內核也生成八邊形樣式(所有 3x3 距離內核都是如此),但試圖沿對角線盡可能準確。這可能是也可能不是最好的主意,但它是這種類型中最符合數學邏輯的八邊形距離內核。

倒角距離內核

尚未提供命名的距離內核。但它在這個階段非常適合我們正在研究的距離內核序列。「倒角」距離內核(尚未實現)僅使用用於填充距離矩陣的數字(通常是整數)來定義。例如,您可以使用 2 個數字來定義任何 3x3「八邊形」類型的距離內核,如上所述。以下是先前整數內核的定義,
切比雪夫 倒角:1,1
曼哈頓 倒角:1,2
分數八邊形  倒角:2,3    /2
分數八邊形替代方案  倒角:3,4    /3
所有這些內核都是簡單的半徑為 1 的內核。給定的值可以被視為它應該使用的實際“距離縮放”值。但是請注意,之前的整數 八邊形 內核需要一個 3 個數字半徑為 2 的 Chamfor 內核來定義它。最著名的 Chamfer 內核是半徑為 2 的內核,“Chamfer:5,7,11”,它可以產生非常準確的距離,並且還生成整數距離值,使其非常適合 Q8 用戶。傳統上,內核(chamfor 5,7,11)的形式為...
'5:  -   11   -   11   -
    11    7   5   7    11
     -    5   0   5    -
    11    7   5   7    11
     -   11   -   11   -'
或者將上述數字乘以 20,以產生 ImageMagick 通常用於距離內核的相同像素距離縮放 (100)....
'5:  -   220   -   220   -
    220  140  100  140  220
     -   100   0   100   -
    220  140  100  140  220
     -   220   -   220   -'
請注意,內核實際上並沒有填充所有內核距離。這是因為這些值將從已經提供的其他值中獲取距離。也就是說,您實際上並不需要填寫整個二維數組來完全定義距離內核,儘管通常這樣做是為了更容易處理。以下是我在研究中發現的其他已知 Chamfer 內核(僅使用整數值)的列表。
倒角:3,4    /3
Chamfer:5,7,11     /5
Chamfer:99,141,221     /100
Chamfer:987,1414,2206     /1000
Chamfer:12,17,27,38,43     /12
[diagram]
如何放置 5 個值來定義半徑為 3 的 Chamfor 內核
上表中突出顯示的內核是最著名和最常用的 Chamfor 距離內核。它僅使用小的整數值生成圖像,因此可以存儲大距離梯度圖像而不會損失精度。它也非常準確,至少足以滿足幾乎所有可以想像的目的。另一個好處是,距離結果不會產生遞歸小數位,而是在標準化時只會產生一位小數。這也是許多圖像處理軟件包經常選擇它的另一個原因。 “Chamfer:5,7,11” 應被視為默認的 “Chamfor” 距離內核。

歐幾里得(騎士移動)距離內核

歐幾里得” 內核是使用精確的浮點距離數生成的。但是要使其與非 HDRI 版本的 ImageMagick 一起使用,需要使用分數對角線距離。例如,對角線的值為 2 的平方根,約為 1.4142 個距離單位。為了使其正常工作,距離按 100 的值縮放(如所有上述內核),以產生分數百分比距離。以下是它生成的默認內核...

  magick xc: -define morphology:showkernel=1  -precision 4 \
          -morphology Distance:0 Euclidean    null:
[IM Text]
現在,通過使用默認的 半徑 1,雖然在準確性方面比以前的內核有了很大的改進,但仍然存在一些限制。基本上,它根據僅 45 度對角線和正交(X 和 Y)移動來提供距離。也就是說,距離有點像國際象棋遊戲中的“騎士移動”。以下是使用默認“歐幾里得”或“騎士移動”內核創建的最大距離和“距離梯度”圖像。

  magick man.gif -threshold 50% +depth \
          -morphology Distance Euclidean    knight_gradient.png


magick identify -format 'Maximum Distance = %[max]' knight_gradient.png magick knight_gradient.png -auto-level knight_gradient.gif rm knight_gradient.png
[IM Output]
[IM Text]
如您所見,對於此特定形狀,您還會獲得“1700”距離單位的距離值。通常,結果將是較小的“切比雪夫”距離或較大的“曼哈頓”距離之間的一些分數距離。它恰好是“100”的簡單倍數,並且恰好與“曼哈頓”距離相同,這純粹是幸運的。到像素的實際距離實際上是對角線距離加上正交(軸)距離的總和。也就是說,這不是一個完美的歐幾里得距離,但它是使用最小的距離內核(半徑為 1)時最接近的距離。
以下是形狀“腿”之間梯度的放大圖。

  magick knight_gradient.gif -crop 25x20+39+69 +repage \
          -scale 500% knight_magnify.gif
[IM Output]
如您所見,漸變的外觀更加圓潤,沒有在「整數」距離核心算法中出現的洋蔥狀「層級」或「階地」效果。這是因為每個像素更有可能被分配到距離邊緣不同的分數距離。然而,漸變的最終形狀實際上大致為「八邊形」,但具有類似指南針的點,而不是像之前「八邊形」距離核心算法那樣上下扁平。對於一般的距離處理(例如「羽化」),這個預設的「歐幾里得」或「騎士移動」核心算法提供了良好的結果。然而,由於您無法獲得「整數」距離,因此您不能使用「1」的距離比例因子,這使得它對於 ImageMagick 的 Q8 版本不太有用。

更大的歐幾里得距離核心算法

通過增加生成的「歐幾里得」核心算法的「半徑」,您可以產生更準確的「畢達哥拉斯」或真正的「歐幾里得」距離度量。半徑越大,結果越準確,但形態學「距離」方法的運行時間會更長,儘管需要的迭代次數會更少。但是,當半徑超過 4 後,您將不會獲得更高的準確度,但速度會大大降低。有關使用非常大的「歐幾里得」核心算法來提高準確度的示例,請參見下面的具有抗鋸齒形狀的距離。這是一個使用推薦半徑 4 的真正「歐幾里得」核心算法,它生成了一個更大的 9×9 核心算法...

  magick xc: -define morphology:showkernel=1  -precision 4 \
          -morphology Distance:0 Euclidean:4     null:
[IM Text]
使用半徑 4 的另一個優點是,核心算法還包含畢達哥拉斯三角形,其邊長為 3、4、5,或者使用預設核心算法比例,單位為 300、400、500。雖然這可以減少結果圖像中的分數分量數量,但實際上只是一個很小的影響。儘管如此,對於更高的準確性來說,這是一個合乎邏輯的選擇。以下是它的應用...

  magick man.gif -threshold 50% +depth \
          -morphology Distance Euclidean:4     euclidean_gradient.png


magick identify -format 'Maximum Distance = %[max]' euclidean_gradient.png magick euclidean_gradient.png -auto-level euclidean_gradient.gif rm euclidean_gradient.png
[IM Output]
[IM Text]
由於使用了這個更大的半徑「歐幾里得」核心算法,最終的最大距離是迄今為止最準確的最大距離測量值。這也使得圖像中不太可能出現多個「最亮」像素,除非形狀非常規則。
以下是形狀“腿”之間梯度的放大圖。

  magick euclidean_gradient.gif -crop 25x20+39+69 +repage \
          -scale 500% euclidean_magnify.gif
[IM Output]
如您所見,漸變在「腿縫」的末端產生了一個近乎完美的圓形漸變。正如我上面所說,使用此核心算法的成本是運行時間略有延長。

距離核心比較

這里再次是放大部分的並排比較。這清楚地顯示了使用的四種距離度量中的每一種生成的截然不同的漸變。
[IM Output]
切比雪夫
(棋盤格)
[IM Output]
曼哈頓
(計程車距離)
[IM Output]
八邊形
(混合)
[IM Output]
歐幾里得
(騎士移動)
[IM Output]
歐幾里得
(半徑 = 4)
這是另一個比較,這次是在不放大像素的情況下,獲取距離左下角附近單個黑色像素的距離。

  magick -size 100x100 xc: -draw 'point 20,80'  distance_start.png

  for kernel in chebyshev manhattan octagonal euclidean euclidean:2 euclidean:4
  do
    magick distance_start.png    -morphology Distance $kernel \
            -auto-level  point_$kernel.png
  done
[IM Output]
切比雪夫
(棋盤格)
[IM Output]
曼哈頓
(計程車距離)
[IM Output]
八邊形
(混合)
[IM Output]
歐幾里得
(騎士移動)
[IM Output]
歐幾里得
(半徑 = 2)
[IM Output]
歐幾里得
(半徑 = 4)
這些圖片清楚地顯示了像素被認為比預期更靠近起始像素的線條,以及各種內核如何隨著它們變得更複雜而變得更平滑。只有最後一張圖片沒有顯示可見的「較近像素」線條,但即使在半徑為 4 時,它們也存在。對於這個內核,線條只出現在距離源很遠的地方。半徑為 7 會產生更好的結果,但速度會大幅降低,但有時需要這種準確性才能避免結果圖像中出現偽影。請記住,只有前三個內核會產生整數距離,這些內核可以用於 ImageMagick 的 Q8 版本(使用適當的比例調整,請參閱各個內核說明)。而這些通常是許多圖像處理軟件包將使用的內容。稍後將在下面的約束距離範例中再次介紹計算與單個點的距離。

特殊的使用者定義距離核心

您不僅限於為您提供的距離內核。只要您遵守規則,在「原點」使用零值,並在其周圍使用遞增的距離值,您就可以產生其他非常有趣的距離效果。
例如,這裡我應用了一個非常小的用戶定義的內核,它只是說使右側的任何像素的值都更大。

  magick man.gif -threshold 50% +depth \
          -morphology Distance  '2x1+0+0: 0,100 ' \
          -auto-level    distance_linear.gif
[IM Output]
請注意腿之間間隙的效果,它會「重置」它產生的緩慢增加的漸變。
在這裡,我僅從兩側創建了一個距離漸變,但每側的比例不同!

  magick man.gif -threshold 50% +depth \
          -morphology Distance  '3x1: 50,0,100 ' \
          -auto-level    distance_sides.gif
[IM Output]
這些只是一些可能的距離內核變體的例子。你能想到其他的嗎?請告訴我。請注意,如果您的圖像結果很糟糕,則您的內核原點設置可能錯誤,或者原點不是「零」值。形態距離函數不會檢查這一點。

具有反鋸齒形狀的距離

距離方法非常有效。但對其功能的最佳測試是將距離函數應用於圓形,然後對其進行陰影處理,以便突出顯示該函數可能產生的即使是最小的誤差。

  magick -size 129x129 xc: -draw 'circle 64,64 60,4' \
          -negate  circle_shape.png

  magick circle_shape.png  -morphology Distance Euclidean:4 \
          -auto-level cone_distance.png

  magick cone_distance.png -shade 135x30 -auto-level \
          +level 10,90%  cone_distance_shade.png
[IM Output] ==> [IM Output] ==> [IM Output]
您可以從上面看到,雖然您確實獲得了「圓錐形」的結果,但它遠非平滑的「圓錐」。它被從邊緣開始的徑向脊網絡覆蓋。如果仔細觀察陰影圓錐的邊緣,您會發現圓錐沒有原始形狀的平滑圓形底面。它是高度「鋸齒狀」或「階梯狀」的,正是這些「台階」被距離函數反射,形成了所見到的徑向脊。問題在於,距離方法不知道圓圈在邊緣周圍使用的表示其平滑外觀的小「灰色」抗鋸齒像素。事實上,任何「灰色」像素通常都被認為是整個像素,而不是它們所代表的抗鋸齒部分邊緣像素。
我們需要做的是以某種方式在結果中包含這些灰色邊緣值,這是通過在應用距離方法之前使用預處理步驟來完成的。

  magick circle_shape.png  -gamma 2 +level 0,100 -white-threshold 99 \
          -morphology Distance Euclidean:4   -auto-level \
          -shade 135x30 -auto-level +level 10,90%   cone_antialiased.png
[IM Output]
所做的是首先將所有這些灰色像素從表示像素在圓形邊界內的多少的表示形式,轉換為表示像素距圓形邊緣有多遠的表示形式。從結果中您可以看到,幾乎所有階梯邊緣誤差都已得到修復。可見的最終誤差僅出現在遠離邊緣的地方,並且在「圓錐」的中心附近變得更加明顯。它們是由距離函數的迭代引起的,每 4 個像素(歐幾里德距離內核的大小)一遍又一遍地迭代。因此,隨著我們距離邊緣越來越遠,微小的誤差會變得更加明顯。
這在大多数情况下通常不是问题,但您可以通过使用更大的欧几里德内核来减少甚至消除那些小错误,以便产生更准确和更平滑的结果。然而,这确实需要更长的时间来生成。

  magick circle_shape.png  -gamma 2 +level 0,100 -white-threshold 99 \
          -morphology Distance Euclidean:7   -auto-level \
          -shade 135x30 -auto-level +level 10,90%   cone_improved.png
[IM Output]
結果是一個近乎完美的抗鋸齒或平滑形狀的距離函數。這裡是另一個例子,這次使用上一節中的兩個用戶定義距離內核

   magick circle_shape.png -gamma 2 +level 0,100 -white-threshold 99 \
           -morphology Distance  '2x1+0+0:0,100'  -auto-level \
           circle_gradient.png

   magick circle_shape.png -gamma 2 +level 0,100 -white-threshold 99 \
           -morphology Distance  '3x1:50,0,100'  -auto-level \
           circle_ridge.png
[IM Output] [IM Output]
如果沒有針對抗鋸齒像素的特殊處理,以上內容將無法在圖像中產生如此平滑的漸變。實際上,我們仍然需要恢復原始形狀的“形狀”。

使用距離羽化形狀

上述技術可以應用於形狀的 Alpha 通道,以便適當“羽化”對象。例如,這裡是一個形狀對象周圍 10 個像素的“平滑”羽化。

   magick rose_orig.png \
           \( +clone -fill black -colorize 100% \
              -fill white -draw 'circle 114,75 110,2' \
           \) -alpha off -compose CopyOpacity -composite \
           -trim +repage rose_shape.png

   magick rose_shape.png \
           \( +clone -alpha extract -virtual-pixel black \
              -gamma 2 +level 0,100 -white-threshold 99 \
              -morphology Distance Euclidean:4,10! \
              -sigmoidal-contrast 3,0% \
           \) -compose CopyOpacity -composite \
           rose_feathered.png
[IM Output] ==> [IM Output]
這將精確保留所有邊緣,這與更簡單的模糊羽化技術不同。我可以將上述內容直接應用於 Alpha 通道,但某些運算符不會將透明度通道視為“Alpha 值”,而是視為“不透明度值”(特別是“-white-threshold”運算符)。因此,我提取了 Alpha 通道,以便在將其合併回最終圖像之前將其作為灰度圖像處理。特殊的距離內核將對 4 像素歐幾里德內核進行三次迭代,以在形狀邊緣附近生成足夠的距離梯度。“-level”運算符然後將其變為從邊緣('0')到形狀內 10 個像素('1000' 個單位)的線性漸變。“-virtual-pixel”設置也可用於確保任何接觸矩形圖像容器邊緣的形狀也被認為是被透明度包圍的。在這種情況下,距離函數的結果是一個“線性斜面”或“斜角”,可以產生一些看起來很銳利的效果。因此,一個小的“-sigmoidal-contrast”修改將使從透明到不透明的過渡變得平滑。強度越高(以上為“3”),羽化在邊緣處就越清晰。如果您希望羽化更平滑地“逐漸變細”為透明,請將上述代碼中的“0%”替換為“50%”,以將 sigmoid 曲線的“肩部”放置在 10 個像素羽化的中間。 點陣圖形狀羽化 如果形狀是點陣圖,例如來自 GIF 圖像或圖像蒙版,則可以簡化上述羽化操作。例如...

  magick figure.gif -channel A -virtual-pixel transparent \
          -morphology Distance Euclidean:4,3!  boolean_feathered.png
[IM Output] ==> [IM Output]
關鍵變化是,您對距離函數的預處理和後處理要少得多,您可以使用“3!”簡單地指定一個特殊的距離單位。這將在形狀的邊緣周圍生成一個 3 像素的線性漸變。這種羽化的另一個例子(更大的“線性羽化”)可以在縮略圖,柔化邊緣中看到。您可以在上述內容中使用“-sigmoidal-contrast”運算符來平滑更大的羽化,但請注意,此時它會將透明度處理為“遮罩”值而不是 Alpha 值。因此,應使用“100%”值而不是先前解決方案中的“05”。對於點陣圖形狀,最好對 Alpha 通道應用“-blur 1x0.7”以使其稍微平滑,然後再將先前更複雜的距離羽化應用於這些結果。

條件或約束形態學

在這裡,我們將研究重複形態學操作被約束或限制在圖像的特定區域或區域內的技術。基本上,這些技術可以用於確保您不會“溢出”或增長超出某些限制或感興趣區域。這通常需要某種“蒙版”圖像,並且通常使用寫保護蒙版來限制更新哪些像素。

條件膨脹

如您所知,膨脹形態學方法會根據給定的核心鄰域擴展特定形狀。「條件膨脹」本質上是相同的,但會設定膨脹在重複應用於影像時可以擴散的限制。繪製填色在某種意義上是終極的「條件膨脹」。它只會填充與起點顏色相同的任何正交(菱形核心鄰域)。例如,我們可以在多個圓盤中的一個圓盤中選擇一個點,然後有條件地膨脹(填色),直到該圓盤完全重新著色,將其與其他形狀分開。

  magick disks.gif -fill red -draw 'color 60,60 floodfill' \
          cond_dilate_draw.gif
[IM Output] ==> [IM Output]
同樣,您可以使用 填色運算子 來執行相同的操作,但前提是起點也與使用者提供的「條件顏色」相符。

  magick disks.gif \
          -fill green -floodfill +10+40 white \
          -fill blue  -floodfill +30+50 white \
          cond_dilate_floodfill.gif
[IM Output]
在這種情況下,「綠色」填色「碰到一個圓盤」(並填充它),而「藍色」填色操作沒有匹配,所以沒有填充任何圓盤。這種「填色」方法的問題是,您只能從使用者提供的一個點進行膨脹。然而,它速度非常快,並且可以對整個影像進行操作。重複或迭代的 膨脹 與填色相同,但可以有多個起點,但對其提供的填充操作沒有限制或邊界的概念。為了限制其效果,我們不僅需要提供「起點」,還需要提供填充的「條件邊界」。為此,我們創建一個 寫入保護遮罩(影像中哪些部分受寫入保護)。

  magick disks.gif disks.gif -morphology Erode:7 Diamond disks_big_center.gif

  magick disks.gif -negate disks_mask.gif

  magick disks_big_center.gif -write-mask disks_mask.gif \
          -morphology Dilate:15 Diamond +write-mask disks_big_found.gif
[IM Output] ==> [IM Output]  + [IM Output] ==> [IM Output]
在上面,我們首先使用 侵蝕方法 來定位任何大於半徑 7(直徑 7x2+1 => 15 像素)的圓盤。然後,我們通過相同的量「有條件地膨脹」發現的點,以便「完美地」恢復找到的物件。請注意,「條件膨脹」與使用 開運算 進行物件恢復有很大不同。該方法會生成核心的內部「菱形」形狀,而不是原始物件的確切形狀。它也不會處理「奇形怪狀」或「偏離中心」的種子點。迭代次數「15」並不重要,但應足夠大以完全恢復物件。
請記住,在執行 基本形態學運算 時,最好使用較小的核心(例如 菱形方形)和 迭代次數,而不是使用半徑較大的核心(例如 圓盤)。

這在進行 條件膨脹 時尤其重要,因為較大的核心實際上可能會「跳過」分隔多個物件的間隙。

不要將「-1」或(接近)無限的迭代次數與寫入遮罩一起使用。IMv7 形態學目前無法意識到像素不可寫入,因此在看到影像不再變化時不會中止,因為它總是在形狀邊緣看到變化(永遠不會被寫入)。

這將在 IMv7 中得到修復,IMv7 提供了一個重大的內部重構,使運算子在寫入受保護的像素方面更加智能。

以下是使用 寫入保護遮罩 的多功能性的另一個示例。找到將被穿過影像的對角線擊中的圓盤。

  magick -size 80x80 xc:black -fill white \
                        -draw 'line 0,0 79,79'   disks_line.gif

  magick disks_line.gif disks.gif \
          -compose Multiply  -composite    disks_line_find.gif

  magick disks_line_find.gif -write-mask disks_mask.gif \
          -morphology Dilate:15 Diamond +write-mask disks_line_found.gif
[IM Output]  + [IM Output] ==> [IM Output]  + [IM Output] ==> [IM Output]
請注意額外的遮罩步驟(使用 乘法合成),它確保只有線條實際穿過的對象才會被「找到」。如果沒有這個步驟,靠近線條且位於「種子點」內核半徑內的對象(如上圖所示,只是接觸)也會被「膨脹」。當然,如果您想包含「附近的對象」,那麼在進行初始遮罩步驟之前,請務必使用適當半徑的圓盤內核來膨脹線條(使其變寬)。與依靠方形內核半徑相比,這將為您提供更多「鄰近」控制。總之,條件膨脹 可以被視為多點 繪製泛洪填充,雖然速度較慢,但在選擇要填充或「發現」的內容方面可以更加靈活。

約束距離

距離 形態學方法可以很容易地用於查找對象內的一個點到邊緣的距離。但它也可以用於查找對象內每個點到另一個點的距離。例如,這裡我發現每個點到單個「種子」點的距離(直線距離)...


magick -size 100x100 xc: -draw 'point 20,80' distance_start.png magick distance_start.png -morphology Distance Euclidean \ -auto-level distance_point.png magick -font Casual -pointsize 140 label:D \ -trim +repage -gravity center -extent 100x100 \ -threshold 20% distance_bounds.png magick distance_point.png \( distance_bounds.png -negate \) \ -compose multiply -composite -auto-level distance_direct.png
[IM Output] ==> [IM Output] ==> [IM Output] ==> [IM Output]
到一個點的距離被對象的形狀所遮罩,因為這些是我們唯一感興趣的點。問題是,上述距離梯度表示到「起點」的「直線」或直接距離。簡單地用對象遮罩該梯度並不會改變這一點。不幸的是,這通常不是使用者想要的「到起點的距離」。如果形狀代表一個島嶼,那麼如果您想從這個島嶼的一端到另一端走「直線」,您會被淋得很濕。 您真正想要的是僅限於「對象內」路徑的距離。也就是說,您希望距離受對象本身「約束」,並遵循對象內部可能的最小路徑。為此,我們可以設置一個 寫入保護遮罩,以便在計算距離梯度時,它不會交叉(寫入)圖像的「禁區」或背景。

  magick distance_start.png -write-mask distance_bounds.png \
          -morphology IterativeDistance:150 Euclidean \
          +write-mask -fill black -opaque white -auto-level \
          distance_constrained.png
[IM Output] ==> [IM Output] ==> [IM Output]
正如您所見,結果是一個正確的「跨圖像距離」梯度,它清楚地顯示了到起點的最大距離(白色)是島嶼的另一端,那裡只是對象間隙的「一步之遙」。
請注意,我沒有簡單地使用普通的 距離方法,而是使用了一個較低級別的「Iterative_Distance」形態學方法。普通的 距離方法 是一種特殊的 2 通道 FAST 距離方法,它被應用於整個圖像。因此,寫入遮罩不會限制其沿像素「行」的操作,因此寫入遮罩幾乎沒有效果。結果是「Distance」將傾向於「跳過」水平間隙,而不管寫入遮罩如何。也就是說,普通的 距離方法 沒有被正確地「約束」。然而,「Iterative_Distance」方法的工作原理更像是一種更簡單的 基本形態學方法,並且僅增量地應用於局部鄰域。它實際上更像是「膨脹」的梯度形式,並且實際上與 真灰度形態學 方法密切相關。由於它是以較小的「增量步驟」處理圖像的,因此「Iterative_Distance」方法將受到寫入遮罩的「約束」。遺憾的是,它也慢得多。上述操作不是對圖像進行 2 次通道,而是執行 150 次通道,如形態學方法的 迭代次數 所示。最好儘可能將此迭代次數保持在較小的水平,但要足夠大以覆蓋圖像中將找到的最大距離。
不要將「-1」或(接近)無限迭代次數與寫入遮罩一起使用。IMv7 Morphology 不理解某些像素是不可寫入的,因此當它看到圖像沒有更多變化時,它不會中止,因為它始終會看到形狀邊緣周圍「不可寫入像素」的變化。

希望 IMv7 能解決這個問題,它提供了一個重要的內部重構,讓運算器能夠更聰明地理解某些像素是不可寫入的,從而避免計算它們或將它們計為「已更改」。

最後,您會注意到我使用了半徑僅為 1 的距離核心,儘管這種核心的準確性不高。這一點很重要,因為較大的核心可能會導致距離梯度跨越任何小於其半徑的間隙而跳躍。請參閱上面的條件膨脹。如果需要更高的準確性,則需要確保沒有任何間隙小於您要使用的距離核心。這包括由於影像邊緣的急彎而產生的間隙。

生成形狀的骨架。

建構中
From HIPR2 Morphology
http://homepages.inf.ed.ac.uk/rbf/HIPR2/morops.htm


The skeleton/MAT can be produced in two main ways. The first is to use some
kind of morphological thinning that successively erodes away pixels from the
boundary (while preserving the end points of line segments) until no more
thinning is possible, at which point what is left approximates the skeleton.

The alternative method is to first calculate the distance transform of the
image. The skeleton then lies along the singularities (i.e. creases or
curvature discontinuities) in the distance transform. This latter approach is
more suited to calculating the MAT since the MAT is the same as the distance
transform but with all points not part of the skeleton suppressed to zero.

Note: The MAT is often described as being the 'locus of local maxima' on the
distance transform. This is not really true in any normal sense of the phrase
'local maximum'. If the distance transform is displayed as a 3-D surface plot
with the third dimension representing the gray-value, the MAT can be imagined
as the ridges on the 3-D surface.



Definition??

Morphological Skeleton (by erosion?), (by thinning)

Skeletons are calculated either by repeated thinning,  or by distance
transform, and finding the 'creases', or ridges on the 3d surface (watershed
transform?).

   mat.gif -morphology HMT Ridges           -threshold 0
   mat.gif -morphology HMT LineEnds         -threshold 0
   mat.gif -morphology HMT Ridges\;LineEnds -threshold 0

   mat.gif -morphology HMT Ridges\;Ridges2  -threshold 0

   mat.gif -morphology TopHat Diamond              -threshold 0

   mat.gif -define morphology:compose=Lighten \
              -morphology TopHat '3@:-,1,- -,1,- -,-,-' -threshold 0


One definition of medial axis transform (MAT) uses the intensity of each point
to represent the distance ot the boundary.  That the skeleton was used as
a mask for the distance transform. The distance transform method is more
suited to this, and it is probably faster to calculate than by thinning.

SKIZ (Skeleton by Influence Zones) is a skeleton of the background, the
negative of the operation.  That is, dividing the regions closest to each
foreground object.  (generated by thickening)

Generally a SKIZ is pruned down to simple areas, or basins, by also eroding
end of line segments, unless they are attached to an image edge.

Identifying shape by their skeletons.
   distance between farthest 'end' points,
   number of 'loops' or regions in image,
   number of triple points.


到骨架的距離

從影像生成原始「形態骨架」的一種快速簡便的方法是對距離梯度應用「禮帽」方法。
例如,以下是在形狀經過稍微開啟以使其輪廓稍微平滑後的骨架。

  magick man.gif \
          -morphology Open  Diamond \
          -morphology Distance  Chebyshev \
          -morphology TopHat Diamond \
          -auto-level    chebyshev_dist_skel.gif
[IM Output]
這基本上是一個形態骨架。它只顯示可以找到最大「正方形」(更常見的名稱為「最大球」)的像素,這就是它看起來不完整的原因。然而,它仍然是一個非常原始的結果,有許多孤立的像素。令人驚訝的是,它確實有效。如果沒有「開啟」,由於形狀的輪廓非常粗糙,結果會非常糟糕。
使用歐幾里得距離度量可以產生更好的形狀骨架。

  magick man.gif \
          -morphology Open  Diamond \
          -morphology Distance Euclidean:4 \
          -morphology TopHat Diamond \
          -auto-level    euclidean_dist_skel.gif
[IM Output]
但正如您所見,您也會得到更多的雜訊,而且骨架雖然更完整,但也非常髒亂,有許多灰階值。
以下是骨架「頭部」的放大圖,顯示它是如何保持分離的。

  magick euclidean_dist_skel.gif -crop 35x28+30+13 +repage \
          -scale 400%   euclidean_dist_skel_mag.gif
[IM Output]
當然,上述內容可以進行閾值處理,並作為遮罩與用於生成它的實際距離梯度一起使用。這將允許您查找構成骨架的最大圓盤的實際大小(距離半徑),從而重新建立原始形狀。

使用 Autotrace 的骨架

骨架生成的另一種替代方法是使用「AutoTrace」程式及其特殊的中心線選項。請注意,由於它涉及印刷和字體轉換,因此它假設處理的是黑色背景上的白色。例如...

  magick man.gif -negate man_at_prep.pgm
  autotrace -centerline -output-format svg man_at_prep.pgm |\
      magick SVG:-  man_centerline.gif
  magick man.gif man_centerline.gif \
          -compose multiply -composite man_at_skeleton.gif
[IM Output] ==> [IM Output] ==> [IM Output] ==> [IM Output]
請注意,由於過程的向量性質,生成的中心線是平滑曲線的形式。它也是斷開的,骨架迴路中有間隙,分支也不連接。然而,我還沒有研究「autotrace」實際上是如何生成這個骨架的。有關使用「AutoTrace」的其他範例,請參閱SVG 輸出處理點陣圖到向量邊緣化