縦横比を無視してリサイズする画像表示関数のコードはこちら。

# 画像を表示する関数
def display_images(title, image_a, image_b):
    ut_now = datetime.datetime.now()
    print(ut_now, '画像を表示')
    # 画像を表示用にリサイズ(仮:縦横比無視)
    resized_image_a = cv2.resize(image_a, (900, 900))
    resized_image_b = cv2.resize(image_b, (900, 900))
    # 画像を表示
    layout = [
        [sg.Text(title)],
        [sg.Image(data=cv2.imencode('.png', resized_image_a)[1].tobytes()),
         sg.Image(data=cv2.imencode('.png', resized_image_b)[1].tobytes())],
        [sg.Button('Exit')]
    ]

    window = sg.Window('Image Display', layout, size=(1900, 1050), location=(0,0))

    while True:
        event, _ = window.read()
        if event == sg.WIN_CLOSED or event == 'Exit':
            break

    window.close()

画像が大きかろうが小さかろうが、縦が長かろうが横が長かろうが、900x900にリサイズして、並べて画面に表示する。

 動作チェック用なので、これで十分なのに、AIへの質問の仕方が悪いのか、いくら質問の仕方を変えても、画像によってはエラーが出る使えない答えしか返ってこない。


画像表示のコードができたので、間違い探しの画像を片側2500~6000dot程度の大きさに拡大し、GIMPで、10度傾けたり、遠近感を出したり、台形や、平行四辺形や、糸巻状、タル状にして、AKAZE検証用の画像を準備した。

検証用の画像で次の関数を使い、共通部分を抜き出せるようになり、間違い探しに進めるようになった。

# 特徴点を検出してマッチングし、変換行列を返す関数
def match_features(image_a, image_b):
    # AKAZE検出器の初期化
    akaze = cv2.AKAZE_create()
    # 画像から特徴点と記述子を検出
    kp1, des1 = akaze.detectAndCompute(image_a, None)
    kp2, des2 = akaze.detectAndCompute(image_b, None)
    # マッチング
    matcher = cv2.BFMatcher(cv2.NORM_HAMMING)
    matches = matcher.knnMatch(des1, des2, k=2)
    # マッチング結果から良いペアをフィルタリング
    good_matches = [m for m, n in matches if m.distance < 0.75 * n.distance]
    # Homographyを計算するために点を抽出
    if len(good_matches) > 10:
        src_pts = np.float32([kp1[m.queryIdx].pt for m in good_matches]).reshape(-1, 1, 2)
        dst_pts = np.float32([kp2[m.trainIdx].pt for m in good_matches]).reshape(-1, 1, 2)
        # Homographyを計算
        M, _ = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0)
        return M
    else:
        return None

# 画像をアラインメントする関数
def align_image(image, matrix, width, height):
    # 画像を変形
    aligned_image = cv2.warpPerspective(image, matrix, (width, height))
    return aligned_image

# 共通部分を抽出する関数
def crop_common_area(aligned_a, image_b):
    # マスクを作成して共通部分を抽出
    mask_a = cv2.cvtColor(aligned_a, cv2.COLOR_BGR2GRAY) > 0
    mask_b = cv2.cvtColor(image_b, cv2.COLOR_BGR2GRAY) > 0
    common_mask = np.logical_and(mask_a, mask_b)
    # マスクを適用して共通部分のみを抽出
    common_a = cv2.bitwise_and(aligned_a, aligned_a, mask=common_mask.astype(np.uint8))
    common_b = cv2.bitwise_and(image_b, image_b, mask=common_mask.astype(np.uint8))
    return common_a, common_b

# 画像を並べて表示
display_images('Original Images', image_a, image_b)

# 画像をマッチングしてアラインメント
M = match_features(image_a, image_b)
if M is not None:
    aligned_a = align_image(image_a, M, image_b.shape[1], image_b.shape[0])
    # アラインメントされた画像を並べて表示
    display_images('Aligned Images', aligned_a, image_b)
    # 共通部分を抽出
    common_a, common_b = crop_common_area(aligned_a, image_b)
    # 共通部分を並べて表示
    display_images('Cropped Common Area', common_a, common_b)
    cv2.imwrite('c:/code/py311/trial/AKAZE/common_a.png', common_a)
    cv2.imwrite('c:/code/py311/trial/AKAZE/common_b.png', common_b)
else:
    sg.popup('Error', 'Not enough matches found to align images.')

しかしながら、4000x3000dot以上など、画像が大きくなると処理に少し時間がかかりすぎるため、AIに質問し、一部を並列処理とすることで、若干の高速化を図った。

# 特徴点検出と記述子計算を行う関数
def detect_and_compute(image, akaze):
    keypoints, descriptors = akaze.detectAndCompute(image, None)
    return keypoints, descriptors

# 特徴点を検出してマッチングし、変換行列を返す関数
def match_features(image_a, image_b):
    # AKAZE検出器の初期化
    akaze = cv2.AKAZE_create()
    ut_now = datetime.datetime.now()
    print(ut_now, '画像から特徴点と記述子を検出')
    # ThreadPoolExecutorを使用して、並列で特徴点検出と記述子計算を行う
    with ThreadPoolExecutor(max_workers=2) as executor:
        # 各画像に対して関数を実行
        future_a = executor.submit(detect_and_compute, image_a, akaze)
        future_b = executor.submit(detect_and_compute, image_b, akaze)
       
        # 結果を待つ
        kp1, des1 = future_a.result()
        kp2, des2 = future_b.result()

    # マッチング
    ut_now = datetime.datetime.now()
    print(ut_now, 'マッチング')
    matcher = cv2.BFMatcher(cv2.NORM_HAMMING)
    matches = matcher.knnMatch(des1, des2, k=2)
    # マッチング結果から良いペアをフィルタリング
    ut_now = datetime.datetime.now()
    print(ut_now, 'マッチング結果から良いペアをフィルタリング')
    good_matches = [m for m, n in matches if m.distance < 0.75 * n.distance]
    # Homographyを計算するために点を抽出
    if len(good_matches) > 10:
        ut_now = datetime.datetime.now()
        print(ut_now, 'Homographyを計算するために点を抽出して計算')
        src_pts = np.float32([kp1[m.queryIdx].pt for m in good_matches]).reshape(-1, 1, 2)
        dst_pts = np.float32([kp2[m.trainIdx].pt for m in good_matches]).reshape(-1, 1, 2)
        # Homographyを計算
        M, _ = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0)
        return M
    else:
        return None

# 画像をアラインメントする関数
def align_image(image, matrix, width, height):
    ut_now = datetime.datetime.now()
    print(ut_now, '画像をアラインメント')
    # 画像を変形
    aligned_image = cv2.warpPerspective(image, matrix, (width, height))
    return aligned_image

# 共通部分を抽出する関数
def crop_common_area(aligned_a, image_b):
    # マスクを作成して共通部分を抽出
    ut_now = datetime.datetime.now()
    print(ut_now, 'マスクを作成して共通部分を抽出')
    mask_a = cv2.cvtColor(aligned_a, cv2.COLOR_BGR2GRAY) > 0
    mask_b = cv2.cvtColor(image_b, cv2.COLOR_BGR2GRAY) > 0
    common_mask = np.logical_and(mask_a, mask_b)
    # マスクを適用して共通部分のみを抽出
    ut_now = datetime.datetime.now()
    print(ut_now, 'マスクを適用して共通部分のみを抽出')
    common_a = cv2.bitwise_and(aligned_a, aligned_a, mask=common_mask.astype(np.uint8))
    common_b = cv2.bitwise_and(image_b, image_b, mask=common_mask.astype(np.uint8))
    return common_a, common_b

次は、間違い探しに進む。



コメント

このブログの人気の投稿