OpenCVのStitcherクラスを使った画像のパノラマ合成

概要

この記事では複数の画像からパノラマ画像を作る機能についてご紹介します、単純につなげるのではなく特徴検出等の応用で、各画像の重なる部分を検出して結合するロジックとなっています。OpenCVのStitcherクラスは、複数の画像を一つの画像につなぎ合わせるための強力なツールです。パノラマモードは、一連の画像を水平方向につなげて広範囲の風景をカバーするのに適しています。例えば、風景写真や建物の全景などを撮影する際に使用します。一方、スキャンモードは、一連の画像を上下左右につなげて、書類のスキャンや大きなポスターの撮影などに適しています。これらのモードを適切に使い分けることで、さまざまなシチュエーションでの画像処理を効率的に行うことができます。
特徴検出については以下の記事で紹介しています。

OpenCVのFeature2Dクラスを使った特徴点抽出とマッチング

OpenCVのORB_create関数を使ったORB特徴点の抽出とマッチング

出力結果

OpenCVのStitcherクラスを使った画像のパノラマ合成

サンプル画像

プログラム全体

#解説1 import cv2 import matplotlib.pyplot as plt #解説2 # 画像を読み込む img1 = cv2.imread('fuji_1.jpg') img2 = cv2.imread('fuji_2.jpg') img3 = cv2.imread('fuji_3.jpg') img4 = cv2.imread('fuji_4.jpg') # 画像のリストを作成する images = [img1, img2, img3, img4] #解説3 # GPUを使用すべきかどうかをチェックする use_gpu = cv2.cuda.getCudaEnabledDeviceCount() > 0 # パノラマモードのStitcherクラスを作成する if not use_gpu: stitcher_panorama = cv2.Stitcher_create(cv2.Stitcher_PANORAMA) else: cv2.Stitcher_create(cv2.Stitcher_PANORAMA, True) # パノラマモードで画像をステッチ(つなぎ合わせ)する status_panorama, pano_panorama = stitcher_panorama.stitch(images) # スキャンモードのStitcherクラスを作成する if not use_gpu: stitcher_scans = cv2.Stitcher_create(cv2.Stitcher_SCANS) else: cv2.Stitcher_create(cv2.Stitcher_SCANS, True) # スキャンモードで画像をステッチ(つなぎ合わせ)する status_scans, pano_scans = stitcher_scans.stitch(images) #解説4 # ステータスがOKなら、画像を表示する fig, axs = plt.subplots(1, 2, figsize=(20, 10)) if status_panorama == cv2.Stitcher_OK: axs[0].imshow(cv2.cvtColor(pano_panorama, cv2.COLOR_BGR2RGB)) axs[0].set_title('パノラマモード') axs[0].axis('off') else: # パノラマモードでのステッチ中にエラーが発生した場合、ステータスコードを表示する print('パノラマモードでのステッチ中にエラーが発生しました、ステータスコード =', status_panorama) if status_scans == cv2.Stitcher_OK: axs[1].imshow(cv2.cvtColor(pano_scans, cv2.COLOR_BGR2RGB)) axs[1].set_title('スキャンモード') axs[1].axis('off') else: # スキャンモードでのステッチ中にエラーが発生した場合、ステータスコードを表示する print('スキャンモードでのステッチ中にエラーが発生しました、ステータスコード =', status_scans) plt.show()

解説

解説1: ライブラリのインポート

import cv2 import matplotlib.pyplot as plt

この部分では、プログラムで必要なライブラリをインポートしています。 今回は入出力が両方画像なので、以下の2ライブラリのみで実行できます。 cv2はOpenCVという画像処理ライブラリで、画像の読み込みや画像処理などを行うために必要です。 matplotlib.pyplotはグラフ描画ライブラリで、画像を表示するために使用します。

解説2: 画像の読み込みとリスト作成

# 画像を読み込む img1 = cv2.imread('fuji_1.jpg') img2 = cv2.imread('fuji_2.jpg') img3 = cv2.imread('fuji_3.jpg') img4 = cv2.imread('fuji_4.jpg') # 画像のリストを作成する images = [img1, img2, img3, img4]

ここでは、cv2.imread関数を使って4つの画像ファイルを読み込み、それらをリストに格納しています。後のつなぎ合わせの処理の時に、一気に画像を読み込むために配列として保持しています、この方が1変数で複数画像が扱えるので勝手も良くなります。

解説3: Stitcherクラスの作成と画像のステッチ

# GPUを使用すべきかどうかをチェックする use_gpu = cv2.cuda.getCudaEnabledDeviceCount() > 0 # パノラマモードのStitcherクラスを作成する if not use_gpu: stitcher_panorama = cv2.Stitcher_create(cv2.Stitcher_PANORAMA) else: cv2.Stitcher_create(cv2.Stitcher_PANORAMA, True) # パノラマモードで画像をステッチ(つなぎ合わせ)する status_panorama, pano_panorama = stitcher_panorama.stitch(images) # スキャンモードのStitcherクラスを作成する if not use_gpu: stitcher_scans = cv2.Stitcher_create(cv2.Stitcher_SCANS) else: cv2.Stitcher_create(cv2.Stitcher_SCANS, True) # スキャンモードで画像をステッチ(つなぎ合わせ)する status_scans, pano_scans = stitcher_scans.stitch(images)

この部分では、パノラマモードとスキャンモードの2つのStitcherクラスを作成し、それぞれのモードで画像をステッチ(つなぎ合わせ)しています。Stitcherクラスは、複数の画像を一つの画像につなぎ合わせるためのクラスです。 パノラマモードは、一連の画像を一つのパノラマ画像にステッチするためのモードです。このモードでは、画像間の相対的な位置関係やカメラの動き(回転やズームなど)を考慮して、画像をステッチします。パノラマモードは、風景写真のステッチングや360度のパノラマ画像の作成などに使用されます。 一方でスキャンモードは、スキャナーから得られる一連の画像を一つの画像にステッチするためのモードです。このモードでは、画像間の相対的な位置関係を考慮して、画像をステッチしますが、カメラの動きは考慮しません。これは、スキャナーから得られる画像は、カメラの動きがないと仮定できるためです。スキャンモードは、書類のスキャンなどに使用されます。

解説4: 画像の表示

# ステータスがOKなら、画像を表示する fig, axs = plt.subplots(1, 2, figsize=(20, 10)) if status_panorama == cv2.Stitcher_OK: axs[0].imshow(cv2.cvtColor(pano_panorama, cv2.COLOR_BGR2RGB)) axs[0].set_title('パノラマモード') axs[0].axis('off') else: # パノラマモードでのステッチ中にエラーが発生した場合、ステータスコードを表示する print('パノラマモードでのステッチ中にエラーが発生しました、ステータスコード =', status_panorama) if status_scans == cv2.Stitcher_OK: axs[1].imshow(cv2.cvtColor(pano_scans, cv2.COLOR_BGR2RGB)) axs[1].set_title('スキャンモード') axs[1].axis('off') else: # スキャンモードでのステッチ中にエラーが発生した場合、ステータスコードを表示する print('スキャンモードでのステッチ中にエラーが発生しました、ステータスコード =', status_scans) plt.show()

最後に、ステッチングの結果を表示しています。ステッチングが成功した場合(ステータスがOKの場合)、ステッチングした画像を表示します。ステッチングが失敗した場合は、エラーメッセージとステータスコードを表示します。これにより、何が問題だったのかを後で調査することができます。

おまけ

ちなみに、広範囲の視野をカバーするために産業用カメラでは魚眼レンズがあります(詳細は下記を参照してください)。これを使用すると、一度に180度以上の視野を撮影することが可能になります。しかし、魚眼レンズの特性上、画像は強い歪み(特に画像の周辺部)を伴いますが、TheImagingSource社のSDKで歪み補正をすることができます。
https://www.argocorp.com/cam/ImagingSource/EntaniyaFisheye.html