0
0

Pythonを用いた総当たりステッチ処理

Posted at

はじめに

このプログラムは、OpenCVライブラリを使用して、画像をステッチし、成功した画像と失敗した画像を分類します。
また、ステッチ成功した画像を保存し、最終的にすべての成功した画像を1つのフォルダにコピーします。

実行環境

python-version 3.8.8
cv2-version 4.7.0

必要なライブラリのインストール

まず、必要なライブラリをインストールします。
以下のコマンドを実行してください。

pip install opencv-python-headless

プログラムの全体像

以下がプログラムの全体像です。
このプログラムを順を追って説明していきます。

import cv2
import os
import shutil
import glob
import copy
import re

# 総当たりでステッチ処理
def stich_round_robin(image_files, save_dir):
    # スキャンモードのStitcherクラスを作成する
    stitcher_scans = cv2.Stitcher_create(cv2.Stitcher_SCANS) 
    # ステッチ成功した画像パスリスト
    success_image_filed = []
    # ステッチ失敗した画像パスリスト
    false_image_files = copy.copy(image_files)
    
    for i in range(0, len(image_files) - 1):
        for j in range(i + 1, len(image_files)):
            # 対象画像読み込み
            images = [cv2.imread(image_files[i]), cv2.imread(image_files[j])]
            # スキャンモードで画像をステッチ(つなぎ合わせ)する
            status_scans, pano_scans = stitcher_scans.stitch(images)
            if status_scans == cv2.Stitcher_OK:
                file_name_i = os.path.splitext(os.path.basename(image_files[i]))[0]
                file_name_j = os.path.splitext(os.path.basename(image_files[j]))[0]
                # 成功したステッチ画像を保存
                new_file_name = re.sub(r'(_\w+)\1', r'\1', f'{file_name_i}_{file_name_j}')
                save_path = os.path.join(save_dir, f'{new_file_name}.jpg')
                cv2.imwrite(save_path, pano_scans)
                success_image_filed.append(save_path)
                # ステッチ失敗した画像パスリストから削除
                for image_file in [image_files[i], image_files[j]]:
                    if image_file in false_image_files:
                        false_image_files.remove(image_file)
                print(f'成功:{file_name_i}{file_name_j}')
            else:
                print(f'失敗:ステータスコード={status_scans}')
    
    return success_image_filed, false_image_files

# 画像ファイルを読み込んでリストにする
target_dir = r'./work/'
result_dir = r'./result/'
image_files = glob.glob(f'{target_dir}*.jpg')
cnt = 0
s_list, f_list = stich_round_robin(image_files, target_dir)
print('結果\n成功\n', s_list)
print('失敗\n', f_list)
for f_img in f_list:
    img_name = os.path.basename(f_img)
    shutil.copy(f_img, f'{result_dir}/{img_name}')

flag = len(s_list)
while flag > 1:
    s_list, f_list = stich_round_robin(s_list, target_dir)
    print('結果\n成功\n', s_list)
    print('失敗\n', f_list)
    for f_img in f_list:
        img_name = os.path.basename(f_img)
        shutil.copy(f_img, f'{result_dir}/{img_name}')
    flag = len(s_list)

img_name = os.path.basename(s_list[0])
shutil.copy(s_list[0], f'{result_dir}/{img_name}')

コードの解説

1. ライブラリのインポート

必要なライブラリをインポートします。

import cv2
import os
import shutil
import glob
import copy
import re

2. 総当たりでステッチ処理を行う関数 stich_round_robin

この関数は指定された画像ファイルリストに対して総当たりでステッチ処理を行います。

def stich_round_robin(image_files, save_dir):
    stitcher_scans = cv2.Stitcher_create(cv2.Stitcher_SCANS) 
    success_image_filed = []
    false_image_files = copy.copy(image_files)
    
    for i in range(0, len(image_files) - 1):
        for j in range(i + 1, len(image_files)):
            images = [cv2.imread(image_files[i]), cv2.imread(image_files[j])]
            status_scans, pano_scans = stitcher_scans.stitch(images)
            if status_scans == cv2.Stitcher_OK:
                file_name_i = os.path.splitext(os.path.basename(image_files[i]))[0]
                file_name_j = os.path.splitext(os.path.basename(image_files[j]))[0]
                new_file_name = re.sub(r'(_\w+)\1', r'\1', f'{file_name_i}_{file_name_j}')
                save_path = os.path.join(save_dir, f'{new_file_name}.jpg')
                cv2.imwrite(save_path, pano_scans)
                success_image_filed.append(save_path)
                for image_file in [image_files[i], image_files[j]]:
                    if image_file in false_image_files:
                        false_image_files.remove(image_file)
                print(f'成功:{file_name_i}{file_name_j}')
            else:
                print(f'失敗:ステータスコード={status_scans}')
    
    return success_image_filed, false_image_files

3. 画像ファイルを読み込んでリストにする

指定されたディレクトリから画像ファイルを読み込みます。

target_dir = r'./work/'
result_dir = r'./result/'
image_files = glob.glob(f'{target_dir}*.jpg')
cnt = 0
s_list, f_list = stich_round_robin(image_files, target_dir)
print('結果\n成功\n', s_list)
print('失敗\n', f_list)
for f_img in f_list:
    img_name = os.path.basename(f_img)
    shutil.copy(f_img, f'{result_dir}/{img_name}')

4. ステッチ処理を繰り返す

成功したステッチ画像をさらにステッチする処理を繰り返します。

flag = len(s_list)
while flag > 1:
    s_list, f_list = stich_round_robin(s_list, target_dir)
    print('結果\n成功\n', s_list)
    print('失敗\n', f_list)
    for f_img in f_list:
        img_name = os.path.basename(f_img)
        shutil.copy(f_img, f'{result_dir}/{img_name}')
    flag = len(s_list)

img_name = os.path.basename(s_list[0])
shutil.copy(s_list[0], f'{result_dir}/{img_name}')

実行方法

1.必要なライブラリをインストールします。
2.スクリプトを保存し、Python環境で実行します。
3../work/ フォルダに画像ファイルを配置します。
4.スクリプトを実行すると、ステッチされた画像が ./result/ フォルダに保存されます。

まとめ

この記事では、OpenCVを使用して画像を総当たりでステッチするPythonプログラムについて説明しました。このプログラムを応用することで、複数の画像を自動的に結合する処理を簡単に実現できます。ぜひ試してみてください。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0