この投稿は
FreeBSDでPerlMagick(その3)画像の加工からの続きです。
また,
FreeBSDでPerlMagick(その1)はじめにに目次があります。
(15) Draw:図形の描画(その2)
PerlMagick での図の描画の例をいつくか示そう。まずは
line,
rectangle,
roundRectangle について書こう。それぞれの書式は以下のようになる。ちなみに,いずれの場合も 100 x 100 ピクセルのキャンバスの上に描画している。描画するための画像ファイルの読込み,あるいは新しいキャンバスを用意については,このブログの
FreeBSDでPerlMagick(その1)はじめに や
FreeBSDでPerlMagick(その2)図と文字を描く を見て欲しい。
$img1->Draw(primitive=>'line', points=>'x0,y0 x1,y1', stroke=>$color, strokewidth=>$width);
$img1->Draw(primitive=>'rectangle', points=>'x0,y0 x1,y1', fill=>'green',
stroke=>$color, strokewidth=>$width);
$img1->Draw(primitive=>'roundRectangle', points=>'x0,y0 x1,y1 wc,hc', fill=>'green',
stroke=>$color, strokewidth=>$width);
line は始点と終点を,
rectangle は対角線上の2点を,
roundRectangle は対角線上の2点と角の丸みを指定する。点と点の間はスペースだが,コンマで区切っても大丈夫だった。
stroke は線を表し,rectangleなら縁の線を表す。指定しなければ枠なしの図形となる。
fill は塗りつぶしの色を表し,
line で指定しても無視される。以下に具体例を示す。例4はスリット付きの角の丸い四角である。
例1:$img1->Draw(primitive=>'line', points=>'0,50 100,100', stroke=>'blue', strokewidth=>2);
例2:$img1->Draw(primitive=>'rectangle', points=>'0,50 100,100', fill=>'green');
例3:$img1->Draw(primitive=>'roundRectangle', points=>'0,50 100,100 10,10', fill=>'green');
例4:$img1->Draw(primitive=>'roundRectangle', points=>'0,25 100,75 10,10', fill=>'green');
$img1->Draw(primitive=>'rectangle', points=>'45,0 55,100', stroke=>'none', fill=>'white');
 |  |  |  |
| 例1:line | 例2:rectangle | 例3:roundRectagle | 例4:roundRectagle
with slit |
次に
arc,
ellipse,
circle について書く。それぞれの書式は以下のようになる。
$img1->Draw(primitive=>'arc', points=>'x0,y0 x1,y1 a0,a1', stroke=>$color, strokewidth=>$width, fill=>'green');
$img1->Draw(primitive=>'ellipse', points=>'x0,y0 rx,ry a0,a1', stroke=>$color, strokewidth=>$width, fill=>'green');
$img1->Draw(primitive=>'circle', points=>'x0,y0 x1,y1', fill=>'green', stroke=>$color, strokewidth=>$width);
arc では,
x0,y0 x1,y1 で四角い描画領域を指定し,その四角の中に辺に接するように角度
a0から
a1までの円弧を描く。角度は右横が0度で,時計回り(下向き)に角度を測る。下が90度方向,左が180度方向,上が270度方向になっている。
gravity オプションが使えれば,角度の指定方法は変わると思われる(gravityが使えるかどうかもわからないので,あくまで推論)
ellipse は中心座標と横方向の半径,縦方向の半径と開始角度,終了角度を指定する。
circle は
x0,y0 で中心座標を指定し,中心座標から点
x1,y1 までを半径とする円を描く。
stroke 等は
lineや
rectangleなどと同じである。
例1:$img1->Draw(primitive=>'arc', points=>'0,0 100,50 0,225',
stroke=>'blue', strokewidth=>2, fill=>'green');
例2:$img1->Draw(primitive=>'arc', points=>'0,0 100,50 225,0', stroke=>'blue', strokewidth=>2, fill=>'green');
例3:$img1->Draw(primitive=>'ellipse', points=>'50,50 50,30 0,225', stroke=>'blue', strokewidth=>2, fill=>'green');
例4:$img1->Draw(primitive=>'circle', points=>'50,50 50,5', stroke=>'blue', strokewidth=>2, fill=>'green');
 |  |  |  |
| 例1:arc | 例2:arc2 | 例3:ellipse | 例4:circle |
(16) Composite:画像の合成
図の合成は
Composite コマンドを使う。詳しいことは
Compositing Imagesを見て欲しいが,以下に例を示しておこう。
# Original画像の読み込み
my $img = Image::Magick->new;
$img->Read($target_pict);
# タイトル用の透明キャンバスの用意
my $img1 = Image::Magick->new;
$img1->Set(size=>'300x50');
$img1->ReadImage('xc:none');
# タイトルの作成
$text='紀伊半島・二木島';
$text = jcode($text)->utf8;
$fontdir='./HGRSMP.TTF';
$color='yellow';
$pointsize=32;
$img1->Annotate(text=>$text,geometry=>'+0+0',font=>$fontdir,fill=>$color,
gravity=>'Center',pointsize=>$pointsize,strokewidth=>1,stroke=>$color);
# 合成
$img->Composite(image=>$img1,compose=>'over',geometry=>'+0+80',gravity=>'Center');
# 出力とメモリの開放
$img->Write($newname);
undef $img1;
undef $img;
ここで,
$img という画像に,
$img1 というタイトル文字列を合成している。今の場合は,単純に上に重ねればいいので
compose を
over にしている。また,場所の指定は,
Center からの相対的な座標で表している。
 |  |
 |
| Original | Title (背景が透明なのでpng で出力) | TitleをCompositeしたもの |
(註):この例は合成を示したいがためにこんなことをしているが,普通は画像(写真)に直接
Anotate で文字を描く方が早い。
(註2):gravity で合成する際の座標原点を指定できるが,左下を指定した場合(SouthWest)にオフセットの値をプラスで記述するとうまくいかなかった。そんな時はマイナスの数値にしてみてほしい。
(17) Quantizeを用いた白黒画像への変換
白黒にする方法として
Quantize を使う方法を紹介する。他にも
Fx を使って演算する方法があるが,それは次の項目にしよう。
Quantize と
Fx で結果は微妙に違うが,大体は同じような白黒画像が得られる。
$img->Quantize(colorspace=>'gray');
Quantize は本来,色の種類を減らすために用いるみたいだが,筆者はまだちゃんと理解できてない。
Quantize に関しては,
Image Magick の使い方のサイトの
Color Quantization and Ditheringを見て欲しい。
 |  |
| オリジナル (160x120) | Quantizeで白黒へ |
(18) Fx:三原色の色チャネルの演算
白黒変換のところで
Fx を使って演算する方法があると書いたが,ここではその
Fx について書いてみよう。
まず
Image Magick での色についてだが,色を指定するのに幾つかの手法があって,よく知られているのが
RGB による指定である。他にも
CMYK や
HSB,
HSLなど幾つもあるらしい。筆者は
RGB しか理解できてないので,
RGB で話をしよう。
RGB では,赤(r, red),青(b, blue),緑(g, green)の3色の和として色を表している。
Image Magick では,色を指定するのに
#ccddff のように16進数を使って表すこともできる。ここで,最初の2桁の
#cc(
# は以降が16進数であることを示している) は
red 成分の濃さを,次の
#dd が
green 成分の濃さを,最後の
#ff が
blue 成分の濃さを表している。16進数で2桁なので,
#00~#ff までの値を取りうる。
Fx を用いると,この3つの色のチャネルに対して演算を行うことができる。例えば以下のように書くと,
green と
blue の色の平均を
red チャネルに代入できる。
$img = $img->Fx(expression=>'(g+b)/2',channel=>'red');
ここで数式の中の
g,
b がそれぞれ
greenチャネル,
blueチャネルを表している。
redチャネルは数式の中では
rと表される。数式は
sin や
cos などのような一般の関数が使えるらしい。次ように書くと,3色の平均を取り,それを全てのチャネルに代入する。結果として白黒画像が得られる。
$img = $img->Fx(expression=>'(r+g+b)/3');
Fx に関しては,
Image Magick サイトの
The Fx Special Effects Image Operatorを見て欲しい。
 |  |  |
| オリジナル (160x120) | Fx(expression=>'(g+b)/2',
channel=>'red') | Fxで'(r+g+b)/3'とした |
(19) Colorize:色をつける
Colorize を使うと,
RGB の3色に別々に色をつけることができる。以下では
Fx で白黒画像にしたものに
Colorize で色をつけている。
$img = $img->Fx(expression=>'(r+g+b)/3');
$color='#fad759';
$opacity='50%';
$img->Colorize(fill=>$color,opacity=>$opacity);
ここで
opacity は不透明度を表し,
opacity が大きいほど画像は薄くなる(?あれ?逆か?)。
 |  |  |
| オリジナル (160x120) | Fxで'(r+g+b)/3'の後
色'#fad759'とopacity 50%で
Colorizeしたもの | Fxで'(r+g+b)/3'の後
色'#ccddff'とopacity 50%で
Colorizeしたもの |
(20) 図の一部を透明にする:TransparentとFx
Image Magick で図を別の図に重ねる時に,図の一部や背景を透明にしたいことがある。
Image Magick では,透明にした図を表すために,
RGB の3つのチャネルに,
alpha チャネル(あるいは
matte チャネル,ないしは
opacity チャネル) と呼ばれるチャネルを1個追加して画像を扱っている。つまり色を表すのに
#ccdd88ff のように16進数8桁で表している。6桁の場合は
alpha チャネルの部分は
#ff(透明ではない) とされる。従って,画像を透明にするには16進数8桁で表される色の最後の2桁を
#00 にすると完全に透明になる。しかし,画像を処理する際には
特定の色のみ透明にしたいことがある。例えば背景を白にしておいて,白い部分だけを透明にしたい,という場合。その場合は
Transparent を使うと特定の色を透明にできる。
$img->Transparent(color => 'White');
この方法を使えば,以下のように新しい白いキャンバスを用意しておいて,白の部分を透明にすることで透明なキャンバスを用意することもできる。
use Image::Magick;
my $img1 = Image::Magick->new;
$img1->Set(size=>'300x300');
# ----------------------------------
$img1->ReadImage('xc:white'); # white canvas
$img1->Transparent(color=>'White');
# ----------------------------------
$img1->Write($newname);
undef $img1;
また,図を描いた上に背景色で図を上書きして,背景色を透明にすると図を切り取ることもできる。
全体を一様に半透明にするには
Fx を用いる。
Fx の使い方のところで書いたが,
Fx では3原色を
red,
green,
blue の3つのチャネルとして演算していたが,透明度のために
alpha チャネル(
a チャネル) に対して演算すると透明度が変化する。
$img1 = $img1->Fx(expression=>'a/2',channel=>'alpha');
このようにすると,透明度が50%に下がる。下記の例では(15) Draw:図形の描画(その2)の例4の画像の背景を透明にしたものと,さらに全体を半透明にしたものを写真に合成している。念のために,今回用いた合成のコマンドを書いておく。
$img->Composite(image=>$img1,compose=>'over',geometry=>'+0+0',gravity=>'Center');
透明化に関しては,
Image Magick の使い方のサイトの
Masking and Background Removalに (2011/4 訂正)
Channels, Masks and Transparencyに詳しく書いてある。
 |  |  |
| オリジナル (160x120) | 白を透明にして合成 | 全体を半透明にして合成 |
(註):色のついた背景(
xc:white などで準備したもの)に対しては上記の処理はうまくいかないことがあった。背景を半透明にするには,
canvas の準備で透明なキャンバスを選び,全面に好みの色(白でもsilverでもgrayでもいい)をベタ塗りする。その上で上記のように
alpha チャンネルの値を減らすとよい。
FreeBSDでPerlMagick(その5)さらに進んだコマンドに続く