つれづれなる備忘録

日々の発見をあるがままに綴る

OpenCVの使い方21 ~ 画像ピラミッド2

 今回は前回の画像ピラミッドを応用した2つの画像のブレンディング処理について紹介する。

atatat.hatenablog.com

1. ピラミッド画像によるブレンディング

以下のりんごとオレンジの画像を左半分と右半分でブレンディングする。

"りんごとオレンジ"
りんごとオレンジ

ピラミッド画像によるブレンディング処理は、

  1. 使用する2枚の画像のガウシアンピラミッド画像を例えば6段階(512x512→16x16)を用意する。

  2. ガウシアンピラミッドから5段階のラプラシアンピラミッド画像を生成する。(6段階目の16x16はガウシアンピラミッド画像)

  3. 次に各段階ごとに得られたラプラシアンピラミッドをりんごは左半分、オレンジは右半分をつなぎ合わせた画像を作る。

  4. 最後にガウシアンピラミッドの6段階目の16x16の左側がりんご、右側がオレンジの画像をアップサンプリングして、5段階目の半分りんご、半分オレンジのラプラシアンピラミッドを加算する処理を元の画像512x512まで繰り返す。

2. ガウシアンピラミッドとラプラシアンピラミッドの生成

りんごの画像を読み込みsrc、オレンジの画像を読み込みsrc2とする。6段階のガウシアンピラミッドはG = cv2.pyrDown(G)とfor文を用いて再帰的に適用することで6段階のガウシアンピラミッドgpA, gpBが得られる。

G = src.copy()
gpA = [G]
for i in range(6):
    G = cv2.pyrDown(G)
    gpA.append(G)
G = src2.copy()
gpB = [G]
for i in range(6):
    G = cv2.pyrDown(G)
    gpB.append(G)

りんごのガウシアンピラミッドgpAを表示してみると、段階iが進むごとに低解像画像になっていることがわかる。

plt.figure(figsize=(9,6))
for i in range(6):
  plt.subplot(2,3,i+1)
  plt.imshow(gpA[i])

"りんごのガウシアンピラミッド"
りんごのガウシアンピラミッド

次にラプラシアンピラミッドを生成する。低解像度の画像をアップサンプリングしていくため、最も解像度が低いgpA[5]:16x16から処理を開始する。

# generate Laplacian Pyramid for A
lpA = [gpA[5]]
for i in range(5,0,-1):
    GE = cv2.pyrUp(gpA[i])
    L = cv2.subtract(gpA[i-1],GE)
    lpA.append(L)

plt.figure(figsize=(9,6))
for i in range(6):
  plt.subplot(2,3,i+1)
  plt.imshow(lpA[i])

最も低解像度の16x16以外は輪郭抽出したような画像になっている。

"ラプラシアンピラミッド"
ラプラシアンピラミッド

オレンジの画像についても同様に処理する。

lpB = [gpB[5]]
for i in range(5,0,-1):
    GE = cv2.pyrUp(gpB[i])
    L = cv2.subtract(gpB[i-1],GE)
    lpB.append(L)

3. ラプラシアンピラミッドのつなぎ合わせと再構成

りんごのラプラシアンピラミッドの左側lpA[:,0:int(cols/2)]とみかんのラプラシアンピラミッドの右側lpB[:,int(col/2):]をnp.hstack()を用いて段階ごとにつなぎあわせる。つなぎ合わせた結果はLSに格納する。

LS = []
for la,lb in zip(lpA,lpB):
    rows,cols,dpt = la.shape
    ls = np.hstack((la[:,0:int(cols/2)], lb[:,int(cols/2):]))
    LS.append(ls)
plt.figure(figsize=(9,6))
for i in range(6):
  plt.subplot(2,3,i+1)
  plt.imshow(LS[i])

"ラプラシアンピラミッドのつなぎ合わせ"
ラプラシアンピラミッドのつなぎ合わせ

再構成は最も解像度が低い16x16を32x32にアップサンプリングした画像と32x32のつなぎ合わせたラプラシアンピラミッドの画像を加算し、加算した画像を64x64にアップサンプリングし、64x64のつなぎ合わせたラプラシアンピラミッドを加算する。これを元の画素数の512x512になるまで繰り返す。

ls_ = LS[0]
plt.figure(figsize=(12,8))
for i in range(1,6):
    ls_ = cv2.pyrUp(ls_)
    ls_ = cv2.add(ls_, LS[i])
    plt.subplot(2,3,i)
    plt.imshow(ls_)

以下再構成の各段階での画像を確認すると、粗いブレンディング画像から細かいブレンディング画像に変化している様子がわかる。

"再構成"
再構成

最後にピラミッド画像を利用したブレンディング画像と2つの画像を直接つなぎ合わせたものと比較する。

direct = np.hstack((src[:,:int(cols/2)],src2[:,int(cols/2):]))
plt.figure(figsize=(10,8))
plt.subplot(1,2,1)
plt.imshow(direct)
plt.title('Direct Blending')
plt.subplot(1,2,2)
plt.imshow(ls_)
plt.title('Pyramid Blending')

直接つなぎ合わせた場合と比較して、りんごとオレンジの輪郭、表面が自然につながっていることがわかるが、元の画像自体がつなぎ合わせる上で、画像の明るさやりんごとオレンジのサイズが合っているなど工夫が必要そうだ。

"ブレンディング画像比較"
ブレンディング画像比較

4. まとめ

今回は画像ピラミッドを応用した2つの画像のブレンディング処理について紹介した。