DJタカヤナギ=サンで学ぶRを用いた画像操作

こんにちは、ホクソエムの市川です。

日々の業務の合間にちょっとクソコラを作りたいこと、あると思います。

でもクソコラに手間はかけたくない。

そんな時に使えるのがimagerパッケージです。

ちなみに画像操作に使えるRのパッケージには他にもEBImageパッケージ、magickパッケージ等があります。

それぞれに利点はあるのですが、EBImageはbioconductorからインストールする必要があるので手間がかかり、magickは画像の上に図形を描くのが意外と面倒だったりします。 繰り返しますがクソコラに手間はかけたくない。

ということで今回はCC0ライセンスで公開されているDJタカヤナギ=サンの画像を用いてimagerパッケージの使い方について学びたいと思います。

インストール

install.packages("imager")

画像の読み込みと表示

画像の読み込みにはload.image()を用います。

読み込んだ画像の情報はprint.cimg()を用います。画像のサイズは幅960px、高さ720pxとなっています。

表示にはplot.cimg()を用います(ちなみにprint()およびplot()だけで、自動的にprint.cimg()、plot.cimg()が呼び出されます。なぜだかわかりますか?わかりますね?)

ここではXY軸を表示したくないのでaxes引数をFALSEに指定しています。

library("imager")
u <- "https://raw.githubusercontent.com/dichika/ojisan/master/takayanagi_dj.jpg" #DJタカヤナギ
dj <- load.image(u)
print(dj)
## Image. Width: 960 pix Height: 720 pix Depth: 1 Colour channels: 3
plot(dj, axes = FALSE)

画像上に図形を表示する

画像上に図形を表示する際はpx.hogehoge()とhightlight()を組み合わせます。 px.hogehoge()で図形のサイズ、座標を指定して、highlight()で表示です。 rで半径を指定し、xyで表示する座標を指定します。 なお、図形はxyの中点に表示されるので注意してください。 その他の図形については?common_pixsetsを参照してください。

ここで画像の幅と高さを取得するためにwidth()とheight()を用いています。 その他の画像情報取得関数については?cimg.dimensionsを参照してください。

plot(dj, axes = TRUE)
highlight(px.circle(r = 40, x = 300, y = 720), col = "orange")
highlight(px.diamond(r = 40, x = 600, y = 350), col = "green")
highlight(px.square(r = 40, x = width(dj)*2, y = height(dj)), col = "black")

画像上にテキストを表示する

テキストを表示するにはRの組込み関数のtext()を用います。 デフォルトでは指定したxy座標を中心にテキストが表示されます。 なお、implot()を用いて表示する方法がチュートリアルには紹介されているのですが、マルチバイト文字の表示に失敗します。

par(family="Hiragino Kaku Gothic Pro W6")
plot(dj, axes = FALSE)
text(x = width(dj)/2, y = height(dj)-100, labels = "キュッキュキュッキュ", col = "orange")

画像を切り取る

画像の一部を切り取るにはimsub()を用います。 画像の範囲指定には条件式が利用できます。 %inr%演算子を用いると矩形で範囲指定できます。

なお、ここで%>%演算子を用いていますがこれはパイプ演算子と呼ばれるものであり、演算子左側の操作を右側の操作に受け渡すものです。

dj %>% imsub(x > width(dj)/2) %>% plot(axes = TRUE) # 画像右半分を切り取る

dj %>% imsub(x %inr% c(411,722), y %inr% c(67,349)) %>% plot(axes = TRUE) # 矩形による範囲指定

この操作はインタラクティブに行うことも可能です。 この際はgrabRect()を用います。 表示された画像に対して、矩形で範囲指定すると、画像左上端と右下端の点の座標が返されます。

grabRect(dj) # インタラクティブな範囲指定
# 以下のような結果が返される。
# x0  y0  x1  y1 
# 411  67 722 349 

画像をぼかす

ちょっとおじさんの画像ばかり見ていると目が辛くなってきましたね。 画像をぼかしてみましょう。 画像をぼかすにはisoblur()を用います。 sigmaの値を大きくすればするほど画像はぼかされていきます。

dj %>% isoblur(sigma = 15) %>% plot(axes =FALSE)

クソコラ実践

さて、ここまでの操作を用いてクソコラを作ってみましょう。 クソコラを作る前にここで別のおじさんを投入します。 こちらもCC0で公開されている画像です。桜が満開ですね。

ojisan <- load.image("https://raw.githubusercontent.com/dichika/ojisan/master/sakura4.jpg") # 別のおじさん
plot(ojisan, axes = FALSE)

この画像とDJタカヤナギ=サンの画像を用いて、クソコラを作ります。 まずresize()を用いて、2つの画像のサイズを揃えます。

dj_mod <- dj %>% resize(size_x = 500, size_y = 500)
ojisan_mod <- ojisan %>% resize(size_x = 500, size_y = 500)

次におじさんの画像から顔画像を抽出します。 この際MS FACE APIを利用します。 本APIの利用方法については以下の記事等をご参照ください。

MS_FACE_KEY <- "取得したスクリプトキー"

なお、APIを利用する際にいったんsave.image()を用いて、画像を一時ファイルに保存しています。

tmp <- tempfile(fileext = ".png")
ojisan_mod %>% save.image(tmp)

library("httr")
url_base <- "https://westus.api.cognitive.microsoft.com/face/v1.0/detect"
result <- POST(url_base, 
               body = upload_file(tmp), 
               query = list(returnFaceAttributes="age,gender,headPose,smile,facialHair,glasses,emotion", 
                            language="en"), 
               add_headers(.headers = c(`Content-Type`="application/octet-stream", 
                                        `Ocp-Apim-Subscription-Key`=MS_FACE_KEY
               )
               )
) %>% content()
bbox <- result[[1]]$faceRectangle
ojisan_sub <- ojisan_mod %>% imsub(x %inr% c(bbox$left, bbox$left + bbox$width),
                                   y %inr% c(bbox$top, bbox$top + bbox$height))
plot(ojisan_sub, axes = FALSE)

抽出した顔画像をDJタカヤナギ=サンの画像に重ねてみましょう。 isoblur()でぼかした後、imdraw()で画像を重ねています。 これはこれで味わい深いですが、ちょっと顔画像が大きいですね。

ojisan_blur <- ojisan_sub %>% isoblur(sigma = 5)
ojisan_pos_x <- 100
ojisan_pos_y <- 200
dj_ojisan <- dj %>% imdraw(ojisan_blur, x = ojisan_pos_x, y = ojisan_pos_y, opacity = 0.9)
plot(dj_ojisan, axes = FALSE)

imresize()でscaleを50%に指定して縮小して重ねることにします。 だいぶ自然なクソコラになってきましたね。

ojisan_blur_half <- ojisan_sub %>% isoblur(sigma = 5) %>% imresize(scale = 0.5)
dj_ojisan2 <- dj %>% imdraw(ojisan_blur_half, x = ojisan_pos_x, y = ojisan_pos_y, opacity = 0.9)
plot(dj_ojisan2, axes = FALSE)

それでは最後の仕上げです。 わかりやすいように赤い円で強調し文字を加えます。

par(family="Hiragino Kaku Gothic Pro W6")
plot(dj_ojisan2, axes = FALSE)
highlight(px.circle(r = bbox$width*0.5*1.1, x = ojisan_pos_x*2.6, y = ojisan_pos_y*2.5), col = "red")
text(x = width(dj)/2, y = height(dj)-100, labels = "おわかりいただけただろうか", col = "white", cex = 1.2)

いかがでしたか? Rだけで自然な心霊写真が作れましたね。

今回使ったimagerパッケージの機能はどれも基本的なものです。 公式サイトには充実した機能紹介があります。ぜひ参考にして皆さんもクソコラ製作を効率化してみてください。

Enjoy!!!