Python OpenCVで間違い探し画像の差分検出
いまものづくり補助金を使って新たなプロダクトを作っています。
これは肝入り案件です。
その中で、自動に汚れなどを検出する機能を導入する予定です。
エンジニアさんたちには発破をかけているのですが自分でも勉強してみよということで
Python OpenCVで間違い探し画像の自動検出
をしてみようと思います。
Pillow
Scikit-image
TensorFlow
Pytorch
でもできようようなので順次試そうかなと思います。
それではスタートです。
OpenCVで間違い探し画像の自動検出
画像の準備
フリーと書いてあったので拝借しました。
1分でできますか?
https://noukatu.com/difference/photo/841
Google Driveにこの画像を入れます。
google colabを開いてdriveをマウント
from google.colab import drive
drive.mount('/content/drive')
マウントの語源を調べてみた
中世英語の「mounten」(上に乗る、馬に乗る)が、現代の「mount」という動詞に発展しました。そこから、「mount」という言葉は「何かを上に置く」や「接続する」という意味だそうです。
画像A1と画像A2を変数に格納
before_image_path = '/content/drive/MyDrive/Project_folder/difference_detection/A1.png'
after_image_path = '/content/drive/MyDrive/Project_folder/difference_detection/A2.png'
OpenCVを使って差分検出
OpenCVをインストール
!pip install opencv-python
画像サイズを合わせるためにcv2.resizeを使う
cv2.resizeで同じサイズに
同サイズではないと二つの画像を左上の1行目、1列目からのピクセルを比較できなくなる。
import cv2
# 画像を読み込み
before_image = cv2.imread('/content/drive/MyDrive/A1.png')
after_image = cv2.imread('/content/drive/MyDrive/A2.png')
# 画像サイズを合わせるために、before_imageのサイズにafter_imageをリサイズ
after_image_resized = cv2.resize(after_image, (before_image.shape[1], before_image.shape[0]))
# リサイズ前後のサイズ確認
print(f"Before image size: {before_image.shape}")
print(f"After image original size: {after_image.shape}")
print(f"After image resized size: {after_image_resized.shape}")
Resizing successful!
cv2.cvtColor関数でグレースケールにしてmatplotlibで表示
cv2.cvtColor関数を使って、読み込んだ before_image と after_image をグレースケールに変換
グレースケールにするのは差分を抽出する際、色の情報が必要ない場合が多いためmatplotlib を使用してグレースケール画像を表示
グレースケールにすることでピクセル単位の明るさの数値を比較することで計算量が軽くなるようです。
plt.imshow関数でグレースケール画像を表示する際に、cmap='gray' を指定することで、グレースケールとして表示
import cv2
from matplotlib import pyplot as plt
# 画像の正しいパス
before_image_path = '/content/drive/MyDrive/Project_folder/difference_detection/A1.png'
after_image_path = '/content/drive/MyDrive/Project_folder/difference_detection/A2.png'
# 画像を読み込み
before_image = cv2.imread(before_image_path)
after_image = cv2.imread(after_image_path)
# グレースケールに変換
before_gray = cv2.cvtColor(before_image, cv2.COLOR_BGR2GRAY)
after_gray = cv2.cvtColor(after_image, cv2.COLOR_BGR2GRAY)
# グレースケール画像の確認
plt.figure(figsize=(10, 5))
plt.subplot(1, 2, 1)
plt.title("Before Image (Grayscale)")
plt.imshow(before_gray, cmap='gray')
plt.subplot(1, 2, 2)
plt.title("After Image (Grayscale)")
plt.imshow(after_gray, cmap='gray')
plt.show()
グレースケール
次に差分を計算し、閾値を設定し差分を強調
cv2.absdiff関数で2枚の画像のピクセルごとの差を計算します。
例として、2枚の画像の同じ場所にあるピクセルの明るさが次のようになっているとします。
画像1のピクセル: 100
画像2のピクセル: 150
このとき、2枚の画像の「差分」は 150 - 100 = 50 になります。
cv2.threshold関数で差分を強調するために、「しきい値処理」 を行います。
例えば、しきい値を 30 に設定するとします。
もし差分が 30より大きければ → 白(255)にする
もし差分が 30以下なら → 黒(0)にする
# 差分を計算
difference = cv2.absdiff(before_gray, after_gray)
# 差分データの一部を表示(最初の10x10ピクセル)
print("Difference (first 10x10 pixels):")
print(difference[:10, :10])
# 差分データの統計情報を表示
print("Difference Statistics:")
print(f"Min value: {difference.min()}")
print(f"Max value: {difference.max()}")
print(f"Mean value: {difference.mean()}")
# 差分を強調するためにしきい値処理
_, thresh = cv2.threshold(difference, 30, 255, cv2.THRESH_BINARY)
# 結果を表示(通常のサイズ)
plt.figure(figsize=(10, 5))
plt.subplot(1, 3, 1)
plt.title("Before Image (Grayscale)")
plt.imshow(before_gray, cmap='gray')
plt.subplot(1, 3, 2)
plt.title("After Image (Grayscale)")
plt.imshow(after_gray, cmap='gray')
plt.subplot(1, 3, 3)
plt.title("Difference (Thresholded)")
plt.imshow(thresh, cmap='gray')
plt.show()
# 差分画像を拡大表示
plt.figure(figsize=(15, 15)) # 画像の大きさを調整(幅15インチ、高さ15インチ)
plt.title("Difference Image (Enlarged)")
plt.imshow(difference, cmap='gray')
plt.show()
差分検出結果
画像の差分データはかなり重いのでサンプルとして最初の10×10ピクセルの差分データをprintしました。
最初の10×10ピクセルとは左上の1行目から、左から右へ10列
以下はBefor/Afterの画像の差分を計算しています。
1行目: [94 97 99 103 105 105 116 128 133 136]
差分画像の最小値、最大値、平均値などを出力して、差分の程度を確認
Differenceの白が濃いところが差分が多い箇所なのでそこに間違いがあります。
わかりづらいので赤くしてみました。
# 差分部分を赤色で表示
plt.figure(figsize=(10, 10))
plt.title("Difference Highlighted in Red")
plt.imshow(cv2.cvtColor(before_image_with_diff, cv2.COLOR_BGR2RGB)) # OpenCVのBGRからRGBに変換
plt.show()
まとめ
今回は、openCVのcvtColor関数を使い2枚の画像をグレースケールに変換。
つぎにabsdiff関数を使い2枚の画像の同じ位置のピクセルごとの差分を計算。
そしてthreshold関数を使い、閾値を設定することにより白と黒のカラーに仕分け。
最後に差分(間違い探し)を検出することに成功しました!