Chapter 05

問題点を解決しよう

eetann / えーたん
eetann / えーたん
2020.12.09に更新

この章の概要

モザイクアート化したい画像とブロック画像のリサイズや類似度の計算での問題点を解決します。

問題点1 画像が歪む

問題点

モザイクアート化したい画像の領域とブロック画像が、必ず同じアスペクト比とは限らないです。ブロック画像をモザイクアート化したい画像の領域にあわせてそのままリサイズしようとすると、画像が歪みます。
画像が歪む

解決法

アスペクト比を合わせるために画像をトリミングしてから比較することにします。
ブロック画像の縦と横どちらを切り抜いて使用するかは、画像の高さを1としたときの幅の大きさで決めます。

ブロック画像の幅のほうが大きい場合

置き換えたい領域の高さにあわせてブロック画像を縮小し、切り抜く。
ブロック画像の幅のほうが大きい場合

ブロック画像の幅のほうが小さい場合

置き換えたい領域のにあわせてブロック画像を縮小し、切り抜く。
ブロック画像の幅のほうが小さい場合

プログラム

ブロック画像Ibをモザイクアートのある領域Imの大きさにあわせてトリミング&縮小する関数trisizeを書きます。
画像の縮小はskimage.transform.resizeを用います。

import skimage.transform
def trisize(Hm, Wm, Ib):
    Hb = Ib.shape[0]
    Wb = Ib.shape[1]
    ratio_m = Wm / Hm
    ratio_b = Wb / Hb
    if ratio_b == ratio_m:
        T = skimage.transform.resize(Ib, (Hm, Wm, 3), anti_aliasing=True)
    elif ratio_b > ratio_m:
        T = skimage.transform.resize(Ib, (Hm, np.floor(ratio_b*Hm), 3), anti_aliasing=True)
        T = T[:, :Wm]
    else:
        T = skimage.transform.resize(Ib, (np.floor(Wm*Hb/Wb), Wm, 3), anti_aliasing=True)
        T = T[:Hm, :]
    return T

Im = I[:100, :180, :]
Ib = skimage.io.imread(imageURLs[2])
T = trisize(Im.shape[0], Im.shape[1], Ib)

images = [Im, Ib, T]
for i, Itmp in enumerate(images, 1):
    plt.subplot(1, 3, i)
    plt.imshow(Itmp)
    plt.axis("off")
    print(Itmp.shape)
plt.gcf().set_size_inches(15, 15)
plt.show()

ちょっと長いなと思ったかもしれませんが、後半は確認のために画像を表示するコードです。
if~elif~elseで各画像の高さを1とした時の幅によって縮小サイズと切り抜く領域を変えています。

左がモザイクアートのある領域、中央がブロック画像、右がモザイクアートの領域にあわせてトリミング&縮小したブロック画像です。print(Itmp.shape)の出力で確かに大きさが一致していることがわかります。
trisize実行結果

問題点2 時間がかかる

問題点

比較画像の画素ごとの色差の合計を計算し、色差の合計が最も小さい組み合わせが一番類似度が大きいということにしました。この処理は、モザイクアート化したい画像のすべての切り分けた領域に対して行うため、とても時間がかかってしまいます。また、画像が大きければ大きいほど時間がかかります。

解決法

改めてモザイクアートについて考えてみます。
モザイクアートでは、色あいが似ている画像で置き換えればよいです。つまり、この範囲はだいたいこの色という情報がわかればいいので、画像の全部の画素を使って計算するのはやめます。8x8に縮小した画像を類似度の計算に用いることにします。
類似度計算のための画像の変換手順

プログラム

8x8に縮小した画像をRGBからL*a*bに変換した画像を返すsmall_lab関数として書きます。

def small_lab(I):
    return skimage.color.rgb2lab(skimage.transform.resize(I, (8, 8, 3), anti_aliasing=True))

このsmall_lab関数の返り値 = 8x8に縮小したL*a*b色空間の画像を類似度の計算に用います。