間違い探しに関しては、グレースケールにしてから比較し、違いの部分を閾値判定で2値化する方法がWebで紹介されているが、色の判定に難がある傾向がみられた。
そこで、それぞれの画像をR、G、Bに分けてから、RとR、GとG、BとBを比較し、違いの部分を閾値判定で2値化してから合成する方法を検討した。
R、G、Bそれぞれの2値化は簡単に出来たが、統合に手間取った。AIに質問しても、まともな答えが返ってこない。
Rに統合したいのに、RGB画像にしてからGBを消してRのみにする答えしか返らない。
RGB別の画像を表示しても、きちんとできており、全く問題無いのに統合ができない。
# RGB別の画像を表示する関数
def display_images3(title, binary_r, binary_g, binary_b):
ut_now = datetime.datetime.now()
print(ut_now, 'RGB別の画像を表示')
# 画像を表示用にリサイズ
resized_image_r = cv2.resize(binary_r, (600, 600))
resized_image_g = cv2.resize(binary_g, (600, 600))
resized_image_b = cv2.resize(binary_b, (600, 600))
# 結果表示用のウィンドウを作成
layout = [
[sg.Text(title)],
[sg.Image(data=cv2.imencode('.png', resized_image_r)[1].tobytes()),
sg.Image(data=cv2.imencode('.png', resized_image_g)[1].tobytes()),
sg.Image(data=cv2.imencode('.png', resized_image_b)[1].tobytes())]
]
# ウィンドウを表示
window = sg.Window('Color Differences with Opening', layout)
while True:
event, values = window.read()
if event == sg.WIN_CLOSED:
break
window.close()
結局何が悪かったかと言えば、2値化しているのに、色情報を持っていると勘違いしていたということ。
単なる白黒画像が3つあると考えれば、足し算をすれば合成できることに気づかなかった!
ぼけ始め?
def compare_images(common_a, common_b, threshold=30):
# 画像を読み込む
image1 = common_a
image2 = common_b
# RGBチャンネルを分割
ut_now = datetime.datetime.now()
print(ut_now, 'RGBチャンネルを分割')
r1, g1, b1 = cv2.split(image1)
r2, g2, b2 = cv2.split(image2)
# それぞれのチャンネルで差分を計算
ut_now = datetime.datetime.now()
print(ut_now, 'それぞれのチャンネルで差分を計算')
diff_r = cv2.absdiff(r1, r2)
diff_g = cv2.absdiff(g1, g2)
diff_b = cv2.absdiff(b1, b2)
# 閾値を適用して二値化
ut_now = datetime.datetime.now()
print(ut_now, '閾値を適用して二値化')
_, binary_r = cv2.threshold(diff_r, threshold, 255, cv2.THRESH_BINARY)
_, binary_g = cv2.threshold(diff_g, threshold, 255, cv2.THRESH_BINARY)
_, binary_b = cv2.threshold(diff_b, threshold, 255, cv2.THRESH_BINARY)
# display_images3('RGBをそれぞれ二値化', binary_r, binary_g, binary_b)
# RGBをRに合成して差分が大きい部分のみを抽出
ut_now = datetime.datetime.now()
print(ut_now, 'RGBをRに合成して差分が大きい部分のみを抽出')
binary_r = binary_b + binary_g + binary_r
diff_combined = cv2.merge([binary_r, np.zeros_like(binary_g), np.zeros_like(binary_b)])
ここからは早く、違いの部分を四角で囲み表示するパターンと、統合された2値化画像を表示するパターンを並べて表示できるようになった。
# 差分がある領域を赤い四角で囲む
ut_now = datetime.datetime.now()
print(ut_now, '差分がある領域を30ドット大きい赤い四角で囲む')
for contour in contours:
if cv2.contourArea(contour) > 5: # 小さな変更を無視する
x, y, w, h = cv2.boundingRect(contour)
# 画像の境界を超えないように調整
x = max(0, x - 15)
y = max(0, y - 15)
xw = min(image1.shape[1], x + w + 30)
yh = min(image1.shape[0], y + h + 30)
# 四角を30ドット大きく描画
cv2.rectangle(image1, (x, y), (xw, yh), (0, 0, 255), 3)
小さな画像を拡大してから変形した画像でマッチングしていると、細かな誤検出が多く出ることもあるが、実際は3264x2448の撮影画像を微妙にマッチングすることを想定しているため、特に問題ないと判断し、検査プログラム作成に進むことにした。
コメント
コメントを投稿