seam carving?
seam carving とは、画像のリサイズをおこなうときに単純な縮小ではなく、
「いい感じ」に画像のいらない部分をつぶしてくれるアルゴリズムです。
この動画 をみると、一体何が起こるのかがわかりやすいと思います。
初めて見るときはまるで魔法のように見えてしまいます。
SigGraph2007 で提案された方法なので、結構昔からある方法です。1
やってみる
IPython Notebook 上で試していたので、notebook上でないと動かないと思います
import matplotlib.pyplot as plt
from skimage import transform
from skimage import filters
import cv2
%matplotlib inline
def carve(image, num, mode='vertical'):
"""「切り取り」をする関数"""
# 画像をグレイスケールに変換し、Sobel gradient magnitude representation を計算します。
# これは "energy map" として、seam carving アルゴリズムに必要な情報となります。
# energy map には、必ずしも Sobel を使う必要はありません。
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
mag = filters.sobel(gray.astype("float"))
carved = transform.seam_carve(image, mag, mode=mode, num=num) # 切り取り!
carved = (carved * 255).astype('uint8')
return carved
# 元画像を読み込みます
original_image_path = 'images/original/japan.jpg'
# load the image
image = cv2.imread(original_image_path)
# show the original image
plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
# 少しずつ切り取り
carved = image
for i in range(21):
carved = carve(carved, num=10, mode='vertical')
plt.imsave('images/carved/japan_v_{}.jpg'.format(10*i), cv2.cvtColor(carved, cv2.COLOR_BGR2RGB))
で、seam carving ってどういうアルゴリズム?
"seam" とは「縫い目」、"carving" とは「彫刻」という意味です。
ここで、「縫い目」とは、画像に対して「上から下」または「左から右」に引かれた線を意味します。
この縫い目が、画像の「どうでもいい部分」を横切るように設定してあげます。
(例えば、下の図 2 の赤い線が「縫い目」です)
縫い目に沿って画像を切り取り、うまいこと重ね合わせることで、冒頭の gif のような画像のリサイズを可能にします。
energy map 上での変化が小さくなるように画像を横切る線を計算したものが縫い目、seam です3。
今回の例では、横方向にしか縮めていませんが、もちろん縦方向へも縮めることが可能です。
また、縮めるだけではなく、拡大することも可能です。4
Deep Learning?
seam carving は Deep Learning ではありません。
が、energy map として Deep Learning で抽出した注目領域を使う等の工夫は今後出てくるかも知れません。
ギャラリー
うまくいかない画像も多いです。以下にはうまくいった例を載せます。
画像中に注目したい部分が分散して出現しているとうまくいきやすいです。
(例えばタージマハルでは尖塔が左右にうまく分散して写り、途中の何もない部分を切り取ることができる)
注目したい部分が一箇所だけしかない画像の場合、左端と右端を順番に切り取っていくような、あまりおもしろくない結果が得られることが多いです。
また、そもそも切り取る余地のない画像 (例えば画像いっぱいに猫が写っている写真など) も苦手でした。(これはそもそも切り取れないのだから仕方ない気がします)
タージマハル
九龍城
画像全体は横方向に縮んでいるのに、左側に見える赤い看板の文字は縮んだりしていないことが見えます。(看板自体は段々縮んでいます)
参考文献
- 紹介ブログ
- 論文
- Scikit-Image による実装