ImageMagick 使用例 -- マスク
- 内部マットチャンネル
-
Off(または-alpha off),Set(または-alpha set),On,
Activate,
Discrete,
Opaque,Transparent,Extract,Copy,
Shape,Remove,Background - ブール値のアルファ透明度
- 色付きの形状としてのマスク
- 数学的合成
- マスクを用いたアルファ合成
-
マスクされた2枚の画像を揃える (作成中)
- クリップマスクとクリップパス
- 縁取りのあるオブジェクトをマスクする
- 既知の背景を除去する
- 差分画像によるマスクとぼかし
- 半透明のエッジを復元する
- ぼかしで埋める
(作成中) これらの例では、透明度の特殊な扱い、透明度チャンネル、マスクの使い方、そして最終的には不要な背景や、看板・文字・スパムといったその他の要素の除去について見ていきます。
アルファチャンネル
画像の透明度(アルファ)チャンネルは完全に任意のものであり、通常の「色」チャンネルとは別に特別な扱いを必要とすることがよくあります。上述の画像のカラースペースを参照してください。透明度チャンネルが存在すると、各種演算子が他の色チャンネルをどう扱うかにも影響することがあります。一般に、完全に透明な色は操作によって完全に無視されるべきだからです。もしそうでなければ、画像の周囲に「黒いハロー」が出てしまいます。これはIM初期の主要なバグで見られたものです。例えばResize Halo Bugや、Blur with Transparency Bugがあります。さらに困ったことに、このチャンネルは画像の「透明度(transparency)」チャンネル、「不透明度(opacity)」チャンネル、あるいは画像の「マスク」と呼ばれることもあります。しかしいずれも同じ、特別な、画像の第4チャンネルを指しています。
その違いを説明するために、動作する例の画像が必要なので、ここでは「三日月」のPNG画像を使います(CopyOpacity合成の例より)。ご覧のとおり、この画像には完全に透明な領域が数多くあります。それだけでなく、私はこの画像を「PNG」画像形式で保存する必要がありました。これは透明色や半透明色を正しく理解して扱える数少ない画像形式の一つです。 この透明度は、IM組み込みの市松模様パターンの上に画像を重ねることで実演できます。これにはアルファ合成を使います。 |
magick composite -compose Dst_Over -tile pattern:checkerboard \
moon.png moon_background.jpg
内部アルファチャンネル
IM v7は内部的に、透明度情報を「アルファ」チャンネルに格納します。これは色チャンネルと同様に、ただのグレースケール画像で、その値は完全に透明(つまりクリア)を表す白から、完全に不透明を表す黒までの範囲を持ちます。それは元画像のシルエットを見たときに得られるようなものです。「[-level](https://imagemagick.org/command-line-options/#level)」や「[-threshold](https://imagemagick.org/command-line-options/#threshold)」のような低レベル演算子は、このデータをアルファとして扱います。不明な点があれば公式オプションリファレンスを確認してください。
作成: 2003年12月10日 (元は 'channels')
更新: 2018年10月2日
著者: Anthony Thyssen, Anthony.Thyssen@gmail.com
例の生成に使用したバージョン: ![[version image]](../static/img/masking/version.gif)
URL: https://usage.imagemagick.org/masking/
以下は、画像から「アルファ」透明度の値を取り出す非常に古い方法です。これは透明度チャンネルを「アルファ」画像ファイル形式として保存するもので、2つの別々のステップと、適切な画像ファイル形式を指定するコマンドが必要でした。 | |
magick moon.png alpha:moon.matte
magick MIFF:moon.alpha moon_matte2.png
# この2つのステップはパイプラインとして1つにまとめることもできます…
magick moon.png alpha:- | magick - moon_matte3.png
![[IM Output]](../static/img/masking/moon_matte3.png)
この、画像の「アルファ」を取り出す手法は、IM v5が使われていた頃には一般的でした。基本的に、画像の透明度にアクセスするために提供されていた唯一の方法だったのです。今ではごく稀にしか使われません。
画像の透明度を制御する
メモリ上の画像の透明度チャンネルを低レベルで制御する演算子が2つあります。新しい方の「[-alpha](https://imagemagick.org/command-line-options/#alpha)」メソッドが現在推奨される制御方法ですが、多くのIM Examplesでは依然として古い「-matte」演算子を示し、使用しています。画像はアルファチャンネルのデータを持てるだけでなく、そのチャンネルのデータが表示可能か(有効か)を定義する「スイッチ」も持ちます。つまり画像はアルファチャンネルに関して3つの状態を取り得ます。 スイッチ |
チャンネルデータ | |
|---|---|---|
| alpha off | アルファデータなし(メモリは確保されていない) | |
| alpha deactivate | 古いアルファデータあり(ただし使用されていない) | |
| alpha on | 現在使用中のアルファデータ | |
各メソッドの挙動が、画像が上記3つの状態のどれにあったかによって変わるという点を覚えておく必要があります。「スイッチ」がoffの場合、アルファデータは実際には全く存在しないかもしれないため、演算子はそれに触れません。そのような場合、古いアルファが手付かずのまま残り、古い状態のままになっていることがあります。後で見るように、これは状況によっては実は有用です。ただし、一部の演算子は何らかの理由でアルファスイッチを自動的にonにしたりoffにしたりすることがあります。例えば「-compose CopyOpacity -composite」は、結果画像で常にアルファチャンネルをonにします。これはこの演算子の仕事がアルファチャンネルにデータをコピーすることだからです。したがって最終結果にはアルファチャンネルが存在しなければなりません。しかし入力データにアルファが存在することには、別の影響が生じることもあります。詳細はCopy_Opacity合成メソッドを参照してください。同様に、色「None」を使ってキャンバスを作成すると、空白の画像が本当に透明になるよう、透明度チャンネルが自動的に作成され有効になります。一方、その他の色名を使ってキャンバスを作成した場合、画像はデフォルトで不透明なので、一般に透明度チャンネルは作成されません。 |
||
以下が各種の「[-alpha](https://imagemagick.org/command-line-options/#alpha)」メソッドと、それらが画像とその透明度にどう影響するかの例です。 |
Alpha Off または「-alpha off」
これは画像上の単純なスイッチで、透明度が画像に及ぼす効果をすべてオフにします。実際には画像に付属するアルファチャンネルを削除したり破壊したりするわけではなく、そのチャンネルが画像に及ぼす効果をオフにするだけです。同様に、チャンネルがオフにされている間は、どの演算子も付属のアルファチャンネルに影響しません。例として「三日月」画像(CopyOpacity合成の例より)を使い、単純に画像のアルファチャンネルをオフにしてみましょう。
magick moon.png -alpha off alpha_off.png
透明度をオフにすると、月の形が完全に消えてしまったことに注目してください。ただし実際にはこうなることは稀です。基本的に「透明」な領域にも色があり、それが通常は見えないだけなのです。この場合、隠れていた色は月画像の生成に使われたフラクタルキャンバス画像でした。この隠れた色は何でもあり得ます。GIF形式がカラーテーブル内で透明を表すために使う単純なGIF透明色から、上のように画像生成中に残されたゴミ色まで様々です。より典型的には、透明色は完全に透明だった任意のピクセルに対して単なる純黒です。エッジに近いピクセルは半透明である場合があり、その場合は部分的にしか見えない有効な色をなお持っていることに注意してください。上記の「[-alpha](https://imagemagick.org/command-line-options/#alpha) Off」操作は、単にチャンネルを「無効化」または「オフ」にしただけです。透明度データそのものはメモリに格納された画像データからクリアされたり除去されたりはしていません。まだ存在していて、ただ今のところ利用できないだけです。しかし… 透明度データがオフにされた状態で画像を保存すると、透明度データはどれも画像ファイル形式に保存されません。したがって、オフにされたアルファデータは画像の保存コピーには存在しなくなります。メモリ上のバージョンには(オフのまま)存在していてもです。また、多くのファイル形式(JPEGなど)は透明度の使用を許さないため、これらのファイル形式は画像保存時に(実際にそうするわけではありませんが)「[-alpha](https://imagemagick.org/command-line-options/#alpha) Off」と同等のことを自動的に行います。一般にこの結果、JPEG画像として保存すると、すべての透明領域が典型的に黒くなります。JPEGファイル形式に保存する前に透明度を正しく除去する方法については、後述のAlpha Remove - 透明度の除去を参照してください。「[+alpha](https://imagemagick.org/command-line-options/#alpha)」演算子は古いコマンドで、「-alpha Off」と全く同じです。つまり透明度チャンネルをオフにするだけです。CopyOpacityアルファ合成メソッドでグレースケールのマスク画像を使う前には、アルファをオフにすることがしばしば必要になることに注意してください。これを行わないと、合成演算子は意図したグレースケールの色を使う代わりに、有効になっている透明度(不透明度チャンネル)をコピーしてしまいます。
Alpha Set または「-alpha set」
「Set」アルファメソッドは、古い「[-alpha on](https://imagemagick.org/command-line-options/#alpha)」オプションと同じです。これは画像が「透明度」つまりアルファチャンネルを持つことを保証しますが、それが存在しなかったりオフにされていたりした場合は、完全に不透明になるよう初期化されます(後述のAlpha Opaqueメソッドを参照)。ただし、画像にすでにアルファチャンネルが存在して有効になっている場合は何もしません。言い換えると、この演算子は現在メモリ上にある画像の見た目を変えることなく、アルファチャンネルが存在することを保証します。したがって、これ単独では画像に何の変化も示しませんが、他の演算子と組み合わせると実際の効果を発揮します。そのため、Alpha Offを使ってアルファチャンネルをオフにし、Alpha Setを使って再び有効にすると、画像はアルファチャンネルを持ちますが、それは完全に不透明、つまり「Set」操作が要求された時点での画像の見た目どおりになります。 |
magick moon.png -alpha off -alpha set alpha_set.png
![[IM Output]](../static/img/masking/alpha_set.png)
有効なアルファチャンネルを持つ画像に適用した場合、変化は起きません。 |
magick moon.png -alpha set alpha_noset.png
![[IM Output]](../static/img/masking/alpha_noset.png)
まとめると、この演算子は、適用した時点での画像の見た目を決して変えるべきではありません。画像が_そのまま_になるようにアルファチャンネルを整えるだけです。これは典型的に、アルファチャンネルが存在するかどうか分からない未知の画像ファイル形式や入力ソースから画像を読み込んだ後に使われます。この演算子は、画像が(JPEGのような画像形式に対して)アルファチャンネルを確実に持つようにする一方で、既存の有効なアルファチャンネル(GIFやPNG形式の場合など)はそのままにします。これは、画像をメモリに読み込んだ後、あるいはもっと重要なことに、画像を処理した後にクリーンなアルファチャンネルを再度有効にしたい場合に、画像がアルファチャンネルを持つことを保証する推奨される方法です。
Alpha On
「[-alpha](https://imagemagick.org/command-line-options/#alpha) On」は、先ほど見たAlpha Offメソッドの正反対です。通常これはあなたの目的には_単純すぎる_ため、ごく稀にしか使うべきではありません。ほぼすべての場合で「[-alpha Set](#alpha_set)」を使うべきです。基本的に「On」メソッドは、画像の透明度データが再び見えるようにスイッチを切り替えるだけです。既存の透明度データは変更されないので、メモリ上の画像にまだ古いアルファチャンネルのデータがある場合、そのデータが突然再び見えるようになります。例えば、ここでは透明度データを「Off」にし、すぐにそれを「On」に戻すことで、元の画像を再現します。 |
magick moon.png -alpha off -alpha on alpha_on.png
![[IM Output]](../static/img/masking/alpha_on.png)
ただし、画像にまだ以前のアルファデータがない場合は、完全に不透明になるよう初期化します。それが論理的に妥当だからです。したがって、メモリに読み込んだばかりの新しい画像に対してはAlpha Setと同等ですが、この目的に使うべきではありません。Alpha Onを使うべき唯一の場面は、以前に何らかの理由で_意図的にアルファをオフにし_、そのデータを今復元したい場合です。例えば、アルファチャンネルをオフにしてからオンにすることで、「[-shade](https://imagemagick.org/command-line-options/#shade)」のような非常に特殊な演算子を適用する前にアルファチャンネルのデータを保存できます。この特殊な使い方の例については陰影付き形状画像を参照してください。
Alpha Activate/Deactivate
それぞれアルファチャンネルを有効化・無効化し、その状態を持続させます。これはImagemagick 6のon/offに相当します。Imagemagick 7では、-alpha off はアルファチャンネルを恒久的に除去するため、-alpha on で再度有効化することはできません。
Alpha Discrete
Alpha Opaque
このメソッドは、画像の透明度が「有効/on」だったか「無効/off」だったかにかかわらず、アルファチャンネルが「アクティブ」であることだけでなく、完全に不透明であることも保証します。例えば…
|
magick moon.png -alpha opaque alpha_opaque.png
![[IM Output]](../static/img/masking/alpha_opaque.png)
古いバージョンのIMでは、これは「[-alpha off](https://imagemagick.org/command-line-options/#alph)」でアルファチャンネルをオフにし、次に「[-alpha on](https://imagemagick.org/command-line-options/#alpha)」でオンにして不透明にリセットする、という両方を使うのと同等でした。 |
magick moon.png -alpha off -alpha on alpha_opaque_matte.png
![[IM Output]](../static/img/masking/alpha_opaque_matte.png)
この操作の後では、元のアルファチャンネルのデータが上書きされているため、画像の元の「形状」はもはや復元できません。もちろんこれは「-alpha off -alpha set」を使うのとも同等ですが、その場合は「-alpha opaque」を使ったほうがよいでしょう。
Alpha Transparent
同様にこれは、アルファチャンネルが「アクティブ」であると同時に完全に透明であることも保証します。 |
magick moon.png -alpha transparent alpha_transparent.png
![[IM Output]](../static/img/masking/alpha_transparent.png)
画像の色データはまだ存在しているので、その後で透明度をオフにすれば、画像の既存の色が再び表示されます。 |
magick moon.png -alpha transparent -alpha off alpha_transparent_off.png
![[IM Output]](../static/img/masking/alpha_transparent_off.png)
もちろん、画像の元の「形状」は実際には破壊されているので、この操作の後ではもはや復元できません。画像全体を完全に透明にする他の方法は透明キャンバスで示されています。
Alpha Extract
「Extract」メソッドは、画像の「アルファ」マスクをグレースケールのチャンネルマスクとして単純にコピーします。
magick moon.png -alpha extract alpha_extract.png
完全に不透明な部分は白、完全に透明な部分は純黒になることに注意してください。画像にはエッジに沿って半透明のピクセルがいくつか含まれていたため(アンチエイリアスにより画像の形状を滑らかに見せるためのもの)、この画像は純粋な白黒ではなく、エッジ周辺にグレーのピクセルも含んでいます。あなたのImageMagickが古いIMv7バージョンの場合は、チャンネル抽出を使ったこれが(ほぼ)同等の手法です。
magick moon.png -channel a -separate +channel -negate alpha_extract.png
「[Extract](#alpha_extract)」メソッドはアルファも「[Off](#alpha_extract)」にしますが、クリアはされないので、アルファチャンネルを「[On](#alpha_extract)」に戻すと、元画像の形状マスクが再作成されます。 |
magick moon.png -alpha extract -alpha on alpha_extract_on.png
![[IM Output]](../static/img/masking/alpha_extract_on.png)
元の色はすべて白に置き換えられ、エッジ周辺がさまざまな濃さのグレーになっていることに注意してください。これは、白背景で透明度を除去すると確認できます(後述のAlpha Removeメソッドを参照)。 |
magick alpha_extract_on.png -background white -alpha remove alpha_edge.png
![[IM Output]](../static/img/masking/alpha_edge.png)
これらの「グレー」のピクセルは、アンチエイリアス形状からのエッジ輪郭で、画像の形状から滑らかなエッジや輪郭を生成するのに巧みに利用されています。このアルファチャンネル保存の副作用は、画像のアルファチャンネルを理解せず使用しないShade演算子を使う際に、特別な利点があります。サブセクション陰影付き形状のマスクを参照してください。
Alpha Copy
「Copy」メソッドは「[Extract](#alpha_extract)」の逆で、本質的に自分自身に対してCopyOpacityを実行します。つまり、グレースケール画像(そのアルファチャンネルが有効かどうかにかかわらず)を形状マスク画像に変換します。
magick alpha_extract.png -alpha copy alpha_copy.png
画像が既存のアルファチャンネルを持っていたかどうかは問題ではありません。これが行うのは、画像のグレースケール値から画像の透明度を作り出すことだけです。形状マスクができたら、各種の色付けやDuff-Porterアルファ合成メソッドを使って、それに色を付けることができます。形状マスクを使う例については色付きの形状としてのマスクを参照してください。
Alpha Shape
グレースケール画像をより使いやすくするため、「Shape」メソッドは(Alpha Extractのように)形状マスクを作成するだけでなく、現在の背景色を使ってそれに色を付けます。
magick alpha_extract.png -background Yellow -alpha shape alpha_shape.png
つまり、画像をシェイプ化してから別の背景色の上にフラット化することで、グレースケールマスクに非常に手早く色を付けることができます。 |
magick alpha_extract.png -background Yellow -alpha shape \
-background Blue -alpha remove alpha_colormask.png
![[IM Output]](../static/img/masking/alpha_colormask.png)
| 背景色は、実はこの「shape」による色付け操作に使うべき正しい色ではありません。形状の前景色を設定するには「fill」色を使うべきです。そのため、どの色を使うべきかは変更される可能性があります。背景色が使われているのは、現在のfill色へのアクセスに内部的な困難があるためだけです。この変更はIMv7の一環として行われる可能性が高いです。
---|---
もちろん、白黒画像を特定の色に直接マッピングするより高速で優れた方法は、より特化した色によるレベル調整を使うことです。これにより、既存画像の透明度チャンネルを有効にしたり変更したりする必要がなくなります。 |
magick alpha_extract.png +level-colors Blue,Yellow level_color.png
![[IM Output]](../static/img/masking/level_color.png)
| 上記は線形カラースペースで色をマッピングするため、視覚的により正しい色のグラデーションを得るには、どこかでsRGBに変換する必要があるかもしれません。
---|---
Alpha Remove
「[-alpha](https://imagemagick.org/command-line-options/#alpha) **Remove**」メソッド(IMv6.7.5で追加)は、現在の「[-background](https://imagemagick.org/command-line-options/#background)」を使って画像から透明度を除去するために設計されています。 |
magick moon.png -background tan -alpha remove alpha_remove.png
![[IM Output]](../static/img/masking/alpha_remove.png)
透明度は「除去」されますが、アルファチャンネルはオンのまま残り、ただし今度は完全に不透明になることに注意してください。アルファチャンネルがもう不要なら、Alpha Offを使って無効化できます。この操作は単純で高速であり、追加のメモリ使用や、代替の透明度除去手法に伴うようなその他の副作用なしに、仕事をこなします。したがって、画像の透明度を除去する好ましい方法です。他の手法について、またはあなたのImageMagickがv6.7.5より古い場合は、後述のより詳しい議論画像から透明度を除去するを参照してください。
Alpha Background
IM v6.5.2-10より、完全に透明なピクセルの隠れた色を現在の背景色に設定する「Background」メソッドが利用可能になりました。通常この色は重要ではありません。アルファチャンネルがオフにされたときにしか見えないからです。しかし、完全に透明なピクセルの色はPNG画像ファイル形式に保存され、大きな画像では、ランダムな未知の完全透明色を持つことが圧縮の扱いに大きく影響することがあります。詳細は圧縮効率を高めたPNGとIMフォーラムの議論アルファチャンネルのゴミを排除するを参照してください。なお、色の混合は一切行われず、完全透明な色への直接的な色の代入だけが行われます。ただしピクセルは完全に透明なままなので、画像に変化は見られません。 例えば、ここではすべての完全透明ピクセルを「HotPink」に設定するのにこれを使います。 |
magick moon.png -background HotPink -alpha Background moon_hotpink.png
![[IM Output]](../static/img/masking/moon_hotpink.png)
ご覧のとおり、これは画像の実際の見た目には何の変化も与えませんでした。変化を見るために、今度はアルファチャンネルをオフにします。 |
magick moon_hotpink.png -alpha off moon_hotpink_off.png
これは透明度の除去とは異なります
形状のエッジはすべての半透明ピクセルを不透明にし、その結果として強いエイリアシング(階段状)のエッジ効果が生じます。なお、通常は不透明専用のPNG24形式であっても、すべての完全透明色が同じであれば、ブール値の透明度を保存できます。詳細はPNGサブ形式の例を参照してください。この色を置き換える処理は、実は「-channel RGB -fill _color_ -opaque None +channel」を行うのとほぼ同じです。直接的な色の置換を参照してください。なお、他の多くの画像処理演算子も、完全透明ピクセルを完全透明の黒(色「None」)にしてしまいます。これは数学的なゼロに相当する色だからです。これを行うことが知られているいくつかの画像操作のまとめを以下に示しますが、どれもこの演算子ほど直接的でも高速でもありません。
magick moon.png \( +clone -alpha off \) \
-compose SrcIn -composite moon_black.png
magick moon.png -channel RGBA -blur 1x.000000001 moon_black.png
magick moon.png -channel RGBA -gaussian 1x0 moon_black.png
magick moon.png -fuzz 0% -transparent none moon_black.png
最後のメソッド(ファズ係数と透明色を参照)は特に便利です。すべての透明色を完全透明の黒(「None」)に設定できるだけでなく、ファズ係数を指定するだけで、ほぼ完全に透明なすべての色(これは有効だが実質的に見えない色を持つ)も設定できるからです。これはデータの損失をいくらか生じますが、ほぼ完全に透明な色を多く含む画像では圧縮を改善するかもしれません。これらほぼ完全に透明なピクセルは、しばしば非常に奇妙だったり誤っていたりする色を持つことがあり、このメソッドを使えば、そうした奇妙なピクセルが他の問題を引き起こす前に除去できます。
画像から透明度を除去する
Alpha Offは単にスイッチを切り替えて透明度チャンネルをオフにするだけですが、透明度の使用を許さないファイル形式に画像を保存しようとしても同じ効果が得られます。例えばJPEGに保存すると…
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'" a.png
magick a.png a.jpg
JPEGファイル形式はアルファ(透明度)チャンネルを保存しないので、単にそれをオフにしただけだということを思い出してください。この場合、透明部分は単に黒になりました(典型的な結果です)。しかし画像のソースによっては、透明領域が他のランダムな、あるいは不適切な色になることも同じくらい簡単に起こり得ます。また多くの場合、半透明ピクセルには、ほぼ完全に透明であるために通常は見えない非常に奇妙な色があることがあります。単に透明度をオフにすると、これらのピクセルが目立ってしまい、結果が予想より悪く見えてしまいます。例えば上の「A」の左上のエッジを見てください。いずれの場合も、単に透明度をオフにするのは典型的に望ましいことではありません。_最良の解決策_は、Alpha Removeメソッドを使って、透明度を背景色の下敷きで手早く簡単に置き換えることです… |
magick a.png -background skyblue -alpha remove -alpha off a_remove.jpg
![[IM Output]](../static/img/masking/a_compose.jpg)
厳密には、JPEGへの保存がこれを自動的に行うので、この場合Alpha Offは不要です。
透明度を除去する別の手法は、何らかの方法で新しい「背景」または「キャンバス」画像を生成し、その背景の上に画像をOver合成して透明度を置き換えることです。できれば、プロファイル、ラベル、キャプション、コメントなど、元画像に存在するメタデータを保持しながら行います。このようなキャンバスを生成する方法は同じサイズの画像キャンバスを作成するで例示されています。以下はそのような方法の一つです… |
magick a.png \( +clone -alpha opaque -fill SkyBlue -colorize 100% \) \
+swap -geometry +0+0 -compose Over -composite \
-alpha off a_compose.jpg
![[IM Output]](../static/img/masking/a_compose.jpg)
これを行うより簡単な他の方法は、内部的に「クローンされた背景キャンバス」を作成する操作を使うことです。これは演算子が実行している、より大きな画像処理操作の一部として生成されます。最も一般的な方法は、画像をフラット化(Flatten)することです。この演算子はこの目的で非常によく使われるため、透明度を除去する処理がしばしば誤って「フラット化(flattening)」と呼ばれてきました。例えば… |
magick a.png -background skyblue -flatten -alpha off a_flatten.jpg
![[IM Output]](../static/img/masking/a_flatten.jpg)
ただしこれは「[mogrify](basics.html#mogrify)」や複数画像のシーケンスでは機能しません。基本的に「[-flatten](https://imagemagick.org/command-line-options/#flatten)」演算子は複数の画像を1枚の画像に統合するために設計されているからです。複数画像でも機能する他の一般的な方法は、適切な「[-bordercolor](https://imagemagick.org/command-line-options/#bordercolor)」を指定して画像にサイズゼロの境界を付けることです。例えば… |
magick a.png -bordercolor skyblue -border 0 -alpha off a_border.jpg
![[IM Output]](../static/img/masking/a_border.jpg)
上記の方法に密接に関連する他の画像処理演算子も、画像から透明度を除去できます。これにはMosaic、Merge、Frameが含まれます。Extent演算子も使うことができ、透明度を除去すると同時に画像を拡大したりクロップしたりできますが、それは最終的に望むサイズが分かっている場合に限ります。透明度を単色で置き換える必要はありません。DIY合成を使えば(上で示したように)、置き換え背景に任意の画像を使えます。この一例は、「[composite](basics.html#composite)」コマンドを使って(Dst_Overで)元画像の「下に」画像をタイル状に並べることです。この合成メソッドは、元画像のメタデータとサイズを保持することを保証します。 |
magick composite -compose Dst_Over -tile pattern:checkerboard \
a.png a_undertile.jpg
![[IM Output]](../static/img/masking/a_undertile.jpg)
| _上記の方法の多くは、処理の一環として、画像が持ちうる仮想キャンバス情報の影響を受けるか、それを破壊する可能性があります。仮想キャンバスが関与する場合は、個々の演算子の詳細をより詳しく調べる必要があるかもしれません。多くの場合、仮想キャンバスの効果は全体的な画像処理に有用なことがあります。
ブール値のアルファ透明度
一部の画像ファイル形式では、アルファチャンネルを完全に除去する必要はなく、純粋なon/off、つまりブール値の透明度だけを許せばよい場合があります。GIFやPNG8のようなインデックス(パレット)画像ファイル形式が典型的です。現在のところ例はGIFのブール値透明度で扱っていますが、いずれここに移すべきものです。
輪郭(ハロー)の透明度
透明度を含む画像の周囲に輪郭を追加したいことがあります。一つの方法は、EdgeOutモルフォロジーを使って元画像の隣接ピクセルをすべて素早く取得し、それらに色を付けてから、元画像とUnder(DstOver)合成することです。
magick knight.png \( +clone \
-channel A -morphology EdgeOut Diamond +channel \
+level-colors red \
\) -compose DstOver -composite knight_outlined.png
これは、半透明のエッジピクセルを含むPNG画像からGIF形式の画像を作成するときに特に便利です。最小限の背景色を提供しつつ、画像の残りの部分は完全に透明なままにします。この問題の詳細については背景パターン上のGIFを参照してください。別の方法は、形状の周囲に柔らかい半透明のハローを生成することです。これを行うには、画像をぼかして色を付け直し、再び元画像とUnder(DstOver)合成します。 |
magick knight.png \( +clone \
-channel A -blur 0x2.5 -level 0,50% +channel \
+level-colors red \
\) -compose DstOver -composite knight_halo.png
![[IM Output]](../static/img/masking/knight_halo.png)
この最後のものは、ソフト輪郭の複合フォント効果を使うのに実は似ていますが、注釈テキストの代わりに形状を持つ画像を使っています。
画像でマスクを使う
画像をマスクする
前に示したように、画像の一部を透明にするために画像をマスクする方法はいくつかあります。どの方法を選ぶかは、画像マスクがグレースケールマスクなのか、形状マスクなのかによって決まります。
画像マスクを編集する
画像のマスクは、持っていると本当に便利なものです。例えば、元画像のマスクを変更することで、画像の一部を非常に簡単に消去できます。「[-draw](https://imagemagick.org/command-line-options/#draw)」演算子は何もないものを描けず、現在のところ消去オプションもないことを思い出してください。ここでは画像を作成し、そのマスクを抽出して変更してから、元画像に戻します。
magick -size 100x100 xc:none -stroke black -fill steelblue \
-strokewidth 1 -draw "circle 60,60 35,35" \
-strokewidth 2 -draw "line 10,55 85,10" drawn.png
magick drawn.png -alpha extract mask.png
magick mask.png -fill black -draw "circle 40,80 60,60" mask_bite.png
magick drawn.png mask_bite.png \
-alpha Off -compose CopyOpacity -composite \
drawn_bite.png
マスクにおける「黒」は透明、白は不透明であることを思い出してください。ですから、表示したくないものの上に黒を描くだけでよいのです。上記の「-alpha Off」操作を忘れないでください。グレースケール画像が不要な透明度チャンネルを含まないようにするのに不可欠です。これで元画像から一口かじり取れました。除去した画像の一部を再び追加することもできます。例えば、ここでは元画像から除去した「かじり跡」の一部を、マスクに白い領域を描くことで再追加します。次にそのマスクをCopyOpacityチャンネル合成を使って再び元画像に戻します。
magick mask_bite.png -fill white \
-draw "circle 50,70 60,60" \
-draw "roundRectangle 78,5 98,25 5,5" \
-alpha off mask_bite2.png
magick composite -compose CopyOpacity mask_bite2.png drawn.png drawn_bite2.png
部分を再追加することについて一言注意です。典型的に、ImageMagickは完全透明な色をすべて黒に置き換えます。これは通常、演算子の背後にある数学がそのように動作するためです。なんといってもそれは完全に透明であり、その色は通常問題にならないはずだからです。つまり、以前に描いたことのない画像の一部を不透明にすると、それは一般に黒になります。画像の透明度の下にある色がそれだからです。しかし上の例では、PNG画像ファイル形式が画像の(透明にされた)元の色を正しく保持したことに気づいたでしょう。そのため、再追加された部分の色は元画像の元の「SteelBlue」色のままでした。画像が他のファイル形式で保存されたり、さらに変更されたりした場合は、これを当てにすべきではありません。
以下は画像から部分を消去する別の方法です。グレースケールマスクを抽出して変更する代わりに、DstOut合成メソッドを使って形状マスクを一種の「消しゴム」ツールとして使います。
magick -size 100x100 xc:none -draw "circle 40,80 60,60" mask_shape.png
magick drawn.png mask_shape.png -compose DstOut -composite drawn_bite3.png
ご覧のとおり、形状マスクの方が扱いやすいことがあります。アルファチャンネルを抽出して復元する必要がなくなるからです。ただし、私が使っているDuff-Porterアルファ合成メソッドでは、透明にされた色を復元することは決してできません。これらのメソッドでは、透明にされた(したがって色が未定義になった)ものは透明なままです。実際、アルファ合成メソッドを使って画像の一部を消去すると、完全透明ピクセルの下の色が破壊されます。それは保持されません。なんといっても、透明な色は実際には本物の色ではないのですから!
色付きの形状としてのマスク
マスクを使って画像に透明度を追加・再追加する以外の方法として、実際にマスクを画像とさまざまな方法で直接組み合わせることがあります。例えば、マスクを、さまざまな色で画像に重ねたいシンボルや形状として使いたいとします。これにはマスクが必要で、特別な「シンボル」フォントから抽出します。 |
magick -font WebDings -pointsize 24 label:Y \
+trim +repage -negate heart_mask.gif
![[IM Output]](../static/img/masking/heart_mask.gif)
ラベル画像を反転(negate)して、黒背景(透明)に白前景(不透明)からなる適切なマスク画像にしたことに注意してください。IM v6.4.3-7より、グレースケールマスクを色付きの形状にする最も簡単な方法は、Alpha Shape演算子を使うことです。これはAlpha Copyとまったく同じですが、最終的な形状に色を付ける追加のステップがあります。 |
magick heart_mask.gif -background Red -alpha Shape heart_red.png
![[IM Output]](../static/img/masking/heart_red.png)
| 生成される形状画像にGIFではなく「PNG」画像形式を使っているのは、GIFのブール値透明度の問題を避けるためです。
---|---
これ以前は、最も簡単な解決策は、アルファマスクをマットチャンネル画像に反転してから、Combineを使って形状画像を生成することでした。 |
magick heart_mask.gif -negate \
-background Gold -channel A -combine heart_gold.png
![[IM Output]](../static/img/masking/heart_gold.png)
この場合の形状マスクの色は、Combineが新しい画像の未定義チャンネルを埋めるために使った「[-background](https://imagemagick.org/command-line-options/#background)」色によって定義されます。より古いがより複雑な方法は、「[CopyOpacity](compose.html#copyopacity)」合成メソッドを使って画像の透明度を与えられたマスクに設定し、次に均一な色付けを使って得られた形状に色を付けることです。これは機能し、長い間使うべき最良の手法でしたが、もはや推奨されません。 |
magick heart_mask.gif \( +clone \) -alpha off \
-compose CopyOpacity -composite \
-fill HotPink -colorize 100% heart_hotpink.png
![[IM Output]](../static/img/masking/heart_hotpink.png)
「シェイプ化」された画像ができたら、あとは画像レイヤー化テクニックとアルファ合成メソッドの一つを使って、組み込みのバラの画像のような任意の背景に画像を重ねるだけです。 |
magick rose: -page +2+2 heart_gold.png \
\( +clone -repage +7+29 \) \
\( +clone -repage +52+14 \) \
-flatten rose_with_love.gif
![[IM Output]](../static/img/masking/rose_with_love.gif)
これは、すべてのシンボルを同じ色にしたい場合は問題ありませんが、複数の色を使いたい場合は複数の中間画像が必要になり、多くの異なる色の多くのシンボルを重ねるには非現実的です。複数色の重ね合わせを作る一つの方法は、画像を読み込んだ直後にシェイプ化された画像の色を付け直すことです。 |
magick rose: \( heart_gold.png -repage +2+2 \) \
\( +clone -fill Red -colorize 100% -repage +7+29 \) \
\( +clone -fill HotPink -colorize 100% -repage +52+14 \) \
-flatten rose_colored_love.gif
![[IM Output]](../static/img/masking/rose_colored_love.gif)
シェイプ化された画像を1枚だけ読み込み、重ねる新しい「レイヤー」ごとにその画像のクローンを色付けし直していることに注意してください。ベース画像を色付けし直す例の詳細については、色の変更の章全体を参照してください。画像内の特定の位置をマークする別の方法についてはシンボルを描くも参照してください。また、より自動化されたレイヤー化テクニックについては地図のピン留めレイヤー化の例も参照してください。
数学的合成
マスクを何らかの背景に重ねる代わりに、マスク自体の白い部分または黒い部分だけで画像を色付けすることに関心があるかもしれません。これは比較的簡単で、いくつかの数学的アルファ合成メソッドを使ってマスクの色を、ある色、タイル、その他の画像に合わせて変えるだけです。例えば「[Multiply](compose.html#multiply)」合成メソッドは、白い領域(乗算値1)を重ねる画像で置き換え、黒い領域(乗算値0)は黒のまま残します。「[Screen](compose.html#screen)」演算子は「[Multiply](compose.html#multiply)」とまったく同じですが、画像を反転するので、実質的に画像の黒い領域を置き換えます。例えば、上記の大きなマスク画像を使って、タイルパターンで生成した大きな画像を重ねてみましょう。
magick mask_bite.png -size 100x100 tile:tile_disks.jpg \
-compose Multiply -composite compose_multiply.png
magick mask_bite.png -size 100x100 tile:tile_water.jpg \
-compose Screen -composite compose_screen.png
「[Multiply](compose.html#multiply)」アルファ合成メソッドは、テキスト画像(つまり白背景に黒文字)の背景を置き換えるのに特に便利です。Postscript文書から生成された画像などです。
マスクを用いたアルファ合成
マスクを用いたアルファ合成の特別な3画像形式では、同じマスクを使って2枚の画像を直接統合できます。 |
magick -size 100x100 tile:tile_water.jpg tile:tile_disks.jpg \
mask_bite.png -composite compose_masked.png
![[IM Output]](../static/img/masking/compose_masked.png)
1枚目の画像がマスクの黒い背景部分を置き換え、2枚目の画像がマスクの白い前景部分を置き換えます。マスク自体は3枚目の画像として与えられます。マスクは2枚の異なる画像を選択して混ぜ合わせ、最終結果を生成するために使われます。これは実際には、2枚の画像をマップ化したBlendのようなものです。結果画像の最終的なサイズとメタデータは、上記操作の1枚目の「背景」画像(黒い部分)から来ることを覚えておいてください。逆向きにしたい場合は、画像を入れ替えてマスクを反転(Negate)してください。そして最後に、「[convert](basics.html#convert)」の代わりに「[composite](basics.html#composite)」コマンドを使う場合は、「重ね」画像(白い部分)を先に、「背景」画像(黒い部分)を2番目に与えることを覚えておいてください。言い換えると、そのコマンドでは最初の2枚の画像を入れ替える必要があります。
マスクされた2枚の画像を揃える
作成中
2枚のマスクされた画像を揃えることについて…
マスクが純粋なブール値であれば、どのように適用しても問題は起きないはずです。
しかし、「滑らかに見せる」ために「アンチエイリアス」、「グレー」、または
「半透明」の縁取りを含むマスクは、適切に注意して扱わないと深刻な
頭痛の種になり得ます。
この議論の残りは「アンチエイリアス」マスクについてです。
つなぎ合わせるアンチエイリアスマスクには2つのスタイルがあります…
* ジグソーパズルのピースのように、または形のあるペグを形のある穴に
はめるように、ぴったり合うもの(境界を共有)
* 不透明な領域に重ねることを意図したマスク(層状)
後者は扱いやすく、完全に不透明な画像の上に色付きの形状を重ねたときに
得られる通常の効果です。基本的に、形状を合成するには「over」合成を
使えばよいのです。
前者の「ジグソー」マスクの方が難しいです。そのようなマスクは、互いに
重なったり下に潜り込んだりすることを意図していません。それでも、当たり前で
通常の「over」合成を使ってつなぎ合わせようとすると、「アンチエイリアスの
エッジ」が統合された半透明のつなぎ目ができてしまいます。
_不適切な「ジグソーマスク」のつなぎ合わせの例(over)_
マスクや形状を持つ「ジグソー」画像をつなぎ合わせる正しい方法は、
**Plus**合成を使って、黒または完全透明の背景で画像を「加算」する
ことです。
_正しい「ジグソーマスク」のつなぎ合わせの例(plus)_
'Dst-In'、'Dst-Out'、'Plus'合成を使ったDIY画像つなぎ合わせの別の例
については、以下の例を参照してください…
https://usage.imagemagick.org/compose/#dstin
このつなぎ合わせの詳細については、3画像アルファ合成のバグレポート
[Composite Mask Bug - Fixed](https://usage.imagemagick.org/bugs/composite_mask/#correct)
でも扱っています。
'over'と'plus'の違いの詳細については['Blend'(plus)対'Dissolve'(over)](compose.html#blend_dissolve)を参照してください。
エッジを揃えたピースを正しくつなぎ合わせる例は
[3d立方体 - アフィン](distorts.html#cube3d)、再び[3d箱 - パースペクティブ](distorts.html#box3d)、
そしてシアーを使った等角立方体
https://usage.imagemagick.org/warping/#sheared_cube
で示されています。
これらの例の大きな問題は、個々のパーツが同じマスクを使って生成された
のではなく、最終位置までゆがめられたことです。
そのため、それらは互いに正確にはぴったり合わず、つなぎ合わされています。
これらの例は'Plus'合成メソッドを使うように更新する必要があります。
改善された結果を生成するためですが、その場合でもマスクは互いに正確には
「合わない」ため、おそらくまだ完全には「正しく」ならないでしょう。
エッジを揃えた正しいマスクを生成する
最良の考え方は、2枚のマスクを別々に描こうとするのではなく、両方のピースに
同じマスク(反転したもの)を使うことです。そうしないと、これまで見てきた
とおり、2枚のマスクが重なるか、隙間ができてしまいます。
正しいマスクのつなぎ合わせ方法…
* マスクを使って一方のピースに透明度を設定する
反転したマスクを使ってもう一方のピースの透明度を設定する
2枚のピースを'Plus'で加算する。
* マスクを使って一方のピースにだけ透明度を追加し、次に
そのピースを完全な画像の上に'Over'合成する。
* 3画像のマスク合成を使う
https://usage.imagemagick.org/compose/#mask
および https://usage.imagemagick.org/masking/#masked_compose
を参照。これはマスクを使って2枚の異なる画像から結果を選択します。
'Over'は'ソース'または'重ね'画像だけをマスクする必要があり、背景画像は
エッジを揃えた半透明のエッジを持つべきではないことを覚えておいてください。
しかし'plus'合成では、つなぐエッジを揃えて、互いの正確な反転マスクで
両方の画像をマスクする必要があります。
警告: Drawは現在、重なりなしにぴったり合う2つの形状を生成すること
ができません!!!!
詳細は[Draw Fill Bounds](draw.html#bounds)を参照してください。
SVGが同じ問題を持つかどうかは確認していません。
特殊な画像マスク
書き込みマスク - ピクセルを変更から保護する
「書き込み」または「クリップマスク」は、既存の画像に同じサイズで追加される特殊なグレースケール画像です。これは、ほとんどの画像処理演算子によって「不変」または「書き込み不可」と分類されるべき画像の領域を定義します。演算子「[-mask](https://imagemagick.org/command-line-options/#mask)」は、メモリ上の画像にリンクする外部画像を取ります。演算子の「plus」形式「[+mask](https://imagemagick.org/command-line-options/#mask)」は画像からマスクを除去します。例えば、ここでは「書き込みマスク」を使って背景ピクセルへの書き込みを保護しながら、色相を回転させて前景の赤いバラを青いバラに色付けし直します。
magick rose: -mask rose_bg_mask.png \
-modulate 110,100,33.3 +mask rose_blue.png
マスクは少し粗いですが、うまく機能しました。ただ、「書き込みマスク」は保護または保存する部分を指定するために使われることを覚えておいてください。IMv7では…
「[-mask](https://imagemagick.org/command-line-options/#mask)」演算子は「書き込み保護」マスクを定義します
より高度な例についてはクロマキーによるマスクを参照してください。これはマスクを書き込みマスクとして適用することよりも、マスクを生成することに重点を置いています。書き込みまたはクリップマスクは、画像内のピクセルが直接変更されるときに機能するよう設計されています。例: negate、level、色付け、modulate、描画、composite、モルフォロジー、畳み込み。新しい画像を生成する演算子(resize、distort、extentなど)に対しては、マスクが新しい画像サイズに対応できないため、元のピクセルを保持できません。そのような操作には、画像の「書き込みマスク」を除去または解除するという副作用もあります。以下はもう一つの例です…
magick -size 70x70 xc:red red_image.png
magick -size 70x70 xc: -draw 'circle 35,35 30,5' write_mask.png
magick red_image.png -mask write_mask.png \
-fill blue -opaque red +mask masked_color_replace.png
マスクと結果画像の両方のエッジが滑らか(アンチエイリアス)になっていることに注意してください。これは、マスクが単なるブール値のマスクではなく、ブレンディングマスクだからです。「書き込みマスク」はブレンディングマスクであり、マスク内の「グレー」ピクセルは、存在するグレーの量に応じて、新しいピクセルと古い画像の値とのブレンドを生成します。これは非常に滑らかなエッジを生み、また変更された領域と変更されていない領域の間に画像全体にわたるグラデーションを生成することもできます。ただし、ブレンディングマスクは単一の操作には適していますが、複数の操作に使うとそのブレンド効果が複数回適用されてしまうので、よくないかもしれません。この問題は、モルフォロジーのようなループ操作で特に顕著です。ただし非ブール値のブレンディングマスクを使う場合に限ります。これが問題になる場合は、おそらく画像のコピーに対してすべての操作を行ってから、元画像に対してマスクを用いたアルファ合成を使ったほうがよいでしょう。注意が必要です。
このマスクの使い方は、実は合成マスクが実際に機能する仕組みそのものです!ただし合成演算子が適用されている間だけです。
magick -size 70x70 xc:green green_image.png
magick red_image.png green_image.png write_mask.png \
-composite masked_composite.png
これは(反転したマスクで)以下と同等です… |
magick write_mask.png -negate -write MPR:mask +delete \
red_image.png -mask MPR:mask \
green_image.png -composite +mask masked_composite_equiv.png
![[IM Output]](../static/img/masking/masked_composite_equiv.png)
つまり、マスクが反転され、最初の「行き先(destination)」画像に適用されます。次に2枚目が最初の画像の上に合成され、元のマスク画像の「白い」領域だけが変更されます。
3画像の「[-composite](https://imagemagick.org/command-line-options/#composite)」操作は「書き込み」マスクを使います
モルフォロジーでは、書き込みマスクは典型的に、操作の条件付きまたは制約付きモルフォロジー形式を生成するために使われます。そのような例の一つが、膨張(dilation)の効果を制限するため、IMの議論フォーラムテキスト周りのノイズを除去するで議論されました。注: -cropは、マスクもクロップして新しい画像に割り当てることで、個々の画像の画像マスクを保持できるはずです。しかしこれは現在のところ行われていません。
クリップマスクとクリップパス
この演算子の「[-clip-mask](https://imagemagick.org/command-line-options/#clip-mask)」形式は、上記とほぼまったく同じですが、ブール値(全か無か)スタイルのマスクのみを提供します。そのため、「ブレンドされた」または滑らかな結果を得ることはできません。例えば… |
magick red_image.png -clip-mask write_mask.png \
-fill blue -opaque red +clip-mask clipped_modulate.png
![[IM Output]](../static/img/masking/clipped_modulate.png)
ご覧のとおり、結果は強くエイリアシングしています(階段状のエッジ)。「[-clip-mask](https://imagemagick.org/command-line-options/#clip-mask)」は「[-mask](https://imagemagick.org/command-line-options/#mask)」のようにブレンドされた結果を生成しないからです。これの唯一の良い点は、わずかに高速なことです(それほどでもありませんが)。これはもともとTIFF画像ファイルのクリップパスを扱えるようにするために提供されたもので、非常に古い演算子(IMv5)です。代わりに新しい「[-mask](https://imagemagick.org/command-line-options/#mask)」演算子を使うべきです。 | _IMv7では、「書き込みマスク」と「クリップマスク」は、技術的にはまったく同じ機能を果たすにもかかわらず、並行して実装されています。そのため、両方のマスクを同時に適用することもできます。
ただし両方を同時に使うことは推奨されず、結果は未定義です。また、この「ブール値マスク」形式はIMv7から削除されました。
TIFF画像のクリップパス
「クリップパス」はTIFF画像ファイル形式の一部であり、TIFF画像内の「形状領域」を定義するために使われるベクターパスを定義します。IMでは、演算子「[-clip](https://imagemagick.org/command-line-options/#clip)」と「[-clip-path](https://imagemagick.org/command-line-options/#clip-path)」がこの「クリップパス」を読み込み、それをクリップマスク(上記)に変換します。そのため、形状を変更から保護する「書き込みマスク」を定義します。TIFF画像に格納されたクリップパスはSVGパス描画として定義され、以下を使ってTIFF画像ファイル形式から抽出できます…
magick identify -format '%[8BIM:1999,2998:#1]' image_clip.tiff
よくある最大の問題は、クリップされていないすべてのものを透明にすることです。これには、マスクが書き込み保護する領域に書き込む必要があります!これは一つの解決策で、画像全体を透明に変換し、次に「クリップパス」をオンにしてから、書き込み可能になった部分を再び不透明(見える状態)にします。
magick input.tiff -alpha transparent -clip -alpha opaque -strip out.tiff
「[+clip](https://imagemagick.org/command-line-options/#clip)」演算子は、(「[+clip_mask](https://imagemagick.org/command-line-options/#clip_mask)」と同様に)クリップマスクをオフにして除去します。ただし、いかなる画像ファイル形式でも、現在のクリップマスクを画像とともに保存するファイル形式はありません。(少なくともIMv7では)
読み込みマスク - ピクセル入力を無視する
書き込みマスクは、画像に書き込まれるピクセルを制限することに注意が必要です。しかし、書き込まれる新しいピクセルデータを作成するために、操作の一部として「読み込まれる」ピクセルを制限するわけではありません。これは基本的に、ぼかし、モルフォロジー、畳み込みのような「領域効果」または「近傍」タイプの演算子を使うと、エッジに近い「書き込み可能なピクセル」が、マスクされた書き込み不可領域の色値を含みうることを意味します。例えば、ここでは画像をぼかす前に前景のバラを書き込み保護します。つまり、この場合はかなり強く、画像の背景部分だけをぼかしたいのです。
magick rose: -mask rose_fg_mask.png \
-blur 0x8 +mask rose_bg_blur_fail.png
![[IM Output]](../static/img/masking/rose_bg_blur_fail.png)
結果は書き込み保護マスクを使ったもので、望んだものではありません。
ご覧のとおり、前景の色がマスクによって保護されていたにもかかわらず、その色はバラの周りの背景をぼかす一部として依然として使われていました。このため、前景に近いぼかされた背景にはっきりとした赤みがかった色合い、つまりハローが出ています。別の言い方をすると、前景の色が周囲の背景に「漏れ出した」のです。これは、レンズのフォーカス効果の一部として画像の背景をぼかしたいときに人々が意図することではありません。人々が本当に望むのは、ぼかしが前景ピクセルを完全に「無視」し、背景の色だけがぼかし処理の一部になることです。つまり、ぼかしが前景ピクセルを「読み込む」のを防ぎたいのです。
IMv7のための読み込みマスクの解決策
IMv7では、ピクセルの色を読み込み不可にする唯一の方法は、そのピクセルを透明にすることです。透明ピクセルは定義上、色を持たないので、その「隠れた色」はぼかし操作が行う計算の一部になりません。これは「裏技」になります。前景ピクセルを透明にし、ぼかし(または他の)操作を適用し、透明度をオフにします(この場合は実際には不要です)。それから画像の前景部分を復元できます。これが複雑に聞こえるなら、実際に複雑です。以下が関与するステップで、手法を明確にするために中間画像も示します…
magick rose: rose_bg_mask.png -alpha off \
-compose CopyOpacity -composite +compose rose_bg_only.png
magick rose_bg_only.png -channel RGBA -blur 0x8 rose_bg_blurred.png
magick rose_bg_blurred.png -alpha off rose_bg_blur_opaque.png
magick rose_bg_blur_opaque.png \
rose: rose_fg_mask.png -composite rose_bg_blur_good.png
結果は、以前ぼかされた背景に「漏れ出していた」赤いハロー効果の除去です。以下は、背景ぼかしの書き込みマスク版と読み込みマスク版の並列比較で、前景の色が背景に「漏れる」のをどう除去したかがはっきり分かります。 ![[IM Output]](../static/img/masking/rose_bg_blur_fail.png)
Write | ![[IM Output]](../static/img/masking/rose_bg_blur_good.png)
Read
---|---
マスク方法の違い
上記の例は、元画像にアルファがないことを前提としています。画像にアルファチャンネルも含まれている場合は、アルファを分離して別々に処理する必要があり、手間が2倍になります。この一例が「distort resize」の議論で示されており、distortを使ってリサイズする画像を囲む仮想ピクセルを無視したいというものでした。詳細は正しいリサイズ(distortを使用)を参照してください。なお、上記はぼかしによる穴埋め技術とも非常に密接に関連しています。唯一の違いは、変更から保護されるのが前景ではなく背景であることです。これにより少し単純になります。本物の「読み込みマスク」がIMv7で利用可能になるべきで、それによって上記は単に「読み込みマスク」と任意で「書き込みマスク」の両方を追加するだけになります。
領域と領域サブ画像
領域は、操作の効果を画像のより小さな領域に制限する別の方法です。例えば、ここでは矩形領域全体を赤く色付けします… |
magick koala.gif -region 40x33+15+5 -fill red -colorize 50% \
koala_region_red.gif
magick koala.gif -alpha set \
-region 40x33+15+5 -alpha transparent koala_region_trans.gif
![[IM Output]](../static/img/masking/koala_region_trans.gif)
「領域画像」を透明にする前に、元画像にアルファチャンネルが有効になっていることを確認する必要があったことに注意してください。これを行わないと、IMは「領域画像」内の透明度を透き通った状態にしてしまい、変化が見られなくなります。詳細は後述の領域の仕組みを参照してください。 | IM v6.6.9-5以前は透明度の保持が壊れており、領域内の透明度の結果は常に「元画像が透き通って見える」状態でした。そのため、画像が透明度の使用を許していても、上記の結果には透明ピクセルが一切含まれませんでした。
---|---
領域を使う最大の理由は、効果を小さな領域に単に制限するだけでなく、実際にその矩形領域を画像から抽出し、それに続くすべての単純な操作をそのより小さな領域に適用することです。これは、非常に大きな画像の非常に小さな領域だけを変更している場合、例えば赤目除去を行う場合に、操作のスコープをその領域に制限するだけでなく、_はるかに高速に_実行でき、抽出された領域画像自体も小さくなることを意味します。まとめると… 書き込みマスクは画像全体に対して操作を実行しますが、実際に変更されるピクセルを制限します。一方、領域はより小さな抽出されたサブ画像を使います。これら2つの方法を一緒に使うことを妨げるものは何もないことに注意してください。ただし、領域にクリッピングマスクを適用する場合、クリッピングマスクは抽出された領域画像のサイズに合致すべきです。
局所領域をワープする
「画像領域」は実際に処理のために元画像の「小さなサブ画像」を抽出するので、特別な「局所化された」円形歪みを使って元画像の小さな領域をワープできます。例えば、ここに縞模様の列があります。
magick -size 600x70 xc:darkred \
-fill white -draw 'roundrectangle 5,5 595,65 5,5' \
-fill black -draw 'rectangle 5,25 595,31' \
-fill red -draw 'rectangle 5,39 595,45' \
lines.gif
これで、領域を定義することで、異なる領域で異なる方法で線を歪めることができます。
magick lines.gif \
-region 90x70+10+0 -swirl 400 \
-region 90x70+100+0 -swirl 400 \
-region 90x70+190+0 -swirl -400 \
-region 120x70+280+0 -implode 1.5 \
-region 100x70+380+0 -implode -7 \
-region 101x70+480+0 -wave 10x50 -crop 0x70+0+10\! \
+region lines_regions.gif
「-implode」と「-swirl」は、歪められた画像の外縁が定義された領域外の画像の残りの部分とぴったり合うという性質を持つため、領域の使用に非常によく適合することに注意してください。つまり、これらは実際に「局所化された画像ワープ」を実行するように設計されています。Wave歪みを使ったとき、得られた「wave」画像が、それが抽出された元の領域に再び収まるように、結果のサイズをクロップしなければならなかったことに注意してください。領域は単純な画像処理演算子で使われたときにのみ機能することを覚えておいてください。他の演算子(別の「-region」演算子を含む)は、その操作が適用される前に領域処理をキャンセルします。
領域の仕組みとその問題点
実際には、領域が機能する仕組みは以下のとおりです…
- 「
-region」演算子に従って、領域引数を使った単純なクロップで、画像からより小さな画像を抽出する。 - それに続く単純な画像処理演算子を、より小さな画像に適用する。
- 単純でない画像演算子が現れたとき、または別の「
-region」演算子が見つかったとき、または「+region」を使って領域がオフにされたときに、抽出された領域がその抽出位置で元画像の上に重ねられる。
領域は画像スタック演算子を使うのに似た方法で機能しますが、それらの演算子のずっと前からImageMagickに存在していました。例えば、IMバージョン5の不可欠な部分でした。例えば、この領域操作があるとします…
... -region WxH+X+Y ...simple-operators... +region ...
結果はこれと同等です(単一画像の場合)…
... \( +clone -crop WxH+X+Y ...simple-operators... \
\) -geometry +X+Y -composite ...
またはこれ(複数画像の場合)…
... \( -clone 0--1 -crop WxH+X+Y ...simple-operators... \
null: +insert \) -geometry +X+Y -layer composite ...
「領域画像」が実際にどのように「元画像」の上に重ねられるかは少しトリッキーです… 元画像に透明度チャンネルが有効になっていない場合、「領域画像」はOver合成を使って合成されます。つまり、領域画像内の透明領域は透き通った状態になり、その背後の元画像が見えるようになります。例えば、ここでは元画像の透明度を意図的にオフにしましたが、その後で領域を回転させて、角にいくつかの透明領域を生成しました。 |
magick koala.gif -alpha off -region 30x30+10+10 \
-alpha on -background None -rotate 30 koala_region_rotate_1.gif
![[IM Output]](../static/img/masking/koala_region_rotate_1.gif)
ご覧のとおり、回転した領域の角(「領域画像」では透明だった)は「元画像」を示しています。基本的に、元画像が透明度を扱えないため、領域画像は透き通った角を持って単に重ねられます。元画像にアクティブな透明度が含まれている場合は、変更された領域画像の透明度も変更できるので、透明度はそのまま「コピー」されます。 |
magick koala.gif -alpha set -region 30x30+10+10 \
-background None -rotate 30 koala_region_rotate_2.gif
![[IM Output]](../static/img/masking/koala_region_rotate_2.gif)
ご覧のとおり、IMはCopy合成を使うので、領域画像に存在する透明度も元画像にコピーされます。何らかの理由で元画像の元の透明度を保持したい場合は、最初にアルファをオフにし、領域画像が復元された後で、それを再びオンにして透明度を復元してください。
拡大または縮小された領域画像は、元画像に「収まらない」ことがあります。例えば、ここでは領域画像をリサイズ(して色付け)して小さくします… |
magick koala.gif -region 30x30+10+10 \
-resize 75% -fill red -colorize 30% koala_region_shrink.gif
![[IM Output]](../static/img/masking/koala_region_shrink.gif)
ご覧のとおり、元の領域は、復元された領域画像によって覆われませんでした。そのため、覆われなかった部分は置き換えられませんでした。同様に、領域が大きくなると、元画像のより多くの部分が重ねられた領域画像によって覆われることがあります。 |
magick koala.gif -region 30x30+10+10 \
-resize 150% -fill red -colorize 30% koala_region_enlarge.gif
![[IM Output]](../static/img/masking/koala_region_enlarge.gif)
どちらの場合も、領域の左上のオフセットは動きません。領域画像を単に縮小して領域エリア内に中央揃えすることはできず、また領域画像を別の位置に配置することもできません。領域画像のサイズが変わらないように注意を払うべきです。ただし、いくつかの特別な状況では、リサイズされた領域を扱うことができます。この一例については上記の「wave歪み」の例を参照してください。 | _「[mogrify](basics.html#mogrify)」と同様に、複数のサブ画像を統合することはできません。それには単純でない画像操作の使用が必要だからです。ただし、別の合成方法として「[-draw](https://imagemagick.org/command-line-options/#draw)」を使うことができます。例についてはMogrifyでのアルファ合成を参照してください。
_
---|---
| _本稿執筆時点では、「領域画像」は元画像からの抽出によるクロップ仮想キャンバスオフセットをまだ含んでいます。これは、この情報が有用だと思うかどうかによって、バグと見なされる場合もそうでない場合もあります。このオフセットは、領域画像が復元されるときには現在使われていません。
オフセットが不要な場合(Distortのような演算子と干渉するため)は、「[-region](https://imagemagick.org/command-line-options/#region)」オプションの後に「[+repage](https://imagemagick.org/command-line-options/#repage)」演算子を続けて、領域画像からオフセットを除去してください。その除去や変更は、元画像への復元には影響しません。
_
---|---
背景の除去
画像処理で最も一般的な問題の一つは、既存の完全に不透明な画像からマスクを生成することです。そのような画像は、World Wide Webからダウンロードされたり、プログラムによって生成されたり、何らかの透明度を提供しない画像形式であったりします。また、何らかのオブジェクトの写真を持っていて、その背景を除去したい場合もあるでしょう。写真は透明度の概念を持たないので、不要な部分を自分で除去する必要があることを覚えておいてください。残念ながら、この問題に対する一般的な解決策はありません。特に、画像の半透明の縁取りも保持したい場合はそうです。結果として、この作業を行う方法とそのバリエーションは何百通りもあり、すべて正確な状況に依存します。画像のマスクと密接に関連するのは、画像が重ねられる予定の背景に合わせた透明度の調整です。これは、ブール値の透明度のみを許すGIF画像ファイル形式への保存の一環として、詳しく説明されています。
単純な背景をマスクする(フラッドフィル)
画像の背景が単純な単一の単色である場合、画像内の色の置換を行うだけで、単純なマスク(と背景除去)を生成できることがよくあります。例えば、以下は単色背景の画像の直接的なフラッドフィルマスクです。 |
magick cyclops.png -alpha set -channel RGBA \
-fuzz 1% -fill none -floodfill +0+0 white \
cyclops_flood_1.png
![[IM Output]](../static/img/masking/cyclops_flood_1.png)
さて、これはうまくいきませんでした。右上の角のフラッドフィルの「シード」点が、画像のすべての部分に実際には届かないからです!!!これに対する解決策は、フラッドフィルが画像の外側のエッジすべてに届く経路を提供するために、画像を少し拡大することです。ただしこのためには背景の色を知る必要があります。 |
magick cyclops.png -bordercolor white -border 1x1 \
-alpha set -channel RGBA -fuzz 1% \
-fill none -floodfill +0+0 white \
-shave 1x1 cyclops_flood_2.png
![[IM Output]](../static/img/masking/cyclops_flood_2.png)
もちろん、あまり良いファズ係数を指定しませんでした。これの問題は、画像内のオブジェクトの周りにハローができることです。これは、ほとんどの画像が、画像の見た目を滑らかにするための特別なピクセルをエッジに沿って含んでいるためです。しかし、この画像は背景に対して相対的に良い黒い境界を持っているので、大きめのファズ設定を使えば、画像を背景からきれいに分離できます。 |
magick cyclops.png -bordercolor white -border 1x1 \
-alpha set -channel RGBA -fuzz 20% \
-fill none -floodfill +0+0 white \
-shave 1x1 cyclops_flood_3.png
![[IM Output]](../static/img/masking/cyclops_flood_3.png)
この手法にはいくつか問題があります。まず、画像の全か無かのマスクであり、エイリアシングした、階段状の、しばしば見苦しいエッジを生成します。これは限定的なGIF画像ファイル形式には問題ありませんが、その画像を別の背景に重ねる予定の場合はあまり良くありません。また、すべてのアンチエイリアスのエッジピクセルを得るのは非常に非常に困難です。そのため、上記の画像を黒い背景に重ねると、通常よりずっと白いピクセルが見えることがあります。 |
magick cyclops_flood_3.png -background black -flatten \
cyclops_flood_3_over.png
![[IM Output]](../static/img/masking/cyclops_flood_3_over.png)
また、十分に高いファズ係数を使うことができたとしても、縁取りピクセルがほとんど残らなかったり、画像の中央に「漏れ」たりする問題が起こりやすくなります。最後に、このような直接的なフラッドフィルは、単純な単一の単色でない背景には機能しません。
縁取りのあるオブジェクトを切り抜く
既存の単色境界を持つ画像は、これらの背景除去の方法に明確な利点があります。境界が、画像の「内側」と「外側」の間の明確な境界線を提供し、それによって背景画像の境界を指定するより良い方法が使えるからです。つまり、どの色を背景と見なすべきかを指定するのではなく、マスクされるオブジェクトの境界をマークする色を指定できます。さらに、境界色が既知であるため、画像のエッジの周りで混ざり合った色は2つの特定の色だけになります。つまり、両方の色が既知であり、エッジがどれくらい透明であるべきかも非常によく分かっています。
作成中
既知の背景を除去する
単純な背景を「ブール値」マスクに除去するのは比較的簡単ですが、背景がそれほど単純でない場合は事情が複雑になります。ただし、背景自体が既知であれば、それを使って他の画像からの除去に役立てられます。IM v6.3.4より、「[ChangeMask](compose.html#changemask)」と呼ばれる特別なアルファ合成メソッドが追加され、画像から既知の背景を直接除去できるようになりました。例えば、ここに未加工の背景画像と、単純なブール値(完全なon/off)透明度を持つGIF画像で重ねられた背景画像があります。「[ChangeMask](compose.html#changemask)」を使うことで、その元の重ねられた画像を(背景と大きく異なる場合は)復元できます。
magick overlay_figure.gif overlay_bgnd.gif \
-compose ChangeMask -composite overlay_removed.png
基本的にこれが行うのは、一方の画像のピクセルがもう一方からどれだけ「異なる」かを判定し、その差が現在のファズ係数より小さければ、そのピクセルを透明にすることです。完全に透明なピクセルだけが画像に追加され、それ以外の場合は元画像が透明度も含めてそのまま残ります。古い「[Difference](compose.html#difference)」合成メソッドを使って比較差分画像を生成することで、この演算子をシミュレートできます…
magick composite overlay_figure.gif overlay_bgnd.gif \
-compose Difference overlay_difference.png
ご覧のとおり、差分画像は変更されていないすべての部分で黒く、変更された部分は色の混合になります。 個々の色チャンネルを分離して足し合わせ、閾値処理することで、2枚の画像のいずれかのチャンネルでの差分のマスクが得られます。 |
magick overlay_difference.png -channel RGB -separate +channel \
-evaluate-sequence add -threshold 0 overlay_mask.png
![[IM Output]](../static/img/masking/overlay_mask.png)
このマスクを使って、変更されていないものをすべて透明に設定できます。 |
magick overlay_figure.gif overlay_mask.png \
-alpha off -compose CopyOpacity -composite \
overlay_removed.png
![[IM Output]](../static/img/masking/overlay_removed.png)
ご覧のとおり、「[ChangeMask](compose.html#changemask)」合成メソッドはこの処理をずっと簡単にします。ただし、これは「on/off」スタイルの背景マスクしか提供しません。ファジーまたはアンチエイリアスのエッジや、結果の透明なぼかしには対応していません。
差分画像によるマスクとぼかし
上記は、エイリアシングしたエッジを持つ画像や、単純でない背景にもさらに応用できます。例えば、ここに白背景の「サイクロプス」があり、これを抽出したいとします。次に、この画像と(左上端のピクセルで定義される)背景色との差分のグレースケール画像を生成します。 |
magick cyclops.png \( +clone -fx 'p{0,0}' \) \
-compose Difference -composite \
-modulate 100,0 -alpha off difference.png
![[IM Output]](../static/img/masking/difference.png)
もちろん、この差分画像はマスクとして直接使うには役立ちません。もし使えば、周囲の背景だけでなく、画像のほとんどを実質的に半透明にしてしまいます。しかし、この差分画像からは、正確に何を達成しようとしているかに応じて、膨大な数の異なる透明度マスクを作成できます。上記の差分画像を調整して、背景色から少しでも異なるすべてのピクセルのマスクを生成できます。 |
magick difference.png -threshold 0 boolean_mask.png
magick cyclops.png boolean_mask.png \
-alpha off -compose CopyOpacity -composite \
cyclops_boolean.png
![[IM Output]](../static/img/masking/cyclops_boolean.png)
ご覧のとおり、「あらゆる差分」のブール値処理は、元の背景のかなりの部分を含む結果になりました。これは、元画像が「アンチエイリアス」されているか、背景とわずかにぼかされているためです(この場合はJPEG形式の画像からリサイズされたことが原因でした)。元画像自体がブール値の重ね合わせ(例: 背景に重ねられたGIF形式の画像)であれば、これは問題になりません。その場合、結果は完璧になります(上記の「ChangeMask」の例を参照)。「[-threshold](https://imagemagick.org/command-line-options/#threshold)」を変えることで、ブール値(on/offのみ)マスクに「ファズ係数」を加え、マスクを画像本体により近づけることができます。 |
magick difference.png -threshold 15% threshold_mask.png
magick cyclops.png threshold_mask.png \
-alpha Off -compose CopyOpacity -composite \
cyclops_threshold.png
![[IM Output]](../static/img/masking/cyclops_threshold.png)
サイクロプス画像の目が、今や透明な穴と見なされていることに気づいてください!この「穴」は、この手法全体の最大の欠点を浮き彫りにします。背景色に近い、あるいはもっと悪いことに背景に正確に一致する画像オブジェクトの部分は、背景と同じものと見なされてしまいます。もちろん、これはドーナツのような「穴のある」オブジェクトの画像では望ましいかもしれませんが、私たちのサイクロプスにとって「穴のある目」は明らかに間違いです。元の「ハロー」効果も、テキストなどでは、別の「ノイズの多い」背景に再び重ねたいときに読みやすくするために望ましいことがあります。マスクを適用する前に少しぼかすことで、ハロー効果を強調でき、結果の「ハロー」が距離によって弱まるようにできます。 |
magick difference.png -bordercolor black -border 5 \
-threshold 10% -blur 0x3 halo_mask.png
magick cyclops.png -bordercolor white -border 5 halo_mask.png \
-alpha Off -compose CopyOpacity -composite cyclops_halo.png
![[IM Output]](../static/img/masking/cyclops_halo.png)
得られた「ハロー」効果は、マスク画像にさらにヒストグラム調整を使うことでさらに変更でき、特定の画像に対する結果を非常に精密に制御できます。適切なパラメータを使えば、周囲のハローが実質的に存在しなくなるまで調整できますが、この方法で完全に除去するのは困難です。改善された手法については次のセクションを参照してください。閾値マスクを生成するときは、マスクのエッジを滑らかにするために、少量のぼかし(例えば「-blur 0x0.707」つまり2の平方根)が実は推奨されます。もちろん結果はブール値にならないので、GIF形式の画像ファイルに保存しようとしないでください。これはぼかしによるぼかし(Blur Feathering)の一例でもあります。ただし、真の距離を使った形状のぼかしとまったく同じではないことに注意してください。しかし、上で作成したような「ビットマップ」または「閾値マスク」を扱う場合、少量のぼかしによるぼかしに続いて、より多めの距離によるぼかしを行うと、おそらく最良の全体的な結果が得られます。
半透明のエッジを復元する
上で使った差分マスク技術は、前のフラッドフィルマスク技術と組み合わせて、より単純なマスク技術で見られたほとんどの問題を解決できます。ここでは多層マスク技術を見ますが、これは画像のエッジに沿ったアンチエイリアスの陰影ピクセルを保持しながら、画像の背景をほぼ理想的に除去できるはずです。ただし、これは既知の背景上にあり、前景ピクセルに対して良好なコントラストの「エッジ」を持つ画像に限られます。この例では、分離するのが非常に難しいものを使うことにしましたが、アンチエイリアス目的で通常持つよりもはるかに多くの陰影ピクセルをエッジの周りに示すものです。影効果のある形状です。 |
magick -size 70x60 xc:none -font Candice -pointsize 50 -stroke black \
-fill black -annotate +12+42 'A' -channel RGBA -blur 0x3 \
-fill tile_disks.jpg -annotate +10+40 'A' \
tile_water.jpg -compose DstOver -composite letter.png
![[IM Output]](../static/img/masking/letter.png)
まず差分画像を生成する必要がありますが、幸運にも背景画像が何であるかは分かっています。もちろん、2枚のマスクを生成できる良好なコントラストがある限り、無地の色背景に対しても同様にうまく機能します。基本的に、差分画像を使うことで背景画像の影響をすべて除去でき、そこから使用するマスクを生成できます。 |
magick letter.png tile_water.jpg \
-compose Difference -composite \
-modulate 100,0 -channel B -evaluate set 0 \
-alpha Off diff_mask.png
![[IM Output]](../static/img/masking/diff_mask.png)
今回はグレースケール差分画像を少し処理し、赤と緑のチャンネルに限定しながら青チャンネルをクリアして、黒-黄の差分画像を生成したことに注意してください。これはトリッキーで、差分画像自体とは別にクリーンなフラッドフィルマスクを生成できるよう、「青」チャンネルを解放します。技術的には緑チャンネルもクリアして2枚目のマスクに使うこともできます。しかし、先走らないようにしましょう。さて、2枚のマスクが必要です。確実に透明になるすべての領域を定義する外側のマスクと、不要な「穴」を生成することなく画像内のオブジェクトの内側を定義するマスクです。そこで、いくつかの異なるファズ係数を使って画像を外側から内側へとフラッドフィルし、使用する内側と外側の2枚のマスクを選べるようにしましょう。
for fuzz in 01 03 06 28 32 34; do \
magick diff_mask.png -fill blue -fuzz $fuzz% \
-bordercolor black -border 1x1 -floodfill +0+0 black \
-shave 1x1 diff_mask_$fuzz.png; \
done
![[IM Output]](../static/img/masking/diff_mask_01.png)
-fuzz 1% | ![[IM Output]](../static/img/masking/diff_mask_03.png)
-fuzz 3% | ![[IM Output]](../static/img/masking/diff_mask_06.png)
-fuzz 6% | | ![[IM Output]](../static/img/masking/diff_mask_28.png)
-fuzz 28% | ![[IM Output]](../static/img/masking/diff_mask_32.png)
-fuzz 32% | ![[IM Output]](../static/img/masking/diff_mask_34.png)
-fuzz 34%
---|---|---|---|---|---|---
上記の画像の青い領域がマスクされている領域です。この目的のために青チャンネルをクリアしたことを思い出してください。1枚目のマスクは、確実に完全透明にしたい画像の領域をマスクすべきです。つまり、最終画像で確実に完全透明になることを期待する部分です。マスクの内側の領域は、画像の黒いハローの影のほとんどをまだ含んでいるべきです。この場合、画像本体と背景の残りの部分との相互作用が多いので、画像を囲む大きな領域をまだ含む「1%」のファズ係数を選びました。より典型的な影のない場合では、この領域はさらに小さく、5や10のような非パーセント値まで小さくできます。2枚目のマスクは、存在するすべての半透明ピクセルを食い尽くすのに十分な大きさの「ファズ」を持つべきです。つまり、境界を完全に除去したり、画像本体に「漏れ」たりすることなく、画像の境界の手前まで、できれば実際に境界の中まで食い込むようにします(上の最後の画像を参照)。このマスクの反転が、実際には最終画像で完全に不透明になる(したがって内側を表す)すべてのピクセルを表します。この選択は難しいことがあり、使用する最良の値を見つけるのに多くの試行錯誤が必要かもしれません。この画像では、大きな問題なく非常に高いファズ「32%」を選べました。基本的に、最終画像に元の「背景」ピクセルがまったく含まれないように、ただしマスクが画像の内側を食い込んだり(漏れたり)しないように、十分高くしようとします。周囲の「エッジ」色に隙間がある場合は、マスクをちょうど良くするために、少し手作業での編集が必要になることさえあります。これで、このマスクを使って画像の「コア」つまり内側を抽出できます。これは、除去しようとしている背景パターンへの半透明が確実に存在しない部分です。 |
magick diff_mask_32.png -channel blue -separate +channel -negate \
letter.png +swap -alpha Off -compose CopyOpacity -composite \
letter_inside.png
![[IM Output]](../static/img/masking/letter_inside.png)
フラッドフィルされたマスク画像から青いマスクをどう抽出したかに注意してください。また、フラッドフィルの全か無かの性質のため、マスクはエッジの周りに激しい階段状つまりエイリアシング効果を示します。これは2枚目のマスクが修正できる問題です。この画像は、元の背景と相互作用しないと分かっているピクセルだけのもので、最終画像でそのまま残されることを覚えておいてください。これには、私が特に復元しようとしている影効果やアンチエイリアスピクセルは含まれていません。それらのピクセルの復元こそが、本当の作業の核心です。マスクを反転して減算(乗算)することで、半透明の縁取りや影のピクセルを抽出したい領域を定義する新しいマスクを生成できます… |
magick diff_mask_01.png -negate diff_mask_32.png \
-channel blue -separate +channel -compose multiply -composite \
mask_aliasing_area.png
![[IM Output]](../static/img/masking/mask_aliasing_area.png)
この領域は次に、差分マスクからアンチエイリアスピクセルを抽出するために使われ、ピクセルがどれくらい透明であるべきかを定義します。これらのピクセルを正規化して、不透明から透明への滑らかな遷移を得ます。 |
magick diff_mask.png -channel red -separate +channel \
mask_aliasing_area.png -alpha Off -compose CopyOpacity -composite \
-background gray30 -compose Over -flatten -normalize \
mask_antialiased_pixels.png
![]()
上記のマスクで色が明るいほど、ピクセルはより不透明になります。同様に、色が暗いほど、より透明になります。ここでグレー背景を使ったのは、画像に存在する透明色が画像の正規化に干渉しないようにするためであることに注意してください。これがないと、この正規化は失敗します。平坦なグレー色自体は重要ではありません。マスク領域の外側にあるので、後で無視されるからです。さて、正しい透明度レベルが得られたので、これらの半透明ピクセルにどの色を使うべきかを知る必要があります。この色は通常、画像のエッジ色と同じで、この場合は単に黒です。しかし、元の背景の相互作用のため、影には暗いグレー色にすることにしました。 | _半透明ピクセルがどの色であるべきかを何らかの方法で見つけ出し、アンチエイリアスピクセルに正しい色を設定できるようにする必要があります。
これは次のいずれかでありえます_
- 固定のエッジ色(例: この例のようにほぼ黒)
- 最も近い完全に不透明なエッジピクセルの色を使う(モルフォロジーを使用。塗りつぶし演算子としてのスパースカラーを参照)
- 計算: アルファと背景色が分かれば、背景色を減算してピクセルの色を補正できます。後述の2つの背景を使った背景除去を参照。
基本的にはあなたの画像次第です。
---|---
ついでに、これらの特別な縁取りピクセルだけを残すように画像を再マスクしましょう。 |
magick mask_antialiased_pixels.png mask_aliasing_area.png \
-compose multiply -composite -negate \
-background '#444' -channel A -combine letter_edging.png
![[IM Output]](../static/img/masking/letter_edging.png)
あとは、画像の内側の「コア」を半透明の縁取りピクセルと層状に重ねるだけです。 |
magick letter_inside.png letter_edging.png \
-background none -flatten letter_recovered.png
![[IM Output]](../static/img/masking/letter_recovered.png)
そして、ほら、背景が除去された画像ができ、完璧なアンチエイリアス画像を生成しました。半透明の縁取りと影が正しく復元されています。まったく異なる背景の上に重ねることさえできます。 |
magick letter_recovered.png tile_aqua.jpg \
-background none -compose DstOver -flatten letter_on_aqua.png
![[IM Output]](../static/img/masking/letter_on_aqua.png)
この例に使った画像は、大きな「エッジ」領域を持つ非常に難しいものです。ほとんどの画像はそれほどひどくありませんが、この方法はおそらく最良かつ最も汎用的な背景除去手法です。これは現在「**[bg_removal](../static/img/scripts/bg_removal)**」というシェルスクリプトにまとめられており、単一のコマンドを使い、一時ファイルを使わず、マスクの実行方法に関する多くの追加オプションを持っています。
2つの背景を使った背景除去
前の手法の大きな問題は、前景オブジェクトに関するすべての情報を完全に復元するのに十分な情報が実際にはないことです。本当に2つの情報を復元する必要があります。前景オブジェクトの各ピクセルがどれくらい透明か、そしてその元の色は何か、です。そして、1枚の画像だけからこの2つの情報を完全に復元することはできません。背景画像がどのように見えるかを正確に知っていても、2つが非常に異なる既知の色でない限り、それを前景オブジェクトから単純に減算することはできません。問題は、見える色が本当に与えられた色(不透明)なのか、それとも別の色と背景のブレンド(半透明)なのかを確信できないことです。何らかの追加情報源がない限り、元の色を必要なアルファ値から分離することはできません。前景オブジェクトのすべての詳細を完全に復元できる唯一の状況は、非常に異なるが完全に既知の2つの背景色を含む2枚の画像がある場合です。その状況では、前景オブジェクトの色とその透明度の両方を復元し、完璧な背景除去を行うのに十分な情報があります。2枚の画像を選ぶ際の重要な要素は、背景色が画像全体にわたってできるだけ異なることです。つまり、色が補色であるだけでなく、すべてのチャンネルで強度が反対であることです。例えば…
異なる背景色が使われていますが、両方の画像にはまったく同じオブジェクトが含まれています。示されているオブジェクトは単純ではなく、多くの半透明色を含んでいます。これは、画像の炎に濃い青の背景が見える様子で分かりますが、この透明度は明るい黄色の背景ではほとんど見えません。2つの色を使うことで、重ねられたオブジェクトの半透明ピクセルが2つの非常に異なる色と混ざり合い、結果として2枚の画像でわずかに異なる色になります。各ピクセルがどれだけ異なるかを測定することで、どのピクセルが半透明で、どれくらいそうなのかを正確に判定できます。本質的に、重ねられたオブジェクトの透明度を完璧に復元できるだけの情報があります。透明度つまり「マスク」の復元はもちろん最初のステップで、実際には非常に簡単なステップです。差分画像を生成し、各チャンネルで見つかった差分を統合して最大化します。 |
magick match_navy.gif match_gold.gif \
-compose difference -composite -separate \
-evaluate-sequence max -auto-level -negate \
match_alpha.png
![[IM Output]](../static/img/masking/match_alpha.png)
この結果画像は、各ピクセルがどれくらい透明であるかの完璧なマップです。本質的に、ソース画像内の元のオブジェクトの「アルファマスク」です。ただし、これは重ねた画像が完全透明と完全不透明の両方の領域を含む場合にのみ機能します。そうでない場合は、上記の正規化ステップ(「-evaluate-sequence max -auto-level」)の代わりに、各チャンネルを2つの背景色の差で割る必要があります。つまり、0.0から1.0の間の値で割るのですが、差が大きいほど良い結果になります。2つの背景色が純黒と純白であれば、正規化は不要で、2枚の画像の差だけで済みます。差は次に反転(Negate)され、最大の差がゼロのアルファつまり完全透明を生成し、差がないと最大のアルファつまり完全不透明を生成します。次の作業はより難しいです。各半透明ピクセルの色が背景によって変更されているため、アルファマスクを使ってソース画像の一方からオブジェクトを抽出することはできません。例えば… |
magick match_navy.gif match_alpha.png \
-alpha Off -compose Copy_Opacity -composite \
match_bad_colors.png
![[IM Output]](../static/img/masking/match_bad_colors.png)
基本的に得られたのは、画像の半透明の「炎」に背景色のひどいハローでした。まったく良い結果ではありません。これは「カラースピル(color spill)」として知られ(クロマキーによるマスクの用語で、ブルーまたはグリーンスクリーン技術としても知られる)、これは大きな問題になりえます。私たちがする必要があるのは、半透明ピクセルから背景色を除去することです。しかし、すでに元画像のアルファチャンネルを復元しているので、元の重ねられた色を復元するために、各ピクセルからどれだけの色を除去する必要があるかを正確に知っています。これを行うには、ソース画像の一方と、抽出したアルファチャンネルだけでなく、そのソース画像の背景の正確な色も知る必要があります。これらの例のように単色背景を使う場合は比較的簡単な問題です。例えば、ここで元の色を復元します… |
magick match_navy.gif match_alpha.png -alpha Off \
-fx "v==0 ? 0 : u/v - u.p{0,0}/v + u.p{0,0}" \
match_alpha.png -compose Copy_Opacity -composite \
match_recovered.png
![[IM Output]](../static/img/masking/match_recovered.png)
半透明ピクセルから除去する背景色として、ソース画像の左上角のピクセル(FX式「u.p{0,0}」)を使いました。必要に応じてこれを調整するか、除去する色を直接代入してください。色復元の鍵は、上記の複雑なFXブレンド減算操作です。これは、アルファマスク(「v」)に従ってソース画像の元の色(「u」)を強調し、次に最終結果から背景色(u.p{0,0}つまり左上角のピクセル)を減算します。この式は分かりやすくはなく、必要な数学を解明してくれたIMフォーラムの議論Undo a Composite -dissolveのHugoRuneに大きな感謝を捧げます。その議論はさらに、すべてのステップがどう機能するか、どう導出されたか、さらには任意の2つの既知だが異なる背景パターンから重ねられたものをどう抽出できるかについても説明しています。以下は全シーケンスを1つのコマンドにまとめたものです。 |
magick match_gold.gif match_navy.gif -alpha off \
\( -clone 0,1 -compose difference -composite \
-separate -evaluate-sequence max -auto-level -negate \) \
\( -clone 0,2 -fx "v==0?0:u/v-u.p{0,0}/v+u.p{0,0}" \) \
-delete 0,1 +swap -compose Copy_Opacity -composite \
match_recovered_2.png
![[IM Output]](../static/img/masking/match_recovered_2.png)
| _IM v6.6.8-3では、FXが'p{}'を使って透明ピクセルを参照すると、実際の完全透明な色の値ではなくゼロ値が得られます!これはバグで、報告されてIM v6.6.8-5で修正されました。このバグがいつ導入されたかは不明です。
これは、アルファ画像を最初にソース画像に統合してから、既知の背景色を使って半透明色つまり「スピル」色を修正しようとした場合にのみ問題になりました。_
---|---
今回は色抽出に「gold」背景画像が使われ、2番目の「[-clone](https://imagemagick.org/command-line-options/#clone)」操作の「0」によって選択されましたが、どちらのソース画像も使えました。一つだけ警告です。上記は左上のピクセルが手付かずの背景色であることを前提としています。そうでない場合は、特定のピクセル色を指定するようにコマンドを変更するか、正しい背景色情報を含む3枚目の画像を使う必要があるかもしれません。背景色が画像全体で一定でない場合は後者の方法が不可欠ですが、その複雑さも修正できます。以下は、純黒と純白の背景色に重ねられた画像のためのより単純なシーケンスです。この場合、色は常に黒背景画像から復元されます。それは単純な除算なので、痛いほど遅いFX DIY演算子の代わりに、より高速なDivide合成を使えるからです。
magick match_black.gif match_white.gif -alpha off \
\( -clone 0,1 -compose difference -composite -negate \) \
\( -clone 0,2 +swap -compose divide -composite \) \
-delete 0,1 +swap -compose Copy_Opacity -composite \
match_recovered_3.png
背景復元のためのスタジオ写真 理想的な背景は、マット(非反射)の黒と、単純な純(非反射)白です。背景はまた、できるだけ滑らかで変化のない陰影であるべきです。背景除去のために特別に写真を撮る場合、2つの補色を使うとうまくいくかもしれません。例えば緑とマゼンタの背景で写真を撮るなどです。基本的に、2枚目の写真を撮る前に背景色のスクリーンを何らかの方法で置き換える必要があります。背景除去では2枚の写真の順序は問題になりませんが、できるだけクリーンで均一であるべきで、主要なオブジェクトとカメラは完全に静止して固定されていなければなりません。より良い方法は、オブジェクトの後ろに白いスクリーンを十分に距離を置いて配置し、オブジェクトから影が出ないように2つの異なる色のランプでそのスクリーンを均一に照らすことかもしれません。この技術を使えば、2つの異なる背景で2枚の写真を撮るのに、スタジオの物理的な変更を必要とせずに、別の背景色に切り替えることができます。これらの2色背景技術は透明なオブジェクトにはうまく機能するはずですが、撮影されるオブジェクトによる反射や、背景のゆがみ、つまり「レンズ」効果は、この技術では記録されず、その透明度だけが記録されます。一方、オブジェクト上の一定の光源の反射は保持されます!もしこれを試したら、ぜひ教えてください。あなたのソース写真と結果の例をここに掲載するために提供してください。あなたの名前を、人々が見られるようにあなたのサイトへのポインタとともに記載します。
ビデオの背景復元 多くの異なるが複雑な背景を持つ十分な枚数の一連の画像(ビデオなど)があれば、すべての画像の最小値と最大値を取って、使用するためのほぼ純粋な白黒の背景画像を生成してみることができます。画像が多いほど、これはうまく機能します。それら2枚の画像があれば、一定のロゴとその半透明度を抽出でき、同じ技術を使ってすべてのフレームからそれを除去できます。ただし、これは一定の半透明の重ね合わせに対してのみ機能し、色や色相の歪みを使うロゴ、あるいは単色のロゴに対しては機能しないかもしれません。しかし、少なくとも正確なロゴの形状を判定することはできます。完全に不透明だったり、より難しかったりするロゴには、穴埋め(次を参照)を使って、周囲の色から欠けたディテールを埋めることができます。詳細はIMフォーラムの議論を参照してください。
穴埋め
マスク、透明度の追加、背景の除去は、不要な要素に対処する一つの方法を提供しますが、結果として実際に欲しいのは「穴」ではないことがよくあります。確かに、穴のある画像を他の画像の上に重ねて埋めることはできますが、それではシームレスな結果が得られないかもしれません。画像から要素を消去するには、それらを単に切り抜くのではなく、穴を囲む部分の色、陰影、質感で置き換えたいものです。以下は、その穴を埋めるために何を使うかを決定するための各種技術です。
埋めるための穴を作る
醜いテキストのある画像があるとします… |
magick zelda_tn.gif -gravity Southwest -annotate +8+20 Zelda zelda_text.jpg
さて、私たちが本当にしたいのはそのテキストを除去することで、最も簡単な方法はそれをマスクして、テキストがあった場所に「穴」を残すことです。これにより問題が単純化されます。何が除去されたかはもはや問題ではなくなり、埋めるべき穴があるだけになるからです。 ![[IM Output]](../static/img/masking/zelda_text.jpg)
ただしこの場合は、ユーザーが画像エディタを素早く使ったかのように、「醜いテキスト」を覆う描画線を使ってマスクを作成します。 |
magick -size 120x90 xc:black -stroke white -strokewidth 7 \
-draw 'stroke-linecap round line 9,62 36,63' \
-threshold 10% zelda_text_mask.gif
![[IM Output]](../static/img/masking/zelda_text_mask.gif)
「穴」自体を作ること自体がトリッキーな問題になりえます。自動化された解決策は、除去しようとしているものが正確に何かに依存することもあれば、それを正確に見つけるために同じ「テキスト」や「ロゴ」を持つ何百もの画像を比較することさえあります。穴が小さいほど最終結果が良くなることに注意してください。元画像からより多くの情報を保持できるほど、結果は良くなります。粗くいびつな形の穴も、非常に滑らかに輪郭を描いた穴よりも良いです。ですから、すべての不要な効果を除去する最小の穴を作るのに時間をかけることが、大きな違いを生むことがあります。 さて、このマスクを使って画像から穴を切り抜きましょう。これはすべての不要な部分を覆っているかどうかの確認にもなります。 |
magick zelda_text.jpg \( zelda_text_mask.gif -negate \) \
-compose CopyOpacity -composite zelda_text_hole.png
ぼかしで埋める
さて、何らかの色で埋める必要のある穴があります。画像から何かを実際に除去したように見えないものです。最も単純な方法の一つは、単に画像をぼかして、穴の周りの色を穴に「広げ」、それから透明度を除去することです。 |
magick zelda_text_hole.png -blur 0x1 -alpha off zelda_text_fill.png
使うぼかしの量は、使う穴のサイズに依存します。 ![[IM Output]](../static/img/masking/zelda_text_fill.png)
さて、このぼかした画像を下敷きにして、以前作った「穴を埋める」ことができます…
magick zelda_text_hole.png zelda_text_fill.png \
-compose Dst_Over -composite zelda_text_removed.png
そしてテキストが除去されました。これは完璧ではありません。その領域の色のぼかしによって、何かが除去されたことが明白になるからです。例えば、ゼルダの頭の隣の窓枠を注意深く見ると、ぼかしの効果が見えます。また、その領域は画像の残りの部分よりも「滑らか」に見え、写真では特に目立ちます。しかし、これは広く使われている高速な技術で、TV放送局が著作権防止策として追加したロゴを除去しようとしたビデオでよく見かけます。除去を隠そうとする代わりに、実際の除去を目立たせるのも一つの方法です。例えば誰かの匿名性を保護したい場合などです。
作成中
他の方法へのリンク。リサイズによるぼかしの穴埋め方法… スパースカラー、シェパード法(高速)。snibgo, 穴を埋めるも参照。エッジピクセルだけをぼかす…塗りつぶし演算子としてのスパースカラー。snibgo, 優先順位で穴を埋めるも参照。色チャンネルに色を設定しながら、隠れた背景チャンネルで距離を計算するモルフォロジー演算子を使いたいところです。これは「Color Diffusion」として知られる、非常に高速で漏れのないシェパード法のような塗りつぶしを生成するはずです。この技術を多用する論文Diffusion Curvesを参照してください。穴埋め(テキスト除去)に関する大規模で古い議論がIMユーザーフォーラムのテキスト除去の議論にあります。より新しい議論は境界から最も近い色で領域を埋めるで、これはぼかしなしで埋めることに重点を置いています。画像の一部を消去するIM以外の「穴埋め」方法はStack Overflow, jpegからテキストを除去するに示されています。例えばPython Skimageを使ったり、Python OpenCV inpaintingを使ったりします。
![[IM Output]](../static/img/masking/moon_background.jpg)
![[IM Output]](../static/img/masking/alpha_off.png)
![[IM Output]](../static/img/masking/alpha_extract.png)
![[IM Output]](../static/img/masking/alpha_copy.png)
![[IM Output]](../static/img/masking/alpha_shape.png)
![[IM Output]](../static/img/masking/moon_hotpink_off.png)
![[IM Output]](../static/img/masking/a.png)
![[IM Output]](../static/img/masking/a.jpg)
![[IM Output]](../static/img/images/knight.png)
![[IM Output]](../static/img/masking/knight_outlined.png)
![[IM Output]](../static/img/masking/drawn.png)
![[IM Output]](../static/img/masking/mask.png)
![[IM Output]](../static/img/masking/mask_bite.png)
![[IM Output]](../static/img/masking/drawn_bite.png)
![[IM Output]](../static/img/masking/mask_bite2.png)
![[IM Output]](../static/img/masking/drawn_bite2.png)
![[IM Output]](../static/img/masking/mask_shape.png)
![[IM Output]](../static/img/masking/drawn_bite3.png)
![[IM Output]](../static/img/masking/compose_multiply.png)
![[IM Output]](../static/img/masking/compose_screen.png)
![[IM Output]](../static/img/images/rose_bg_mask.png)
![[IM Output]](../static/img/masking/rose_blue.png)
![[IM Output]](../static/img/masking/red_image.png)
![[IM Output]](../static/img/masking/write_mask.png)
![[IM Output]](../static/img/masking/masked_color_replace.png)
![[IM Output]](../static/img/masking/green_image.png)
![[IM Output]](../static/img/masking/masked_composite.png)
![[IM Output]](../static/img/masking/rose_bg_only.png)
![[IM Output]](../static/img/masking/rose_bg_blurred.png)
![[IM Output]](../static/img/masking/rose_bg_blur_opaque.png)
![[IM Output]](../static/img/masking/koala_region_red.gif)
![[IM Output]](../static/img/masking/lines.gif)
![[IM Output]](../static/img/masking/lines_regions.gif)
![[IM Output]](../static/img/images/overlay_figure.gif)
![[IM Output]](../static/img/images/overlay_bgnd.gif)
![[IM Output]](../static/img/masking/overlay_difference.png)
![[IM Input]](../static/img/images/match_navy.gif)
![[IM Input]](../static/img/images/match_gold.gif)
![[IM Input]](../static/img/images/match_black.gif)
![[IM Input]](../static/img/images/match_white.gif)
![[IM Output]](../static/img/masking/match_recovered_3.png)
![[IM Output]](../static/img/masking/zelda_text_hole.png)
![[IM Output]](../static/img/masking/zelda_text_removed.png)