縦横比を無視してリサイズする画像表示関数のコードはこちら。
# 画像を表示する関数
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
次は、間違い探しに進む。
コメント
コメントを投稿