ImageMagick 範例 --
色彩量化與抖動

索引
ImageMagick 範例前言與索引
色彩縮減簡介 (涉及的內容)
影像中的色彩 (影像使用的色彩)
色彩量化 (減少影像中的色彩數量)
誤差修正抖動 (或偽隨機抖動)
臨界值抖動方法
有序模式抖動 (使用平鋪臨界值映射)
自訂抖動模式與臨界值映射 (以您自己的方式抖動影像)
減少顏色數量或替換特定顏色是影像處理中非常複雜和困難的步驟,而這正是本範例頁面所涵蓋的主題。這包括確定要使用的顏色(顏色量化),以及如何將這些顏色放置在影像上(抖動和圖案化)。它還包括生成點陣圖或雙色影像,甚至處理布林(開/關)透明度。這一點非常重要,以至於顏色縮減或量化通常會自動地在幕後進行,以便 ImageMagick 可以執行其最初的主要任務,即將影像從一種檔案格式轉換為另一種顏色較少的格式,例如 GIF、XPixmap 和 XBitmap 格式。了解這是如何運作的可以讓您更好地控制這個過程,從而改進存儲在特定影像檔案格式中的結果影像。

色彩縮減簡介

色彩縮減是 ImageMagick 中非常重要的一個方面。例如,要將包含數百萬種顏色的 JPEG 或 PNG 影像轉換為最多包含 256 種顏色的 GIF 影像,您真的需要能夠以高效且有效的方式減少顏色。通常在影像格式轉換過程中,這會在幕後自動發生,但也有其他時候您需要手動執行此操作。減少影像中的顏色數量通常是一個三步驟過程,
  1. 首先,您通常需要調查圖像使用的顏色。不僅要查看實際使用了多少種顏色,還要查看特定顏色的使用頻率。如果只有一個像素使用某種特定顏色,那麼保留這種顏色就沒有什麼意義,儘管有時您仍然需要這樣做。
  2. 接下來,您需要以某種方式決定要將圖像限制到的最終顏色集。您可能希望 IM 嘗試確定特定圖像的“最佳”顏色集。其他時候,您可能需要更通用和全局的顏色集,以便用於任何圖像。您甚至可能希望專門添加或刪除將使用的顏色集中的顏色。
  3. 最後,您需要修改圖像,使其僅使用您選擇的顏色。您最好希望結果看起來不錯,或者您可能希望它能夠很好地壓縮、比較或優化。
更複雜的是,這些步驟通常是相互關聯的,因為一種替換顏色的方法通常只能使用特定的顏色集來應用。如果您正在使用特定的顏色集,則不需要進行某種顏色調查,或者您可能需要為特定顏色設置例外情況。基本上,雖然顏色簡化通常是在幕後自動處理的,但至少要了解它正在發生什麼,以及它的影響是什麼。

顏色調查

這可能是最不重要的一點,雖然 IM 為您提供了執行調查的方法,但用戶很少為了減少顏色而這樣做。我將把進一步的討論留到相關章節「提取圖像顏色」。

顏色選擇(量化)

有關良好的初步概述,請參閱維基百科,顏色量化。選擇顏色有四種基本方法。這四種顏色控制方法:量化預定義顏色映射均勻顏色閾值;正如您將看到的,它們都有其局限性。以下是這四種方法的示例…

  magick colorwheel.png +dither    -colors 32          color_quantize.gif
  magick colorwheel.png +dither -remap colortable.gif  color_predefined.gif
  magick colorwheel.png +dither   -posterize 3         color_uniform.gif
  magick colorwheel.png \
                  -separate -threshold 50% -combine     color_threshold.gif
[IM Output] ==> [IM Output] [IM Output] [IM Output] [IM Output]
最終影像中顯示的顏色數量僅為代表性集合,但每種情況下大約為 32 種顏色(僅有 8 種顏色的閾值除外)。由此您可以了解每種方法的預期結果。除了第一種方法(「-colors」)會根據目前的影像內容實際挑選顏色之外,所有其他方法都具有固定的顏色集(根據運算元引數),與進行顏色簡化的影像無關。由於測試影像主要為白色,因此會選取許多較淺的顏色。它使用稱為「自適應空間細分」的技術(使用八叉樹)來調查影像中的顏色。然後嘗試在給定的限制內選擇一組特定的顏色,以最佳地匹配特定影像。請參閱下方的顏色量化運算元。「-remap」可讓您為 IM 提供自己預先定義的顏色集(請參閱使用者定義的顏色映射表)。以上使用的顏色映射表「colortable.gif」是一組專為舊X Window 圖示庫挑選的 32 種顏色,並設計用於卡通風格的圖示。(詳情請參閱AIcon 庫,X 圖示顏色選擇)。使用「-posterize」也可以將每個顏色通道數學劃分為一組顏色級別或強度,從而產生「均勻顏色映射表」。也就是說,每個通道都設定為一組恆定值或強度的顏色映射表。最後可以使用「-threshold」處理影像的所有或特定顏色通道,基本上使每個顏色通道都變成純布林值或開/關狀態。也就是說,每個顏色通道都可以賦予零值或 MaxRGB(取決於 IM 的「Q」級別)。然而,這只會產生一組最少約 8 種顏色的顏色集。一個非常有限的顏色集。閾值也相當於「-posterize」級別「1」,它會挑選 2 種顏色。

應用顏色集

擁有一組顏色後,下一個問題是如何將顏色應用於影像,以便用所選的顏色集替換現有的顏色。這稱為「抖動」,之所以這樣命名是因為它具有「我應該選這個還是選那個?」的非此即彼性質。基本上,抖動的想法是將不同顏色的像素彼此靠近放置,以欺騙眼睛看到影像中的顏色比實際使用的顏色更多。也就是說,由於人眼將相鄰顏色「融合」在一起的方式,影像中該區域的顏色與影像的原始顏色更加匹配。關於抖動的最佳介紹之一是在維基百科上,但您需要跳過開頭的「音訊抖動」部分。這提供了一組很好的範例,說明了在顏色集有限的情況下使用抖動像素模式的好處。基本的顏色替換樣式包括...
  • 直接顏色映射(閾值和色階化)
  • 隨機抖動(純粹隨機放置像素)
  • 誤差修正抖動(偽隨機像素模式)
  • 有序擴散像素抖動(規則的像素模式)
  • 數位半色調(不同大小的點)
直接映射 如果最接近的顏色在一個給定的集合中,就像上面顯示的那樣。基本上,你會得到不同的純色區域,顏色不變。當應用於顏色緩慢變化的圖像時,例如真實生活中的天空照片,你會在圖像中看到顏色帶,尤其是在原本應該是平滑顏色漸變的地方,例如天空區域。結果通常被認為不是很好。直接顏色映射通常被認為可以接受的唯一情況是徽標、符號、圖標和卡通圖像。它實際上很少被選用。這就是為什麼你通常必須關閉正常的抖動方法,如果你不想直接映射圖像中的顏色。然而,抖動有其自身的問題。一旦圖像被抖動,顏色圖案就會成為圖像的一部分。一旦出現這種圖案,就很難去除。此外,多次對圖像重新應用抖動通常是一個壞主意,因為這只會降低圖像質量。因此,下面大多數量化示例通常會向你展示如何為每種技術創建未抖動的版本。這樣做的目的是讓你可以在抖動隱藏該信息之前查看選擇了哪些顏色。隨機抖動 是最簡單的抖動方法。它也被認為是最差的抖動方法。然而,它有一些特殊用途。在 IM 中,它僅適用於兩種顏色,因此通常僅限於特殊情況下的位圖抖動。有關更多信息,請參見下面的 帶閾值的隨機抖動誤差修正抖動 通常被認為是跨圖像抖動顏色的最佳通用方法,因為它將產生與圖像中區域原始顏色最接近的近似值。它也是目前唯一可以抖動任何顏色集的方法,因此可以用於所有四種顏色簡化技術。有關更多詳細信息,請參見下面的 E-Dither 的工作原理。然而,誤差修正抖動有一些嚴重的 問題,尤其是在圖像動畫方面。最後兩種抖動技術有序擴散像素數位半色調 也被認為是一種很好的方法,並且非常適用於動畫,但目前它不能使用任何顏色集,只能使用一組固定的均勻顏色。它提供了一種使用圖案為圖像著色的方法,讓你能夠產生其他方法不容易產生的有趣效果。
顏色簡化的所有這些方面都是重要的技術,通過理解,你可以改進圖像操作的結果,超越 IM 提供的通用默認值。非常值得研究。

圖像中的顏色

有關圖像的信息,例如使用的顏色數量和整體分佈,對於試圖決定使用哪些最佳技術的程序和腳本來說非常重要。在這裡,我將介紹一些可以用於確定此類信息的方法,而不僅僅是用於顏色簡化。

提取影像色彩

提取顏色表

你可以使用詳細的 "identify" 從圖像中提取調色板,使用以下任何方法,這些方法基本上都做完全相同的事情。

  magick identify -verbose  image.png
  magick image.png miff:- | identify -verbose -
  magick image.png  -verbose -identify null:
  magick image.png  -verbose info:
如果顏色超過 1024 種,則上述任何詳細標識的輸出都不會返回顏色表或直方圖!因此,對於大型彩色圖像,這是一個碰運氣的事情,不推薦使用,儘管它仍然有用。
然而,更好的方法是生成圖像的 "histogram:" 並提取結果中包含的註釋。

  magick tree.gif  -format %c  -depth 8  histogram:info:-
[IM Output]
[IM Text]
info:”輸出格式已添加到 IM v6.2.4 中。對於此版本之前的 IM,請使用..

  magick tree.gif histogram:- | identify -depth 8 -format %c -
這些方法的問題在於,您會得到顏色的純文字輸出,您需要根據自己的需求進行解析。但是,從 IM v6.2.8-8 開始,「-unique-colors」運算器會將圖像轉換成一個較小的圖像,其中僅包含原始圖像中找到的每個唯一顏色的一個像素,全部排列在一行中。這表示您可以將圖像轉換成更簡單的顏色表圖像,列出存在的每種顏色。圖像的寬度返回顏色的數量,如果您需要實際列出顏色,您可以將其輸出為「txt:」圖像格式。例如,以下是樹木圖像的顏色表。

  magick tree.gif -unique-colors -scale 1000%  tree_colors.gif
  magick tree.gif -unique-colors -depth 16  txt:-
[IM Output]
[IM Text]
這個簡化的顏色表作為一種將生成的顏色色圖存儲在一個非常小的檔案中的方式也非常重要。這些色圖對於「-remap」色彩縮減運算器尤其重要。(請參閱下面的預定義顏色表)如果您希望獲得的圖像不僅包含圖像中的顏色,還包含顏色計數,這裡有一個從IM 論壇討論中開發的顏色直方圖解決方案。

  magick rose: -colors 256 -format %c histogram:info:- |
    sed 's/:.*#/ #/' |
      while read count color colorname; do
        magick -size 1x$count xc:$color miff:-
      done |
        magick - -alpha set -gravity south -background none +append \
                unique_color_histogram.png
[IM Output] ==> [IM Output]
請注意,我必須對圖像進行色彩縮減,因為內建的「rose:」圖像包含 3020 種獨特的顏色,這將花費很長時間並生成一個非常長的圖像。上面顯示的玫瑰 GIF 圖像包含相同的色彩縮減集。生成的圖像仍然包含相同數量的像素,儘管填充了額外的透明像素,並且正如您所見,顯示出以綠灰色、強烈的紅色以及非常強烈的純白色峰值為主。這可能不是最好的通用顏色直方圖方法,但它適用於此圖像。
histogram:」和「-unique-colors」運算器的顏色順序未定義,但似乎按紅色、綠色和最後藍色通道值排序。這對於特定圖像可能不是最好的方法,但通常不可能將 3 維顏色排序為 1 維順序。

提取平均顏色

可以使用「-scale」將圖像縮小到單個像素,從而非常快速地找到圖像的平均顏色。例如,這裡是內建「rose:」圖像的平均顏色。我使用FX Escape 格式輸出顏色,該格式返回可以直接在 IM 中使用的顏色字符串,而無需更改。

  magick rose: -scale 1x1\! -format '%[pixel:s]' info:-
[IM Text]
使用「%[pixel:...]FX Escape的問題在於,它可能會返回顏色名稱(例如「white」或「silver」),而不是 RGB 值。但是,您可以通過使用三個FX Escapes來模擬這一點,以返回所需位深度的實際 RGB 值。例如...

  magick rose: -scale 1x1\! \
     -format '%[fx:int(255*r+.5)],%[fx:int(255*g+.5)],%[fx:int(255*b+.5)]' info:-
[IM Text]
從 IM v6.3.9 開始,有許多新的「-format」escape可以用於提取有關圖像的更具體信息,而無需解析冗長的「identify」或「info:」輸出。例如,您可以通過從圖像的紅色通道圖像中獲取「%[mean]」灰度值來獲取平均紅色通道顏色。

  magick rose: -channel R -separate -format '%[mean]' info:
[IM Text]

提取特定顏色

從命令列中,有兩種基本方法可以從圖像中提取特定像素顏色。一種是在特定像素位置使用FX Escape(例如「%[pixel:...]」或「%[fx:...]」)(見上文)...

  magick rose: -format '%[pixel:p{40,30}]' info:-
[IM Text]
或者,您可以通過使用「-crop」剪切出您可能感興趣的單個像素來簡化圖像,並使用之前的任何方法。例如...

  magick rose: -crop 1x1+40+30 -depth 8 txt:-
[IM Text]

特定(或接近)顏色的計數

這可以用於獲取特定顏色的像素計數或百分比。你要做的是將不是該顏色的任何東西變成黑色,然後將該顏色變成白色。例如,讓我們獲取“樹”圖像中“yellow”太陽的顏色數量。

  magick tree.gif -fill black +opaque yellow \
                   -fill white -opaque yellow \
                   -print "yellow sun pixels = %[fx:w*h*mean]\n"   null:
[IM Text]
有一個需要注意的地方,如果測試的顏色本身是黑色,則它將不起作用。要處理黑色(或非常深的顏色),請交換填充以將非黑色顏色映射到白色,然後反轉結果以生成所有黑色像素的白色遮罩。請記住,“-print”選項等同於使用“-format ... -write info:”,並且可以在圖像處理中的任何位置使用。然後,我使用特殊的“null:”文件格式刪除了不需要的圖像。您也可以保存圖像以用作以後工作的遮罩。請注意,雖然這對於小圖像效果很好,但對於更大的圖像(如高分辨率數碼照片),“平均值”將不夠準確,無法獲得準確的像素計數!基本上,上述“平均值”的使用適用於生成比率,但不適用於精確的像素計數。要獲得準確的像素計數,最好使用具有準確像素計數的直方圖“註釋”輸出(見上文)。以上內容還可以使用“-opaque”運算符之前的模糊因子選項“-fuzz”來指定“接近”顏色。

比較兩種色彩

因此,您有兩種特定的顏色,並且想要比較它們。您可以使用“magick compare”獲取 RMSE(基於標準誤差)...

  magick compare -metric RMSE xc:Navy xc:blue null:
[IM Text]
這很好,因為它將為您提供兩種顏色之間的距離,無論是在值方面,還是在從黑到白的標準化距離百分比方面。但是,此方法無法正確處理透明度。例如,比較“完全透明的黑色”與“完全透明的白色”。

  magick compare -metric RMSE xc:'#0000' xc:'#FFF0' null:
[IM Text]
透明顏色實際上應該具有零距離,因為無論底色如何,完全透明都是相同的。相反,我們得到了 4 維超立方體距離)。因此,上述顏色距離方法僅適用於比較完全不透明的顏色。
除了獲得實際距離之外,您還可以使用模糊因子來檢查兩種顏色是否接近。

  magick compare -fuzz 20% -metric AE xc:Navy xc:Blue null:
  magick compare -fuzz 30% -metric AE xc:Navy xc:Blue null:
[IM Text]
但是請記住,如果像素不匹配(錯誤像素數),結果將為“1”。要獲得分隔這些值的實際“模糊”因子距離,您可以使用“FUZZ”指標。

  magick compare -metric FUZZ xc:Navy xc:Blue null:
[IM Text]
“標準化”值顯示實際距離為 28.7%。使用模糊因子與在涉及透明度時計算 RMSE 不同。也就是說,因為模糊因子被設計成將任何兩種完全透明的顏色視為相等。因此,“完全透明的黑色”和“完全透明的白色”完全相等(產生值 0 或無錯誤像素)...

  magick compare -metric FUZZ xc:'#0000' xc:'#FFF0' null:
[IM Text]
顏色比較的另一種方法是嘗試使用適當的模糊因子百分比替換顏色。例如...

  magick xc:Navy  -fuzz 20% -fill Blue -opaque Blue txt:
[IM Text]
由於“Navy”沒有變為“Blue”,因此它與“Blue”的差異超過 20%。而

  magick xc:Navy  -fuzz 30% -fill Blue -opaque Blue txt:
[IM Text]
這確實將顏色更改為“Blue”,因此我們現在知道“Navy”彼此相距 20% 到 30% 之間。要在腳本中執行此操作,請使用以下內容...

  fuzz=%1
  color1="red"
  color2="#e00"

  color2=`magick xc:"$color2" -format '%[pixel:s]' info:`
  result=`magick xc:"$color1" -alpha set -channel RGBA -fuzz $fuzz \
            -fill $color2 -opaque $color2 -format '%[pixel:s]' info:`
  if [ "$result" = "$color2" ]; then
    echo "Colors match according to Fuzz Factor"
  else
    echo "Colors DO NOT match"
  fi
特殊選項“-alpha set -channel RGBA”對於允許我們對透明和接近透明的顏色進行模糊匹配非常重要。

顏色量化

顏色量化運算符

顏色量化的主要工具,以及所有自動顏色簡化內部使用的工具,是「-colors」運算子。它實現了「自適應空間細分」顏色簡化演算法,這是一個非常好的顏色簡化演算法。以下是一個典型的例子,我有一個包含許多顏色的「色輪」圖像,我們要求 IM 使用各種抖動方法將顏色數量減少到僅 64 種顏色。

  magick colorwheel.png  -dither None       -colors 64  colors_64_no.gif
  magick colorwheel.png  -dither Riemersma  -colors 64  colors_64_rm.gif
  magick colorwheel.png  -dither FloydSteinberg \
                                             -colors 64  colors_64_fs.gif
[IM Output] ==> [IM Output] [IM Output] [IM Output]
IM 預設會使用「抖動」來對圖像上的顏色進行陰影處理。這樣可以防止顏色在平滑變化的漸層上發生突然變化。如果關閉抖動(使用「None」或「+dither」設定),您可以清楚地看到哪些顏色合併在一起以產生 IM 認為最適合此特定圖像的顏色集。您還可以查看如果未進行抖動,顏色漸層將產生的突然顏色變化。當然,此圖像使用的顏色比大多數圖像多得多。因此,雖然 64 種顏色的限制對於許多圖像來說通常是可以接受的,但對於此圖像來說是完全不可接受的。換句話說,顏色量化會嘗試為特定圖像找到最佳的顏色集。以下是一些 IM 標誌部分的顏色量化示例,使用了極少量的顏色。

  magick logo: -resize 40% -crop 100x100+105+50\! -normalize  logo.png
  magick logo.png  +dither             -colors 8  colors_8_no.gif
  magick logo.png  -dither Riemersma   -colors 8  colors_8_rm.gif
  magick logo.png  -dither FloydSteinberg \
                                        -colors 8  colors_8_fs.gif
[IM Output] ==> [IM Output] [IM Output] [IM Output]
將其與內建「rose:」照片圖像的一些結果進行比較。

  magick rose: +dither             -colors 16 colors_16_no.gif
  magick rose: -dither Riemersma   -colors 16 colors_16_rm.gif
  magick rose: -dither FloydSteinberg \
                                     -colors 16 colors_16_fs.gif
[IM Output] ==> [IM Output] [IM Output] [IM Output]
如您所見,卡通類圖像比真實照片需要少得多的顏色才能產生合理的結果。
IM 中目前僅實現了一種顏色量化演算法「自適應空間細分」,並且由於它運行良好,因此幾乎不需要添加其他演算法。但是,隨著回饋,該演算法正在穩步改進。

順帶一提:作為參考,「Gifsicle」程式列出了許多其他顏色量化方法(使用其「--color-method」選項)。我不知道這些顏色量化方法與 IM 相比如何。如果您找到有關不同顏色量化方法的良好參考,請發送郵件給我。

顏色量化內部

選擇在圖像中使用的有限顏色數量的過程稱為顏色量化,這是一個非常複雜的過程,涉及許多因素。ImageMagick 網站顏色簡化演算法中提供了完整的技術說明。但是,我將嘗試在此處說明其中一些更重要的方面。可能最大的因素是圖像中使用的實際顏色。如果圖像中很少有像素「接近」特定顏色,那麼為圖像選擇特定顏色是沒有用的。因此,顏色的選擇不僅取決於圖像中使用的顏色,還取決於「接近」該顏色的像素數量。我可以通過嘗試將兩個不同的雙色圖像簡化為單一共同顏色來輕鬆證明這一點。

  magick -size 4x1 xc:blue -draw 'fill red   point 0,0' \
                                                -scale 20 colors_rb.gif
  magick -size 4x1 xc:red   -draw 'fill blue point 3,0' \
                                                -scale 20 colors_br.gif
  magick colors_rb.gif  -colors 1  colors_rb2.gif
  magick colors_br.gif  -colors 1  colors_br2.gif
[IM Output] ==> [IM Output]
[IM Output] ==> [IM Output]
如您所見,最終的單一顏色不僅取決於存在的顏色,還取決於圖像中每種顏色的數量。

  magick -size 20x640  gradient: -rotate 90  gradient.png
  magick gradient.png   +dither  -colors 5   colors_gradient.gif
[IM Output]
請注意,顏色量化在當前色彩空間內是均勻的。
FUTURE: Just what are the effects of the "-treedepth"  setting?
Mail me if you know

顏色量化和色彩空間

影響選擇哪些顏色的另一個重要因素是準確定義我們所說的「接近」或「附近」的顏色是什麼意思。這由用於量化(顏色選擇)的色彩空間定義,並且(從 IM v6.2.8-6 開始)由「-quantize」色彩空間設定控制。「-quantize」設定在選擇的顏色數量非常少時變得尤為重要。為了說明這一點,讓我們使用各種不同的色彩空間並定義不同的「顏色距離」來簡化標準「色輪」圖像。

  for S in    RGB CMY sRGB GRAY \
              XYZ LAB LUV  \
              HSL HSB HWB  \
              YIQ YUV OHTA ; do \
     magick colorwheel.png   -quantize $S   +dither -colors 16 \
             -fill black -gravity SouthWest -annotate +2+2 $S \
             colors_space_$S.gif; \
  done
[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]
如您所見,所選顏色的組織方式很大程度上取決於色彩空間。 sRGB(紅、綠、藍)色彩立方體通常會至少選取接近主色的顏色。 sRGB 色彩空間非常擅長為卡通圖像和圖標選取顏色,但實際上對於一般的照片圖像來說卻是一個糟糕的色彩空間。 CMY 色彩空間與 sRGB 色彩空間完全相同,因為顏色通道只是簡單地反轉以在 sRGB 和 CMY 色彩空間之間進行轉換。 因此,量化顏色最終會得到大致相同的解決方案。
CMYK 色彩空間(未顯示)也會產生相同的結果,但原因不同。 因為在內部「K」通道和圖像「顏色表」使用相同的數據指針(請參閱 調色板通道),所以 IM 在量化之前會將其轉換回 CMY。

sRGB 色彩空間與 RGB 一樣會產生相似的結果,但經過調整以去除色彩空間中接近黑色的顏色數量。 因此,色輪中心可供選擇的顏色較少,從而產生更大的「不太黑」的斑點。 XYZ 色彩空間也非常類似於線性 RGB 色彩空間。 這裡最大的區別是顏色軸已經偏移,以便更好地包含我們能看到的所有可能顏色(甚至是我们通常看不到的顏色),因此色輪中的顏色數據會被壓縮得更多,結果是量化似乎變得更加分散。 LAB 和 LUV 色彩空間基於彼此不同但相似的顏色軸。 這導致顏色量化的排列方式不同。 涉及「色調」通道的特殊色彩空間,例如 HSL(色調飽和度、亮度)、HSL(色調、飽和度、亮度)和 HWB(色調、白色、黑色),都具有作為其色彩空間一部分的循環色輪表示。 實際上,生成此色輪使用的是 HSL 色彩空間。 請參閱 生成色輪
在撰寫本文時,IM 使用的顏色距離算法沒有考慮到色彩空間「色調」的循環性。 這方面的算法非常不同。 因此,在「紅色」路徑上會出現強烈的間斷,其中「色調」會循環,導致在顏色量化過程中選擇的紅色很少。
YIQ、YUV 的設計目的是產生更自然的「柔和」和「中間色調」的顏色,這些顏色更適合於照片和具有微妙色調的現實世界圖像,尤其是膚色。 Helmut Dersch 在 他的網站 上指出,您應該考慮使用 LAB 色彩空間進行扭曲。
在舊版本的 IM 中(特別是 IM 5 版),用於量化的色彩空間是使用「-colorspace」選項設置的。 然而,在 IM 6 版中,此運算符用於修改圖像在內存中的存儲方式,因此不是顏色量化的設置。

因此,在 IM v6.2.8-6 中,提供了「-quantize」設置來完成這項工作。 但是,它只是「-colors」(顏色量化過程)的設置。 它不會對使用「-remap」和「-posterize」等運算符或各種抖動技術進行的顏色替換和抖動產生任何影響。
如需可用的色彩空間完整清單,請參閱 "-colorspace" 運算子。您可以透過查看隨機純色點的範例,瞭解更多色彩空間對顏色選擇的影響。這些範例使用顏色量化來減少隨機影像中不同色彩空間的顏色數量。

量化不會保留顏色

請注意,在以上所有影像中,顏色量化實際上從未選取純黑色。請注意,影像中只有一個純黑色像素,而且無論如何都沒有太多接近黑色的顏色。因此,最終影像中出現的唯一黑色是稍後作為影像標籤的一部分添加的。即使是「GRAY」色彩空間影像也沒有產生純黑色。事實上,這些影像都不包含任何原色或次要顏色,例如:紅色、藍色、綠色、青色、洋紅色!唯一的例外是白色,因為這些影像確實包含了大量的純白色,使其成為「偏好顏色」(請參閱下文)。然而,這種情況並不是錯誤!首先,在上述範例中,通常不會選取「黑色」,因為原始影像中的黑色非常少,因此顏色量化通常不太擔心深色。事實上,它產生了更多較淺的顏色,因為這些顏色在影像中更常見。有關具體範例,請參閱上一節。其次,由於量化試圖選取與影像中現有顏色像素數量最多的顏色接近的顏色,因此最好不要匹配「純」原色或次要顏色,因為這些顏色始終位於所用色彩空間的最極端。 「偏色」往往比「原色」匹配更多顏色,因此它們被選中的頻率更高。所以讓我說清楚...
顏色量化("
-colors
") 通常會避免選取原色!
從 IM 版本 6.3 開始,顏色量化功能已修改為嘗試包含原始影像中非常常見的顏色。 因此,如果影像包含單一顏色的區域(例如上方的「白色」),則該顏色通常會包含在最終顏色表中。 這在一定程度上改善了情況,尤其是對於類似「卡通」的影像或具有純色背景的影像。 通常會選擇「純色」以幫助避免我們將在下方查看的抖動斑點顏色表解決方案中的特定顏色目前,只有幾種方法可以確保將「特定顏色」包含到所選顏色中以供稍後抖動。一種方法是照常對影像進行量化,但然後輸出生成的顏色表(使用「-unique-colors」)。現在,您可以調整該顏色表,使您的特定顏色確實是該顏色。最後,您可以使用重新映射顏色運算子使用提供的顏色表對影像進行抖動。顏色表可能不再是影像的最佳顏色,並且其他一些顏色也可能應該調整,但它會接近您想要的顏色表。或者,在使用「-colors」之前,附加(放大影像)要保留在影像中的特定顏色的大色塊。添加特定顏色的大「樣本」將使該顏色更有可能在最終顏色表中被選中。此外,所有其他顏色隨後將自動調整以更好地適應該顏色表)。如果這有效,則您添加的顏色樣本應保持不變(不抖動)。之後,您可以裁剪影像以移除添加的樣本。如果它不起作用,那麼 IM 至少應該添加了接近所需「特定顏色」的顏色,因此在對原始影像使用重新映射顏色之前只需要稍微調整生成的顏色表。如果您嘗試這樣做,無論成功還是失敗,請告訴我您的進展如何。理想情況下,我希望看到一種方法來指定少量必須是最終顏色表一部分的特定顏色,然後以某種方式要求 IM 為特定影像選擇顏色表中其餘顏色的最佳顏色。

色彩量化與透明度

ImageMagick 預設情況下不僅會生成完全不透明的顏色,還會嘗試生成半透明的顏色。這樣,包含透明陰影或其他疊加效果的影像不會失去這些效果。但是,從 IM v6.2.6 開始,涉及透明度的顏色量化已修改為將所有完全透明的顏色視為相同的顏色。這是一種線性修改,因此與完全不透明的情況相比,僅半透明的顏色也被認為更接近。由於這種修改,IM 顏色量化仍將生成半透明顏色,但會更多地關注影像中的不透明顏色,而較少關注完全透明的顏色。例如,我在這裡生成了一個彩虹漸變顏色,影像頂部完全不透明,底部完全透明。我在背景圖案上顯示了這些影像,以便您可以看到影像的透明程度。

  magick xc:red xc:yellow xc:green1 xc:cyan xc:blue \
          +append -filter Cubic -resize 100x100\!  -size 100x100 \
          gradient: -alpha off -compose CopyOpacity -composite alpha_gradient.png
  magick alpha_gradient.png  +dither  -colors 256  alpha_colors_256.png
  magick alpha_gradient.png  +dither  -colors 64   alpha_colors_64.png
  magick alpha_gradient.png  +dither  -colors 15   alpha_colors_15.png
[IM Output] ==> [IM Output] [IM Output] [IM Output]
如您所見,當我們要求 IM 減少此圖像所需的顏色數量時,它建立了更多的不透明顏色,並為更透明的部分使用了更少的完全透明顏色。結果是所選顏色的分佈非常好,尤其是在顏色數量非常少的情況下。但是,正如我上面所指出的,不僅不會選取原色,而且由於完全相同的原因,也不會選取完全透明的顏色。實際上,甚至不會選取完全不透明的顏色!換句話說,上一個範例中顏色量化圖像中的每種顏色都是半透明的。讓我說清楚。
當涉及透明度時,IM 顏色量化
可能不會選擇任何完全不透明的顏色,甚至完全透明的顏色!
當然,從 IM v6.3 和「常見顏色」錯誤修復(請參閱上面的量化不會保留顏色)開始,如果圖像包含許多不透明和完全透明的顏色(通常情況如此),則不太可能發生這種情況。由於某些圖像可能包含許多半透明顏色,例如涉及煙霧或陰影效果的圖像,因此您可能想進行試運行,以確保選擇完全透明的顏色以包含在生成的圖像中。然後,您可以將最透明的顏色映射到完全透明,然後自己執行重新映射顏色。如果您真的想確保生成的圖像中同時包含完全不透明和完全透明的顏色,則可以對 Alpha 色板執行歸一化或對比度拉伸。例如,在這裡,我通過使用「-contrast-stretch」來確保主要顏色選擇是不透明的。儘管對於更正常的情況來說,這可能有點過於繁瑣。

  magick alpha_gradient.png  +dither  -colors 15 \
          -channel A -contrast-stretch 10%  alpha_colors_15n.png
[IM Output] ==> [IM Output] ==> [IM Output]
這對於不允許半透明顏色的 GIF 圖像、不允許透明度的 JPG,甚至不需要量化即可正確保存的 PNG 來說都不是問題。僅當涉及大量半透明顏色時,您可能會強制減少圖像中的顏色時,這才會成為一個問題。請記住,對於 GIF 格式,保存半透明顏色是徒勞的。因此,如果您計劃自己對此類圖像格式進行顏色量化,則需要告訴 IM 在生成其縮減的顏色集時忽略圖像透明度。您可以通過使用特殊的「-quantize」顏色空間設置「transparent」來做到這一點。

  magick alpha_gradient.png -quantize transparent \
                            +dither  -colors 15   alpha_colors_15qt.png
[IM Output] ==> [IM Output]
請注意,色彩量化完全忽略顏色的透明度,並且完全沒有觸及圖像的 Alpha 色板。這表示您可以用更適合您圖像的方式處理 Alpha 色板,完全獨立於其他顏色。事實上,您可以在使用「-colors」之前或之後執行此操作,而不會有任何問題。結果不會有任何差異。因此,當您要將圖像儲存為使用布林值或不透明格式(例如 GIF 或 XPM 圖像格式)時,建議使用此量化色彩空間來減少圖像的顏色數量。如果您計算產生的顏色數量,您還會發現它產生的顏色數量與要求的完全相同。因此,如果您也需要完全透明的顏色(很可能),那麼您需要將「-colors」的參數至少減少 1,以便在圖像最終的顏色表中為其留出空間。因此,要處理 GIF 檔案格式的 256 色顏色表限制,您需要將顏色減少到 255 色,而不是 256 色,為「-transparent-color」設定定義的完全透明顏色索引留出額外的空間。請針對較小的顏色表大小調整此設定。當 IM 儲存為 GIF 檔案格式時,此量化行為會自動執行,但當您在產生全域或共用顏色表時需要自行進行量化時,這一點就很重要。當然,您仍然需要處理半透明像素,以便它們符合您想要的圖像外觀。
FUTURE: This last part will probably move to a new section on 'Dithering
Alpha Channel' to be created in the near future. And a reference to this
section added here. 
以下是一些僅將 Alpha 色板抖動為布林值或開/關設定的範例,而不會影響圖像中的其餘顏色通道。

  magick alpha_gradient.png \
          -channel A   -threshold 50%       alpha_dither_threshold.gif
  magick alpha_gradient.png \
          -channel A -ordered-dither checks alpha_dither_checks.gif
  magick alpha_gradient.png \
          -channel A -ordered-dither o8x8   alpha_dither_ordered.gif
  magick alpha_gradient.png \
          -channel A -ordered-dither h8x8a  alpha_dither_halftone.gif

  magick alpha_gradient.png -channel RGBA -separate \
          \( +clone -monochrome \) \
          +swap +delete -combine alpha_dither_monochrome.gif
  magick alpha_gradient.png -channel RGBA -separate \
          \( +clone -dither FloydSteinberg -monochrome \) \
          +swap +delete -combine alpha_dither_monochrome_fs.gif
  magick alpha_gradient.png -channel RGBA -separate \
          \( +clone -remap pattern:gray50 \) \
          +swap +delete -combine  alpha_dither_map.gif
  magick alpha_gradient.png -channel RGBA -separate \
          \( +clone -dither FloydSteinberg -remap pattern:gray50 \) \
          +swap +delete -combine  alpha_dither_map_fs.gif
[IM Output] [IM Output] [IM Output] [IM Output]
[IM Output] [IM Output] [IM Output] [IM Output]
當您抖動 Alpha 色板的副本時,您可以使用「-monochrome」或「-remap」進行抖動,請確保圖像是純灰階圖像,而不是包含透明度的形狀遮罩。如果您不這樣做,您最終可能會因為 Alpha 色板仍然存在而產生非線性效應。

您可以使用多種方法從圖像中提取和還原 Alpha 色板,作為灰階遮罩,以便進行抖動。以上使用通道分離組合來執行此操作。其他方法則使用Alpha 提取複製不透明度合成

錯誤校正抖動

如前言所述,錯誤校正抖動通常被認為是在減少的顏色集中產生原始圖像最真實表示的最佳選擇。它還將自身限制在任何預先定義的顏色調色板中,無論是使用者提供的,還是由 IM 顏色量化常式確定的。因此,它是 IM 運算子提供的通用顏色縮減的邏輯預設選擇,「-colors」、「-remap」、「-posterize」和「-monochrome」。

誤差擴散抖動方法

從 6.4.2-9 版開始,IM 現在提供多種抖動樣式或方法,可以使用「-dither」設定進行選擇。在此之前,IM 僅限於使用Riemersma 抖動希爾伯特曲線抖動的變體,您可以使用「-dither Riemersma」進行設定。現在,您也可以使用「-dither FloydSteinberg」選擇 Floyd-Steinberg 抖動。您可以使用以下方法查看您的 IM 版本中實作了哪些類型的抖動方法...

  magick -list dither
[IM Text]
例如,以下是使用不同抖動方法抖動的色輪。

  magick colorwheel.png -dither Riemersma      -colors 16 dither_riemersma.gif
  magick colorwheel.png -dither FloydSteinberg -colors 16 dither_floyd.gif
[IM Output] [IM Output]
如您所見,Floyd-Steinberg 抖動比默認的 Riemersma 抖動產生更均勻的抖動圖案。它們之間最大的區別在於它們各自如何分配相鄰像素之間的“顏色誤差”。那麼,讓我們來看看 E-Dither 是如何工作的。

誤差擴散抖動的運作方式

重新編寫中
IM 用於一般抖動的特定方法是「希爾伯特曲線誤差修正抖動」的變體。這實際上是一種非常好的抖動技術,定義明確且速度相當快。如需完整說明(以及非常相似的變體),請參閱... Riemersma 抖動。基本上,圖像中的每個像素都是按照稱為「希爾伯特曲線」的非常複雜的路徑進行查看的。為像素分配與該像素值最接近的顏色,並且將像素原始顏色與所選顏色之間的任何差異保存並添加到下一個像素的顏色值(始終是相鄰像素)中,然後再次選擇新顏色。通過這種方式,所選顏色與圖像原始顏色之間的任何顏色變化都會分佈到同一區域中的其他像素。結果是,雖然只會將特定顏色分配給最終圖像,但該區域的基本整體顏色將與原始圖像非常匹配。例如,這是一個小的灰色圖像,我要求 IM 使用不包含原始顏色的顏色集進行抖動。生成的圖像被放大,以便您可以看到分配的單個彩色像素。

  magick -size 10x10 xc:'#999999' -scale 80x80  dither_not.gif
  magick -size 10x10 xc:'#999999' \
          -remap colortable.gif   -scale 80x80  dither.gif
[IM Output] ==> [IM Output]
如您所見,由於原始圖像的顏色不在指定的顏色表中,因此使用給定顏色表中三個最接近顏色的圖案來近似原始顏色。 如果我們要平均上述抖動圖案產生的顏色,我們將得到顏色 [IM 文字],這與圖像原始平均顏色 [IM 文字] 非常接近,這就是產生的抖動圖案的全部意義所在。然而,由於用於分配顏色的“路徑”很複雜(儘管通常保留在局部區域),因此顏色分配會產生基本隨機的圖案。然而,從技術上講,它並不是隨機的,因為相同的圖像會產生相同的圖案,但結果也可能是隨機的,或者至少是偽隨機的。「F-S」抖動實際上只是自 1970 年代初創建以來開發的幾種「柵格化 E-抖動」中的一種(第一種)。它也可能是實施最廣泛的,儘管它不被認為是最好的。有關此類算法的更完整摘要,請參閱論文 抖動算法。從 IM v6.4.3 開始,它也可以直接在 IM 中使用,並且其實現方式是按照從圖像頂部到底部的逐行“蛇形”路徑。

  magick -size 10x10 xc:'#999999'  -dither FloydSteinberg \
          -remap colortable.gif   -scale 80x80  dither_fs.gif
[IM Output] ==> [IM Output]
我發現「Floyd-Steinberg 抖動」特別是產生了比「希爾伯特曲線抖動」更像“雜湊”的像素圖案,實際上它就是這樣設計的。這種規則的圖案可以使小型彩色圖標圖像的低級手動清理變得容易得多。這是我過去在 Anthony 的圖標庫 中經常做的事情,但現在通常不再需要這種事情了,除了可能的小型單色圖像。

E-抖動問題 - 對變化敏感

使用誤差校正抖動時面臨的最大問題之一是您會得到一個基本隨機的像素圖案,該圖案對變化也非常敏感。例如,在這裡採用原始的灰色圖像,並在再次抖動之前將一個像素替換為不同的顏色。結果是希爾伯特曲線抖動所遵循的路徑上更遠處的每個像素的抖動圖案都發生了完全變化。

  magick -size 10x10 xc:'#999999' -draw 'fill #C28 point 2,2' \
          -remap colortable.gif   -scale 80x80   dither_modified.gif
  magick compare dither.gif dither_modified.gif dither_difference.gif
[IM Output]
原始抖動
[IM Output]
一個像素的變化
==>
 
[IM Output]
變化的比較
如您所見,僅在圖像中添加一個像素就會導致抖動模式發生巨大變化!即使圖像的整體外觀(未放大時)基本相同(這畢竟是良好抖動算法的目的),結果圖像也只需要一位更改就會變得不同。「magick compare」圖像還顯示了抖動模式的變化程度。在這種情況下,大約 80% 的像素被分配了完全不同的顏色。在希爾伯特曲線抖動中,單個像素的變化實際上會導致之後的每個像素都可能不同,這意味著 0% 到 100% 的抖動模式可能不同。這僅取決於變化發生在複雜希爾伯特曲線中的哪個位置。然而,Floyd-Steinberg 抖動僅沿一個方向進行圖像處理,因此單個像素的變化只會修改變化一側的模式。

  magick -size 10x10 xc:'#999999' -draw 'fill #C28 point 2,2' \
          -dither FloydSteinberg -remap colortable.gif \
          -scale 80x80   dither_fs_modified.gif
  magick compare dither_fs.gif dither_fs_modified.gif dither_fs_difference.gif
[IM Output]
FS 抖動
[IM Output]
一個像素的變化
==>
 
[IM Output]
變化的比較
如您所見,它也存在完全相同的問題。單個像素的變化會導致在該像素之後處理的圖像區域的抖動模式幾乎完全改變。也就是說,從那一行向下。對於單個圖像,抖動顏色的結果模式並不重要。圖案的平均顏色應使圖像具有該圖像區域的適當顏色。但是,當您有一個動畫,其中一個圖像後面跟著其他非常相似的圖像,並且有大面積的恆定顏色時,變化的抖動圖案就會變得非常明顯,並且會作為低水平的背景「噪音」而令人煩惱。例如,這裡我生成了相同抖動顏色的 3 個圖像動畫,但每幀有一個像素的變化。我還放大了一個中心區域,以便您可以更清楚地看到這種變化的模式。

  magick -size 80x80 xc:'#999999' \
          \( +clone -draw 'fill #C28 point 2,2' \) \
          \( +clone -draw 'fill #28C point 2,2' \) \
          -remap colortable.gif  -set delay 50 -loop 0   dither_anim.gif
  magick dither_anim.gif -crop 10x10+40+40 +repage \
                              -scale 80x80     dither_anim_magnify.gif
[IM Output] ==> [IM Output]
如您所見,您會看到圖像背景中出現一種攪動,這是由 E-Dither 生成的偽隨機性引起的。在大多數情況下,使用的顏色彼此足夠接近,因此不會使這種“抖動噪聲”可見。但是當抖動顏色明顯不同時(在這種情況下是由於使用了顏色表而強制執行的),它肯定會成為一個問題。有關顯示此“抖動噪聲”的動畫的更實際示例,請參閱視頻色彩優化。模式的變化還會導致動畫優化出現問題。也就是說,不同的模式意味著簡單的幀優化無法減少幀疊加的大小。有關一種解決方案,請參閱模糊顏色優化,儘管這僅在攪動使用非常相似的顏色時才有效。
與其他抖動方法(例如閾值有序抖動)不同,「-channel」設置不會影響顏色量化或誤差校正抖動。基本上它在這些圖像操作的工作方式中沒有地位。
有序抖動沒有任何這些問題,包含對變化緊鄰區域的變化。不幸的是,通常也限於使用數學導出的顏色集。(請參閱使用統一顏色表的有序抖動)。

誤差擴散抖動的像素斑點

E-Dithers 的另一個問題是,它們可能會在原本顏色相當均勻的區域中產生偶爾出現的奇怪顏色像素。例如,灰階影像中偶爾出現的綠色像素。或者如下面的範例所示,在原本是純藍色的區域中出現白色像素。這在包含具有大量顏色的物件以及其他純色不變區域的大型影像中尤其如此。這在彩色物件疊加在平面彩色背景上的情況下尤其典型,就像您經常在圖表和繪圖中看到的那樣。您可以在上面測試範例的放大圖中看到這樣一個奇怪顏色的像素,其中一個額外的淺紫色像素被添加到距離小的單個像素更改相當遠的地方。然而,添加到上面圖像中的奇怪顏色像素並不明顯,並且顏色表確實很好地覆蓋了影像,因此奇怪的像素與用於對影像進行抖動的正常三種顏色相當接近。對於更極端的例子,這裡我有一個模糊的漸變背景,我將其顏色大量減少到 64 種顏色,以真正強調誤差校正抖動。

  magick -size 100x60 xc:SkyBlue \
          -fill DodgerBlue -draw 'circle 50,70 15,35' \
          -fill RoyalBlue  -draw 'circle 50,70 30,45' \
          -blur 0x5  -colors 64     speckle_gradient.gif
[IM Output]
正如您在這個高度縮減的顏色表中看到的那樣,誤差校正抖動在表示原始漸變方面做得相當不錯。但是,如果我們在上面添加一塊純白色...

  magick -size 100x60 xc:SkyBlue \
          -fill DodgerBlue -draw 'circle 50,70 15,35' \
          -fill RoyalBlue  -draw 'circle 50,70 30,45' -blur 0x5 \
          -fill white -draw 'rectangle 40,40 60,55' \
          -colors 64   speckle_problem.gif
[IM Output]
您可以看到 E-dither 突然開始在我們之前沒有的影像上部區域產生一些白色像素。
這裡是放大部分的放大圖,因此您可以更清楚地看到這些像素...

  magick speckle_problem.gif -crop 15x15+75+0 +repage \
          -scale 90x90    speckle_prob_mag.gif
[IM Output]
奇怪的顏色像素是由兩個因素造成的。首先,顏色量化被迫在影像的最終顏色表中包含單一的純白色(但沒有其他白藍色反鋸齒顏色),從而允許抖動過程使用這種額外的顏色。但是由於 E-Dithers 會慢慢累積誤差,尤其是在極端顏色的區域中,例如在上面影像的頂部。最終,誤差將累積到一個足以使一種額外顏色最接近的值。因此,每隔一段時間就會在偽隨機位置輸出一個高對比度的白色像素來“校正誤差”。結果是白色像素的非常輕微的斑點。誤差累積越慢,這些白色像素的分佈就越分散,它們出現的位置就越“不合適”。**最佳解決方案**是切換到其他沒有有限顏色表的影像格式。例如,將您的 GIF 格式影像轉換為 PNG。這將避免顏色量化(減少)的需要,因此也避免了對減少的顏色進行抖動的需要。下一個解決方案是用其他一些“本地化”任何誤差的抖動方法來替換 E-dither 的使用,例如有序抖動。然而,這在目前 IM 中並不容易應用。有關一種此類方法,請參閱更好的有序抖動結果,直到找到更通用的方法。如果切換到另一種影像格式或使用不同的抖動方法不可行(而且通常不可行),那麼您就只能嘗試針對該特定影像解決問題。**最好的解決方法**是以某種方式確保在導致 E-Dither 誤差累積的大量顏色組之外還有其他顏色。然而,正常的顏色量化不會這樣做。它傾向於選擇一組表示顏色組的平均顏色。我們需要的是額外的顏色來“圍繞”大型顏色組的邊緣,而不是簡單的平均顏色。例如,在這裡我使用了一個圓圈而不是一個正方形,這樣不僅添加了純白色,還添加了许多白藍色。由於圓形邊緣的反鋸齒處理,這些顏色會自動添加,以使其外觀更平滑。

  magick -size 100x60 xc:SkyBlue \
          -fill DodgerBlue -draw 'circle 50,70 15,35' \
          -fill RoyalBlue  -draw 'circle 50,70 30,45' -blur 0x5 \
          -fill white -draw 'circle 50,45 40,40' \
          -colors 64  speckle_fixed.gif
[IM Output]
以及與之前相同區域的放大圖。

  magick speckle_fixed.gif -crop 15x15+85+0 +repage \
          -scale 90x90    speckle_fix_mag.gif
[IM Output]
如您所見,額外的顏色提供了藍色-青色漸層之外的更多顏色。雖然這些額外的顏色意味著可用於實際漸層的顏色會減少,但它們確實提供了其他藍白色,允許 E-dither 更快、更頻繁地自我校正,以避免累積誤差過大。也就是說,我們並不是要防止 E-dither 的斑點,只是為抖動演算法提供更好的顏色來處理。如果您仔細觀察圖像的放大部分,您仍然會看到斑點圖案,但顏色更接近背景顏色,而且它們的數量更多,產生了更均勻的斑點分佈。另一種方法是生成我們自己的顏色表,也許基於 IM 生成的顏色表,並添加適當的顏色以防止誤差累積。然而,這並不容易做到,尤其是在三維色彩空間中。對於這個特定的圖像示例,防止「斑點」的一種方法是使用略少的顏色單獨生成和抖動背景,然後覆蓋白色方塊及其附加顏色。

  magick -size 100x60 xc:SkyBlue \
          -fill DodgerBlue -draw 'circle 50,70 15,35' \
          -fill RoyalBlue  -draw 'circle 50,70 30,45' -blur 0x5 \
          -colors 63 \
          -fill white -draw 'rectangle 40,40 60,55'  speckle_perfect.gif
[IM Output]
這會在圖像中添加「白色」,但背景不會有任何斑點效果,因為在使用誤差校正抖動時白色不可用。結果是圖像正好有 64 種顏色,並且完全沒有斑點。然而,這非常取決於圖像和您想要實現的目標,因此並不是解決斑點問題的通用解決方案。
添加額外顏色的更普遍的替代方法是嘗試從最終抖動的圖像中去除斑點。也就是說,以某種方式清理圖像。然而,這本身就是一個棘手的問題,因為您不希望刪除作為正常抖動圖案一部分的像素。我們需要做的是找到與周圍所有顏色截然不同的彩色像素,但這些像素也被某種距離與所有其他相似顏色很好地隔離。 您是否有更好的圖像濾鏡解決方案? 摘要對我來說,斑點是一個非常惱人的問題,特別是對於使用非常有限的顏色表的桌面圖標圖像。我自己經常編輯較小的「圖標」圖像,以消除斑點或修復其他一些抖動效果,例如垂直條紋。如果您知道其他更好的解決方案,請告訴我。

單色抖動點陣圖影像

-monochrome」運算符是「-colors」運算符的特殊形式,用於生成點陣圖圖像。因此,它是一個理想的運算符,不僅可以演示「希爾伯特曲線抖動」,還可以更仔細地觀察顏色選擇。以下是一個典型示例。

  magick logo.png  -monochrome     monochrome.gif
[IM Output]
該運算符僅根據其灰階亮度「強度」或「級別」對圖像進行抖動,但它不會直接抖動整個灰階範圍,而是將最極端的值閾值化為其最大值。我們可以通過要求 IM 對漸變圖像進行抖動來看到這一點。

  magick -size 15x640 gradient: -rotate 90 \
                   -monochrome     monochrome_gradient.gif
[IM Output]
如您所見,漸變只有大約中間 50% 的顏色被「-monochrome」運算符抖動。特別感謝 Ivanova <flamingivanova@punkass.com> 指出了 IM 工作原理的這個有趣事實。如果您想使用整個灰階範圍進行抖動,可以使用「-remap」運算符,並使用純黑白顏色圖(由內置圖案圖像提供)。

  magick logo.png  -remap pattern:gray50  mono_remap.gif
  magick -size 15x640 gradient: -rotate 90 \
                   -remap pattern:gray50     mono_remap_gradient.gif
[IM Output]
[IM Output]
通過使用「-remap」更仔細地選擇顏色,您可以有效地生成與「-monochrome」運算符相同的「閾值」範圍,或您喜歡的任何其他閾值範圍。

  magick xc:gray20  xc:white  +append   ctrl_colors.gif
  magick logo.png -colorspace Gray \
          -remap ctrl_colors.gif  -normalize  mono_remap_ctrl.gif
  magick -size 15x640 gradient: -rotate 90 \
          -remap ctrl_colors.gif  -normalize  mono_remap_grad_ctrl.gif
[IM Output]
[IM Output]
-monochrome」 的實際作用是先將給定的圖像轉換為灰階圖像,然後執行雙色「色彩量化」,以決定用於對圖像進行抖動的閾值顏色。下一節的範例將探討這個部分。
目前「+dither」設定對「-monochrome」的結果沒有影響。 然而,這在未來可能會有所改變,因此在使用此運算子時,請確保在腳本中沒有將其關閉。

雙色量化

您可以使用色彩量化來選擇圖像中最佳的兩種顏色,而不是自己選擇兩種控制顏色,方法是使用「-colors」運算子。

  magick logo.png   -colors 2 -colorspace gray  -normalize \
                                                 colors_monochrome.gif
[IM Output]
但是,結果將與使用「-monochrome」不同,因為我們沒有先將圖像轉換為灰階。而是直接在選擇的兩種非灰色值之間對圖像進行抖動。也就是說,選擇了最佳的兩種顏色來對圖像進行抖動,而不是兩個灰階亮度級別。因此,對於例如僅使用大約相同灰階「級別」顏色的圖像,它將產生更好的結果。例如,在這裡我們對紅藍漸層使用「-colors」,以及「-monochrome」位圖抖動運算子。 正如您所看到的,結果並不相同。

  magick -size 20x640 gradient:red-blue -rotate 90    gradient_rb.png
  magick gradient_rb.png   -colors 2 -colorspace gray \
                                -normalize        colors_threshold.gif
  magick gradient_rb.png       -monochrome       mono_threshold.gif
[IM Output] [IM Output] [IM Output]
由於藍色和紅色具有非常接近的強度,因此上述「-monochrome」運算子無法找到與位圖抖動的任何差異。 然而,使用「-colors」量化方法可以毫無問題地找到可接受的顏色來進行抖動。 您還可以發現只有中間部分的顏色被抖動了。 這是因為色彩量化在其選擇的兩個顏色「群集」的中間選擇了顏色。 因此,位於選定顏色「外部」的顏色實際上會直接閾值化為該顏色,而無需抖動。 這表明量化顏色空間外部的顏色不會被抖動,儘管這一事實很難在實際中加以利用。
通過在量化之前將「-colorspace」設置為灰階,您將重現「-monochrome」運算子的內部操作。

  magick logo.png -colorspace gray   -colors 2  -normalize \
                                                 monochrome_equivelent.gif
[IM Output]
最後,通過關閉抖動,您可以比使用固定的「-threshold」設置產生更自動的圖像顏色分離。

  magick logo.png  -colorspace gray  +dither  -colors 2  -normalize \
           threshold_two_grays.gif
[IM Output]
請記住,「-monochrome」目前會忽略「+dither」設定,因此您不能僅使用該運算子來執行「智能閾值」。
如果刪除圖像處理色彩量化階段的「-colorspace」,您可以根據該圖像可能的最佳顏色分離(而不是灰階顏色分離)對圖像進行閾值處理。

  magick logo.png  +dither  -colors 2  -colorspace gray -normalize \
           threshold_two_color.gif
[IM Output]

使用預先定義的調色盤進行抖動

如上所示,「-colors」會嘗試選擇一組最佳的有限顏色來呈現圖像。使用「-remap」時,您可以為 IM 提供要用於圖像的最終顏色集,無論您是打算對這些顏色進行抖動,還是僅將其替換為最接近的顏色。參數以包含您要使用的所有顏色的圖像形式給出。如果您要將大型彩色圖像縮減為僅包含其顏色列表,則可以使用「-unique-colors」,然後再使用「-remap」保存以供日後使用。
請注意,雖然「-remap」運算子接受任何要使用的圖像,但請勿將 JPEG 圖像用於此圖像,否則由於其「有損壓縮」會產生額外的顏色,因此您會得到很多額外的顏色。

另一方面,使用 JPEG 生成額外的顏色可能有助於解決之前看到的「斑點」問題!
例如,在這裡,我將 IM 標誌中使用的顏色限制為預定義的已命名 X 視窗顏色映射。默認值是「Riemersma」抖動,但從 IM v6.4.4 開始,「-dither」已擴展為允許選擇其他抖動方法,例如「FloydSteinberg」。當然,您仍然可以使用「+dither」選項關閉抖動。

  magick logo.png  -dither None       -remap colortable.gif  remap_logo_no.gif
  magick logo.png  -dither Riemersma  -remap colortable.gif  remap_logo_rm.gif
  magick logo.png  -dither FloydSteinberg \
                                       -remap colortable.gif  remap_logo_fs.gif
[IM Output]  + [IM Output] [IM Output] [IM Output] [IM Output]
如您所見,IM 嘗試使用給定的顏色合理地呈現圖像,儘管結果遠不如允許 IM 選擇要使用的顏色集時獲得的圖像好。請注意,這個「colortable.gif」圖像從未設計用於抖動圖像,而是作為一組顏色,用於為更原始的舊式 X 視窗彩色顯示器設計卡通風格的彩色圖標(有關詳細信息,請參閱Anthony 的 X 視窗圖標庫AIcons 顏色選擇)。另請注意,最終圖像並未使用此映射提供的全部 32 種顏色,儘管當啟用某種形式的抖動時(分別為 ),映射中將使用更多顏色,而不是關閉抖動時()。最後一個範例顯示了選擇良好的顏色映射是多麼重要。因此,我建議您讓 IM 使用「-colors」運算子最佳化圖像中使用的顏色選擇,並根據您的需要進行修改,除非您有更迫切的理由不這麼做。最後一點,雖然您可以指定「-colors」將在其中找到最佳顏色集的色彩空間,但您目前無法為顏色映射或抖動階段定義色彩空間。我所有的實驗似乎都表明,顏色集的應用(誤差校正抖動和最近顏色替換)是基於 RGB 空間。「-quantize」色彩空間設定僅用於選擇顏色,而不用於映射顏色。因此,如果使用顏色映射是個壞主意,為什麼還要使用它?有一些常見的原因,通常是因為您需要更多地控制圖像中使用的特定顏色調色板。另一位使用者也將顏色映射分離出來,以便他可以在 Risograph(一種數位印刷系統)上使用它。*如果您知道我下面沒有提到的使用「-remap」運算子的另一個原因 - 請發送郵件給我。*

常用或「最佳」調色盤

在處理多個圖像時,另一種技術是為所有涉及的圖像生成一個通用的顏色表。基本上,您將所有圖像附加在一起成為一個大圖像,然後使用「-colors」運算子找出一個適用於所有圖像的良好顏色映射。獲得該顏色映射圖像後,您可以使用它使用這個剛生成的預定義顏色映射為每個原始圖像重新著色。或者,您可以使用特殊的「+remap」運算子,它對 255 色的顏色映射執行相同的操作。它會計算顏色數量,執行顏色量化以形成良好的通用顏色映射,然後在需要時對圖像進行抖動以使用該映射。但是,「-remap」和「+remap」形式都有一個對 GIF 動畫非常重要的功能。它會將所有圖像轉換為「-type」為「Palette」的圖像,並且所有圖像都使用相同的顏色調色板。原因是,在寫入 GIF 圖像時,第一個圖像的顏色調色板將用於檔案格式的「全域顏色映射」。然後,在寫入每個圖像時,它會注意到這些圖像使用相同的顏色集,因此它不會建立「本地顏色映射」。這可以為最終 GIF 檔案中的每個圖像節省高達 256 × 3 或 768 位元組的顏色映射空間。只有「-remap」運算子可以做到這一點。因此,在處理 GIF 時,特別是 GIF 動畫時,這一點很重要,需要牢記。有關更多詳細資訊和範例,請參閱GIF 動畫,全域顏色表

網頁安全顏色

在 WWW 創建之初,電腦顯示器的可用顏色範圍有限,而且網頁瀏覽器通常對圖像使用一組較簡單的顏色。因此,通常會將圖像重新著色為此顏色集,以使其體積更小,並確保它們在用戶瀏覽器上看起來正常。如需更多詳細資訊,請參閱網頁樣式指南,抖動。為了幫助實現這一點,IM 提供了這個特殊 216 色表的內建色圖圖像,稱為「netscape:」。因此,讓我們看看我們的測試圖像在使用這些顏色的舊網頁瀏覽器顯示器上看起來如何。

  magick logo.png         -remap netscape:  remap_netscape.gif
  magick logo.png +dither -remap netscape:  remap_netscape_nd.gif
[IM Output]  + [IM Output] [IM Output] [IM Output]
這個顏色集是由顯示器和電腦工程師設計的數學確定的調色板,而不是平面藝術家設計的,雖然它足夠通用,可以很好地用於照片等真實圖像,但對於包含大面積平面顏色的圖像來說非常糟糕,例如徽標、背景、電腦生成的圖像(如圖表)和卡通圖像。基本上,這適用於顏色變化很大的區域,但對於較大的恆定顏色平面區域,會應用三種顏色(通常)的抖動,例如 IM 徽標測試圖像(上圖)的淡藍色襯衫。換句話說,如果您要設計用於網頁的圖像或徽標,您通常會嘗試在大的平面區域中使用此調色板中的顏色,並且僅在顏色深淺不同的區域中使用抖動顏色。您可以使用上述命令測試圖像在更原始的電腦顯示器上的顯示效果,並編輯圖像以使用這些顏色,以便它們能夠正常工作。這對於符號和導航圖像尤其重要。當然,如今,由於遊戲和網路用戶的需求,您可以非常確定大多數用戶都擁有沒有這些舊顏色限制的現代電腦顯示器,但是這種「網頁安全調色板」的使用仍然存在,因為它確實還有其他好處,例如圖像壓縮。有關在現代世界中使用網頁安全顏色的討論,請參閱網頁安全調色板之死?,以及可能更重要的觀點,來自第一個識別此顏色圖的平面設計師,Lynda Weinman

生成顏色圖

為任何圖像或一組特定圖像確定良好的顏色圖可能非常重要。當您處理將用於 GIF 動畫的圖像序列時,這一點尤其重要。基本上,您希望使其僅需要一個顏色表,即可用於動畫的所有幀,而不是為每一幀使用單獨的顏色表。換句話說,您希望所有圖像都使用一個顏色圖。在這種情況下,您實際上只有兩種選擇。您可以嘗試創建一個適用於任何圖像的顏色圖,也可以嘗試針對您要應用的特定圖像集優化顏色圖。

網頁安全顏色圖

[IM 輸出] 第一種方法通常是數學產生的顏色表,例如 IM 內建的「netscape:」顏色表。這提供了 216 種顏色,可以很好地放入 GIF 格式的 256 色限制內,並且仍然有空間處理圖像透明度,甚至可以為特殊目的添加一些額外的顏色,例如陰影或文字疊加。此顏色表是透過為三個顏色通道中的每一個通道創建 6 個級別的顏色而生成的,產生 6×6×6 種顏色或 216 種顏色。野獸的數量。由於僅使用了 219 種顏色,因此它仍然有空間(對於 GIF 圖像)為特定目的向顏色表添加更多顏色。例如,透明顏色以及更多灰階陰影。實際上,舊的 Macintosh 版本的網路安全顏色表正是這樣做的,試圖改善其整體效果,但它僅用於 Macintosh 網路客戶端。由於其簡單性及其在全球資訊網上的普遍使用,這可能是最常見的「均勻」(或數學推導的)顏色表。

均勻 332 顏色表

另一個常用的均勻顏色映射是「332 RGB 顏色表」。該數字指的是用於表示 8 位顏色索引中每種顏色的位數。也就是說,3 位(或 8 級)紅色,3 位綠色和 2 位(或 4 個顏色級別)藍色,因為我們的眼睛對藍色的反應不佳。這給出了 3+3+2 位或 8 位顏色索引,或 256 種顏色。非常適合有限的 GIF 顏色表。但是,它不會為 GIF 透明色或其他特殊用途顏色留出任何空間。以下是讓 IM 生成此顏色表的一種方法...

  magick -size 16x16 xc: -channel R -fx '(i%8)/7' \
                          -channel G -fx '(j%8)/7' \
                          -channel B -fx '((i>>3&1)|(j>>2&2))/3' \
          -scale 600% colormap_332.png
[IM Output]
在 IM 版本 6.2.9-2 之前,「-fx」運算符中缺少位移運算符「>>」和「<<」。
一種更簡單的方法是使用操作「-ordered-dither threshold,8,8,4」(請參見示例區域)使用均勻顏色級別的有序抖動。與上述 DIY FX 方法相比,這是一種更容易、更快的技術,甚至允許您使用其他內建抖動映射來更好地處理漸變。此映射的唯一缺點是它實際上根本不提供任何「灰色」。但是,當使用抖動時,這個缺點可能是一個優點,因為輕微的顏色差異減少了灰階漸變中顏色邊界變化的影響,使其看起來更加平滑。

真彩色 16 位顏色表

X Window 在很少使用的 16 位視覺類別中使用了與上述「332 顏色表」類似的均勻顏色表。在這種情況下,16 位用於顏色索引,顏色索引分為 5 位紅色、5 位綠色和 6 位藍色。換句話說,此顏色表更像是「556 顏色表」,並且最好使用「閾值」抖動映射使用均勻顏色級別的有序抖動來實現。具體來說,操作為「-ordered-dither threshold,32,32,64」。然而,很少看到 16 位顏色表,因為使用顏色表的圖像通常需要 8 位顏色表。因此,我不會進一步說明。

伽瑪校正的均勻顏色表

目前 IM 並不直接支援 Gamma 校正色彩映射。建議您先將圖片(假設您擁有 Q16 或更高編譯時 品質 版本的 IM)從 sRGB 或任何 Gamma 等級轉換為線性 RGB 模型,然後再進行抖色。這也適用於許多其他影像處理操作,例如調整大小、模糊等。請參閱 使用 Gamma 校正調整大小 範例。

Posterize,使用均勻色彩映射重新著色

這個運算子的原始目的(使用參數 '2')是僅使用 8 種基本顏色重新著色圖片,就像使用僅使用基本顏色的簡單且便宜的海報印刷方法生成圖片一樣。因此,這個運算子被命名為 Posterize。「-posterize」運算子實際上是一種特殊的色彩縮減運算子,它根據圖片中每個顏色通道給定的顏色「級別」數量生成色彩映射,並使用誤差校正抖色來抖動圖片。

  magick netscape: -scale 50%  +dither  -posterize 2   posterize_2_ns.gif
  magick netscape: -scale 50%  +dither  -posterize 3   posterize_3_ns.gif
  magick netscape: -scale 50%  +dither  -posterize 6   posterize_6_ns.gif
[IM Output] [IM Output] [IM Output] [IM Output]
如您所見,「-posterize」參數為「2」表示每個顏色通道僅提供 2 種顏色,為 3 通道 RGB 圖片生成僅包含 8 種顏色的映射,如上所示。基本上,它會使用 8 種顏色的閾值集重新著色圖片。參數為「3」會根據包含中間色調的 27 種顏色色彩映射圖片顏色。而參數為「4」會生成 64 色色彩表,「5」則會生成 125 色色彩映射。當然,如上所述,參數為「6」會重現內建「netscape:」圖片提供的 216 種顏色集。請注意,「-posterize」參數為「0」或「1」是沒有意義的,並且在最新的 IM 版本中,只會將圖片轉換為純黑色(雖然合乎邏輯,但卻毫無用處)。結果是圖片已使用數學推導或「均勻」色彩映射重新著色。您可以在漸層圖片上更清楚地看到這一點,產生均勻分佈的海報化灰階。

  #magick -size 20x640  gradient: -rotate 90  gradient.png
  magick gradient.png  +dither  -posterize 5   posterize_gradient.gif
[IM Output]
例如,讓我們以不同的級別對 IM 標誌圖片進行海報化處理...

  magick logo.png  +dither -posterize 2  posterize_logo.gif
  magick logo.png          -posterize 2  posterize_logo_dither.gif
  magick logo.png          -posterize 6  posterize_6_logo.gif
[IM Output] ==> [IM Output] [IM Output] [IM Output]
作為更好的測試,讓我們對陰影「色輪」圖片進行海報化處理。

  magick colorwheel.png  +dither  -posterize 2   posterize_2_cw.gif
  magick colorwheel.png  +dither  -posterize 3   posterize_3_cw.gif
  magick colorwheel.png  +dither  -posterize 6   posterize_6_cw.gif
[IM Output] [IM Output] [IM Output] [IM Output]
啟用抖色後,結果如下...
[IM Output] [IM Output] [IM Output] [IM Output]
當然,我們在下一節中看到的許多點陣圖抖色也可以使用各種抖色樣式生成 2 級有序抖色。但是,很少有抖色可以使用更多灰階。 有序抖色 從 IM v6.2.9 開始也是一種海報化方法,因為它目前在使用均勻色彩映射進行抖色方面存在限制。但是,與「-posterize」產生的偽隨機抖色相比,抖色模式更加均勻,樣式選擇也更多。將這些與上面抖色的「-posterize」版本進行比較。

  magick colorwheel.png  -ordered-dither o8x8,2   posterize_2_od.gif
  magick colorwheel.png  -ordered-dither o8x8,3   posterize_3_od.gif
  magick colorwheel.png  -ordered-dither o8x8,6   posterize_6_od.gif
[IM Output] [IM Output] [IM Output] [IM Output]
threshold」抖色映射(而不是上面使用的「o8x8」)有效地將「-ordered-dither」轉換為非抖色海報化方法。最後,有序抖色 允許您為每個顏色通道指定不同的顏色級別數量。這是「-posterize」運算子目前不允許的。

閾值抖色方法

臨界值影像

將圖片轉換為黑白點陣圖(彩色)圖片的最簡單方法是使用「-threshold」。這實際上是一個簡單的數學運算子,僅提供一個截止值。任何等於或低於該值的顏色都將變為黑色,而任何大於該值的顏色都將變為白色。

  magick logo.png     -threshold   -1   threshold_0.gif
  magick logo.png     -threshold  25%   threshold_25.gif
  magick logo.png     -threshold  50%   threshold_50.gif
  magick logo.png     -threshold  75%   threshold_75.gif
  magick logo.png     -threshold 100%   threshold_100.gif
[IM Output] [IM Output] [IM Output] [IM Output] [IM Output]
如您所見,「-1」值會將所有顏色都變成白色,而「100%」則會將所有顏色都變成黑色。「50%」當然是最常用的值。
值 '0' 是一個特殊情況,它會將所有非純黑色的顏色轉換為白色。當然,如果圖像沒有純黑色,那麼您將只會得到一個純白色的圖像!

  magick logo.png  -threshold   0    threshold_black.gif
[IM Output]
如果您實際上想要將所有非純白色的顏色變成黑色,那麼我建議您對反轉後的圖像進行閾值處理,而不是嘗試找出要使用的正確閾值(比 IM 當前的“MaxRGB”小一),該值取決於您的特定 IM 在品質或“Q”設定中的編譯時間。

  magick logo.png  -negate -threshold 0 -negate threshold_white.gif
[IM Output]
-threshold”運算子可以歸類為終極“對比度”運算子,它通過閾值級別最大化顏色差異。 然而,它是一個灰度運算子,這意味著可以使用“-channel”設定來調整要將運算子應用於哪個顏色通道。 例如,您可以對圖像的每個單獨通道進行閾值處理,以產生與未抖動的 2 級“-posterize”運算相同的效應。

  magick logo.png  -channel R -threshold 50% \
                     -channel G -threshold 50% \
                     -channel B -threshold 50%   threshold_posterize.gif
[IM Output]
請注意,“-threshold”將圖像中的任何透明度視為蒙版通道,而不是 Alpha 通道(就像它在 IM 內部存儲一樣)。 因此,如果您打算將此運算子應用於 Alpha 通道,則需要注意。 有關更多詳細資訊,請參閱蒙版通道
如需更自動化的閾值處理技術,您可以使用我們之前展示過的雙色量化技術。
例如,這將根據圖像中找到的最佳兩種顏色對圖像進行閾值處理。 這些顏色可能不一定是灰度或甚至相反的顏色,而只是最能代表整個圖像的兩種顏色。 然後將這兩種顏色映射(使用“-normalize”)到純黑色和白色。

  magick logo.png  +dither  -colors 2  -colorspace gray -normalize \
             threshold_two_color.gif
[IM Output]

隨機抖動和閾值

-random-threshold”運算子是一種特殊形式的點陣圖圖像轉換器。 在這種情況下,它使用非常簡單的“隨機抖動”來確定特定像素是變成白色像素還是黑色像素。 與“-threshold”或“-monochrome”運算子,甚至與上一節中的變體不同,選定的通道(使用“-channels”設定)不會合併成單個灰度通道並作為單個單元進行抖動。 相反,“-random-threshold”對每個選定的通道進行操作,完全獨立於彼此。
當然,直接使用運算子將導致使用隨機抖動對圖像進行 2 級色調分離。

  magick logo.png  -random-threshold  0x100%  random_posterize.gif
[IM Output]
轉換為灰度將在對圖像中的所有通道進行抖動之前使它們相等。 但是由於每個通道都獨立於彼此並以隨機方式進行抖動,因此結果並不像您期望的那樣是點陣圖圖像。 相反,您將獲得彩色像素的飛濺,尤其是對於中間色調顏色。

  magick logo.png  -colorspace Gray -random-threshold  0x100% \
                                                   random_greyscale.gif
[IM Output]
以下是產生適當隨機抖動點陣圖圖像的正確方法。

  magick logo.png  -colorspace Gray -channel B \
          -random-threshold 0x100%    -separate   random_monochome.gif
[IM Output]
基本上,它所做的只是對灰度圖像的一個通道進行抖動,然後使用“-separate”通道運算子提取該通道作為最終的點陣圖圖像。 棘手但有效。
作為此運算子的特殊功能,如果使用“-channels”選項“All”,則 IM 將確保產生點陣圖圖像。

  magick logo.png  -channel All -random-threshold 0x100% random_all.gif
[IM Output]
不過請注意,使用這種方法會忽略並遺失任何 Alpha 色板,因此通常不建議使用。我自己也是偶然從原始碼中發現這個古老的功能。既然您現在知道如何使用運算子從彩色影像正確產生點陣圖,讓我們來看看參數如何影響抖動的範圍。這也清楚地顯示了此抖動產生的像素「群集」。

  #magick -size 20x640  gradient: -rotate 90  gradient.png
  magick gradient.png  -channel All \
                        -random-threshold 0x100%  random_grad_0x100.gif
  magick gradient.png  -channel All \
                        -random-threshold 10x90%  random_grad_10x90.gif
  magick gradient.png  -channel All \
                        -random-threshold 25x75%  random_grad_25x75.gif
  magick gradient.png  -channel All \
                        -random-threshold 50x50%  random_grad_50x50.gif
[IM Output] [IM Output] [IM Output] [IM Output]
-random-threshold」設定為「0x100%」將會產生純粹「隨機抖動」的影像。如果兩個邊界設定為相同的值(甚至超過彼此),它只會產生純粹的「-threshold」影像。使用任何其他邊界集(通常使用百分比指定)將會將點陣圖臨界值設定在給定範圍之外,同時為給定範圍內的值產生隨機抖動模式。
使用稍小的範圍可以獲得最佳效果,就像使用「-monochrome」運算子一樣。在大多數情況下,「30x80%」左右的值可能是最佳結果。

  magick logo.png  -channel All -random-threshold 30x80%  random_30x80.gif
[IM Output]
當然,結果仍然不是很好。但這是您可以獲得的最簡單和最差的抖動形式。實際發生的情況是,隨機抖動模式傾向於產生像素「群集」,而不是平滑的抖動模式。這是由於亂數產生器中的高頻「雜訊」所致。然而,在非常高的解析度下,隨機抖動已被證明可以產生極好的結果,如果足夠隨機的話。 IM 使用加密級別的隨機性,因此它很可能是非常隨機的,儘管影像很少在如此高的解析度下使用,以至於無法以這種方式使用。有人建議對這種抖動進行一種「修復」,即使用隨機的「藍色雜訊」產生器(一種高頻濾波器,與聲音製作中使用的低頻「粉紅色雜訊」濾波器相反)。這應該可以消除像素的群集,但在數位上很難實現。尚未發現「藍色雜訊隨機抖動」的已知實現,而且不太可能被創造出來。

有序抖動

雖然隨機抖動會產生隨機的像素塊,而各種誤差修正抖動會產生基本上隨機的點陣圖案,但有序抖動基本上是相反的。它的設計是盡可能在數學上是確定的。如此確定,您實際上需要指定它應用於抖動圖像的圖案。「-ordered-dither」運算子將使用給定的預定義圖案對圖像中選定的每個「-channels」進行抖動。該參數定義了要使用的圖案(稱為閾值映射)。這些閾值映射分為三種基本樣式。擴散像素抖動,其中像素盡可能彼此遠離放置,以避免「聚集」和拼接瑕疵。或者將它們聚集在一起形成緊密的點,使它們更容易機械印刷,這種技術稱為數位半色調。我們還將介紹一些專門的藝術閾值映射,甚至設計我們自己的抖動圖案或閾值映射。在每種情況下,閾值映射中開啟或關閉的像素數量取決於被抖動為點陣圖的圖像(或單個顏色通道)的灰度級強度。該映射以一致的方式添加像素閾值級別,因此一旦像素在特定「閾值」處開啟,它就會對任何較淺的灰色保持開啟狀態。這種一致性非常重要,否則會沿著抖動圖案變化邊界產生瑕疵。關於這一點,重要的是圖像中每個像素的結果是純粹數學確定的,與圖像中的任何其他像素無關。因此,對原始圖像的任何微小更改對圖像中任何其他區域都絕對沒有影響,這是誤差修正抖動存在的一個問題,如我們上面所見。這一點對於視頻圖像和優化動畫的一致抖動至關重要。

擴散像素抖動

有序抖動的最初目的,以及大多數圖形程序員期望在您使用有序抖動時獲得的結果,有時更準確地稱為「擴散像素有序抖動」。這意味著隨著閾值強度的增加,像素會被添加到平鋪映射中,以便它們盡可能地彼此遠離並均勻分佈。這會產生高度一致的圖案,在大多数现代顯示器上看起來非常平滑且幾乎看不見。此類圖案已針對 2 的冪的平鋪尺寸(即 2、4 和 8 的平鋪尺寸)制定出來。儘管 IM 也為 3x3 閾值映射平鋪提供了合理的閾值圖案。以下是 IM 目前提供的內置有序抖動集。請記住,參數反映了有序抖動的平鋪尺寸。

  magick logo.png    -ordered-dither o2x2    logo_o2x2.gif
  magick logo.png    -ordered-dither o3x3    logo_o3x3.gif
  magick logo.png    -ordered-dither o4x4    logo_o4x4.gif
  magick logo.png    -ordered-dither o8x8    logo_o8x8.gif
[IM Output] [IM Output] [IM Output] [IM Output]
請注意,較大的平鋪尺寸如何讓您模擬更多「顏色級別」,但也會在某些級別產生更明顯的缺陷或矩形像素陣列。
o8x8」有序抖動長期以來一直是 IM 核心代碼的一部分,但沒有被使用。它只是在 IM v6.2.9 中作為「-ordered-dither」運算子的選項添加的,當時 IM 示例開始詳細說明該運算子的使用。

此時,映射被賦予了更明確的名稱,以便進一步擴展「-ordered-dither」運算子,儘管舊的向後相容「平鋪尺寸」名稱被保留作為新名稱的別名。

此外,產生「o3x3」和「o4x4」的「映射」也進行了全面修改,以產生更好的「擴散像素」抖動圖案。在此之前,映射會產生明顯的像素「團塊」。

請參閱有序抖動升級筆記頁面,以獲取在 IM v6.3.0 版本正式發佈升級之前舊模式的範例,以及在開發過程中所做的其他變更。
當然,您需要先將圖像使用 Magick 轉換為灰階,才能產生圖像中所有通道的適當點陣圖,但是由於該過程不是隨機的,因此您不需要像使用 -random-threshold 運算符那樣對圖像進行後處理,從而大大簡化了操作。

  magick logo.png -colorspace Gray  -ordered-dither o2x2  logo_bw_o2x2.gif
  magick logo.png -colorspace Gray  -ordered-dither o3x3  logo_bw_o3x3.gif
  magick logo.png -colorspace Gray  -ordered-dither o4x4  logo_bw_o4x4.gif
  magick logo.png -colorspace Gray  -ordered-dither o8x8  logo_bw_o8x8.gif
[IM Output] [IM Output] [IM Output] [IM Output]
作為參考,以下列出了應用於灰階漸層的每個 "-ordered-dither"「擴散像素」模式,因此您可以清楚地看到它們的外觀。

  # Threshold Non-Dither / Minimal Checkerboard Dither
  magick gradient.png   -ordered-dither threshold  od_threshold.gif
  magick gradient.png   -ordered-dither checks     od_checks.gif
  # Diffused Pixel Dither
  magick gradient.png   -ordered-dither o2x2       od_o2x2.gif
  magick gradient.png   -ordered-dither o3x3       od_o3x3.gif
  magick gradient.png   -ordered-dither o4x4       od_o4x4.gif
  magick gradient.png   -ordered-dither o8x8       od_o8x8.gif
[IM Output] [IM Output]
[IM Output] [IM Output] [IM Output] [IM Output]
由特定有序抖動產生的有效或偽級別模式的數量通常(但不總是)等於模式中的像素數量加一。因此,'o3x3' 有序抖動將在生成的圖像中為每個通道(黑色、白色和 8 個人工灰色模式)產生 3×3+1 或 10 個有效灰度級。上面還顯示了兩個特殊的最小抖動閾值映射
  1. 一個不產生任何額外灰度級的直線「50% 閾值」非抖動,以及
  2. 一個「棋盤格」或棋盤抖動模式,它只插入一個模式以向生成的漸層添加一個額外的「偽級別」。

數位半色調抖動

IM v6.2.8-6 中的 "-ordered-dither" 擴展了一組數位半色調抖動模式(感謝 Glenn Randers-Pehrson)。所有這些都設置為產生一個簡單的 45 度點模式。在 IM v6.3.0 中,這進一步擴展了一組類似的更大的非角度半色調。
在 IM v6.3.0 發佈之前,半色調網屏是通過使用 '{number}x1' 形式的參數來選擇的。隨著有序抖動的重新開發,這個限制被解除了,選擇了更好的命名,並添加了額外的半色調網屏(正交形式)(請參閱下面的示例參數)。
請注意,數位半色調嚴格來說並不是真正的半色調網屏,後者旨在處理機械沉積在紙張、紙板甚至金屬等介質上的圓形墨點。這些點在印刷過程中可能會重疊和塗抹,因此需要進行一些非線性級別調整。這對於產生純粹的數位半色調效果是不需要的。有關該過程的更多詳細信息,請參閱文檔抖動和半色調(PDF)。也就是說,有序抖動數位半色調模式確實提供了與報紙和廉價印刷雜誌中相同的基本效果。

  # Halftone Screen (45 degree angle)
  magick logo.png   -ordered-dither h4x4a    logo_h4x4a.gif
  magick logo.png   -ordered-dither h6x6a    logo_h6x6a.gif
  magick logo.png   -ordered-dither h8x8a    logo_h8x8a.gif
  # Halftone Screen (orthogonal)
  magick logo.png   -ordered-dither h4x4o    logo_h4x4o.gif
  magick logo.png   -ordered-dither h6x6o    logo_h6x6o.gif
  magick logo.png   -ordered-dither h8x8o    logo_h8x8o.gif
[IM 輸出] [IM 輸出] [IM 輸出]       [IM 輸出] [IM 輸出] [IM 輸出]
再次使用 "-colorspace" 運算符生成圖像的真實點陣圖抖動。

  # Halftone Screen (45 degree angle)
  magick logo.png -colorspace Gray  -ordered-dither h4x4a logo_bw_h4x4a.gif
  magick logo.png -colorspace Gray  -ordered-dither h6x6a logo_bw_h6x6a.gif
  magick logo.png -colorspace Gray  -ordered-dither h8x8a logo_bw_h8x8a.gif
  # Halftone Screen (orthogonal)
  magick logo.png -colorspace Gray  -ordered-dither h4x4o logo_bw_h4x4o.gif
  magick logo.png -colorspace Gray  -ordered-dither h6x6o logo_bw_h6x6o.gif
  magick logo.png -colorspace Gray  -ordered-dither h8x8o logo_bw_h8x8o.gif
[IM 輸出] [IM 輸出] [IM 輸出]       [IM 輸出] [IM 輸出] [IM 輸出]
最後,另一個漸層參考圖像清楚地顯示了半色調網點圖案,以及網點圖案中的像素塊如何隨著灰階變化而彼此增長。

  # Halftone Screen (45 degree angle)
  magick gradient.png   -ordered-dither h4x4a      od_h4x4a.gif
  magick gradient.png   -ordered-dither h6x6a      od_h6x6a.gif
  magick gradient.png   -ordered-dither h8x8a      od_h8x8a.gif
  # Halftone Screen (orthogonal)
  magick gradient.png   -ordered-dither h4x4o      od_h4x4o.gif
  magick gradient.png   -ordered-dither h6x6o      od_h6x6o.gif
  magick gradient.png   -ordered-dither h8x8o      od_h8x8o.gif
  magick gradient.png   -ordered-dither h16x16o    od_h16x16o.gif
  # Circle Halftones (black and white)
  magick gradient.png   -ordered-dither c7x7b      od_c7x7b.gif
  magick gradient.png   -ordered-dither c7x7w      od_c7x7w.gif
[IM Output] [IM Output] [IM Output]
[IM Output] [IM Output] [IM Output] [IM Output]
[IM Output] [IM Output]
在 ImageMagick 6.2.9 版之前,上述所有閾值排序網點映射都是 IM 唯一可行的功能。現在情況已經改變,允許用戶添加自己的圖案,甚至可以將它們貢獻給 IM 社群。 「圓形」半色調閾值是由 Glenn Randers-Pehrson 在 IM v6.6.5-6 中添加的。

偏移半色調網點

上述半色調網點的唯一問題是,完全相同的閾值映射(圖塊)以相同的方式應用於所有顏色通道。這意味著相同的原色集以相同的「中心」排列成點。為了獲得所謂的「偏移印刷」,閾值圖案以特定圖案旋轉,使顏色形成小尺寸的「玫瑰花圖案」,從而破壞了原本可能形成的更可怕的干涉(摩爾紋)圖案。該圖基本上解釋了這個過程,並在維基百科頁面上有非常詳細的解釋,半色調
[IM Output]
但是請注意,旋轉的網屏並不能很好地平鋪,因此最好的方法是直接生成旋轉圖案,而不是使用圖塊閾值圖案。以下是一種使用小的旋轉 2x2 像素棋盤格圖案(這是可以使用的最小「網屏」)為圖像賦予偏移半色調印刷外觀的方法。

  magick colorwheel.png  -set option:distort:viewport '%wx%h+0+0' \
          -colorspace CMYK -separate null: \
          \( -size 2x2 xc: \( +clone -negate \) \
                +append \( +clone -negate \) -append \) \
          -virtual-pixel tile -filter gaussian \
          \( +clone -distort SRT 60 \) +swap \
          \( +clone -distort SRT 30 \) +swap \
          \( +clone -distort SRT 45 \) +swap \
          \( +clone -distort SRT 0 \)  +swap +delete \
          -compose Overlay -layers composite \
          -set colorspace CMYK -combine -colorspace RGB \
          offset_colorwheel.png
[IM Output]
請注意,四個旋轉的「網屏」應用於整個圖像,實際上是 CMYK 色彩空間中的「-combine」步驟從網屏圖像中提取 4 個不同的顏色通道。此外,最後一個「黑色」通道的「無操作」變形也很重要,因為它會根據在其他通道旋轉期間使用的 Gaussian 濾鏡來模糊輸入棋盤格圖案,即使該網屏本身沒有被旋轉。在這裡,我使用了 SRT 變形 的縮放功能來生成旋轉的圖塊,以創建更大、更模糊的「網屏圖案」。

  magick parrots_med.png  -set option:distort:viewport '%wx%h+0+0' \
          -colorspace CMYK -separate null: \
          \( -size 2x2 xc: \( +clone -negate \) \
                +append \( +clone -negate \) -append \) \
          -virtual-pixel tile -filter gaussian \
          \( +clone -distort SRT 2,60 \) +swap \
          \( +clone -distort SRT 2,30 \) +swap \
          \( +clone -distort SRT 2,45 \) +swap \
          \( +clone -distort SRT 2,0  -blur 0x0.7 \) +swap +delete \
          -compose Overlay -layers composite \
          -set colorspace CMYK -combine -colorspace RGB \
          offset_parrots.png
[IM Output]
請注意,圖案仍然非常「方形」,尤其是所有其他圖案都源自的黑色網屏。 未來展望:將上述 2 像素棋盤格替換為「pattern:gray50」像素級棋盤格圖案。可以使用 Gaussian 濾鏡選項來調整縮放圖案的模糊度。或者,您可以模糊縮放圖案並對其進行閾值處理,以製作更圓的點。然後可以像以前一樣旋轉它以創建 4 色網屏。如果可以使用更大的網屏並使用六邊形點圖案而不是我上面使用的棋盤格圖案,那就更好了。
請注意,這並不是像真正的網版印刷那樣真正生成彩色網點,而是通過簡單地將顏色網版與原始圖像相乘來偽造的。你可以看到,紅色鸚鵡與綠色背景的邊緣處有明顯的顏色變化,這就是這種情況。僅使用純色網點的真正網版印刷不會有任何網點顏色變化。應該是純色網點的大小發生變化,這取決於源圖像中由網點代表的區域中顏色的平均值。要真正生成僅包含每個顏色通道中適當大小的圓點的真正網版印刷圖像,需要做更多的工作。需要確定每個顏色通道中每個網點的平均顏色,並由此確定生成的彩色網點(抗鋸齒圓圈)的適當大小。有人想試試嗎? 以上內容來自 IM 論壇討論 CMYK 半色調效果 中的一段討論,該討論探討了 Photoshop 如何“偽造”這種效果,以及 ImageMagick 如何實現相同的效果。該討論還與 黑白半色調抖動 相關,後者更詳細地探討了如何使用適當大小的實際網點生成真正的半色調網屏。然而,該討論並沒有進一步討論使用偏移(旋轉)網屏。這樣的網屏可能需要旋轉圖像以生成網點,然後再為特定的顏色通道將網點圖案旋轉回來。

XML 臨界值映射

從 IM 6.3.0 版本開始,映射不再使用 IM 源代碼中內置的固定集合(如前所示),而是從程序外部的一組 XML 數據文件中讀取。作為此更改的一部分,您現在可以列出“-ordered-dither”運算符可以使用的可用“閾值映射”。

  magick identify -list threshold
[IM Output]
上面的列表不僅顯示了可用的閾值映射,還顯示了為向後兼容或備用命名提供的別名,以及在我自己的個人“thresholds.xml”XML 數據文件(保存在我的主目錄的“.magick”子目錄中)中定義的別名。當“-ordered-dither”正在尋找映射時,將使用它在上面列表中找到的第一個映射。因此,您不能覆蓋系統定義的閾值模式。系統文件“thresholds.xml”(其路徑由上面的“-list”選項給出)包含 XML 文件格式的完整摘要。格式非常簡單(通過 IM 進行錯誤檢查),允許用戶定義和創建自己的有序抖動閾值映射。例如,以下是我在個人“threshold.xml”文件中定義的“diag5x5”閾值映射的副本。
[IM Output]
如果仔細觀察,它會創建一個簡單的 5x5 映射,其中包含一條對角線,隨著閾值級別的增加,該對角線會變得更粗。映射中的級別編號從 0 到 5,比除數小 1,除數聲明它需要將顏色漸變分成多少個“灰度”。以下是用這個個人閾值映射進行抖動的漸變。

  magick gradient.png   -ordered-dither diag      od_diag.gif
[IM Output]
以下是一個使用該閾值對簡單陰影圖像的 Alpha 通道進行抖動的示例,這是我設計它的目的。

  magick -size 70x60 xc:none -font Candice -pointsize 50 \
          -fill black -annotate +10+45 'A' -channel RGBA  -blur 0x5 \
          -fill white -stroke black -draw "text 5,40 'A'"   shadow.png

  magick shadow.png  -channel A  -ordered-dither diag   shadow_diag.gif
[IM Output] ==> [IM Output]
很酷吧!稍後將詳細介紹 Alpha 通道的抖動。首先,我還需要展示如何使用擴展“-ordered-dither”運算符的著色功能。

使用均勻顏色級別的有序抖動

隨著 IM v6.3.0 的發佈,不僅“-ordered-dither”使用的臨界值映射已更改為從外部檔案讀取,而且內部操作也得到了增強,允許它使用數學定義的“色階”顏色映射。這表示您可以生成比“誤差修正抖動”更確定的圖像抖動。這對於涉及動畫的色彩縮減尤其重要,因為您不會遇到幀之間的色彩差異問題。色階級別使用附加到要使用的臨界值映射名稱的額外逗號分隔數字列表傳遞給“-ordered-dither”參數。如果沒有提供任何數字,則運算子會回復到正常的 2 色(或色階級別 1)顏色映射。例如,“checks,6”參數將使用經典的網頁安全顏色映射(色階級別 6)顏色映射(也由“netscape: 內建顏色映射圖像定義)。但是,由於使用了“checks”的最小抖動映射,因此在 6 個顏色級別中的每一個級別之間添加了單獨的額外抖動級別,從而在圖像的每個通道中產生了 11 個偽彩色級別。換句話說,即使每個通道僅使用 6 個顏色級別(產生 6^3 或 216 種顏色),級別之間的單個抖動模式也會將抖動增加到有效的 11 個級別(產生有效的 11^3 或 1331 種顏色)。例如,以下是用 6 個灰階和各種臨界值映射抖動的灰階漸層。第一個映射“threshold”是一個特殊的非抖動有序抖動臨界值映射,僅顯示使用的顏色。

  magick gradient.png   -ordered-dither threshold,6  od_threshold_6.gif
  magick gradient.png   -ordered-dither checks,6     od_checks_6.gif
  magick gradient.png   -ordered-dither o2x2,6       od_o2x2_6.gif
  magick gradient.png   -ordered-dither o4x4,6       od_o4x4_6.gif
  magick gradient.png   -ordered-dither o8x8,6       od_o8x8_6.gif
[IM Output] [IM Output] [IM Output] [IM Output] [IM Output]
如您所見,即使僅使用 6 種顏色,通過有序抖動,您也可以增加用於定義漸層的有效顏色數量,達到您難以察覺實際使用了多少種顏色的程度!您不僅可以為所有通道定義色階級別數,而且與“-posterize”誤差修正抖動選項不同,您還可以為每個通道指定級別。這些數字按照“-channels”設置分配給通道。例如,在這裡,我們使用特殊的 332 顏色映射(8 級紅色和綠色,4 級藍色)對漸層進行了抖動,該映射定義了總共 256 種顏色。

  magick gradient.png   -ordered-dither o8x8,8,8,4   od_o8x8_884.gif
[IM Output]
由於每個通道的顏色級別數不同,因此上圖不僅包含純灰色,還包含一些藍色和黃色像素,這些像素相互抵消以產生額外的灰階。現在,將O-抖動版本與使用 2 和 6 的色階級別和“332 顏色映射”(8 級紅色和綠色,4 級藍色)的誤差修正抖動版本進行比較。

  magick logo.png  -ordered-dither o8x8        logo_o8x8_2.gif
  magick logo.png  -posterize 2                logo_posterize_2.gif
  magick logo.png  -ordered-dither o8x8,6      logo_o8x8_6.gif
  magick logo.png  -posterize 6                logo_posterize_6.gif
  magick logo.png  -ordered-dither o8x8,8,8,4  logo_o8x8_332.gif
  magick logo.png  -remap colormap_332.png     logo_remap_332.gif
[IM 輸出] [IM 輸出]     [IM 輸出] [IM 輸出]     [IM 輸出] [IM 輸出]
以上每對圖像中的第一張圖像都是經過數學排序的抖動處理,而第二張圖像是經過偽隨機“誤差校正”抖動處理。最後一對圖像使用特殊的“332 色彩映射表”(請參閱生成色彩映射表),它被認為可能是對 256 色限制的一般圖像進行色階化處理的最佳色彩映射表。通道級別的奇數差異為這張卡通圖像產生了稍微更好的顏色漸變效果。正是為了能夠生成“332 色彩映射表”,"-ordered-dither" 運算符才包含了為每個顏色通道指定單獨級別的功能。

更好的有序抖動結果

讓我們仔細看看剛才生成的 6 級有序抖動

  magick logo.png -ordered-dither o8x8,6 -format %k info:
[IM Text]
如您所見,對於這張圖像,我們甚至沒有接近填滿 GIF 色彩表(256 色限制)。基本上,由於圖像通常主要由藍色組成,因此即使是 6 級均勻色彩映射表中的紅色或綠色陰影也很少被使用。但是,通過增加色階化級別的數量,我們可以更好地填充 GIF 色彩表,從而生成更好的有序抖動圖像。

  magick logo.png -ordered-dither o8x8,13 -format %k info:
[IM Text]
這會產生足夠多的顏色,僅略低於 GIF 色彩表的限制。隨著顏色數量的增加,結果看起來比簡單的標準均勻色彩映射表的結果好得多。

  magick logo.png -ordered-dither o8x8,13    logo_o8x8_13.gif
[IM Output]
如您所見,使用較高的“級別”值,"-ordered-dither" 可以生成與顏色量化相當的圖像,達到顏色量化和誤差校正抖動所生成的特定顏色選取效果。這些圖像的重點不在於它們的品質高。畢竟,完整的顏色量化可以更容易地為圖像生成更好的色彩映射表。但圖像中的低級抖動模式是固定的,無論可能發生什麼細微變化。在有序抖動圖像中,只有區域變化會被改變。也就是說,它們沒有誤差擴散抖動敏感性,這種敏感性會導致 GIF 動畫中的畫面優化出現問題。(請參閱優化問題)當然,對於動畫,您需要使用 "-append" 將所有圖像附加在一起,然後才能檢查實際使用了多少種顏色。並且在使用 "-ordered-dither" 後,您需要使用特殊的 "+remap" 選項,以強制 IM 為所有圖像生成“通用的全局色彩映射表”,即使您已經執行了顏色減少和抖動處理。*這種確定顏色級別數量的方 法並不簡單,但確實有效。我希望找到一種方法讓 IM 自動確定最佳級別,特別是針對 GIF 動畫。*

DIY 抖動模式和閾值映射

之前我向您展示了新的 "-ordered-dither" 運算符可以接受使用者自訂的抖動模式。在這裡,我將向您展示如何建立自己的抖動模式。具體來說,是一種我發現對生成由水平線組成的陰影很有用的特殊模式。

多圖像抖動模式

您需要做的第一件事是創建一組圖像來定義您要創建的圖案。圖案應該以正確尺寸的純黑色圖像作為第一個圖像(所有像素關閉)開始,並以純白色圖像作為結尾(所有像素開啟)。下一個圖像應該是中間 50% 灰度的圖案,定義您要達成的抖動的基本樣式。例如,以下是我的初始 DIY 抖動圖案。我將其保存到一個多圖像 GIF 文件(不是 GIF 動畫)中...

  magick -size 2x2 xc:black \
          \( +clone -draw 'fill white line 0,0 1,0' \) \
          xc:white     dpat_hlines2x2.gif
  montage dpat_hlines2x2.gif    -tile x1 -background none -frame 2 \
          -filter box  -geometry 32x32+5+0    dpat_hlines2x2_imgs.gif
[IM Output]
這是您可以獲得的最簡單的抖動圖案圖像集,它與“方格”或“棋盤抖動”非常相似,但具有水平線,而不是棋盤圖案。所以你可以看到這個抖動圖案會是什麼樣子,這裡是一個相當簡單的 DIY 有序抖動,它直接使用了閾值抖動圖像集。

  magick gradient.png   dpat_hlines2x2.gif \
          -virtual-pixel tile  -fx 'u[(floor((n-1)*u)+1) % n]' dgrad_hlines2x2.gif
[IM Output]
如您所見,抖動圖案並不花哨。“-fx”函數是顏色查找表函數的變體,即 IM 抖動查找圖案類型函數。並且使用“tile”的“-virtual-pixel”設置,該函數甚至不需要知道您正在使用的抖動圖案圖像的大小。
在 IM 版本 6.2.9-2 之前,使用像這樣計算的索引的“-fx”運算符使用“-virtual-pixel”已被破壞。
讓我們再次嘗試這個抖動圖案集,但使用一個簡單的陰影圖像...

  magick shadow.png dpat_hlines2x2.gif  -channel A \
          -virtual-pixel tile  -fx 'u[floor((n-1)*u)+1].g' \
          shadow_dpat_hlines2x2.gif
[IM Output] ==> [IM Output]

自訂有序抖動臨界值映射

上面的 DIY 抖動圖案是您可以獲得的最簡單的抖動圖案,因此我們可以直接將其轉換為 XML 閾值映射,以便快速內置的“-ordered-dither”運算符可以使用它。這是最終的 XML 定義,我將其保存在我的主目錄“~/.magick/thresholds.xml”中的個人閾值映射文件中。
[IM Output]
XML 格式非常簡單,它定義了一個 2x2 像素的地圖。第一個黑色圖像的值為零,並且沒有像素,因此不存在零值。中間圖像中開啟(變為白色)的像素設置為“1”,其餘或第二個圖像像素的值為“2”。“divisor=”定義了此抖動圖案表示的圖像數量或偽彩色級別(假彩色級別),因此它的值為“3”。它會分割像素值,以定義要開啟該像素的顏色級別。因此,前兩個像素針對大於 1/3 的顏色開啟,而後兩個像素針對大於 2/3 的顏色值開啟。也就是說,每個像素值代表一個“閾值”級別,這就是抖動圖案也稱為閾值映射的原因。定義的其餘部分定義了您可以用於有序抖動運算符的閾值映射的名稱(和可選的別名)。讓我們來試試看...

  magick gradient.png  -ordered-dither hlines2x2  od_hlines2x2.gif
  magick shadow.png  -channel A \
          -ordered-dither hlines2x2   shadow_hlines2x2.gif
[IM Output]
[IM Output] ==> [IM Output]
如您所見,結果相當不錯,但我們可以做其他事情來改善結果。通過調整映射中的閾值,我們可以更改邊界,這樣它就不會將顏色空間分成 3 個相等的部分...
[IM Output]
請注意,我如何將除數增加到“10”,以便將顏色級別分成十個相等的部分。然後,我更改了閾值設置,以便圖案從透明端(黑色)的 30% 閾值開始,到完全不透明(白色)的 90% 閾值結束。以下是更改閾值映射的結果。

  magick gradient.png  -ordered-dither hlines2x2a  od_hlines2x2a.gif
  magick shadow.png -channel A \
          -ordered-dither hlines2x2a  shadow_hlines2x2a.gif
如您所見,這擴展了使用純水平線作為抖動模式的半透明像素範圍。這提供了更好的陰影效果,儘管它可能只應用於比此處使用的示例更清晰的陰影。但請注意,這種對閾值的更改非常少見。雖然在本例中,考慮到預期用途是合理的。基本上,它沒有正確定義漸變,也不允許圖案的明暗變化。為此,我們需要創建一個更複雜的閾值映射,包含更多像素和更多圖案。

自訂水平線抖動

在這裡,我將上面創建的簡單水平線抖動模式擴展為一組圖案,以產生從“關閉”到“開啟”的更平滑的漸變。結果如下。

  montage dpat_hlines.gif   -filter box   -geometry 60x20+2+0 \
          -tile x1 -background none  -frame 2   dpat_hlines_images.gif
  magick gradient.png  dpat_hlines.gif  \
          -virtual-pixel tile  -fx 'u[(floor((n-1)*u)+1) % n]' \
          dgrad_dpat_hlines.gif
  magick shadow.png dpat_hlines.gif  -channel A \
          -virtual-pixel tile  -fx 'u[floor((n-1)*u)+1].g' \
          shadow_dpat_hlines.gif
[IM Output]
[IM Output]
[IM Output] ==> [IM Output]
如您所見,它現在由 9 個 12x4 像素的圖像組成。它並不代表您可以擁有的所有像素模式,但这增强了线条的效果。此外,我將其高度加倍,以便適當地抖动线条中的间隙。以下是使用此抖動模式的另一個示例...

  magick -size 120x55 xc:white  -draw 'fill #777 ellipse 50,43 30,5 0,360' \
          -motion-blur 0x15+180   -blur 0x2      sphere_shadow.png
  magick sphere_shadow.png dpat_hlines.gif \
          -virtual-pixel tile  -fx 'u[(floor((n-1)*u)+1) % n]' \
          sphere_shadow_dither.gif
  magick sphere_shadow_dither.gif   -fill red  -stroke firebrick \
          -draw 'circle 35,25 35,5'     sphere_shadow_hlines.gif
[IM Output] ==> [IM Output] ==> [IM Output]
下一步是將這組抖動模式通過 magic 轉換為單個閾值映射圖像,而不是一組多個圖像。這是通過使用一些花哨的圖像處理來合併所有圖像來實現的。
[IM Output]
[IM Output]

  magick -size 1x10 gradient: -flip -crop 1x1 +repage -delete 0,-1 \
          -scale 12x4\! null: \( dpat_hlines.gif -delete 0 \) \
          -alpha off -compose CopyOpacity -layers Composite \
          -reverse -compose Over -flatten -alpha off dmap_hlines.png
[IM Output]
值“10”比抖動模式中的圖像數量多 1,而“-scale 12x4\!”是要轉換為閾值映射的抖動模式的大小。結果是一個灰度圖,沒有純黑色或純白色。用於像素的灰度級別意味著如果顏色級別等於或高於該灰度值,則應開啟該像素。也就是說,每個灰度級別都是顏色值從黑色變為白色的“閾值”級別。如果您想以另一種方式查看圖像,則深色像素通常会导致這些像素针对更多颜色级别開啟。而淺色像素僅在圖像顏色變得非常亮時才開啟。這幾乎與圖像的實際外觀相反,但如果您仔细想想,這確實是有道理的。我還使用了 PNG 圖像而不是 GIF 圖像作為映射,因為只需要保存一個圖像,更重要的是,嘗試保留閾值的 16 位質量级别。 GIF 只能處理 8 位顏色级别。現在我們可以使用單個圖像和每個像素直接與抖動閾值圖像(或映射)進行更簡單的閾值比較來抖動我們的圖像。

  magick gradient.png dmap_hlines.png \
          -virtual-pixel tile  -fx 'u>=v'   dgrad_dmap_hlines.gif
[IM Output] ==> [IM Output]
看看閾值映射有多簡單。您只有一張圖像,並且每個通道只需進行一次直接比較即可進行抖動。這使得使用閾值映射進行抖動非常非常快。比全彩色量化快得多。這種簡單性就是 ImageMagick 和大多數圖形軟件使用閾值映射來保存各種抖動模式的原因。
大於或等於(“>=”)測試直到 IM 6.2.9-2 版才添加到“-fx”運算符中。如果這是一個問題,請在上面使用反向測試“v<u”。
然而,如果使用者想要使用多種顏色級別進行抖動,這種簡單性就會變得更加複雜。這個概念證明最初是在頁面 色階化有序抖動 的範例中完成,然後才被納入 IM 核心函數。現在我們已經合併了閾值圖像,接下來需要將上面的圖像轉換為 IM 可以直接讀取的 XML 閾值映射,並使用「-ordered-dither」運算符。為此,我們需要將圖像輸出為代表其所代表的 9 個灰度級的數字。最好使用 NetPBM 或 PBMplus 圖像格式,並使用「NetPbm」圖像處理軟體進行深度調整。這個軟體包通常是標準的 Linux 安裝,因此大多數人應該已經擁有它,或者可以從他們的軟體發行版中安裝它。「pnmdepth」數字仍然是閾值圖像包含的灰度級數。

  magick dmap_hlines.png pgm:- | pnmdepth 9 | pnmnoraw > dmap_hlines.pgm
[IM Text]
上面所有數字(「P2」圖像魔術識別符號除外)都是生成適當「閾值映射」所需的數字,您可以將其添加到您的個人「thresholds.xml」檔案中。例如,以下是從上面建立的結果閾值映射項目。
[IM Output]
以下是使用此閾值映射的範例。

  magick shadow.png  -channel A  -ordered-dither hlines   shadow_hlines.gif
[IM Output] ==> [IM Output]
這就是您可以從圖像的進程生成複雜的閾值映射的方法。

使用符號模式進行抖動

現在,雖然您可以對大多數抖動操作使用單一閾值映射或閾值圖像,而不是多圖像模式集,但这並不表示多圖像映射沒有自己的用途。您可以使用一組查找圖像一次性平鋪多個區域,而不是一次平鋪一個區域。例如,通過縮放一個簡單的圖像,然後用特定的符號替換圖像中的每個像素。例如,在這裡我採用了非常小的「眼睛」圖像 [IM 輸出],並用各種符號替換單個像素,為原始圖像中的每個像素生成這樣的模式。

  montage dpat_symbols.gif   -geometry +5+0 \
          -tile x1 -background none -mattecolor blue  -frame 3 \
          dpat_syms_images.gif
  magick eyes.gif -alpha off -colorspace sRGB -grayscale Average \
          -alpha off -scale 1600% -negate  \
          dpat_symbols.gif -virtual-pixel tile -fx 'u[floor(15.9999*u)+1]' \
          eyes_syms.gif
[IM Output]
[IM Output]
蒙太奇 用於展開多圖像 GIF 圖像,以便您可以查看其內容,而不會使其「動畫化」。您可以調整要使用的「-grayscale」強度方法,從普通的「Rec709Luminance」到更暗的「Rec709Luma」,或使用非線性「sRGB」色彩空間或線性「RGB」色彩空間的「average」。您甚至可以調整值的「-gamma」縮放比例,以獲得最佳的顏色分佈。有很多可能性,什麼是好的更多地取決於您的符號排列,而不是實際選擇的方法。上面的關鍵是以某種方式確保輸入圖像中的每種顏色都產生唯一的符號,而這可能很難實現。此範例可用於建立愛好者可以遵循的十字繡或編織指南,從較小的電腦圖像生成更大比例的藝術品。您可以使用此技術使用一組平鋪彩色圖像來平鋪灰度圖像。結果有點像許多舊電腦戰爭遊戲中看到的景觀地圖。

  montage dpat_map.gif   -geometry +5+0 -tile x1  -background none  \
          dpat_map_images.gif
  magick -seed 100 \
          -size 200x200 plasma:'gray(50%)-gray(50%)' -blur 0x15 \
          -channel G -auto-level +channel -set colorspace sRGB \
          dpat_map.gif -virtual-pixel tile  -fx 'u[floor(5.999*u.g)+1]' \
          map.gif
[IM Output]
[IM Output]
請注意,我需要確保 IM 將灰階影像視為已處於最終的 sRGB 色彩空間中(如同圖磚影像一樣),即使實際上用於 FX 索引查找的是線性 RGB 資料。如果沒有這個設定,生成的「地圖」會偏向於樹木繁茂的景觀,而水域的機會很小。如您所見,任何一組影像都可以用於圖磚,這些影像甚至不需要彼此對齊,甚至不需要是相同大小的圖磚。當然,如果圖磚大小相同且彼此密切相關,例如 3 個藍色「海洋」圖磚,則平鋪圖案可以從一個平鋪區域「流動」到另一個平鋪區域。通過用數字影像替換圖磚,您還可以生成一種數字繪畫指南。但是,可能需要進行一些額外的處理來為不同的區域添加邊框。這將留作練習,將您的解決方案郵寄給我,您就可以在 IM 範例中使用您的名字作為此技術的作者。

有序抖動隨機筆記和未來可能性

建構中

使用少量顏色的有序抖動。

當對小型影像使用少量顏色時,像 IM 的希爾伯特曲線誤差校正抖動這樣的偽隨機抖動,甚至更簡單的 Floyd-Steinberg 誤差校正抖動(請參閱上面的誤差校正抖動)會產生非常難看的結果。理想情況下,應將有序抖動與低顏色和小型圖示影像一起使用,以產生更美觀的結果。但是,目前 IM 中的有序抖動只能使用「固定」的數學生成顏色表,而不能僅僅使用「最佳」顏色的集合。

具有任何顏色映射的有序抖動

有一些演算法允許您對有序抖動使用一組特定的顏色。基本上,通過將有序抖動演算法可以生成的「偽彩色」(可能涉及三色抖動)添加到給定的顏色映射中來「填充」它。然後,您可以將影像的單個像素「映射」到這個「擴展顏色映射」。從初始映射到特定的偽彩色,可以從生成該偽顏色的閾值映射中選擇實際顏色,從而對該顏色的區域進行有序抖動,從而將整個影像抖動到一組給定的顏色。由於我有圖示和 GIF 動畫的背景,我當然希望看到實現任何顏色的有序抖動,但我還沒有找到關於如何使用一組固定顏色進行有序抖動的實用參考。