ImageMagick 使用例 -- 複数画像のレイヤー
- ImageMagick 使用例 序文と索引
- レイヤー入門
- 画像の連結(Append) (-append)
- 画像の配列を連結する
- 重ね合わせ付きの連結
-
スマッシュ連結(Smushing) (-smush)
-
composite コマンドを使う (composite, -geometry)
- convert の composite 演算子 (-composite, -geometry)
-
複数の画像を描画する (-draw 'image ..')
- モザイク(Mosaic) - キャンバスの拡張
- 統合(Merging) - 新しいレイヤー画像を作る
- 合体合成(Coalesce) - 段階的なレイヤー化
- 合成メソッドとレイヤー化
- 画像の計算による配置
- 画像の2段階配置
- 地図上のピン
- 影のレイヤー
-
平均(Mean), 最小値/最大値(Min/Max Value), 中央値ピクセル(Median Pixel), 加算(Add), 乗算(Multiply) Poly - 多項式を用いた複数画像の統合 複数の画像を互いに重ね合わせて、より大きな「合成画像」を生成することは、一般に画像の「レイヤー化」を使うものとして知られています。これらの例は、複数の画像「レイヤー」を組み合わせて、最終的なより大きく複雑な画像を生成することを扱います。
画像のレイヤー化入門
これまでに述べたように、ImageMagick は単一の画像ではなく、画像のシーケンス(連続)やリストを扱います。これにより、IM を2つの非常に特別な画像処理技法に使えます。たとえば、リスト内の各画像を時間の中の1コマと考えれば、リスト全体を_アニメーション_とみなせます。これは別の IM 例ページで探求します。アニメーションの基礎を参照してください。あるいは、シーケンス内の各画像を、透けて見えるオーバーヘッド・トランスペアレンシーの一式の_レイヤー_と考えることもできます。すなわち、各画像が最終画像の小さな一部を表します。たとえば、最初(最下層)のレイヤーは背景画像を表せます。その上にぼんやりと透けて見える影を置けます。次のレイヤー画像にはその影を落とす物体を入れます。さらにその上に、その物体の上に書かれたテキストのレイヤーを置きます。すなわち、画像つまり「レイヤー」のシーケンスを持ち、それぞれがより複雑な画像にひとつずつ部品を加えていけるのです。各画像レイヤーは、他のどのレイヤーからも完全に独立して移動・編集・変更でき、さらに複数画像ファイル(TIFF:、MIFF:、XCF: など)として、あるいは個別の画像として、将来の処理のために保存できます。これこそが画像レイヤー化の要点です。すべての画像レイヤーが作成されて初めて、平坦化(Flatten)、モザイク(Mosaic)、または統合(Merge)によって、すべてのレイヤー化された画像を1枚の最終画像にまとめます。
画像の連結(Append)
連結(Appending)は、複数画像を扱うために用意された複数画像操作の中で、おそらく最も単純なものです。基本的に、メモリ内の現在の画像シーケンスを、隙間なく列または行に結合します。「[-append](https://imagemagick.org/command-line-options/#append)」オプションは垂直方向に連結し、プラス形式の「[+append](https://imagemagick.org/command-line-options/#append)」は水平方向に連結します。たとえば、ここでは一連の文字画像を横並びに連結して、しゃれた単語を作ります。これは、「フォント」の個々の「グリフ」つまり文字が結合されるのと似た方法です。
magick font_A.gif font_P.gif font_P.gif font_E.gif font_N.gif \
font_D.gif font_E.gif font_D.gif +append append_row.gif
上の例は、(ごく基本的な意味で)フォントの扱われ方に似ています。本物のフォントと違って2色に限定されず、個々の文字画像から非常にしゃれたカラフルなアルファベットを生成できます。こうした「画像フォント」の多くは WWW でダウンロードできます。ごく小さなセットは Anthony's Icon Library の Fonts for Text and Counters にあります。上で使った Blue Bubble Font もそこで見つけたものです。また、「[+append](https://imagemagick.org/command-line-options/#append)」演算子が、連結したいすべての画像を現在の画像シーケンスに追加した後の、最後の操作として実行されている点にも注目してください。これはたとえば、画像にラベルを連結するのにとても便利です… |
magick rose: -background LawnGreen label:Rose \
-background white -append append_label.jpg
![[IM Output]](../static/img/layers/append_label.jpg)
「[-background](https://imagemagick.org/command-line-options/#background)」色が、埋められなかった余白を埋めるために使われた点に注意してください。もちろん、すべての画像が同じ幅であれば、この埋め草のための余白は残りません。IM v6.4.7-1 以降は、「[-gravity](https://imagemagick.org/command-line-options/#gravity)」設定を使って、画像をどのように結合すべきかを指定できます。たとえば垂直方向の連結では、「Center」設定により、最終的な結果画像に対して画像が中央揃えになります(「North」または「South」設定でも同様です)。 |
magick rose: -background LawnGreen label:Rose \
-background white -gravity center -append \
append_center.jpg
![[IM Output]](../static/img/layers/append_center.jpg)
当然ながら、「East」gravity 設定では画像が右側に揃えられます。 |
magick rose: -background LawnGreen label:Rose \
-background white -gravity east -append \
append_east.jpg
![[IM Output]](../static/img/layers/append_east.jpg)
「[+append](https://imagemagick.org/command-line-options/#append)」を使う場合も、同様の垂直方向の整列が実現できます。 | _IM v6.4.7 より前は、連結する画像を整列させるのははるかに難しく、一般に右揃えには「[-flop](https://imagemagick.org/command-line-options/#flop)」を使う必要がありました。あるいは中央揃えの連結のために「[-extent](https://imagemagick.org/command-line-options/#extent)」や「[-border](https://imagemagick.org/command-line-options/#border)」を使って画像幅を調整していました。
たとえば、これは古い 6.3.2 版の IM でも動作します…_ | |
magick rose: -background SkyBlue label:Rose \
-background White -gravity center -extent 200x \
-append -trim +repage append_center_old.jpg
![[IM Output]](../static/img/layers/append_center_old.jpg)
同じコマンド内で複数の連結操作を、操作結果について競合や混乱なく使うこともできます(これは IM v6 より前ではそうではありませんでした)。 |
magick font_{0,0,6,1,2}.gif +append dragon_long.gif \
-background none -append append_multi.gif
![[IM Output]](../static/img/layers/append_multi.gif)
各行の画像を連結し、その下により大きな画像を連結しました。これは非常に単純で素直です。括弧を使えば、より大きな画像の後で数字だけを連結できます。たとえば、ここではすべての数字をまとめて連結してから、数字の前に読み込んだドラゴン画像に対して垂直方向に連結します。 |
magick dragon_long.gif '(' font_{0,0,6,2,9}.gif +append ')' \
-background none -append append_parenthesis.gif
![[IM Output]](../static/img/layers/append_parenthesis.gif)
| 上の括弧は、UNIX シェルで使うときは、クォートで囲むか、バックスラッシュ(「\」)でエスケープしなければなりません。さもないとシェルがまったく別のものとして解釈してしまいます。
---|---
| 関与する画像が2枚だけだったので、括弧を使う代わりに単に「[+swap](https://imagemagick.org/command-line-options/#swap)」や「[-reverse](https://imagemagick.org/command-line-options/#reverse)」を使うこともできました。
---|---
画像の配列を連結する
これをさらに進めて、画像全体の配列を作り、行ごとまたは列ごとに組み立てることができます。 |
magick \( font_1.gif font_2.gif font_3.gif +append \) \
\( font_4.gif font_5.gif font_6.gif +append \) \
\( font_7.gif font_8.gif font_9.gif +append \) \
\( -size 32x32 xc:none font_0.gif +append \) \
-background none -append append_array.gif
![[IM Output]](../static/img/layers/append_array.gif)
厳密には、まだ画像が読み込まれていないので最初の括弧は不要ですが、これによりコマンド全体が統一的に見え、画像の配列を作るという意図が示されます。等しいサイズの画像の配列を作る別の方法については、Montage の連結モードも参照してください。 | _「[-append](https://imagemagick.org/command-line-options/#append)」演算子は実際の画像のみを連結し、仮想キャンバス(画像のページ)サイズや画像のオフセットは使いません。ただし、仮想キャンバス情報がおかしな状態のままになるようで、キャンバスサイズが合算され、オフセットが未定義の値に設定されてしまいます。
これはバグとみなしてよく、入力画像か結果のいずれかについて、保存前、あるいはこの情報が重要になりうる操作で使う前に、「[+repage](https://imagemagick.org/command-line-options/#repage)」で仮想キャンバスをリセットする必要があることを意味します。
この状況は、おそらく将来の操作の拡張で修正されるでしょう。したがって注意が必要で、特にタイル切り抜きされた画像を再連結する場合は気をつけてください。_
---|---
重ね合わせ付きの連結
IM フォーラムで、あるユーザーがいくらか重ね合わせて画像を連結する簡単な方法を尋ねました。多くの解決策が提示されました。これは最も単純な解決策の1つで、重なりの量を1か所で指定します。 |
magick granite: rose: -gravity east -background none \
\( -clone 1 -chop 30x0 \) \( -clone 0,2 +append \) \
-delete 0,2 +swap -composite append_overlap.gif
![[IM Output]](../static/img/layers/append_overlap.gif)
上の例は、より一般的な解決策となるような、典型的には画像サイズを伴う画像配置の計算をいっさい必要としませんでした。下の画像レイヤーの扱いを参照してください。ここで行ったのは、重なる部分を切り落としてから、その結果を最初の画像に連結して最終的な画像サイズを作り出すことです。その上に元の画像を(gravity 付きで)合成して、実際の重なりを生成します。垂直方向の重ね合わせ、あるいは右から左への重ね合わせにも比較的簡単に変更できます。
スマッシュ連結(Smushing)
画像を連結するもう1つの方法はスマッシュです。「[-smush](https://imagemagick.org/command-line-options/#smush)」演算子は、連結(Append)演算子(上記参照)とよく似た働きをしますが、画像間にどれだけの空白(または逆に詰める量)を入れたいかを引数に取ります。たとえば、先ほどの例をもっと簡単にやってみましょう。 |
magick granite: rose: -background none -gravity Center \
+smush -20 smush_overlap.png
![[IM Output]](../static/img/layers/smush_overlap.png)
これはとてもうまく動きますが、演算子が本来そのために設計されたものではなく、おそらくかなり遅くなります。スマッシュが本来意図しているのは、「形を持つ画像」を可能なかぎり近づけることです。たとえば、ここでは文字「A」と「V」を生成し、それらの間の空白を可能なかぎり小さくして「スマッシュ」します。 |
magick -background none -pointsize 72 \
-fill red label:A -fill blue label:V \
+smush 0 smush_append.png
![[IM Output]](../static/img/layers/smush_append.png)
2つの文字が、画像の「形」の空白を利用して、連結よりもはるかに近く連結された点に注目してください。上の例の隙間は、2つの文字のアンチエイリアスされた縁ピクセルによって生じています。これが「[-smush](https://imagemagick.org/command-line-options/#smush)」の設計意図ですが、多くの計算を必要とするため、連結(Append)(上記参照)よりもかなり遅くなります。引数はその最終位置のオフセットで、通常は隙間を作るために正の値ですが、重なりを作るために負にすることもできます。 |
magick -background none -pointsize 72 \
-fill red label:A -fill blue label:V \
+smush -15 smush_offset.png
![[IM Output]](../static/img/layers/smush_offset.png)
非常に大きな負の値を使うと、画像が文書化されていない方法でクリップされることがあります。
複数の画像ペアの合成
合成(Composition)は、2つの個別の画像を統合するために使われる低レベルの操作です。ほとんどすべてのレイヤー化技法は、最終的には、画像が1枚だけ残るまで2つずつ画像を統合する処理に帰着します。そこでまず、画像ペアの低レベル合成を行う方法を見ていきましょう。
composite コマンドを使う
ImageMagick で2つの画像を結合する伝統的な方法は、「magick composite」コマンドによるものです。このコマンドは一度に2つの画像しか結合できず、各操作の結果をファイルに保存します。もちろん、これを使って複数の画像を1枚ずつレイヤー化することは妨げられません… |
magick -size 100x100 xc:skyblue composite.gif
magick composite -geometry +5+10 balloon.gif composite.gif composite.gif
magick composite -geometry +35+30 medical.gif composite.gif composite.gif
magick composite -geometry +62+50 present.gif composite.gif composite.gif
magick composite -geometry +10+55 shading.gif composite.gif composite.gif
![[IM Output]](../static/img/layers/composite.gif)
| _すべての入力画像は、出力画像が開かれる前に ImageMagick によって読み込まれるので、入力画像の1つに出力できます。これにより、上で示したように同じ画像に対して問題なく繰り返し作業できます。
「JPEG」のような非可逆画像フォーマットでこれを行ってはいけません。フォーマットの誤差が累積し、ベース画像がすぐに劣化するからです。_
---|---
「[-geometry](https://imagemagick.org/command-line-options/#geometry)」設定を使えば、重ね合わせる画像を配置するだけでなくリサイズすることもできます。 |
magick -size 100x100 xc:skyblue comp_resize.gif
magick composite -geometry 40x40+5+10 balloon.gif comp_resize.gif comp_resize.gif
magick composite -geometry +35+30 medical.gif comp_resize.gif comp_resize.gif
magick composite -geometry 24x24+62+50 present.gif comp_resize.gif comp_resize.gif
magick composite -geometry 16x16+10+55 shading.gif comp_resize.gif comp_resize.gif
![[IM Output]](../static/img/layers/comp_resize.gif)
「magick composite」コマンドには、他にもいくつかの利点があります。「[-compose](https://imagemagick.org/command-line-options/#compose)」オプションで画像が背景にどのように描かれるかを制御でき、その相対位置は「[-gravity](https://imagemagick.org/command-line-options/#gravity)」設定によって影響されます。また、重ね合わせを「[-tile](https://imagemagick.org/command-line-options/#tile)」して、タイルの上限を指定する必要なく背景画像を覆い尽くすこともできます。これは「magick composite」を使うときにのみ利用できる機能です。この方法の大きな欠点は、複数のコマンドを使うことであり、IM は次のコマンドが再び読み込むために、作業中の画像をパイプラインまたはディスクに書き出さなければならない点です。他の画像の上に画像を重ねる「magick composite」コマンドの使用例をもっと知りたい場合は、「画像の重ね合わせによる注釈付け」と「Gravity を使った画像配置」を参照してください。
convert の composite 演算子
「[-composite](https://imagemagick.org/command-line-options/#composite)」演算子は「magick」コマンド内で利用できます。詳細は IM における画像合成を参照してください。これにより、上記と同じことを、すべて1つのコマンドで行えます。 |
magick -size 100x100 xc:skyblue \
balloon.gif -geometry +5+10 -composite \
medical.gif -geometry +35+30 -composite \
present.gif -geometry +62+50 -composite \
shading.gif -geometry +10+55 -composite \
compose.gif
![[IM Output]](../static/img/layers/compose.gif)
これはまず「skyblue」色のキャンバス画像を作成し、続いて後続の各画像を指定された位置にそのキャンバスへレイヤー化します。ここで「[-geometry](https://imagemagick.org/command-line-options/#geometry)」は非常に特殊な演算子で、次の「[-composite](https://imagemagick.org/command-line-options/#composite)」操作の重ね合わせ位置を設定するだけでなく、現在の画像シーケンスの_最後_の画像(最後の画像のみ)を「[-resize](https://imagemagick.org/command-line-options/#resize)」もします。 |
magick -size 100x100 xc:skyblue \
balloon.gif -geometry 40x40+5+10 -composite \
medical.gif -geometry +35+30 -composite \
present.gif -geometry 24x24+62+50 -composite \
shading.gif -geometry 16x16+10+55 -composite \
compose_geometry.gif
![[IM Output]](../static/img/layers/compose_geometry.gif)
便利ではありますが、この「[-geometry](https://imagemagick.org/command-line-options/#geometry)」の「リサイズ」という副作用は避けることを推奨します。基本的に、これは後方互換性のための効果に過ぎず、状況によっては他の効果を生むことがあるからです。次がより冗長な推奨記法です… |
magick -size 100x100 xc:skyblue \
\( balloon.gif -resize 40x40 \) -geometry +5+10 -composite \
\( medical.gif \) -geometry +35+30 -composite \
\( present.gif -resize 24x24 \) -geometry +62+50 -composite \
\( shading.gif -resize 16x16 \) -geometry +10+55 -composite \
compose_resize.gif
複数の画像を描画する
「magick」を使えば、描画プリミティブを使って、作業中のキャンバスに画像を重ね合わせることもできます。 |
magick -size 100x100 xc:skyblue \
-draw "image over 5,10 0,0 'balloon.gif'" \
-draw "image over 35,30 0,0 'medical.gif'" \
-draw "image over 62,50 0,0 'present.gif'" \
-draw "image over 10,55 0,0 'shading.gif'" \
drawn.gif
magick -size 100x100 xc:skyblue \
-draw "image over 5,10 40,40 'balloon.gif'" \
-draw "image over 35,30 0,0 'medical.gif'" \
-draw "image over 62,50 24,24 'present.gif'" \
-draw "image over 10,55 16,16 'shading.gif'" \
drawn_resize.gif
![[IM Output]](../static/img/layers/drawn_resize.gif)
「描画される」画像は、重ね合わせの過程で回転・拡大縮小・アフィン歪みを加えることもできます。ただし、思いどおりに動かすのは厄介になることがあります。描画される画像は、テキストと同じく「[-gravity](https://imagemagick.org/command-line-options/#gravity)」の影響を受けます。
複数画像のレイヤー化
画像の真のレイヤー化には、各画像ペアを個別に1つずつ合成する必要なしに、複数の画像を組み合わせる方法が必要です。ここで、さまざまな [-layers](https://imagemagick.org/command-line-options/#layers) 演算子のメソッドが真価を発揮します。レイヤー化された画像の順序は重要になりうるので、特殊な画像シーケンス(リスト)演算子を理解しておくとよいでしょう。「レイヤー化された画像」は、「アニメーションのフレーム」の扱いと実質的に同一である点に注意してください。そのため、個々の「レイヤー」や「フレーム」を処理する技法については、アニメーションの基礎とアニメーションの加工の両方も参照することを推奨します。実際、アニメーションでも画像処理に同じ [-layers](https://imagemagick.org/command-line-options/#layers) 演算子をよく使います。
平坦化(Flatten) - 背景画像へ重ねる
「[-layers](https://imagemagick.org/command-line-options/#layers) **flatten**」画像リスト演算子(あるいはその短縮形「[-flatten](https://imagemagick.org/command-line-options/#flatten)」)は、基本的に、与えられた各画像を背景に「合成」して1枚の画像にします。ただし画像の位置は、それぞれの現在の仮想キャンバス、つまりページオフセットを使って指定されます。たとえば、ここでは素敵なキャンバスを作成し、そのキャンバスに重ねたい各画像を指定します。 |
magick -size 100x100 xc:skyblue \
-fill dodgerblue -draw 'circle 50,50 15,25' \
\( -page +5+10 balloon.gif \) \( -page +35+30 medical.gif \) \
\( -page +62+50 present.gif \) \( -page +10+55 shading.gif \) \
-layers flatten flatten_canvas.gif
![[IM Output]](../static/img/layers/flatten_canvas.gif)
| _IM v6.3.6-2 の時点で、「[-flatten](https://imagemagick.org/command-line-options/#flatten)」演算子は「[-layers](https://imagemagick.org/command-line-options/#layers) 'flatten'」メソッドの単なる別名です。
したがって、「[-flatten](https://imagemagick.org/command-line-options/#flatten)」オプションは、同名の「[-layers](https://imagemagick.org/command-line-options/#layers)」メソッドの短縮形とみなせます。_
---|---
上で行ったように初期キャンバスを作成する必要はありません。代わりに「[-flatten](https://imagemagick.org/command-line-options/#flatten)」に作らせることもできます。キャンバスの色は現在の「[-background](https://imagemagick.org/command-line-options/#background)」色になり、そのサイズは最初の画像の仮想キャンバスサイズによって定義されます。 |
magick \( -page 100x100+5+10 balloon.gif \) \( -page +35+30 medical.gif \) \
\( --page +62+50 present.gif \) \( -page +10+55 shading.gif \) \
-background dodgerblue -layers flatten flatten_page.gif
![[IM Output]](../static/img/layers/flatten_page.gif)
| _「[-gravity](https://imagemagick.org/command-line-options/#gravity)」設定は、「[-geometry](https://imagemagick.org/command-line-options/#geometry)」設定で定義された画像配置には影響しますが、「[-page](https://imagemagick.org/command-line-options/#page)」設定で設定された仮想キャンバスオフセットを使う画像配置には影響しません。これはそのようなオフセットの定義の一部です。詳細は Geometry とページオフセットの違いを参照してください。
「[-gravity](https://imagemagick.org/command-line-options/#gravity)」による配置が必要な場合は、上記の複数画像合成メソッドか、両方の配置方法を同時に扱える特殊なレイヤー合成メソッドのいずれかを見てください。_
---|---
いずれかの画像が定義された仮想キャンバス領域に現れない場合、その画像は適宜クリップされるか無視されます。たとえば、ここではより小さなキャンバスサイズを使ったため、後続の画像がそのキャンバスに完全には現れていません。 |
magick \( -page 75x75+5+10 balloon.gif \) \( -page +35+30 medical.gif \) \
\( -page +62+50 present.gif \) \( -page +10+55 shading.gif \) \
-background dodgerblue -flatten flatten_bounds.gif
![[IM Output]](../static/img/layers/flatten_bounds.gif)
平坦化(Flatten)の通常の使い方は、複数の画像「レイヤー」を統合することです。すなわち、より大きな画像のさまざまな部分を、通常は括弧を使って画像演算子を生成中の単一「レイヤー」画像に限定しつつ生成し、最終的な結果を平坦化してまとめます。たとえば、典型的な使い方の1つは影画像レイヤーを作成し、その上に元の画像を平坦化することです。たとえば… |
magick balloon.gif \( +clone -background navy -shadow 80x3+5+5 \) +swap \
-background none -flatten flatten_shadow.png
![[IM Output]](../static/img/layers/flatten_shadow.png)
影を元の画像の下に置きたかったので、2つの画像を入れ替え(swap)て正しい順序に並べる必要があった点に注意してください。 | _生成した影画像を加えるのに平坦化(Flatten)を使うことは推奨されません。生成された影画像は負の画像オフセットを持つことがあるからです。
影画像の節で示した推奨解決策は、後で見るより高度なレイヤー統合技法を使うことです。_
---|---
仮想キャンバスはサイズのみで構成されるため、結果の画像はそのサイズになりますが、仮想キャンバスオフセットを持たないので、最終画像に存在するオフセットを気にする必要はありません。画像を重ね合わせるキャンバスを定義するためにこの仮想キャンバスを使うということは、これを使って画像の周りに囲み枠を加えられるということです。たとえば、ここでは画像を特定のサイズに「埋め込む」ために、画像のサイズと仮想オフセットを設定します。 |
magick medical.gif -set page 64x64+20+20 \
-background SkyBlue -flatten flatten_padding.gif
![[IM Output]](../static/img/layers/flatten_padding.gif)
もちろん、IM がより大きな領域内に画像を自動的に中央揃えするような、画像を埋め込むより良い方法もあります。 不思議なことに、まったく同じ扱いを使って、元の画像より小さい仮想キャンバスに画像を「クリップ」つまり切り抜く(Crop)こともできます。ただしこの場合は、「切り抜き」位置を配置するために負のオフセットを使いたいでしょう。切り抜きの「ウィンドウ」を配置するのではなく、画像をオフセットしているからです。 |
magick logo: -repage 100x100-190-60 -flatten flatten_crop.gif
![[IM Output]](../static/img/layers/flatten_crop.gif)
もちろん、ビューポート切り抜きのほうが、「[-flatten](https://imagemagick.org/command-line-options/#flatten)」が行うキャンバス生成と重ね合わせの余分な処理なしに、これをよりうまく行えます。また、画像がビューイングウィンドウに部分的にしか含まれていなかった場合に、ビューポート全体を覆うように画像自体を「拡張」することもありません。「[-flatten](https://imagemagick.org/command-line-options/#flatten)」演算子のよくある誤用は、画像から透明度を除去することです。すなわち、画像が持つかもしれない透明度を、背景色に重ねることで取り除くというものです。しかし、複数画像が関与する場合これは機能しないため、もはや推奨されません。
モザイク(Mosaic) - キャンバスの拡張
「[-layers](https://imagemagick.org/command-line-options/#layers) **mosaic**」演算子(あるいはその「[-mosaic](https://imagemagick.org/command-line-options/#mosaic)」短縮形)は、平坦化演算子のキャンバス拡張版のようなものです。最初の画像のキャンバスサイズだけに基づいて初期キャンバスを作るのではなく、モザイク演算子は、すべての画像を保持するのに十分な大きさのキャンバスを(正の方向にのみ)作ります。たとえば、ここでは適切な仮想キャンバスすら設定しませんが、「[-mosaic](https://imagemagick.org/command-line-options/#mosaic)」演算子は、すべての画像レイヤーを保持するのにそのキャンバスがどれだけ大きくなければならないかを算出します。 |
magick \( -page +5+10 balloon.gif \) \( -page +35+30 medical.gif \) \
\( -page +62+50 present.gif \) \( -page +10+55 shading.gif \) \
-background dodgerblue -layers mosaic mosaic.gif
![[IM Output]](../static/img/layers/mosaic.gif)
| _IM v6.3.6-2 の時点で、「[-mosaic](https://imagemagick.org/command-line-options/#mosaic)」演算子は「[-layers](https://imagemagick.org/command-line-options/#layers) 'mosaic'」の単なる別名です。
したがって、「[-mosaic](https://imagemagick.org/command-line-options/#mosaic)」オプションは、同名の「[-layers](https://imagemagick.org/command-line-options/#layers)」メソッドの短縮形とみなせます。_
---|---
「[-mosaic](https://imagemagick.org/command-line-options/#mosaic)」も「[-flatten](https://imagemagick.org/command-line-options/#flatten)」も、依然として「原点」つまり 0,0 ピクセルから始まるキャンバスを作る点に注意してください。これは画像の「仮想キャンバス」つまり「ページ」の定義の一部であり、このため両方の演算子で最終画像が仮想オフセットを持たず、キャンバス全体が実際のピクセルデータで完全に定義されていることを保証できます。また、「[-mosaic](https://imagemagick.org/command-line-options/#mosaic)」はキャンバスを正の方向(下端または右端)にのみ拡張する点にも注意してください。上端と左端は仮想原点に固定されているからです。これはもちろん、「[-mosaic](https://imagemagick.org/command-line-options/#mosaic)」が負のオフセットを持つ画像を依然としてクリップすることを意味します… |
magick \( -page -5-10 balloon.gif \) \( -page +35+30 medical.gif \) \
\( -page +62+50 present.gif \) \( -page +10+55 shading.gif \) \
-background dodgerblue -mosaic mosaic_clip.gif
統合(Merging) - 新しいレイヤー画像を作る
「[-layers](https://imagemagick.org/command-line-options/#layers) **merge**」演算子は、前述の演算子とほぼ同一で、IM v6.3.6-2 で追加されました。与えられたすべての画像を、それぞれのオフセットで保持するのにちょうど十分な大きさのキャンバス画像のみを作ります。モザイク(Mosaic)と同様にキャンバスを拡張しますが、正の方向だけでなく負の方向にも拡張します。基本的に、レイヤー画像を統合するときに、クリップやオフセットなどの側面を気にする必要がないということです。すべての画像が互いの位置に対して相対的に統合されます。出力には原点が含まれることや、原点が拡張キャンバスの一部であることが保証されません。そのため、レイヤー統合(Layers Merge)の出力には、正にも負にもなりうる「レイヤーオフセット」が含まれることがあります。言い換えれば… レイヤー統合(Layers Merge)はレイヤー画像を統合して新しい_レイヤー画像_を生成します。そのため、終わった後にそのオフセットを望まない場合は、最終的な保存の前に「[+repage](https://imagemagick.org/command-line-options/#repage)」演算子を入れたくなるでしょう。たとえば、ここはこれまで使ってきたのと同じレイヤー画像のセットです… |
magick \( -page +5+10 balloon.gif \) \( -page +35+30 medical.gif \) \
\( -page +62+50 present.gif \) \( -page +10+55 shading.gif \) \
-background dodgerblue -layers merge +repage layers_merge.gif
![[IM Output]](../static/img/layers/layers_merge.gif)
ご覧のとおり、画像は互いに相対的に配置されたすべての画像を保持するのにちょうど十分な大きさしかなく、一方で、結果画像の仮想キャンバス原点に対するオフセットは破棄しました。クリップや余計な不要な空白なしに相対位置を保つこの性質が、この変種を非常に強力にしています。今度は、ある画像に負のオフセットを与えて、これを再びやってみましょう… |
magick \( -page -5-10 balloon.gif \) \( -page +35+30 medical.gif \) \
\( -page +62+50 present.gif \) \( -page +10+55 shading.gif \) \
-background dodgerblue -layers merge +repage layers_merge_2.gif
![[IM Output]](../static/img/layers/layers_merge_2.gif)
ご覧のとおり、「balloon」はクリップされず、他の画像との相対的な距離を保つために、ただ他から遠ざけられただけです。もちろん、上の例の「[+repage](https://imagemagick.org/command-line-options/#repage)」演算子は、最終画像の絶対的な仮想キャンバスオフセットを取り除き、画像間の相対的な画像配置だけを保ちます。このオフセットを取り除いたのは、GIF アニメーションの一部でないかぎり、ウェブブラウザがしばしば画像オフセット、特に負の画像オフセットを正しく扱えないからです。しかし、もしこのオフセットを取り除かなければ、すべての画像は生成された単一レイヤー画像内の仮想キャンバス上で正しい位置に留まり、統合された画像にさらに画像を処理・追加し続けられます。通常は、「[-background](https://imagemagick.org/command-line-options/#background)」色に「None」を使い、統合画像の未使用領域を透明にします。単一の画像に適用した場合、レイヤー統合(Layer Merging)は画像内の透明度を不透明な背景色で置き換えますが、画像の元のサイズと、その画像にあるオフセットは保ちます。ただし画像の仮想キャンバスサイズは、その画像のサイズとオフセットに「最適合」するよう調整されることがあります。この演算子の本来の目的は、個々の画像のオフセットに関係なく、複数の歪み画像を統一された全体に、よりたやすく統合できるようにすることでした。たとえば、より大きな「パノラマ」を作るために写真を整列させる場合です。中心となる歪みのないベース画像(オフセットなし)から始め、この演算子を使って、その出発点の中心画像に合わせて整列・歪曲された他の画像を(負または正のオフセットを使って)その周りに重ね合わせるだけでよいのです。共通の制御点に合わせて画像を歪曲してこの演算子を使う他の例については、3D アイソメトリック写真キューブと 3D 透視ボックスを参照してください。この演算子を使う他の例は、単純な一連の重なり合う写真の生成です。
「-layers trim-bounds」操作を使うと、すべての画像が、相対位置を保ちつつ、
最小限のキャンバスサイズ上で正のオフセットを持つことを保証できます。
しかも実際に画像を1枚の最終画像へレイヤー統合することはありません。
これにより、画像が実際に統合される前にさらなる処理を行えます。
たとえば、その画像グループに対して相対的にさらに画像を配置しつつ、
結果として得られる仮想キャンバスの境界を参照するといったことです。
ただし、画像に透明度がある場合は、まず画像からその透明度をトリムするのが
おそらくよい考えで、理想的な使い方は次のようになります…
-alpha set -bordercolor none -border 1x1 -trim -layers trim-bounds
これは、実際の画像データのあらゆる透明領域を含めて画像レイヤーを最小化しつつ、
すべてが最小サイズの有効な仮想(正の)キャンバス上に収まることを保証します。
合体合成(Coalesce) - 段階的なレイヤー化
「[-layers](https://imagemagick.org/command-line-options/#layers) **coalesce**」画像演算子(あるいはその「[-coalesce](https://imagemagick.org/command-line-options/#coalesce)」短縮形)は、本来は GIF アニメーションを画像のシーケンスに変換するために設計されています。例については、アニメーションの合体合成を参照してください。しかし、これは「[-flatten](https://imagemagick.org/command-line-options/#flatten)」と非常に密接に関連しており、この点で複数レイヤー画像に対して非常に有用な効果を持ちます。 たとえば、単一の画像に対して合体合成(Coalesce)を使うと、「[-background](https://imagemagick.org/command-line-options/#background)」色「None」または「Transparency」で平坦化(Flatten)を使うのとまったく同じ仕事をします。すなわち、画像のキャンバスを透明ピクセルで「埋め尽くし」ます。 |
magick \( -page 100x100+5+10 balloon.gif \) -layers coalesce coalesce_canvas.gif
![[IM Output]](../static/img/layers/coalesce_canvas.gif)
複数のレイヤーからなる画像を扱う場合、合体合成(Coalesce)を使って画像の「段階的なレイヤー化」を生成できます。ただしこれを行うには、演算子による「GIF アニメーション」の扱いを無効にするために、いくつかの注意が必要です。
magick \( -page 100x100+5+10 balloon.gif \) \( -page +35+30 medical.gif \) \
\( --page +62+50 present.gif \) \( -page +10+55 shading.gif \) \
-set dispose None -coalesce miff:- |\
montage - -frame 4 -tile x1 -geometry +2+2 \
-background none -bordercolor none coalesce_none.gif
上の例では、すべての「[-dispose](https://imagemagick.org/command-line-options/#dispose)」設定を「[None](anim_basics.html#none)」に「[-set](https://imagemagick.org/command-line-options/#set)」しています。これは事実上、「[-coalesce](https://imagemagick.org/command-line-options/#coalesce)」に、各フレームを以前の重ね合わせの結果の上に重ねるだけにせよと伝えています。その結果、最初の画像は単に画像のキャンバスを透明な背景で「埋め尽くした」ものになります。次の画像は、前の画像にそのレイヤーを重ねたものです。以下同様です。画像シーケンスの「段階的な」平坦化です。したがってシーケンスの最後の画像は、透明な背景で通常の「[-flatten](https://imagemagick.org/command-line-options/#flatten)」を行った場合と同じになります。「[-dispose](https://imagemagick.org/command-line-options/#dispose)」設定に「[Background](anim_basics.html#background)」を使っていたら、まったく異なる種類の効果が得られます。この場合、「[-coalesce](https://imagemagick.org/command-line-options/#coalesce)」は、各画像のキャンバスを、まるで完全に別々の画像であるかのように「埋め尽くす」だけになります!
magick \( -page 100x100+5+10 balloon.gif \) \( -page +35+30 medical.gif \) \
\( --page +62+50 present.gif \) \( -page +10+55 shading.gif \) \
-set dispose Background -coalesce miff:- |\
montage - -frame 4 -tile x1 -geometry +2+2 \
-background none -bordercolor none coalesce_bgnd.gif
ただし、平坦化(Flatten)、モザイク(Mosaic)、統合(Merge)とは違い、「[-coalesce](https://imagemagick.org/command-line-options/#coalesce)」演算子は現在の「[-compose](https://imagemagick.org/command-line-options/#compose)」アルファ合成設定を_使わない_点に注意してください。GIF アニメーションの処理に必要なため、「[Over](compose.html#over)」合成メソッドのみを使います。より標準的な画像レイヤー化演算子で異なる「[-compose](https://imagemagick.org/command-line-options/#compose)」メソッドを使うことは、次の一連の例の主題です。
合成メソッドとレイヤー化
3つのレイヤー化メソッド、平坦化(Flatten)、モザイク(Mosaic)、統合(Merge)は、「[-compose](https://imagemagick.org/command-line-options/#compose)」設定を使って、各画像を順に重ね合わせる際の合成メソッドを決定します。そのため、これらの関数は、指定された色の初期「[-background](https://imagemagick.org/command-line-options/#background)」キャンバスを設定できる、複数画像版の「[-composite](https://imagemagick.org/command-line-options/#composite)」演算子と考えられます。ただし、既定のアルファ合成「Over」以外を使う場合は、適用前にいくらか考える必要があり、さもないと予期しない結果になります。これらの演算子が開始キャンバスを生成するために使う「[-background](https://imagemagick.org/command-line-options/#background)」色が、その上に各画像(最初の画像を含む)が合成される際にどう影響するかも考える必要があるかもしれません。たとえば、「[DstOver](compose.html#dstover)」を使って、後続の各画像を前の画像の_下_に置いてみましょう… |
magick \( -page 100x100+5+10 balloon.gif \) \( -page +35+30 medical.gif \) \
\( --page +62+50 present.gif \) \( -page +10+55 shading.gif \) \
-background none -compose DstOver -flatten flatten_dstover.gif
![[IM Output]](../static/img/layers/flatten_dstover.gif)
ここでは背景を透明に設定しました。さもないと、他のすべての画像がこの初期キャンバスの「下」に置かれてしまうため、結果には背景キャンバスしか見えなくなるからです! これは、既存の画像に合わせてサイズ指定したキャンバスで示したように、画像を特定の色で「空白化」する方法を提供します。ここはより実用的な例です。背景キャンバスを最初にして画像をレイヤー化する(一部の画像処理状況では厄介で不自然)のではなく、画像を上から下へ、つまり前景から背景の順に生成するだけでよいのです。 |
magick rose: -repage +10+10 \
\( +clone -background black -shadow 60x3+5+5 \) \
\( granite: -crop 100x80+0+0 +repage \) \
-background none -compose DstOver -layers merge layer_dstover.gif
![[IM Output]](../static/img/layers/layer_dstover.gif)
最初の3行がそれぞれ1つのレイヤー画像を生成し、最後の行がすべてのレイヤーを前のレイヤーの下に統合し、事実上順序を逆にします。
ご覧のとおり、上の例の画像処理は、各画像を順に(透明な開始キャンバスで)下敷きにするだけで、影生成で通常見られるよりも単純で明快でした。
もちろん、代わりに画像リストを反転(Reverse)するだけでも、同じくらい簡単にできました。 |
magick rose: -repage +10+10 \
\( +clone -background black -shadow 60x3+5+5 \) \
\( granite: -crop 100x80+0+0 +repage \) \
-reverse -layers merge layer_reverse.gif
![[IM Output]](../static/img/layers/layer_reverse.gif)
ただし、これは既存の画像の順序を入れ替えるだけで、レイヤー化メソッドが作る「開始背景キャンバス」には影響しない点に注意してください。合成メソッドは、興味深い効果を生むためにも使えます。たとえば、3つの円を描いて、それらを「Xor」合成メソッドで重ね合わせると、最小限の手間で、変わった複雑そうな記号が得られます。 |
magick -size 60x60 \
\( xc:none -fill blue -draw 'circle 21,39 24,57' \) \
\( xc:none -fill red -draw 'circle 39,39 36,57' \) \
\( xc:none -fill green -draw 'circle 30,21 30,3' \) \
-background none -compose Xor -flatten flatten_xor.png
レイヤー合成(Layers Composite) - 2つのレイヤーリストを統合する
IM v6.3.3-7 で、「[-layers](https://imagemagick.org/command-line-options/#layers)」メソッド「**Composite**」が追加され、完全に別々の2つの画像セットを合成できるようになりました。コマンドラインでこれを行うには、最初の_宛先(destination)_画像リストがどこで終わり、重ね合わせる_ソース(source)_画像リストがどこで始まるかを定義する、特殊な「[null:](files.html#null)」マーカー画像が必要です。しかし、それがこのメソッドの唯一の実質的な複雑さです。基本的に、最初のリストの各画像が2番目のリストの対応する画像に対して合成され、事実上2つのリストを統合します。2番目のリストは、通常のComposite 演算子(上記参照)と同様に、Geometry オフセットを使って最初のリストに対してグローバルに配置できます。Gravity も、計算を行うために最初の画像のキャンバスサイズを使って適用されます。その「グローバルオフセット」に加えて、各画像ペアが合成される際には、画像個々の仮想オフセットも保たれます。1つの特殊なケースも処理されます。いずれかの画像リストに画像が1枚しか含まれない場合、その画像はもう一方のリストのすべての画像に対して合成されます。またその場合、合成の宛先側でなくても、大きい方のリストの画像メタデータ(アニメーションのタイミングなど)が保たれます。
このレイヤー化演算子は、2つのアニメーションを合成するときによく使われます。アニメーションは、時間方向にレイヤー化された画像リストの一種とみなせます。このため、例のうちアニメーションの加工の節で説明するほうが適切です。詳細は複数画像のアルファ合成を参照してください。
画像レイヤーの扱い
上記のさまざまなレイヤー演算子を使って複数の画像をレイヤー化することは、非常に汎用的な技法です。多数の画像を個別に作業し、終わったらそれらすべてを1つの統一された全体にまとめられます。これまで、複数の画像を多くの異なる方法で統合(合成またはレイヤー化)するさまざまなやり方を示してきました。ここでは、それらの技法を実際にどう活用するかについて、より実用的な例をいくつか紹介します。
サムネイル画像のレイヤー化
この技法を、複数のサムネイルをさまざまな複雑な方法で統合するのにも使えます。ここでは、画像を読み込んで配置する際にソフトエッジを加えることで、タイル状のキャンバスの上に、画像のかなり素敵な構図を生成できます。
magick -page +5+5 holocaust_tn.gif \
-page +80+50 spiral_stairs_tn.gif \
-page +40+105 chinese_chess_tn.gif \
+page \
-alpha Set -virtual-pixel transparent \
-channel A -blur 0x10 -level 50,100% +channel \
\( -size 200x200 tile:tile_fabric.gif -alpha Set \) -insert 0 \
-background None -flatten overlap_canvas.jpg
画像の計算による配置
仮想キャンバスオフセット(ページ)は、多くの方法で設定できます。具体的には、これを画像ごとの属性として「[-set](https://imagemagick.org/command-line-options/#set)」でき、各画像ごとに異なる位置を計算することさえできます。たとえば、ここでは大きな画像セット(すべて同じサイズの小さなアイコン画像)を読み込んで、それらを円形に配置します。
magick {balloon,castle,eye,eyeguy,ghost,hand_point,medical}.gif \
{news,noseguy,paint_brush,pencil,present,recycle}.gif \
{shading,skull,snowman,storm,terminal,tree}.gif \
\
-set page '+%[fx:80*cos((t/n)*2*pi)]+%[fx:80*sin((t/n)*2*pi)]' \
\
-background none -layers merge +repage image_circle.png
上の例の鍵は、正規化された画像インデックス(FX 式「t/n」)を使って、各画像ごとに 0.0 から 1.0 にわずかに満たない値を作る「[-set](https://imagemagick.org/command-line-options/#set) page」操作です。この値は次に、FX 式をパーセントエスケープとして使い、半径 80 ピクセルの円内に画像を(角度で)配置するようにマッピングされます。計算される位置は画像の左上隅(中心ではありません。ただしそれは簡単な調整です)で、これを統合(Merge)して新しい画像を生成します。配置はオフセットが正か負かに関係なく行われます。これが統合レイヤー化演算子の威力です。すなわち、すべての画像を互いに相対的なまま、新しい1枚の画像を生成しました。最後の「[+repage](https://imagemagick.org/command-line-options/#repage)」は、統合されたレイヤー画像の最終的な負のオフセットを取り除きます。これはもはや不要であり、結果画像を表示する際に問題を起こしうるからです。最初の画像(結果では最も右)が他のすべての画像の下にレイヤー化されている点に注意してください。最後の画像がこの最初の画像の下になるよう、レイヤー化を真に循環的にしたい場合は、最初の画像を半分に分け、上半分をシーケンスの末尾に置くとよいかもしれません。そうすれば最初の画像の上半分が最後の画像の上にレイヤー化され、下半分は2番目の画像の下に留まります。この技法は強力ですが、画像を整数オフセットにしか配置できません。画像のより正確なサブピクセル配置が必要な場合は、単に仮想オフセットを調整するのではなく、画像を正確なサブピクセル位置へ歪曲(平行移動)する必要があります。
段階的に計算される位置
FX 式を使うと、画像を処理しながらその属性を設定しつつ、他の画像のいくつかの画像属性にアクセスできます。これは、前の画像の計算済みの位置に対して相対的に、各画像の位置を設定できることを意味します。たとえば、これは各画像の位置を前の画像の右側に設定します。すなわち、前の画像の位置にその幅を加えたものです。
magick rose: netscape: granite: \
\
+repage -set page '+%[fx:u[t-1]page.x+u[t-1].w]+0' \
\
-background none -layers merge +repage append_diy.png
各画像は、前の画像の位置を参照してその幅を加えることで、前の画像の位置に連結されます。この前の位置は実際には、IM が各画像をループ処理して「page」(仮想オフセット)属性を設定する際に、ちょうど計算されたものです。結果は DIY 版の連結(Append)演算子に相当し、ここから独自の変種を発展させられます。最初の画像の位置計算の間に設定された「u[-1].w」によって、シーケンス全体が実際にずらされる点に注意すべきです。これは現在の画像シーケンスの最後の画像の幅になるはずです。ただし、その全体的な変位は、最後の「[+repage](https://imagemagick.org/command-line-options/#repage)」によって破棄されます。追加の計算を使ってこのオフセットを無視させることもできますが、上の例では不要です。 | _「u[t]」のような画像インデックスを使う場合、すべての画像セレクタ「u」「v」「s」は、与えられた「[index]」に従って同じ画像を参照します。そのため、このインデックス動作(および将来これが変わった場合に備えて)の覚え方として「u」(最初つまり0番目の画像)を使うほうがよいでしょう。
詳細は FX、DIY 画像演算子を参照してください。_
---|---
ここは別の例です。各画像は、その画像の位置と幅の両方を使って、前の画像に対して相対的にオフセットされ、重ね合わせ付きの連結を計算します。
magick font_[0-9].gif \
-set page '+%[fx:u[t-1]page.x+u[t-1].w-8]+%[fx:u[t-1]page.y+4]' \
-background none -layers merge +repage append_offset.gif
他の画像の属性にアクセスできるこの能力には、他の画像のピクセルデータも含まれます。つまり、色の値が他の画像の「マッピングされた位置」を表す特殊な画像を作れるということです。もちろん、その「マッピング」画像も配置されてしまうので、重ね合わせを実行する前に取り除く必要があります。そうした特殊な「位置マッピング」画像を作ることがどれほど有用かは別の問題です。これはあくまで1つの可能性に過ぎません。
画像の2段階配置
画像処理を2つのステップに分けることで、単純化できます。1つのステップは画像の生成・歪曲・配置・装飾の追加に使い、最後のステップですべてを統合します。たとえば、写真ストアの大きな元画像からポラロイドサムネイルを作り、それぞれを個別に処理(その側面を分離して単純に保つ)してみましょう。
center=0 # 最初の画像の中心の開始位置。
# 相対的な変化だけが重要なので、これは何でもよい。
for image in ../img_photos/[a-m]*_orig.jpg
do
# 各画像に加える相対オフセットとして、前の画像に 70 を足す
#
center=`magick xc: -format "%[fx: $center +70 ]" info:`
# 画像を読み込み、装飾を加え、中央揃えのパディング/トリムを使って
# 次の位置(前の画像に対して相対的)に画像の中心を配置する。
#
magick -size 500x500 "$image" -thumbnail 240x240 \
-set caption '%t' -bordercolor Lavender -background black \
-pointsize 12 -density 96x96 +polaroid -resize 30% \
-gravity center -background None -extent 100x100 -trim \
-repage +${center}+0\! MIFF:-
done |
# 配置済み画像のパイプラインを読み込み、統合する
magick -background skyblue MIFF:- -layers merge +repage \
-bordercolor skyblue -border 3x3 overlapped_polaroids.jpg
上のスクリプトは複雑に見えますが、実際はそうではありません。単にループ内で各サムネイル画像を生成し、同時に各画像を中央パディング(Extentを使用)してトリム(Trim)し、画像の「中心」が仮想キャンバス上の既知の位置にくるようにしているだけです。実際にはその位置を計算することもできますが、それには一時ファイルが必要になることがあるので、すべての画像についてよく知られた位置にあることを保証するほうがよいのです。次に画像は(相対的な「[-repage](https://imagemagick.org/command-line-options/#repage)」演算子を使って、キャンバスオフセット参照)平行移動され、生成される各画像が前の画像のちょうど 60 ピクセル右になるようにされます。すなわち、各画像の中心が、アスペクト比や回転で変わりうる画像の実際のサイズに関係なく、固定された距離だけ離れて配置されます。このスクリプトのもう1つの大きなコツは、各「レイヤー画像」を一時ファイルに保存する代わりに、MIFF: ファイルフォーマットを使って画像をパイプラインに書き込めることです。これは MIFF 画像ストリーミングとして知られる手法です。これが機能するのは、「MIFF:」ファイルフォーマットが、仮想キャンバスオフセットなどすべての画像メタデータを保ちつつ、複数の画像を単純に連結して1つのデータストリームにできるからです。この技法は、他の多くのスクリプトの良い出発点になります。画像を生成または加工し、最終的なサイズと位置を好きなように計算できます。別の例として、スクリプト「[hsl_named_colors](../static/img/scripts/hsl_named_colors)」があります。これは ImageMagick にある名前付き色のリストを取り、それらを HSL 色空間でその色のチャートに並べ替えます。その出力は色の指定で見られます。他の可能性には次のようなものがあります…
- どんな種類のサムネイル(あるいは他の装飾(Fluff))を使ってもよく、あるいは単に生の小さなサムネイルを直接使ってもよい。
- 最初の画像が中央にあり、他の画像がその最初の画像の下に左右に並ぶように、ピラミッドのように画像を生成する。
- 互いに相対的な特定の X・Y 座標に画像を置くことで、画像を弧・円・らせんに配置する。たとえば、PhD Circle、Sunset Flower、Fibonacci Spiral。
- 色に従って画像を配置する。たとえば、Book Covers。
- 時刻や投稿時刻で画像を配置する。たとえば、Year of Sunsets
基本的に、仮想キャンバス上での画像の配置は完全に自由であり、その後はすべての画像を保持するのに必要なキャンバスの最終サイズの算出を、単に IM に任せられます。
地図上のピン
ここは典型的なレイヤー化の例で、色付きのピンを地図上の特定の位置に置きます。
左にあるのは「押しピン」画像です。ピンの先端は位置 +18+41 にあります。また、ヴェネツィアの地図の画像があり、地図上のさまざまな点にピンを刺したいとします。たとえば「Accademia」はピクセル位置 +160+283 にあります。押しピンをその位置に揃えるには、ピンの先端の位置を地図の位置から引く必要があります。これにより、「ピン」画像のオフセット +142+242 が得られます。ここがレイヤー化された画像を使った結果です。
magick map_venice.jpg -page +142+242 push_pin.png \
-flatten map_push_pin.jpg
この例は IM フォーラムの議論 Layering Images with Convert からのものです。これをさらに自動化しましょう。 地図に置きたい各ピンの位置と色を列挙したファイルがあります。ファイル内の位置名は使われず、列挙されたピクセル位置への参照コメントに過ぎません。
このテキストファイルを読み込んで、ループで「ピン」を作りましょう。
pin_x=18 pin_y=41
cat map_venice_pins.txt |\
while read x y color location; do
[ "X$x" = "X#" ] && continue # データ内のコメントをスキップ
x=$(( x - pin_x )) # 地図の x,y をピン画像のオフセットへ
y=$(( y - pin_y ))
# 'color' を色モジュレート(色相のみ)の設定へ変換
# 元の押しピンが純粋な 'red' 色であることを前提とする
mod_args=$(
magick xc:$color -colorspace HSL txt: |
tr -sc '0-9\012' ' ' |\
awk 'NR==1 { depth=$3 }
NR==2 { hue=$3;
print "100,100," 100+200*hue/depth
}'; )
# 押しピンを再着色して配置する
magick push_pin.png -repage +${x}+${y} -modulate $mod_args miff:-
done |\
# 配置済み画像のパイプラインを読み込み、統合する
magick map_venice.jpg MIFF:- -flatten map_venice_pins.jpg
これは、元のピンの色が赤(色相 0)であることを前提とし、Modulate 演算子を使って、適切なスケーリング計算とともに他の色へ再着色する点に注意してください。色相を変えない(no-op の)モジュレート引数は 100 で、200 の値で循環する(一種の疑似パーセント値)点に注意してください。今後の課題: 地図を透視歪曲し、地図上の「深さ」に応じてピンサイズを調整し、歪みによるピン位置の変化を計算し、歪んだ地図に「ピン留め」する。 上の例は、MIFF 画像ストリーミングとして知られる手法を使い、各画像をループ内で個別に生成してから、それを「レイヤー化」コマンドに「パイプ」して最終画像を生成しました。代替の方法(PHP スクリプトでよく使われる)は、「生成されたコマンド」手法を使うことで、実行する長い「magick」コマンドをシェルスクリプトで生成します。画像ワーピングアニメーションのスクリプトはこの手法を使っています。どちらの方法も、一時画像を生成する必要を避けます。
影のレイヤー
重なり合う画像のセットで半透明の影効果を正しく扱うことは、見た目よりもずっと難しいのです。影付きの写真をただ重ね合わせるだけだと、影が二重に適用されてしまいます。すなわち、2つの重なり合う影は非常に暗くなりますが、実際には、重なり合う画像と同じようには影が重ならないのです。画像の各部分は、単に影が付くか付かないかのいずれかであるべきです。すなわち、影は画像のどの部分にも一度だけ適用されるべきです。光源が2つ別々にあるのでないかぎり、より暗い領域が生じてはなりません。そして光源が2つあると、事はさらに難しくなります。Tomas Zathurecky < tom @ ksp.sk > 氏がレイヤー化された画像での影効果を扱う課題に取り組み、この問題を扱うための画像アキュムレータ手法を開発しました。基本的に、画像を1枚ずつスタックの一番下に追加する必要があります。新しい画像を追加するとき、それをスタックに追加する前に、それまでのすべての画像の影が新しい画像を暗くする必要があります。ただし、新しい画像に落ちる影だけが追加されるべきです。新しい画像に落ちない影は、後でそれが他の画像や(あれば)背景に落ちるまで無視される必要があります。ここは1つの例です… |
magick \
\( holocaust_tn.gif -frame 10x10+3+3 \
-background none -rotate 5 -repage +0+0 \) \
\
\( spiral_stairs_tn.gif -frame 10x10+3+3 \
-background none -rotate -15 -repage -90+60 \) \
\( -clone 0 -background black -shadow 70x3+4+7 \
-clone 1 -background black -compose DstATop -layers merge \
-trim \) \
\( -clone 2,0 -background none -compose Over -layers merge \) \
-delete 0--2 \
\
\( chinese_chess_tn.gif -frame 10x10+3+3 \
-background none -rotate 20 -repage +60+90 \) \
\( -clone 0 -background black -shadow 70x3+4+7 \
-clone 1 -background black -compose DstATop -layers merge \
-trim \) \
\( -clone 2,0 -background none -compose Over -layers merge \) \
-delete 0--2 \
\
\( +clone -background black -shadow 70x3+4+7 \) +swap \
-background none -compose Over -layers merge +repage \
layers_of_shadows.png
![[IM Output]](../static/img/layers/layers_of_shadows.png)
上のプログラムは複雑に見えますが、実際はかなり素直です。最初の画像は、画像の累積スタックを開始するために使われます(画像インデックス #0)。その最初の画像をスタックの初期化に使いたくなければ、単一の透明ピクセル(「-size 1x1 xc:none」)から始めることもできました。さて、画像スタックの一番下に新しい画像を追加するには、毎回同じ一連の操作を適用します…
- まず、サムネイル画像がメモリに読み込まれ、回転や相対配置(負になることもある)が適用されます。望むなら、この時点で画像に他のサムネイル化操作を加えることもできますが、この例ではそれらはすでに実行済みです。新しい画像が画像インデックス #1 を形成します。
- 次に、前の画像スタック(#0)を取得し、適切な色・ぼかし・オフセット・環境光のパーセントで影を生成します。
- この影を新しい画像(#1)に重ね合わせ、新しい画像の「
[ATop](compose.html#atop)」に落ちる影だけを残します。また(任意で)結果にトリム操作を適用して、影付け操作で加わった余分な空白を取り除き、画像 #2 を形成します。 - これで、新しい画像(#2)を累積する画像スタック(#0)に追加するだけです。
- そして、最後の1枚を除く、それまでの作業画像をすべて削除します。
さらに画像を追加するには、基本的に上のブロックの操作を繰り返すだけです。すべての画像をスタックに追加した後は、累積されたスタックの画像に対して通常の影付け操作を行うだけです。(多くのウェブブラウザが嫌う)残った画像オフセットを取り除きます。統合(Merge)を使えば、仮想オフセット、特に負のものを自動的に扱えるので、前の画像配置に対して相対的に好きな場所に画像を置くだけで済みます。また、負のオフセットを持つより大きな画像を生成しうる影を、適切に適用できます。
さて、上の例は複数レイヤー画像の影を適切に扱いますが、影はオフセットされてはいるものの、実はすべての画像に対して等しくオフセットされています! 本来起こるべきことは、影がスタックのより深い画像に落ちるほど、よりオフセットされ、よりぼやけるべきだということです。すなわち、最上部の画像は、最下部の画像に比べて、背景に非常にぼやけた影を落とすべきなのです。これは実際にはより難しく、画像のスタックを追跡するだけでなく、スタックが大きくなるにつれて影がどれだけ「ぼやけた」かも追跡する必要があるからです。したがって、実際にはアキュムレータが2つ必要です。(上記のような)画像スタックと、画像を追加するにつれての影の累積です。たとえば、ここは同じ画像セットですが、深さとともにぼやけが増す影を付けたものです。 |
magick xc:none xc:none \
\
\( holocaust_tn.gif -frame 10x10+3+3 \
-background none -rotate 5 -repage +0+0 \) \
\( -clone 1 -background black -shadow 70x0+0+0 \
-clone 2 -background black -compose DstATop -layers merge \
-clone 0 -background none -compose Over -layers merge \) \
\( -clone 2,1 -background none -compose Over -layers merge \
-background black -shadow 100x2+4+7 \) \
-delete 0-2 \
\
\( spiral_stairs_tn.gif -frame 10x10+3+3 \
-background none -rotate -15 -repage -90+60 \) \
\( -clone 1 -background black -shadow 70x0+0+0 \
-clone 2 -background black -compose DstATop -layers merge \
-clone 0 -background none -compose Over -layers merge \) \
\( -clone 2,1 -background none -compose Over -layers merge \
-background black -shadow 100x2+4+7 \) \
-delete 0-2 \
\
\( chinese_chess_tn.gif -frame 10x10+3+3 \
-background none -rotate 20 -repage +60+90 \) \
\( -clone 1 -background black -shadow 70x0+0+0 \
-clone 2 -background black -compose DstATop -layers merge \
-clone 0 -background none -compose Over -layers merge \) \
\( -clone 2,1 -background none -compose Over -layers merge \
-background black -shadow 100x2+4+7 \) \
-delete 0-2 \
\
\( -clone 1 -background black -shadow 70x0+0+0 \
-clone 0 -background none -compose Over -layers merge \) \
-delete 0-1 -trim +repage \
layers_of_deep_shadows.png
![[IM Output]](../static/img/layers/layers_of_deep_shadows.png)
結果を注意深く見てください。影のオフセットとぼやけ具合が、画像の部分ごとに異なっています。隣接するレイヤーの画像の間では非常に薄く、しかしある画像、あるいはずっと深い背景に落ちるときには非常に厚くなっています。もちろんこの例では、影のオフセットはおそらく大きすぎますが、結果は非常にリアルに見え、レイヤーに奥行き感をよりよく与えています。影付けの操作を2つのステップに分けた点に注目してください。累積された影(画像インデックス #1)を新しい画像(#2)に適用するとき、ぼかしやオフセットなしで(この場合「70x0+0+0」)環境光のパーセントだけを加えます。次に新しい画像を、累積する画像スタック(#0)に追加します。しかし、新しい画像(#2)の影を累積された影(#1)に直接、これもまたぼかしやオフセットなしで加えた後で、初めてすべての影をぼかしてオフセットし、新しい累積された影画像を形成します。言い換えれば、スタックが厚くなるにつれて、累積された影画像はますますぼやけてオフセットされていきます。より深い画像の影だけが、それほど効果を累積していないのです。このプログラムは本質的に、影の適用を、段階的な影アキュムレータから分離します。これにより、次のようなことを制御できます…
- リアルな影(上記のとおり): 70x0+0+0 と 100x2+4+7
- 一定の影(基本例のとおり): 70x2+4+7 と 100x0+0+0
- 一定のぼかし、ただし累積的なオフセット: 70x2+0+0 と 100x0+4+7
- 一定かつ漸進的なオフセットの両方: 60x0+4+7 と 100x0+1+1
- 累積的な環境光効果: 80x0+0+0 と 95x2+4+7
これらのほとんどはおそらく非現実的ですが、別の状況では見栄えがよいかもしれません。また、「-compose ATOP」合成の前に「-background」色を設定すると、影の色(実際には色付きの環境光)を定義できます。最終的な背景レイヤーに最終的に落ちる影に別の色を使う(最後の「-background black」設定)ことすらでき、あるいはそれを完全に省いて、画像がどんな背景の上にもないように(つまり宙に浮いているように)見せることもできます。非常に汎用性が高いのです。
Tomas Zathurecky 氏は、レイヤー化された画像のリストを全体として扱うことで、その影を扱う別の方法をさらに開発しました。私自身では可能とは考えなかったことです。この方法の利点は、画像を1枚ずつ累積して同じブロックの操作を何度も繰り返す必要なく、画像のリスト全体を一括して扱えることです。まずは再び、より単純な「一定の影」問題を見てみましょう。 |
magick \
\( holocaust_tn.gif -frame 10x10+3+3 \
-background none -rotate 5 -repage +0+0 \) \
\( spiral_stairs_tn.gif -frame 10x10+3+3 \
-background none -rotate -15 -repage -90+60 \) \
\( chinese_chess_tn.gif -frame 10x10+3+3 \
-background none -rotate 20 -repage +60+90 \) \
\
-layers trim-bounds \
\
\( -clone 0--1 -dispose None -coalesce \
-background black -shadow 70x2+4+7 \
xc:none +insert null: +insert +insert xc:none \) \
-layers trim-bounds -compose Atop -layers composite \
\
-fuzz 10% -trim \
-reverse -background none -compose Over -layers merge +repage \
coalesced_shadows.png
![[IM Output]](../static/img/layers/coalesced_shadows.png)
最初の演算子のブロックは、単にレイヤー化された画像のリストを生成しているだけです。前に示したように、別途プログラムされたループでもよいでしょう。操作は「-layers trim-bounds」、つまりすべての画像を含むように全画像の仮想キャンバスを拡張し、すべてのオフセットが正であることも保証する境界トリミング操作から始まります。これがクローンされ、合体合成(Coalesce)されて影付けされ、影の進行リストを別途作成します。これでレイヤー合成を使って、影と元の画像リストを統合できます。ここでの複雑さは、統合の前に、2つのリストを分ける特殊な「null:」マーカー画像を加えるだけでなく、影リストをオフセットするために特殊な空白画像「xc:none」も加える必要があることです。そうすれば、各影画像が元のリストの次の画像の「[ATop](compose.html#atop)」に重ね合わされます。あとは、正しく影が付いた画像を、下から上へ(反転(Reverse))の順に統合するだけです。
「深い影」を扱うには、レイヤー計算が必要です。 |
magick \
\( holocaust_tn.gif -frame 10x10+3+3 \
-background none -rotate 5 -repage +0+0 \) \
\( spiral_stairs_tn.gif -frame 10x10+3+3 \
-background none -rotate -15 -repage -90+60 \) \
\( chinese_chess_tn.gif -frame 10x10+3+3 \
-background none -rotate 20 -repage +60+90 \) \
\
\( -clone 0--1 \
-set page '+%[fx:page.x-4*t]+%[fx:page.y-7*t]' -layers merge \) \
-layers trim-bounds +delete \
\
\( -clone 0--1 \
-set page '+%[fx:page.x-4*t]+%[fx:page.y-7*t]' \
-dispose None -coalesce \
-set page '+%[fx:page.x+4*t]+%[fx:page.y+7*t]' \
-background black -shadow 70x2+4+7 \
xc:none +insert null: +insert +insert xc:none \) \
-layers trim-bounds -compose Atop -layers composite \
\
-fuzz 10% -trim \
-reverse -background none -compose Over -layers merge +repage \
coalesced_deep_shadows.png
![[IM Output]](../static/img/layers/coalesced_deep_shadows.png)
前に使ったのと同じ一連のブロックが見られますが、最初の境界トリミングの設定と、後の「漸進的な影リスト」に必要なオフセットの計算が、はるかに複雑になっています。ただし、この影は現状では深さとともにぼやけが増すことはありません。 | 上の例は、IMv7 の「magick」コマンドを使えばずっと単純になります。「-shadow」の引数に直接「fx 計算」を使えるようになるので、深さに応じて影のより大きなオフセットを計算できるだけでなく、深さとともに影をよりぼやけさせることもできます。
---|---
歪んだ透視画像の配置
歪んだ画像を整列させるのは厄介になりえます。ここでは、そうした画像を非常に特定の位置で一致するように整列させることを見ていきます。ここに、各画像上の特定の点を強調表示した2つの画像があります。
2番目の画像は 65% 半透明なので、青い画像に合成したときに透けて見え、印を付けた点が揃っているか確認できます。印を付けた制御点そのものは、それぞれ座標 59,26(青)と 35,14(赤)にあります。単に2つの画像を重ね合わせるだけなら、オフセットを引いて2つの画像を互いの上に「合成」すればよく、オフセット +24+12 が得られます。 |
magick align_blue.png align_red.png -geometry +24+12 \
-composite align_composite.png
![[IM Output]](../static/img/layers/align_composite.png)
このオフセットは負になることもある点に注意してください! それは間もなく扱います。これは座標が整数のピクセル座標であるからこそ機能します。一致する座標がサブピクセル位置の場合(写真モンタージュでは典型的にそうです)、単純な合成は機能しません。また、何らかの歪みが関与する場合(これも実写画像ではよくあります)にもうまく機能しません。そして、これがこれから探求する問題です。
画像を歪曲するときは、2つのピクセルが整列したままになるようにしたいでしょう。それを行う最善の方法は、整列させたい点を歪み制御点として使うことです。これにより、それらが適切に配置されることが保証されます。 |
magick align_blue.png \
\( align_red.png -alpha set -virtual-pixel transparent \
+distort SRT '35.5,14.5 1 75 59.5,26.5' \
\) -flatten align_rotate.png
![[IM Output]](../static/img/layers/align_rotate.png)
distort は「キャンバスオフセット」を持つ「レイヤー画像」を生成するので、単にCompositeを使って画像を重ね合わせる(低レベルすぎる)ことはできず、代わりに平坦化(Flatten)演算子を使って、distort が生成したオフセットを用いて画像を配置する必要があります。「ピクセル」座標に 0.5 を足した点にも注目してください。これは、ピクセルが面積を持つのに対し、数学的な点は持たないからです。そのため、ピクセルの中心を整列させたい場合は、ピクセル内の中心「点」の位置に 0.5 を足す必要があります。詳細は画像座標とピクセル座標の違いを参照してください。上の例のもう1つの問題は、重ね合わされた画像が、Composite 演算子が行うのと同様に、青い背景キャンバス画像によって「クリップ」されたことです。すなわち、「青」画像が合成の間、結果のための「クリッピングビューポート」を提供したのです。これを防ぐには、代わりにレイヤー統合(Layer Merge)を使います。これは、合成されるすべての画像を保持するのに十分な大きさの「ビューポート」キャンバスを自動的に計算します。 |
magick align_blue.png \
\( align_red.png -alpha set -virtual-pixel transparent \
+distort SRT '35.5,14.5 1 75 59.5,26.5' \
\) -background none -layers merge +repage align_rotate_merge.png
![[IM Output]](../static/img/layers/align_rotate_merge.png)
「統合(merge)」の結果として、画像は(画像のレイヤー位置を保つために)「負の」オフセットを持ちます。結果を表示するために、多くのブラウザが画像内の負のオフセットを扱えないので、そのオフセットを破棄する必要がありました。これは最終画像を保存する前に「+repage」を使って行います。(結果をウェブに表示せず)さらに処理を行うつもりなら、後の処理のために画像位置が正しい既知の位置に留まるよう、そのオフセットを保ちます(「+repage」を取り除きます)。
さて、上で示したのと同じ技法は、透視(Perspective)のようなより複雑な歪みを行う場合にも当てはまります。 |
magick align_blue.png \
\( align_red.png -alpha set -virtual-pixel transparent \
+distort Perspective '35.5,14.5 59.5,26.5
0,0 32,4 0,%h 14,36 %w,%h 72,53 ' \
\) -background none -layers merge +repage align_perspective.png
![[IM Output]](../static/img/layers/align_perspective.png)
この技法の問題は、内部制御点を使って透視歪みを配置することです。すなわち、画像の内側の1点と、縁の周りの3点です。これは実際の透視形状を制御しづらくします。どの制御点でも小さく動かすと、「自由な角」が激しく動きうるからです。より正確な「最小二乗フィット」で画像を配置するために大きな「登録点」リストを使っている場合、状況はさらに悪化することがあります。その場合、関心のある点は、画像の歪曲に使う「登録された」制御点のどれの近くにもないでしょう。代替案は、単に必要なように画像を歪曲してから、関心のある点を整列させるために、結果の画像をどう平行移動すればよいかを割り出すことです。これを機能させるには、歪みの結果として「関心点」がどう動いたかを知る必要があります。これが、画像、特に実写画像を歪曲して配置する際の本当の問題です。たとえば、ここでは4隅すべてを使って特定の(仮に望ましいとする)歪み形状を生成するように画像を歪曲しますが、この時点では制御点を整列させようとはせず、歪みを適用するだけです… |
magick align_blue.png \
\( align_red.png -alpha set -virtual-pixel transparent \
+distort Perspective '0,0 10,12 0,%h 14,40
%w,0 68,6 %w,%h 63,48 ' \
\) -background none -layers merge +repage align_persp_shape.png
![[IM Output]](../static/img/layers/align_persp_shape.png)
ご覧のとおり、赤い画像は歪曲されましたが、赤い制御点の位置は、整列させたい青い制御点の近くにまったくありません。赤い点はおそらく正確なピクセル位置にはなく、サブピクセルのオフセットが関与するので、これら2つの点を単純に測ることはできません。まず赤い点が正確にどこにあるかを計算する必要があります。それを行うには、上の歪みを verbose を有効にして再実行し、透視の順方向マッピング係数を得ます。これらは次に、透視投影歪みで説明されているように計算に使えます。
magick align_red.png -define distort:viewport=1x1 -verbose \
+distort Perspective '0,0 10,12 0,%h 14,40
%w,0 68,6 %w,%h 63,48 ' null:
私たちが欲しいのは、歪みで使われる計算済みの係数だけです。そのため宛先画像は不要なので、「null:」画像ファイルフォーマットを使って出力するだけにします。また、歪みビューポートを使って、生成する新しい画像がわずか 1 ピクセルの大きさだと distort に伝えます。そうすれば、歪みの準備と verbose レポートは行いますが、その後は1つの「宛先」ピクセルだけを歪曲し、それは破棄されます。これで多くの処理時間を節約できます。実際、歪みがその計算の一部としてソース画像のメタデータ(パーセントエスケープ「%w」と「%h」に必要)を使っていなければ、ソース画像「align_red.png」すら不要でしょう。その場合は、入力画像にも単一ピクセルの「null:」画像を使えたはずです。また、この情報収集ステップでは、仮想ピクセル、背景、その他のものには本当に関心がないので、それらの機能を設定することを気にする必要はありません。
さて、distort 情報を得られたので、出力の3行目と4行目から8つの透視係数を抽出する必要があります。これらは次に、赤い制御点を新しい歪んだ位置にマッピングし、そこから青い制御点を引くことで、印を付けた赤い座標を青い座標に整列させるのに必要な、実際の平行移動量を得るのに使えます。
bluex=59; bluey=26
redx=35; redy=14
magick align_red.png -verbose \
+distort Perspective '0,0 10,12 0,%h 14,40
%w,0 68,6 %w,%h 63,48 ' null: 2>&1 |\
tr -d "'," |\
awk 'BEGIN { redx='"$redx"'+0.5; redy='"$redy"+0.5';
bluex='"$bluex"'+0.5; bluey='"$bluey"'+0.5; }
NR == 3 { sx=$1; ry=$2; tx=$3; rx=$4; }
NR == 4 { sy=$1; ty=$2; px=$3; py=$4; }
END { div = redx*px + redy*py + 1.0;
dx = ( redx*sx + redy*ry + tx ) / div;
dy = ( redx*rx + redy*sy + ty ) / div;
printf "red point now at %f,%f\n", dx, dy;
printf "translate shape by %+f %+f\n", bluex-dx, bluey-dy; }'
上の例は「tr」テキストフィルタを使って、出力から余分なクォートとカンマを取り除いています。次に「awk」プログラムを使って係数を抽出し、赤いマーカーを青いマーカーに合わせるために「順方向マッピング」するのに必要な浮動小数点の数学を行います。制御点の「ピクセル座標」に再び 0.5 を足して、ピクセルの中心が計算に使われるようにした点に注意してください。画像座標とピクセル座標の違いを参照してください。さて、歪んだ画像に必要な平行移動量がわかったので、その平行移動を歪みに加える方法が2つあります。1つは透視投影の係数を適切に修正する(容易でない)こと。あるいは、元の各宛先座標に平行移動量を加えるだけ(とても容易)でもよいでしょう。ここは後者(宛先座標に平行移動を加える)の結果です… |
magick align_blue.png \
\( align_red.png -alpha set -virtual-pixel transparent \
+distort Perspective '0,0 31.408223,15.334305
0,%h 35.408223,43.334305
%w,0 89.408223, 9.334305
%w,%h 84.408223,51.334305 ' \
\) -background none -layers merge +repage align_persp_move.png
![[IM Output]](../static/img/layers/align_persp_move.png)
右に、制御点の周りで結果を切り抜いて拡大し、完全に整列していることを示しました! |
magick align_persp_shape.png -crop 19x19+50+17 +repage \
-scale 500% align_persp_shape_mag.png
![[IM Output]](../static/img/layers/align_persp_shape_mag.png)
ご覧のとおり、2つのピクセルが、どちらかの側へのサブピクセルのはみ出しもなく、完全に整列しています。どんなにわずかな不整列でも、中央のピクセルのどちらか側に非対称な着色として現れます。この拡大では、透視歪みによる赤い十字の左右の側のわずかな非対称の差すら示されています。すなわち、このピクセルレベルの目視テストがどれほど正確かということです。
よく似たより単純な問題は、Distort を使ったテキスト配置で扱っています。
Evaluate-Sequence - 複数画像を直接統合するメソッド
「[-evaluate-sequence](https://imagemagick.org/command-line-options/#evaluate-sequence) 」メソッドは、同じサイズの複数画像を、非常に特定の方法で統合するために設計されています。ある意味で、これはEvaluate と Function 演算子と、上で見た複数画像合成技法を組み合わせたものです。提供されるメソッドの多くは、通常の複数画像レイヤー化合成技法でも実行できますが、すべてではありません。この演算子は「[-evaluate](https://imagemagick.org/command-line-options/#evaluate)」と同じメソッドを使うので、「-list Evaluate」でそれらのリストを取得できます。ただし、それらのいくつか(「Mean」や「Medium」など)は、本当にこの演算子と一緒に使うときにのみ有用です。
複数画像の平均(Mean)
本質的に、古い「-evaluate-sequence mean」も新しい「[-evaluate-sequence](https://imagemagick.org/command-line-options/#evaluate-sequence) **mean**」も、提供されたすべての画像の平均を作ります。たとえば、ここはバラ画像の、その上下反転・左右反転版すべてを使った平均です。 |
magick rose: -flip rose: \( -clone 0--1 -flop \) \
-evaluate-sequence mean average.png
![[IM Output]](../static/img/layers/average.png)
同じ固定シーンの数百枚の画像を平均することで、動いている人物のような過渡的な効果のほとんどを除去し、それらを目立たなくできます。ただし、過渡的な効果が多く生じる領域には、取り除くのが非常に難しい「幽霊のようなぼやけ」が残ることがあります。動画シーケンスは個々のフレームを見ると非常にノイズが多いことで知られているので、連続するが変化しない複数のフレームを平均して、はるかに良い、よりクリーンでシャープな結果を生成できます。アリゾナ大学の Matt Leigh 氏は、この技法を顕微鏡画像の解像度向上に使ったと報告しています。彼は同じ「対象」の複数の画像を撮り、それらをすべて平均して結果の信号/ノイズ比を上げます。彼は、他の人もこの目的で有用だと感じるかもしれないと示唆しています。2つの画像を平均する代替案は、「composite -blend 50%」画像操作を使うことです。これは異なるサイズの2つの画像でも機能します。詳細は2つの画像をブレンドするの例を参照してください。IM ディスカッションフォーラムでは、コンピュータのメモリを埋め尽くす(非常に遅くする)ことなく数千枚の画像を平均できるよう、一度に10フレームずつシーケンスを平均する議論がありました。これに関連し、関連する数学を含むのが、議論 Don't load all images at once です。「mean」を使う別の代替案は、各画像を個別に重み付けできる、より新しい Poly 演算子を使うことです。
複数画像の最大値/最小値(Max/Min)
「Max 」と「Min 」メソッドは、画像のシーケンスから最大(明るい)値と最小(暗い)値を取得します。これも基本的に、明るく・暗くする合成メソッドを複数画像で使うのと同等ですが、複数の画像に対して行います。背景キャンバスの色を適切に選べば、同等の合成メソッドで平坦化演算子を使えます。 |
magick rose: -flip rose: \( -clone 0--1 -flop \) \
-evaluate-sequence max max.png
magick rose: -flip rose: \( -clone 0--1 -flop \) \
-evaluate-sequence min min.png
![[IM Output]](../static/img/layers/min.png)
警告: これは(強度による)ピクセルの選択ではなく、値の選択です。これは、出力画像が異なる画像からの個々の赤・緑・青の値からなる結果になり、入力画像のいずれにも見られない新しい色を生むことがあることを意味します。強度によって最大/最小でピクセルを選択する必要がある場合は、強度による明るくする合成メソッドを参照してください。
強度による中央値ピクセル(Median)
「[-evaluate-sequence](https://imagemagick.org/command-line-options/#evaluate-sequence) **Median**」は、与えられたすべての画像から、中央のピクセルの強度を持つピクセルを探します。すなわち、各位置について、各画像からピクセル強度を収集してソートします。次に、シーケンスの中央に位置するピクセルを選びます。これは、画像のコレクションのピクセルを単に平均する代替としても使えます。これはたとえば、ある画像を上下2つの「制限」画像と組み合わせて使えます。ピクセルは中央の強度になるので、元の画像からのピクセルか、「制限」画像からのピクセルのいずれかが得られます。言い換えれば、これを使って元の画像の強度を「クリップ」できます。奇妙ですが本当です。画像が偶数枚の場合、中央の明るい側のピクセルが選ばれます。そのため、画像が2枚だけの場合、この演算子はピクセルごとの「強度による明るくする」と同等になります。要点は、各ピクセルが完全に1つの画像から来て、強度でソートされることです。各ピクセルの正確な色は完全に与えられた画像の1つから来るので、新しい色は生成されません。たとえば、ここはバラ画像の、その上下反転・左右反転版すべてを使った中央値強度のピクセルです。それほど滑らかではないものの、ピクセルの強度に基づくため、シャープな境界が得られうる点に注目してください。 |
magick rose: -flip rose: \( -clone 0--1 -flop \) \
-evaluate-sequence median median.png
複数画像の加算(Add)
「Add 」メソッドは、もちろん単にすべての画像を加算します。
magick ... -evaluate-sequence add ...
これは、平坦化(Flatten)を使ってすべての画像を Plus 合成するより速い(より直接的な)版です…
magick ... -background black -compose plus -layers flatten ...
このように画像を加算すると、画像の量子範囲(Quantum Range)を非常に簡単にオーバーフローしうるため、HDRI 版の IMを使わないかぎり「クリップ」されることがある点に注意してください。これが、一般に代わりに平均、つまり Meanが使われる理由です。これはすべての画像を均等に分割して、結果の画像がクリップされないようにします。別の代替案は、各画像を個別に重み付けできる、より新しい Poly 演算子を使うことです。
複数画像の減算(Subtract)
「Subtract 」メソッドは、各画像を最初の画像から減算します。少なくとも、それがすべきことです。内部的には引数が入れ替わっており、それまでの結果を次の画像から減算しています。あぁぁぁ! しかし、Linear Burn 合成メソッドの特性を利用すれば、2番目以降の画像を最初の画像から減算できます。基本的に、最初の画像以外をすべて反転(Negate)し、開始背景色として「white」(反転されたゼロ)を設定すれば、平坦化(Flatten)を使ってすべての画像を最初の画像から減算できます。
magick ... \
-negate \( -clone 0 -negate \) -swap 0 +delete \
-compose LinearBurn -background white -flatten \
...
複数画像の乗算/除算(Multiply/Divide)
「Multiply 」と「Divide 」は「[-evaluate-sequence](https://imagemagick.org/command-line-options/#evaluate-sequence)」のメソッドとして受け付けられますが、「[-evaluate](https://imagemagick.org/command-line-options/#evaluate)」と同様に、正規化された色値ではなく実際の色値を使うため、予期しない奇妙な結果を生みます。その結果、乗算と除算のスケールが大きすぎます。これはバグに分類できるかもしれません。当面は、Multiply については、期待どおりに機能する同等の「flatten」メソッドを使うほうがよいでしょう。
magick ... -background white -compose multiply -layers flatten ...
Poly - 多項式を用いた複数画像の統合
「[-evaluate-sequence](https://imagemagick.org/command-line-options/#evaluate-sequence)」、特に「mean」メソッド(画像の平均)と密接に関連するのが、「[-poly](https://imagemagick.org/command-line-options/#poly)」演算子(IM v6.8.0-5 で追加)です。この演算子には、メモリ内の各画像について2つの数のリストが与えられます。1つは各画像に乗算的な重みを与えるためのもの、もう1つは各画像にべき指数を与えるためのものです。これにより、各画像が多項式方程式への変数入力であるかのように、画像のリストを統合できます。各画像の色値は、正規化された 0 から 1 の値であるかのように扱われます。各値のペアについて、画像の色(正規化済み)はまず2番目の「べき」指数で累乗され、次に1番目の数で重み付け(乗算)されます。指数が「1」なら、値は単に与えられた重みで乗算されます。しかし指数が「0」なら、重みが最終値になり、正規化された色の定数加算(0.0 から 1.0 の値)を生みます。現在の画像シーケンスに単一ピクセルの画像を提供でき、これは(重みと指数 = 1.0 を使って)チャネルごとに異なる正規化色値で、特定の色を加えるのに使えます。あるいは「NULL:」画像(または他の任意のがらくた画像)を提供し、指数 0.0 を使えます。これは、与えられた重み係数を定数として加えるだけになります。最終画像は、FX DIY 演算子と同様に、最初の画像(およびそのサイズと他のメタデータ)から生成されます。たとえば… |
magick rose: granite: null: -poly '1,1 2,1 -1.0,0' poly_rose.png
![[IM Output]](../static/img/layers/poly_rose.png)
これは「rose:」(重み 1、べき 1 で未加工)を取り、これに「granite:」画像の色値の2倍を加え(重み = 2)、最後に「null:」画像を使って、指数 0(画像入力を無視)と重み値 -1.0 で 1 の値を減算します。結果の画像は次と同等です…
rose + 2.0*granite - 1.0
または
rose + 2.0*(granite-0.5)
言い換えれば、バラの画像にノイズの多い花崗岩のテクスチャのオーバーレイ(50% グレーのバイアス付き)が与えられます。これは実際、非常に強い「[Hard_Light](compose.html#hardlight)」合成のライティング効果とまったく同じですが、花崗岩オーバーレイの重み付けが非常に明示的です。これが他の複数画像操作に対して持つ鍵となる違いは、各画像を個別に重み付けできること、しかも余分な中間画像を必要とせず、すべての計算を単一の画像処理操作で実行できることです。これにより、非 HDRI 版の ImageMagick で、量子の丸め、クリッピング、その他の効果を最終結果に及ぼすことを避けられます。(量子効果を参照)。これはたとえば、大量の画像の重み付き平均を実行するのに使えます。たとえば、より小さな画像グループを平均し、次にそれらのグループを平均するといったことです。
![[IM Output]](../static/img/layers/append_row.gif)
![[IM Output]](../static/img/layers/compose_resize.gif)
![[IM Output]](../static/img/layers/drawn.gif)
![[IM Output]](../static/img/layers/mosaic_clip.gif)
![[IM Output]](../static/img/layers/coalesce_none.gif)
![[IM Output]](../static/img/layers/coalesce_bgnd.gif)
![[IM Output]](../static/img/layers/flatten_xor.png)
![[IM Output]](../static/img/layers/overlap_canvas.jpg)
![[IM Output]](../static/img/layers/image_circle.png)
![[IM Output]](../static/img/layers/append_diy.png)
![[IM Output]](../static/img/layers/append_offset.gif)
![[IM Output]](../static/img/layers/overlapped_polaroids.jpg)
![[IM Output]](../static/img/layers/map_push_pin.jpg)
![[Data File]](../static/img/layers/map_venice_pins.txt.gif)
![[IM Output]](../static/img/layers/map_venice_pins.jpg)
![[IM Output]](../static/img/layers/align_blue.png)
![[IM Output]](../static/img/layers/align_red.png)
![[IM Text]](../static/img/layers/align_persp_verbose.txt.gif)
![[IM Text]](../static/img/layers/align_persp_coord.txt.gif)
![[IM Output]](../static/img/layers/max.png)
![[IM Output]](../static/img/layers/median.png)