图像比较不适用于相机拍摄的图像

Image Comparison not working with Camera captured images

[![在此处输入图片描述][1]][1][![在此处输入图片描述][2]][2]我正在比较两张图片的差异。
问题是当我从网上下载一些图像时它工作正常,但当我试图比较从 Phone 相机捕获的图像时它不起作用。知道我哪里做错了吗?

我在 Google Colab 工作。我尝试使用 'structural_similarity' 和 dilate 以及 findContours 方法,两者都不适用于相机图像。

我尝试使用模板匹配,然后对齐图像,然后尝试捕捉差异,但仍然得到相同的结果。

正如您在图片中看到的那样 - 它显示了所有 nits n 位的差异,但没有显示更大的对象作为差异。

Phone 捕获的图像 1:

Phone 截图2:

这是我的代码:

import cv2
from skimage.metrics import structural_similarity
import imutils

ref = cv2.imread('/content/drive/My Drive/Image Comparison/1.png')
target = cv2.imread('/content/drive/My Drive/Image Comparison/2.png')
gray_ref = cv2.cvtColor(ref, cv2.COLOR_BGR2GRAY)
gray_compare = cv2.cvtColor(target, cv2.COLOR_BGR2GRAY)

(score, diff) = structural_similarity(gray_ref,gray_compare, full=True)
diff = (diff * 255).astype("uint8")
thresh = cv2.threshold(diff, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]
contours = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = imutils.grab_contours(contours)

no_of_differences = 0

for c in contours:
    (x, y, w, h) = cv2.boundingRect(c)
    rect_area = w*h
    
    if rect_area > 10:
        no_of_differences +=1
        cv2.rectangle(ref, (x, y), (x + w, y + h), (0, 0, 255), 2)
        cv2.rectangle(target, (x, y), (x + w, y + h), (0, 0, 255), 2)

print("# of differences = ", no_of_differences)
scale_percent = 60 # percent of original size
width = int(ref.shape[1] * scale_percent / 100)
height = int(target.shape[0] * scale_percent / 100)
dim = (width, height)
  
# resize image
resized_ref = cv2.resize(ref, dim, interpolation = cv2.INTER_AREA)
resized_target = cv2.resize(target, dim, interpolation = cv2.INTER_AREA)
cv2_imshow(resized_ref)
cv2_imshow(resized_target)
cv2.waitKey(0)

您的解决方案存在两个主要问题:

  • structural_similarity returns 正值和负值(范围 [-1, 1])。
    转换:diff = (diff * 255).astype("uint8") 适用范围 [0, 1],但对于范围 [-1, 1],我们可以使用以下转换:

     diff = ((diff+1) * 127.5).astype("uint8")  # Convert from range [-1, 1] to [0, 255].
    
  • 使用具有自动阈值 cv2.THRESH_OTSUcv2.threshold 不足以对图像进行阈值处理(至少在 structural_similarity 之后应用时)。
    我们可以将其替换为 adaptiveThreshold - 自适应高斯阈值。
    (我建议的解决方案仍然不是最优的,因为我必须手动调整参数,但找到一个通用的解决方案似乎太难了)。
    thresh = cv2.threshold(diff, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1] 替换为:

     thresh = cv2.adaptiveThreshold(diff, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 175, 30)  # Use adaptive gaussian threshold instead of cv2.THRESH_OTSU
    

代码示例(不使用 Google Colb):

import cv2
from skimage.metrics import structural_similarity
import imutils

ref = cv2.imread('1.png')
target = cv2.imread('2.png')

ref = ref[(ref.shape[0]-480):(ref.shape[0]+480), (ref.shape[1]-768):(ref.shape[1]+768), :]
target = target[(target.shape[0]-480):(target.shape[0]+480), (target.shape[1]-768):(target.shape[1]+768), :]

gray_ref = cv2.cvtColor(ref, cv2.COLOR_BGR2GRAY)
gray_compare = cv2.cvtColor(target, cv2.COLOR_BGR2GRAY)

(score, diff) = structural_similarity(gray_ref, gray_compare, full=True)

#diff = (diff * 255).astype("uint8")
diff = ((diff+1) * 127.5).astype("uint8")  # Support negative values (range of diff is [-1, 1])

#thresh = cv2.threshold(diff, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]
thresh = cv2.adaptiveThreshold(diff, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 175, 30)  # Use adaptive gaussian threshold instead of cv2.THRESH_OTSU

contours = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = imutils.grab_contours(contours)

no_of_differences = 0

for c in contours:
    (x, y, w, h) = cv2.boundingRect(c)
    rect_area = w*h

    if rect_area > 10:
        no_of_differences +=1
        cv2.rectangle(ref, (x, y), (x + w, y + h), (0, 0, 255), 2)
        cv2.rectangle(target, (x, y), (x + w, y + h), (0, 0, 255), 2)

print("# of differences = ", no_of_differences)
scale_percent = 60 # percent of original size
width = int(ref.shape[1] * scale_percent / 100)
height = int(target.shape[0] * scale_percent / 100)
dim = (width, height)
  
# resize image
resized_ref = cv2.resize(ref, dim, interpolation = cv2.INTER_AREA)
resized_target = cv2.resize(target, dim, interpolation = cv2.INTER_AREA)
cv2.imshow('diff', diff)
cv2.imshow('thresh', thresh)
cv2.imshow('resized_ref', resized_ref)
cv2.imshow('resized_target', resized_target)
cv2.waitKey()
cv2.destroyAllWindows()

原文diff = (diff * 255).astype("uint8")

可以看到,有数据溢出。

diff = ((diff+1) * 127.5).astype("uint8"):

原文thresh = cv2.threshold(diff, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]
如您所见,thresh 的一半左右是白色的。

thresh = cv2.adaptiveThreshold(diff, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 175, 30)的结果:


resized_target:

resized_ref:

备注:
您 post 编辑的图像包含标记,但大小不同。
下次,尝试 post 清理图像而不是屏幕截图...