ImageMagick で画像を自由自在に操りたい

あまり多くの日本語資料が無いImageMagicですが、画像処理についてはかなり高性能なため、是非活用したいところです。

サーバ側での手軽な画像処理だと、PHP GD などがなじみ深いと思いますが、その違いなども含めて検討していきます。

PHP GDでの躓き

PHP GDをあきらめた大きなの原因は2つ。もしかすると解消の仕方があるのかもしれませんが、私はこの件がありPHP GDをあきらめました。

基本的に整数(int)で座標等を指定する

画像を移動する、位置を指定して切り取り貼り付ける、などの処理は基本的に整数で指定します。
これだと、スライドショーなど連続した画像を作る際にfloatでの計算結果をintに直さなければならず、結果カクカクとした動きになることが多くあります。
この解消法を見つけることができませんでした。

回転の処理が思う結果にならない

これもスライドショーなどを作成する場合ですが、ゆっくりと画像を回転させたいのに思うような結果にならない場合があります。
同じパラメーターで連続画像を出力して ffmpeg でムービー化 (BGMは仮)

[音がでます]
GDで回転
ImageMagickで回転 (-rotate x)
ImageMagickで回転 (-distort SRT x)

作成時のソース

ImageMagick(-rotate x)
convert ./1.jpg -alpha Set -depth 8 -resize 66.666666666667% -rotate 0.2 -gravity center -extent 640x480 -fill "rgb(255,255,255)" -transparent white ./img/00002.jpg

ImageMagick(-distort SRT x)
convert ./1.jpg -alpha Set -depth 8 -resize 66.666666666667% -distort SRT 0.2 -gravity center -extent 640x480 -fill "rgb(255,255,255)" -transparent white ./img/00002.jpg

-rotate と -distort についての参考

連続して角度を指定しているにも関わらず、GDの方は2コマ程度変化なく、次のコマで大きく回転することなどがありました。
回転角度は float 指定できるので、問題ないかと思ったのがこの結果で、解決方法が見つけられませんでした。
imagerotate

但し処理は重い

上記の画像生成の処理時間について、ざっくりとした計算になりますが、画像90枚あたりの処理時間は PHP GD およそ 4.8秒、ImageMagick およそ 18.6秒で、体感でも4倍程度の時間がかかる感じがします。
PHP GD から ImageMagickに切り替えるにはこのあたりがネックになりそうです。

ちなみに、GraphicsMagick の場合

-distort オプションが使えず -rotate で およそ 7.9秒でした。
GraphicsMagickで回転 (-rotate x)
やりようはあるのだと思いますが、とりあえずはGraphicsMagickは考えないことにします。

作成時のソース

GraphicsMagick(-rotate x)
gm convert ./1.jpg -alpha Set -depth 8 -resize 66.666666666667% -rotate 0.2 -gravity center -extent 640x480 -fill "rgb(255,255,255)" -transparent white ./img/00002.jpg

ちなみに 2016/4 現在 Amazon linux では sudo yum install GraphicsMagick でインストールできました。

ImageMagickを試す

一応使えそうなことが分かったので、いろいろ試します。

リサイズ

まずリサイズから。
元画像 3456x2304 約800万画素のデジカメ写真。

では無いものから

ImageMagickは様々なサイズ指定オプションがあります。「では無い」ものから試してみましょう。

では無い

1 サイズ指定しない 
convert 0.jpg result_000.jpg

2 pageのサイズ指定 
convert -page 640x640 0.jpg result_001.jpg

3 size と pageのサイズ指定 
convert -size 640x640 -page 640x640 0.jpg result_002.jpg

これらは元画像のサイズに影響は及ぼしません。

リサイズ -resize

リサイズしてみます。

リサイズ

1 縦横指定 大きな画像から縮小 
convert -resize 640x640 0.jpg result_011.jpg

2 縦横指定 小さな画像から拡大 元画像  結果
convert -resize 640x640 10_small.jpg result_012.jpg

3 横指定縦自動 
convert -resize 640x 0.jpg result_013.jpg

4 縦指定横自動 
convert -resize x640 0.jpg result_014.jpg

1の大きな画像からは、横幅がフィットして 640x427 の画像が出来ました。
特にオプションを付けないリサイズは、縦横いずれも指定サイズに収まるように、縦横比比例で縮小されます。

2の小さな 480x320 の画像から、横幅がフィットして 640x427 の画像が出来ました。
拡大された割にはきれいな画像です。

3の横指定縦自動は、横幅がフィットして 640x427 の画像が出来ました。
結果1と同じです。

4の縦指定横自動は、縦幅がフィットして 960x640 の画像が出来ました。

リサイズ 応用 位置指定

リサイズの応用編です。

出力する画像サイズを指定

1 サイズ指定
convert -resize 640x640 0.jpg -extent 640x640 result_031.jpg

2 サイズ指定 + -gravity オプションでセンター指定
convert -resize 640x640 0.jpg -gravity center -extent 640x640 result_032.jpg

3 サイズ指定 + -gravity オプションで 上 / 左 指定
convert -resize 640x640 0.jpg -gravity NorthWest -extent 740x740 result_033.jpg

4 サイズ指定 + -gravity オプションで 上 / 中央 指定
convert -resize 640x640 0.jpg -gravity North -extent 740x740 result_034.jpg

5 サイズ指定 + -gravity オプションで 上 / 右 指定
convert -resize 640x640 0.jpg -gravity NorthEast -extent 740x740 result_035.jpg

6 サイズ指定 + -gravity オプションで 左 指定
convert -resize 640x640 0.jpg -gravity West -extent 740x740 result_036.jpg

7 サイズ指定 + -gravity オプションで 右 指定
convert -resize 640x640 0.jpg -gravity East -extent 740x740 result_037.jpg

8 サイズ指定 + -gravity オプションで 下 左 指定
convert -resize 640x640 0.jpg -gravity SouthWest -extent 740x740 result_038.jpg
9 サイズ指定 + -gravity オプションで 下 中央 指定
convert -resize 640x640 0.jpg -gravity South -extent 740x740 result_039.jpg

10 サイズ指定 + -gravity オプションで 下 右 指定
convert -resize 640x640 0.jpg -gravity SouthEast -extent 740x740 result_040.jpg

1は単に出力サイズを指定したものです。画像は上寄せになっています。
2のようにgravityオプションでcenter を指定すると、縦横中央に配置されます。
3~10はわかりやすいように出力サイズを一回り大きくして、左上から右下まで、それぞれに寄せる方法の例示です。
参照

リサイズ 別解

後程整理しますが、こんな方法もあります。

geometry オプションと resize オプション

1-1 geometry オプション
convert 0.jpg -gravity center -geometry 640x640 -extent 740x740 result_055.jpg

1-2 resize オプション
convert 0.jpg -gravity center -resize 640x640 -extent 740x740 result_056.jpg


2-1 geometry オプション
convert 0.jpg -gravity center -geometry 640x640+100+100 -extent 740x740 result_057.jpg

2-2 resize オプション
convert 0.jpg -gravity center -resize 640x640+100+100 -extent 740x740 result_058.jpg

3-1 geometry オプション
convert 0.jpg -gravity center -geometry 20%x20% -extent 740x740 result_059.jpg

3-2 resize オプション
convert 0.jpg -gravity center -resize 20%x20% -extent 740x740 result_060.jpg

4-1 geometry オプション
convert 0.jpg -gravity center -geometry 20%x20%+500+500 -extent 740x740 result_061.jpg

4-2 resize オプション
convert 0.jpg -gravity center -resize 20%x20%+500+500 -extent 740x740 result_062.jpg
5 位置を微調整したい
convert 0.jpg -gravity center -geometry +200+200 -resize 640x640 -extent 740x740 result_063.jpg
convert -gravity center -geometry +200+200 0.jpg -resize 640x640 -extent 740x740 result_064.jpg
convert -gravity center -geometry +200+200 -resize 640x640 0.jpg -extent 740x740 result_065.jpg
convert -resize 640x640 -gravity center -geometry +200+200 0.jpg -extent 740x740 result_066.jpg
いずれでも失敗

1 だと、geometryオプションと risizeオプションはまったく同じ結果になります。

-geometry(幾何学) オプションに指定する値は geometryという型です。
resize などもこの型を使用します。

2 は結果が大きく異なります。
3 のサイズに%を指定した場合はどちらも同じ結果です。
4 のサイズを%指定した場合でも、offsetを指定すると2と同じく異なる結果になります。
5 で、位置の微調整を試みていますが、この場合いずれの書き方でも失敗しています。

リサイズ 位置調整 キャンバスを作ってから合成する1

canvas に 画像を compsite (合成)して位置の調整をします。

1 composite オプション を付けない
convert -size 740x740 canvas:white -resize 640x640 0.jpg -gravity center -extent 740x740 result_071.jpg

2-1 リサイズ → 画像 → グラヴィティの順
convert -size 740x740 canvas:white -resize 640x640 0.jpg -gravity South -composite -extent 740x740 result_072.jpg

2-2 リサイズ → グラヴィティ → 画像の順
convert -size 740x740 canvas:white -resize 640x640 -gravity South 0.jpg -composite -extent 740x740 result_073.jpg

2-3 グラヴィティ → リサイズ → 画像の順
convert -size 740x740 canvas:white -gravity South -resize 640x640 0.jpg -composite -extent 740x740 result_074.jpg

2-4 グラヴィティ → 画像 → リサイズの順
convert -size 740x740 canvas:white -gravity South 0.jpg -resize 640x640 -composite -extent 740x740 result_075.jpg

2-5 画像 → グラヴィティ → リサイズの順
convert -size 740x740 canvas:white 0.jpg -gravity South -resize 640x640 -composite -extent 740x740 result_076.jpg

2-6 画像 → リサイズ → グラヴィティの順
convert -size 740x740 canvas:white 0.jpg -resize 640x640 -gravity South -composite -extent 740x740 result_077.jpg



3-1 キャンバスを黒くして リサイズ → 画像 → グラヴィティの順
convert -size 740x740 canvas:black -resize 640x640 0.jpg -gravity South -composite -extent 740x740 result_078.jpg

3-2 キャンバスを黒くして 画像 → リサイズ → グラヴィティの順
convert -size 740x740 canvas:black 0.jpg -resize 640x640 -gravity South -composite -extent 740x740 result_079.jpg

1 は合成するオプション composite を付けていないため、キャンバスと画像が別々の画像ファイルとして出力されます。

2 の期待するところは 2の4,5,6です。
ここでは一旦、「画像指定より前にresizeがあるとその領域を確保するが画像は縮小されない」「画像指定より後ろにresizeがあると画像そのものを縮小する」ということがわかります。

3 では画像の前に置いた resize オプションはどこに効いているのかをわかりやすくするために、キャンバスを黒くしてみました。
画像全体は 740x740です。
キャンバスも 740x740 で作成していますので、実は下記のようになっています。
3-1 キャンバスに「だけ」リサイズが利いている。
3-2 キャンバスと画像の「両方」にリサイズが利いている。画像は横幅がフィットするように縮小されるため、キャンバスが見える部分が黒く残る。

リサイズ 位置調整 キャンバスを作ってから合成する2

geometryオプションを使用して位置を調整します。このオプションも、キャンバスと同じく設置する位置を注意して見てください。

canvas に 画像を compsite (合成)して位置の調整をします。geometryオプションを使用します。


元の resize
convert 0.jpg -gravity center -resize 640x640 -extent 740x740 result_056.jpg

1 gravity → geometry → 画像 → resize
convert -size 740x740 canvas:blue -gravity center -geometry +200+200 0.jpg -resize 640x640 -composite -extent 740x740 result_081.jpg

2 gravity → 画像 → geometry → resize
convert -size 740x740 canvas:blue -gravity center 0.jpg -geometry +200+200 -resize 640x640 -composite -extent 740x740 result_082.jpg

1 と 2 の違いは geometry が画像指定の前に来ているか後ろに来ているかです。
2が正解に思えそうですが、先ほどの例と同じように 740x740の画像サイズのうち、640x640にキャンバスごと縮小されています。
つまり、「キャンバス生成」→「画像配置」→「移動」→「キャンバス、画像ともリサイズ指定にフィットするように縮小」という事でしょうか。
ただこの説明では矛盾がある気がします。ここでは一旦「うまくいかなかった」という結論だけにして正解を求めます。

リサイズ 位置調整 一旦これが正解

オプションを何に対して適用するのか、その指定をします。

canvas に 画像を compsite (合成)して位置の調整をします。geometryオプションを使用します。


1 カッコを使って指定
convert -size 740x740 canvas:blue -gravity center \( 0.jpg -geometry +200+200 -resize 640x640 \) -composite -extent 740x740 result_090.jpg

これで得たい結果が得られました。
オプションを適用したい画像とオプションを ( ) カッコでくくります。
この場合、適用したい画像と、 geometryオプション、resizeオプションをくくると、画像だけに適用されます。
バックスラッシュでエスケープしないとエラーになるようです。

オプションの指定について整理

一旦オプションの指定について整理します。
ただ、ここまでの経験則ですので正しいとは限りません。

・オプションはその記述の前にある要素すべてに適用される。
・()でくくると、くくった要素にのみ適用される。

画像の切り取り

リサイズが出来たところで、今度はより任意に画像のリサイズと切り取りが出来るように試してみましょう。
ゴールとしては、まず先ほどの画像を高さ 640px に合わせて縮小し、左右も 640pxで裁ち落します。
次に、複数の画像を640x640の中に並べることにします。

resize のサイズ指定 オプション記号


resize のサイズ指定のオプション記号による出力の違いを見ます。

1 指定しない
convert 0.jpg -gravity center -resize 640x640 result_104.jpg
convert 0.jpg -gravity center -geometry 640x640 result_101.jpg

2 ^ 指定
convert 0.jpg -gravity center -resize 640x640^ result_105.jpg
convert 0.jpg -gravity center -geometry 640x640^ result_102.jpg

3 ! 指定
convert 0.jpg -gravity center -resize 640x640! result_106.jpg
convert 0.jpg -gravity center -geometry 640x640! result_103.jpg


4 ^ 指定 + extent
convert 0.jpg -gravity center -resize 640x640^ -extent 640x640 result_107.jpg

1 はデフォルトの動作で、以前も登場したものです。指定範囲に縦横収まります。
 640x640の指定に対し、640x427の画像が出力されました。

2 の ^ 指定は縦横の小さい方を埋めるように縮小し、大きいほうは範囲外にはみ出します。
切り取るわけではないので、結果 640x640 の指定をはみ出し、 940x640の画像が出力されます。

3 の ! 指定はアスペクト比を無視し、縦横とも指定のサイズに拡縮します。
結果 640x640 の指定に対し、アスペクト比の変わった 640x640の画像が出力されます。

いずれも resize {size} でも giometry {size} でも結果は同じです。
4 の ^ 指定に extent オプションを指定することで、望みどおりの指定サイズに収まる切り取り画像を得ることが出来ました。

縦に 3分割


次に画像をさらに3分割してみます。640は3で割り切れないので、間に 2pxずつ入れるものとして 212pxで切り出します。

1 左
convert 0.jpg -gravity West -resize 640x640^ -extent 212x640 result_110.jpg

2 中
convert 0.jpg -gravity center -resize 640x640^ -extent 212x640 result_111.jpg

3 右
convert 0.jpg -gravity East -resize 640x640^ -extent 212x640 result_112.jpg

縦に3分割してみます。
これは今までの応用で、 ^オプションを付けてリサイズ、gravityを指定して得る場所を選択して extent で 212x640 の切り出しサイズを指定すれば実現できます。

3つの画像を 縦に 3分割 して、一つに合体する

複数の画像を合成するのは初めてですので難しそうに思えますが、今までの応用で意外と簡単にできます。
元画像 はこちら


1
convert -size 640x640 canvas:blue \
\( 0.jpg -gravity West -resize 640x640^ -extent 212x640 \) -composite \
\( 1.jpg -gravity center -resize 640x640^ -extent 212x640 \) -composite \
\( 2.jpg -gravity East -resize 640x640^ -extent 212x640 \) -composite \
result_120.jpg

縦に3分割した3つの画像を 一つに並べて合成できました。
canvas を作成して、画像ごとに ( ) で括って composite で合成すればできます。

良い部分を選んで 一つに合体する

せっかくなので動物の顔が移っている個所を選んで合成してみましょう。
ここまで来ると、割と直感的に出来るのではないでしょうか。


1 composite に gravity 指定
convert -size 640x640 canvas:blue \
\( 0.jpg -gravity center -resize 640x640^ -extent 212x640 \) -gravity West -composite \
\( 1.jpg -gravity center -resize 640x640^ -extent 212x640 \) -gravity center -composite \
\( 2.jpg -gravity West -resize 640x640^ -extent 212x640 \) -gravity East -composite \
result_121.jpg

2 さらに微調整 失敗
convert -size 640x640 canvas:blue \
\( 0.jpg -gravity center -resize 640x640^ -extent 212x640 \) -gravity West -composite \
\( 1.jpg -gravity center -resize 640x640^ -extent 212x640 \) -gravity center -composite \
\( 2.jpg -gravity West -geometry +20+100 -resize 640x640^ -extent 212x640 \) -gravity East -composite \
result_122.jpg

convert -size 640x640 canvas:blue \
\( 0.jpg -gravity center -resize 640x640^ -extent 212x640 \) -gravity West -composite \
\( 1.jpg -gravity center -resize 640x640^ -extent 212x640 \) -gravity center -composite \
\( 2.jpg -gravity West -resize 640x640^ -geometry +20+100 -extent 212x640 \) -gravity East -composite \
result_123.jpg

convert -size 640x640 canvas:blue \
\( 0.jpg -gravity center -resize 640x640^ -extent 212x640 \) -gravity West -composite \
\( 1.jpg -gravity center -resize 640x640^ -extent 212x640 \) -gravity center -composite \
\( 2.jpg -gravity West -resize 640x640^ -extent 212x640 -geometry +20+100 \) -gravity East -composite \
result_124.jpg


3 試しに () を入れ子にして 微調整 失敗
convert -size 640x640 canvas:blue \
\( 0.jpg -gravity center -resize 640x640^ -extent 212x640 \) -gravity West -composite \
\( 1.jpg -gravity center -resize 640x640^ -extent 212x640 \) -gravity center -composite \
\( 2.jpg -gravity West -resize 640x640^ \( -extent 212x640 -geometry +20+100 \) \) -gravity East -composite \
result_125.jpg

4 extent の代わりに crop(切り取り)を使用して 微調整 成功
convert -size 640x640 canvas:blue \
\( 0.jpg -gravity center -resize 640x640^ -extent 212x640 \) -gravity West -composite \
\( 1.jpg -gravity center -resize 640x640^ -extent 212x640 \) -gravity center -composite \
\( 2.jpg -gravity West -resize 640x640^ -crop 212x640+40+100 \) -gravity East -composite \
result_126.jpg

1 画像ごとに ( ) で括って、というのを、処理ごとに ( ) で括ると考えた場合、extent の gravity と composite のgravity をそれぞれ指定すればよい事がわかります。
2 さらに微調整を試みましたが、結果はどれも失敗に見えます。
3 試しに geometry と extent を ( ) で囲みましたが、これも失敗です。

4 extent (範囲)の代わりに、crop (切り取り)で処理したら、無事成功しました。シロテテナガザルノ子供も見えました。

extent と crop で少し混乱

extent と crop の使い分けで少し混乱しました。


1 gravity を center で extent 指定
convert -size 640x640 canvas:blue \
\( 0.jpg -gravity center -resize 640x640^ -extent 320x640 \) -gravity West -composite \
result_510.jpg

2 gravity を center で crop 指定
convert -size 640x640 canvas:blue \
\( 0.jpg -gravity center -resize 640x640^ -crop 320x640 \) -gravity West -composite \
result_511.jpg

3 gravity を West で extent 指定
convert -size 640x640 canvas:blue \
\( 0.jpg -gravity West -resize 640x640^ -extent 320x640 \) -gravity West -composite \
result_512.jpg

4 gravity を West で crop 指定
convert -size 640x640 canvas:blue \
\( 0.jpg -gravity West -resize 640x640^ -crop 320x640 \) -gravity West -composite \
result_513.jpg

5 gravity を East で extent 指定
convert -size 640x640 canvas:blue \
\( 0.jpg -gravity East -resize 640x640^ -extent 320x640 \) -gravity West -composite \
result_514.jpg

6 gravity を East で crop 指定
convert -size 640x640 canvas:blue \
\( 0.jpg -gravity East -resize 640x640^ -crop 320x640 \) -gravity West -composite \
result_515.jpg
7 解決 gravity 指定しない crop は WidthxHeight+X+Y で指定
convert -size 640x640 canvas:blue \
\( 0.jpg -resize 640x640^ -crop 320x640+0+0 \) -gravity West -composite \
result_541.jpg

convert -size 640x640 canvas:blue \
\( 0.jpg -resize 640x640^ -crop 320x640+160+0 \) -gravity center -composite \
result_543.jpg

convert -size 640x640 canvas:blue \
\( 0.jpg -resize 640x640^ -crop 320x640+320+0 \) -gravity East -composite \
result_545.jpg

crop には gravity を指定せず、gravity に指定する geometry値で設定をすると解決しました。

エフェクトを掛けてみる

3分割がルーレットのように見えるので、試しによりそう見えるエフェクトを掛けてみます。


1 画像の一つを回転させる
convert -size 640x640 canvas:blue \
\( 0.jpg -gravity center -resize 640x640^ -extent 212x640 \) -gravity West -composite \
\( 1.jpg -gravity center -resize 640x640^ -extent 212x640 \) -gravity center -composite \
\( 2.jpg -gravity West -resize 640x640^ -crop 212x640+40+100 -roll +0+300 \) -gravity East -composite \
result_127.jpg



2 blur で画像をエフェクトする
convert -size 640x640 canvas:blue \
\( 0.jpg -gravity center -resize 640x640^ -extent 212x640 \) -gravity West -composite \
\( 1.jpg -gravity center -resize 640x640^ -extent 212x640 \) -gravity center -composite \
\( 2.jpg -gravity West -resize 640x640^ -crop 212x640+40+100 -roll +0+300 -blur 0x15 \) -gravity East -composite \
result_129.jpg


3 motion-blur で画像をエフェクトする
convert -size 640x640 canvas:blue \
\( 0.jpg -gravity center -resize 640x640^ -extent 212x640 \) -gravity West -composite \
\( 1.jpg -gravity center -resize 640x640^ -extent 212x640 \) -gravity center -composite \
\( 2.jpg -gravity West -resize 640x640^ -crop 212x640+40+100 -roll +0+300 -motion-blur 0x30 \) -gravity East -composite \
result_130.jpg

4 motion-blur で画像をエフェクトする 2
convert -size 640x640 canvas:blue \
\( 0.jpg -gravity center -resize 640x640^ -extent 212x640 \) -gravity West -composite \
\( 1.jpg -gravity center -resize 640x640^ -extent 212x640 \) -gravity center -composite \
\( 2.jpg -gravity West -resize 640x640^ -crop 212x640+40+100 -roll +0+300 -motion-blur 0x30+90 \) -gravity East -composite \
result_134.jpg

5 motion-blur で画像をエフェクトする 3
convert -size 640x640 canvas:blue \
\( 0.jpg -gravity center -resize 640x640^ -extent 212x640 \) -gravity West -composite \
\( 1.jpg -gravity center -resize 640x640^ -extent 212x640 \) -gravity center -composite \
\( 2.jpg -gravity West -resize 640x640^ -crop 212x640+40+100 -roll +0+300 -motion-blur 0x90+90 \) -gravity East -composite \
result_136.jpg

5 blur + motion-blur で画像をエフェクトする
convert -size 640x640 canvas:blue \
\( 0.jpg -gravity center -resize 640x640^ -extent 212x640 \) -gravity West -composite \
\( 1.jpg -gravity center -resize 640x640^ -extent 212x640 \) -gravity center -composite \
\( 2.jpg -gravity West -resize 640x640^ -crop 212x640+40+100 -roll +0+300 -blur 0x5 -motion-blur 0x30+90 \) -gravity East -composite \
result_137.jpg

1 roll というオプションで 3つ目の画像だけ回転しているようにしました。
rollオプションの値も geometry の指定です。
2 の blur でぼやかして、回転中の見えづらさを表現しています。
blur 参照

3 の motion-blur でよりそれっぽいエフェクトを加えることができます。
motion blur 参照
値の指定は
-motion-blur radius ( 半径のみ )
-motion-blur radius x sigma + angle ( 半径、シグマ、アングル) です。

横に流れている感じになってしまっているので、アングルを 90°変えて縦に流します。
4 で angle を90°に指定して、それっぽい画像になりました。
5 はさらに流れを大きくしています。
6 は blur と motion-blur を組み合わせたものです。
ちなみに同じマシンで、処理した場合、4のシグマが30の処理時間は約5秒、5のシグマが90の処理時間は約14秒でした。

配置位置を微調整 gravity の設定された composit に対する geometry オプション

切り取る位置の微調整は前にできましたので、今度は配置する位置の微調整をしたいと思います。


1 画像配置を微調整する
convert -size 640x640 canvas:blue \
\( 0.jpg -gravity center -resize 640x640^ -extent 212x640 \) -gravity West -geometry +20+10 -composite \
\( 1.jpg -gravity center -resize 640x640^ -extent 212x640 \) -gravity center -geometry -40+20 -composite \
\( 2.jpg -gravity West -resize 640x640^ -crop 212x640+40+100 -roll +0+300 -motion-blur 0x30+90 \) -gravity East -geometry +60+40 -composite \
result_140.jpg


それぞれの画像の、 composite に gravity が設定されていますが、さらに geometry でピクセルを指定して位置を微調整します。
注意点は、gravity ( 重心、重力 ) という基準点の設定にある事。
右寄せ、左寄せではなく、『重心点』として West 、 East などを設定していることです。
そのため、
gravity が West (左端)に設定されているライオンの画像は、geometryの横が +20で『右』に20ピクセル移動
gravity が East (右端)に設定されているテナガザルの画像は、geometryの横が +60で『左』に60ピクセル移動
という動作の違いがあります。

画像の回転

今度は画像の回転をします。

画像を回転させる rotate と distort

切り取る位置の微調整は前にできましたので、今度は配置する位置の微調整をしたいと思います。


1 基準の画像
convert -size 740x740 canvas:gray \( -gravity center 107.jpg \) -composite -extent 740x740 result_160.jpg

2 routete
convert -size 740x740 canvas:gray \( -gravity center -rotate 30 107.jpg \) -composite -extent 740x740 result_161.jpg
convert -size 740x740 canvas:gray \( -gravity center 107.jpg -rotate 30 \) -composite -extent 740x740 result_162.jpg
convert -size 740x740 canvas:gray \( -gravity center 107.jpg \) -rotate 30 -composite -extent 740x740 result_163.jpg

3 distort
convert -size 740x740 canvas:gray \( -gravity center -distort SRT 30 107.jpg \) -composite -extent 740x740 result_164.jpg
convert -size 740x740 canvas:gray \( -gravity center 107.jpg -distort SRT 30 \) -composite -extent 740x740 result_165.jpg
convert -size 740x740 canvas:gray \( -gravity center 107.jpg \) -distort SRT 30 -composite -extent 740x740 result_166.jpg

1の画像を基準として処理します。
2 rotete で回転させます。どの記述方法でも結果は同じです。
3 distort (ゆがめる、ねじる、曲げる、ひずませる 参考) で回転させます。こちらもどの記述方法でも結果は同じです。
distort の値について
distort に SRT を指定した場合、値を一つ設定すると Angle の設定になります。
回転した画像の周囲の、本来画像が無いはず部分がおかしくなっていますが、これについては後程触れます。

回転の余白を透明にする rotate

roteteの回転で、キャンバスのグレイの部分が消えてしまっていました。その原因と解決を例示します。
わかりやすいように、キャンバスと生成画像を大きくします。


1 基準の画像
convert -size 900x900 canvas:gray \( -gravity center 107.jpg \) -composite -extent 1200x1200 result_170.jpg

2 回転
convert -size 900x900 canvas:gray \( -gravity center -rotate 30 107.jpg \) -composite -extent 1200x1200 result_171.jpg

3 バックグラウンドに alphaチャンネル付の透明色を指定
convert -background 'rgba(0,0,0,0)' -size 900x900 canvas:gray \( -gravity center -rotate 30 107.jpg \) -composite -extent 1200x1200 result_172.jpg

4 書き出し画像フォーマットによる違い Jpeg
convert -background 'rgba( 20,120,220,0)' -size 900x900 canvas:gray \( -gravity center -rotate 30 107.jpg \) -composite -extent 1200x1200 result_173.jpg
5 書き出し画像フォーマットによる違い PNG32
convert -background 'rgba( 20,120,220,0)' -size 900x900 canvas:gray \( -gravity center -rotate 30 107.jpg \) -composite -extent 1200x1200 png32:result_175.png

1 は基準となる画像です。まだ回転させていません。
2 は、画像を回転させたものです。画像が回転した矩形で生成されているため、その範囲が白べたに塗られてしまっています。
3 は、背景色として透過色を設定しています。 -background 'rgba(0,0,0,0)'Qiitaの記事
この場合、キャンバスが無い部分も透過色になるので、jpgeで書き出すとその部分は黒になります。
jpegは R , G , B のみの 3チャンネルで、4チャンネル目のアルファチャンネルが無いため、単に #000000 の黒になるのです。

4 試しに、アルファチャンネルは 0のまま、RGBチャンネルにも値を入れた場合の結果です。
5 は同じパメーターで、PNG32で書き出した場合です。
Jpegで結果を得る場合は、は合成後に出力する際にアルファチャンネルは削除されるので、RGBに設定された値が残ります。
PNG32の場合はアルファチャンネルも残るため、RGBに色が設定されていてもアルファチャンネルに指定された不透明度が 0 であれば透過します。
ちなみに、確かアルファチャンネルという名前はチャンネル(値を入れる箱)の名前で、値そのものは Opacity値 とか、他の言い方もあった気がします。

distort による回転 virtual-pixel オプション

distort による回転で画像の周囲が期待通りになっていない件を解消します。


1 回転
convert -size 740x740 canvas:gray \( 107.jpg -distort SRT 30 \) -gravity center -composite result_191.jpg

2 回転 白で埋める
convert -size 740x740 canvas:gray \( 107.jpg -virtual-pixel white -distort SRT 30 \) -gravity center -composite result_192.jpg

3 回転 透明で埋める
convert -size 740x740 canvas:gray \( 107.jpg -virtual-pixel transparent -distort SRT 30 \) -gravity center -composite result_193.jpg
または
convert -background 'rgba( 20,120,220,0)' -size 740x740 canvas:gray \( 107.jpg -virtual-pixel background -distort SRT 30 \) -gravity center -composite result_193.jpg

4 その他の virtical-pixel 指定
convert -size 740x740 canvas:gray \( 107.jpg -virtual-pixel checker-tile -distort SRT 30 \) -gravity center -composite result_194.jpg
convert -size 740x740 canvas:gray \( 107.jpg -virtual-pixel dither -distort SRT 30 \) -gravity center -composite result_195.jpg
convert -size 740x740 canvas:gray \( 107.jpg -virtual-pixel edge -distort SRT 30 \) -gravity center -composite result_196.jpg
convert -size 740x740 canvas:gray \( 107.jpg -virtual-pixel horizontal-tile -distort SRT 30 \) -gravity center -composite result_197.jpg
convert -size 740x740 canvas:gray \( 107.jpg -virtual-pixel horizontal-tile-edge -distort SRT 30 \) -gravity center -composite result_198.jpg
convert -size 740x740 canvas:gray \( 107.jpg -virtual-pixel mirror -distort SRT 30 \) -gravity center -composite result_199.jpg
convert -size 740x740 canvas:gray \( 107.jpg -virtual-pixel random -distort SRT 30 \) -gravity center -composite result_200.jpg
convert -size 740x740 canvas:gray \( 107.jpg -virtual-pixel tile -distort SRT 30 \) -gravity center -composite result_201.jpg
convert -size 740x740 canvas:gray \( 107.jpg -virtual-pixel vertical-tile -distort SRT 30 \) -gravity center -composite result_203.jpg
convert -size 740x740 canvas:gray \( 107.jpg -virtual-pixel vertical-tile-edge -distort SRT 30 \) -gravity center -composite result_204.jpg

1 は単に回転させた状態です。本来画像が無いはずの場所には、周辺を引き延ばしたようなデータで埋められています。
2 はその部分を白くしたものです。
virtual-pixel というオプションがその設定です。
virtual-pixel について
3 は今回得たい結果です。透明色で埋めるのですが、前者は「透明色 ( transparent )を指定」です。 後者は「透明色を指定」ではなく「背景 ( background ) に透明色を指定」した上で「virtual-pixelに背景色を指定」という指定方法です。
virtual-pixel は直接 -virtual-pixel 'rgba( 20,120,220,0)' というような指定が出来ない様なので、特定の色で埋めたい場合この方法を使ったほうが良いようです。

+distort

ここまでは distort の指定に -記号を使ってきました。これは、回転等させてももともとの画像サイズをはみ出すことはありません。
+ 記号に変えると、次のようになります。


1 - 記号
convert -background 'rgba( 20,120,220,0)' -size 740x740 canvas:gray \( 107.jpg -virtual-pixel background -distort SRT 30 \) -gravity center -composite result_193.jpg

1 + 記号
convert -background 'rgba( 20,120,220,0)' -size 740x740 canvas:gray \( 107.jpg -virtual-pixel background +distort SRT 30 \) -gravity center -composite result_193-2.jpg

記号を + に変えると、処理後に拡大した画像領域まで広がります。
元の画像領域内で処理したければ -記号、はみ出す部分も含めて処理したい場合は + 記号です。

回転の中心を設定する rotate

次に rotete による回転の中心を設定します。


1 回転
convert -background 'rgba(20,120,220,0)' -size 900x900 canvas:gray \( -gravity center -rotate 30 107.jpg \) -composite -extent 1200x1200 result_180.jpg

2 geometoryを設定してみる
convert -background 'rgba(20,120,220,0)' -size 900x900 canvas:gray \( -gravity center -geometry +40+40 -rotate 30 107.jpg \) -composite -extent 1200x1200 result_181.jpg
3 gravity を South にしてみる
convert -background 'rgba(20,120,220,0)' -size 900x900 canvas:gray \( -gravity South -rotate 30 107.jpg \) -composite -extent 1200x1200 result_182.jpg

1の回転の中心をオフセットしようとした場合です。
2 のrotate に geometry が有効か試した例ですが、単に画像の配置位置が変わりました。
3 のgravity を South にした場合ですが、これも画像の配置位置が変わりました。
回転の中心点をオフセットするのはこの方法ではないようです。

rotate での検討は一旦ここまで。

回転の中心を設定する distort

次に distort による回転の中心を検討します。
distort オプションの SRT 指定には、ほかにもいろいろな指定方法があります。


1 軸をずらして回転
convert -size 740x740 canvas:gray \( 107.jpg -virtual-pixel transparent -distort SRT '-300-300 5' \) -gravity center -composite result_210.jpg
convert -size 740x740 canvas:gray \( 107.jpg -virtual-pixel transparent -distort SRT '-300-300 10' \) -gravity center -composite result_211.jpg
convert -size 740x740 canvas:gray \( 107.jpg -virtual-pixel transparent -distort SRT '-300-300 15' \) -gravity center -composite result_212.jpg
convert -size 740x740 canvas:gray \( 107.jpg -virtual-pixel transparent -distort SRT '-300-300 20' \) -gravity center -composite result_213.jpg
convert -size 740x740 canvas:gray \( 107.jpg -virtual-pixel transparent -distort SRT '-300-300 25' \) -gravity center -composite result_214.jpg
convert -size 740x740 canvas:gray \( 107.jpg -virtual-pixel transparent -distort SRT '-300-300 30' \) -gravity center -composite result_215.jpg

2 回転 しながらフレームイン
convert -size 740x740 canvas:gray \( 107.jpg -virtual-pixel transparent -distort SRT '-50-50 0.6 20' \) -gravity center -composite result_220.jpg
convert -size 740x740 canvas:gray \( 107.jpg -virtual-pixel transparent -distort SRT '-50-50 0.7 15' \) -gravity center -composite result_221.jpg
convert -size 740x740 canvas:gray \( 107.jpg -virtual-pixel transparent -distort SRT '-50-50 0.8 10' \) -gravity center -composite result_222.jpg
convert -size 740x740 canvas:gray \( 107.jpg -virtual-pixel transparent -distort SRT '-50-50 0.9 5' \) -gravity center -composite result_223.jpg
convert -size 740x740 canvas:gray \( 107.jpg -virtual-pixel transparent \) -gravity center -composite result_224.jpg

3 アニメーションgif
convert -delay 10
\( 107.jpg -virtual-pixel transparent -distort SRT '-50-50 0.35 7.5' \)
\( 107.jpg -virtual-pixel transparent -distort SRT '-50-50 0.4 30' \)
\( 107.jpg -virtual-pixel transparent -distort SRT '-50-50 0.45 27.5' \)
\( 107.jpg -virtual-pixel transparent -distort SRT '-50-50 0.5 25' \)
\( 107.jpg -virtual-pixel transparent -distort SRT '-50-50 0.55 22.5' \)
\( 107.jpg -virtual-pixel transparent -distort SRT '-50-50 0.6 20' \)
\( 107.jpg -virtual-pixel transparent -distort SRT '-50-50 0.65 17.5' \)
\( 107.jpg -virtual-pixel transparent -distort SRT '-50-50 0.7 15' \)
\( 107.jpg -virtual-pixel transparent -distort SRT '-50-50 0.75 12.5' \)
\( 107.jpg -virtual-pixel transparent -distort SRT '-50-50 0.8 10' \)
\( 107.jpg -virtual-pixel transparent -distort SRT '-50-50 0.85 7.5' \)
\( 107.jpg -virtual-pixel transparent -distort SRT '-50-50 0.9 5' \)
\( 107.jpg -virtual-pixel transparent -distort SRT '-50-50 0.95 2.5' \)
\( 107.jpg \)
-delete 0 -loop 0 result_225.gif

連続で見るとわかりやすいですが、軸が確かに画像の中心からずれて回転しています。
SRT 指定の '+x+y angle' という指定です。
参考
2 他にもスケールを同時に指定することもできますので、回転しながらフレームイン、という連続写真も作成できます。
3 それを応用して、アニメーションgif画像で出力するとこうなります。

エフェクト、装飾を活用してみる

画像の装飾などを活用してみましょう。

ポラロイド写真風 polaroid

ポラロイド写真風の画像を作成します。
polaroid オプション 事例


1 装飾前
convert 107.jpg -bordercolor white -background gray result_300.png

2 polaroid 装飾 0°
convert 107.jpg -bordercolor white -background gray -polaroid 0 result_301.png

3 polaroid 装飾 連続
convert 107.jpg -bordercolor white -background gray -polaroid 3 result_302.png
convert 107.jpg -bordercolor white -background gray -polaroid 3.5 result_303.png
convert 107.jpg -bordercolor white -background gray -polaroid 4 result_304.png

4 回転を distort で
convert 107.jpg -bordercolor white -background gray -polaroid 0 -virtual-pixel transparent -distort SRT 3 result_310.png
convert 107.jpg -bordercolor white -background gray -polaroid 0 -virtual-pixel transparent -distort SRT 3.5 result_311.png
convert 107.jpg -bordercolor white -background gray -polaroid 0 -virtual-pixel transparent -distort SRT 4 result_312.png

5 重ねてみる
convert -size 900x900 canvas:#fff8f3 \
\( 107.jpg -bordercolor white -background gray -polaroid -49 \) -gravity center -geometry -200+200 -composite \
\( 107.jpg -bordercolor white -background gray -polaroid 127 \) -gravity center -geometry -10-230 -composite \
\( 107.jpg -bordercolor white -background gray -polaroid 8 \) -gravity center -geometry +100+100 -composite \
result_320.png

1 はpolaroid オプションをつけていません。元画像 640x640 に対して、出力も当選 640x640です。
2 はpolaroid オプションを設定して、角度を 0°に指定したものです。
装飾が元画像の周囲に施されるため、画像サイズは 708x698 になりました。フチの形に合わせて、画像も微妙に歪がかかっています。

3 は連続回転させてみたものです。
angle はfloat で指定できますので、スムーズな回転が出来そうです。
画像サイズは回転が 0で 708x698 だったものが、742x734 → 747x740 → 752x746 と変化します。

4 は回転を distort で行った場合です。
この場合は画像サイズは変わらず、708x698 で、はみ出す部分は切り落とされます。

5 いままでの画像操作を応用して、重ね合わせの画像も作ってみました。

カラー、セピア など

多数のオプションがあるので、さしあたり グレースケール化とセピア化をしています。
オプション

1 色を変えて懐かしいイメージを作成する

convert -size 900x900 canvas:#fff8f3 \
\( 107.jpg -bordercolor white -background gray -sepia-tone 67% -evaluate add -20% -polaroid -49 \) -gravity center -geometry -240+200 -composite \
\( 107.jpg -bordercolor white -background gray -colorspace gray -polaroid 127 \) -gravity center -geometry -10-270 -composite \
\( 107.jpg -bordercolor white -background gray -polaroid 8 \) -gravity center -geometry +130+100 -composite \
result_321.png

一番下の画像には、 sepia-tone を設定してセピア調にした上で、 evaluate でコントラストを沈めています。
間の画像はグレイスケールに変換しています。
一番上は何も加工していない画像です。




--- ここから先は作成中 ---