🐍
[Python] OpenCVによる2次元ノルムを使った画像比較について
はじめに
OpenCVで画像比較をしていました。
大した知識がないのでインターネットで調べて、2次元ノルムを使った方法を採用してみました。
しかし、目につくコードがどうやら間違っているようなので正しいと思われるコードを乗せることにしました。
環境
python
Python 3.10.4 (tags/v3.10.4:9d38120, Mar 23 2022, 23:13:41) [MSC v.1929 64 bit (AMD64)]
OpenCv
>>> cv2.__version__
'4.5.5'
正しいと思われるコード
以下は、どの程度に通っているかパーセントで取得できます。
python
import numpy as np
import cv2
def getMaxL2(height, width, dtype=np.uint8):
info = np.iinfo(dtype)
white = np.ones((height, width, 3), dtype) * info.min
black = np.ones((height, width, 3), dtype) * info.max
return cv2.norm(white, black, cv2.NORM_L2)
def getSimilarity(image1, image2, maxL2=None):
if image1.shape != image2.shape:
return 0.0
if maxL2 is None:
maxL2 = getMaxL2(image1.shape[0], image1.shape[1])
l2 = cv2.norm(image1, image2, cv2.NORM_L2)
similarity = 1 - l2 / maxL2
print(f"Similarity = {similarity}, L2 = {l2}")
return similarity
目につく間違い
インターネットで調べてみると、以下のようなコードが紹介されています。
一致している場合は、1.0
を返して正しいように思えます。
しかし、一致していない場合は、マイナスの値が帰ってきてどの程度に通っているか判断が付きません。
python
def getSimilarityNG(image1, image2):
if image1.shape != image2.shape:
return 0.0
l2 = cv2.norm(image1, image2, cv2.NORM_L2)
similarity = 1 - l2 / (image1.shape[0] * image1.shape[1])
print(f"Similarity = {similarity}, L2 = {l2}")
return similarity
テストコード
OpenCVは、RGBではなくてBGRだったので名前の付け方がおかしいですが見なかったことにしてください。
python
white = np.ones((3, 3, 3), np.uint8) * 0
gray = np.ones((3, 3, 3), np.uint8) * 127
black = np.ones((3, 3, 3), np.uint8) * 255
red = np.ones((3, 3, 3), np.uint8) * np.array((255, 0, 0), dtype=np.uint8)
green = np.ones((3, 3, 3), np.uint8) * np.array((0, 255, 0), dtype=np.uint8)
blue = np.ones((3, 3, 3), np.uint8) * np.array((0, 0, 255), dtype=np.uint8)
yellow = np.ones((3, 3, 3), np.uint8) * np.array((255, 255, 0), dtype=np.uint8)
magenta = np.ones((3, 3, 3), np.uint8) * np.array((255, 0, 255), dtype=np.uint8)
cyan = np.ones((3, 3, 3), np.uint8) * np.array((0, 255, 255), dtype=np.uint8)
print("OK")
getSimilarity(white, black)
getSimilarity(black, black)
getSimilarity(white, gray)
getSimilarity(black, gray)
getSimilarity(red, white)
getSimilarity(red, black)
getSimilarity(red, green)
getSimilarity(red, magenta)
print("NG")
getSimilarityNG(white, black)
getSimilarityNG(black, black)
getSimilarityNG(white, gray)
getSimilarityNG(black, gray)
getSimilarityNG(red, white)
getSimilarityNG(red, black)
getSimilarityNG(red, green)
getSimilarityNG(red, magenta)
実行結果
OK
Similarity = 0.0, L2 = 1325.018867790191
Similarity = 1.0, L2 = 0.0
Similarity = 0.5019607843137255, L2 = 659.9113576837423
Similarity = 0.4980392156862745, L2 = 665.1075101064489
Similarity = 0.42264973081037416, L2 = 765.0
Similarity = 0.18350341907227385, L2 = 1081.8733752154178
Similarity = 0.18350341907227385, L2 = 1081.8733752154178
Similarity = 0.42264973081037416, L2 = 765.0
NG
Similarity = -146.22431864335456, L2 = 1325.018867790191
Similarity = 1.0, L2 = 0.0
Similarity = -72.32348418708247, L2 = 659.9113576837423
Similarity = -72.9008344562721, L2 = 665.1075101064489
Similarity = -84.0, L2 = 765.0
Similarity = -119.20815280171308, L2 = 1081.8733752154178
Similarity = -119.20815280171308, L2 = 1081.8733752154178
Similarity = -84.0, L2 = 765.0
Discussion