首页 > 解决方案 > 使用 OpenCV Python 检测和可视化两个图像之间的差异

问题描述

我有两张图片,想清楚地说明差异在哪里。我想为这两个图像添加颜色,以便用户可以在一两秒内清楚地发现所有差异。

例如,这里有两张图片有一些不同:

左图.jpg:

第一张图片

右图.jpg:

第二张图片

我目前使差异明显的方法是创建一个蒙版(两个图像之间的差异),将其着色为红色,然后将其添加到图像中。目标是用强烈的红色清楚地标记所有差异。这是我当前的代码:

import cv2

# load images
image1 = cv2.imread("leftImage.jpg")
image2 = cv2.imread("rightImage.jpg")

# compute difference
difference = cv2.subtract(image1, image2)

# color the mask red
Conv_hsv_Gray = cv2.cvtColor(difference, cv2.COLOR_BGR2GRAY)
ret, mask = cv2.threshold(Conv_hsv_Gray, 0, 255,cv2.THRESH_BINARY_INV |cv2.THRESH_OTSU)
difference[mask != 255] = [0, 0, 255]

# add the red mask to the images to make the differences obvious
image1[mask != 255] = [0, 0, 255]
image2[mask != 255] = [0, 0, 255]

# store images
cv2.imwrite('diffOverImage1.png', image1)
cv2.imwrite('diffOverImage2.png', image1)
cv2.imwrite('diff.png', difference)

差异.png:

在此处输入图像描述

diffOverImage1.png

在此处输入图像描述

diffOverImage2.png

在此处输入图像描述

当前代码的问题: 计算出的掩码显示了一些差异,但不是全部(参见例如右上角的小块,或蓝色包上的绳索)。这些差异仅在计算掩码中非常轻微地显示,但它们应该像其他差异一样清晰地显示为红色。

输入: 2张有一些差异的图像。

预期输出: 3 个图像:两个输入图像,但突出显示了差异(以可配置的颜色清楚地突出显示),以及仅包含差异的第三个图像(掩码)。

标签: pythonimageopencvimage-processingcomputer-vision

解决方案


为了可视化两个图像之间的差异,我们可以采用定量方法来确定图像之间的确切差异,使用图像质量评估中引入的结构相似性指数(SSIM) :从错误可见性到结构相似性。此方法已在scikit-image库中实现,用于图像处理。您可以scikit-image使用pip install scikit-image.

使用structural_similarity()scikit-image 中的函数,它返回一个score和一个差异图像,diff. 表示两个输入图像之间的score结构相似性指数,可以落在范围 [-1,1] 之间,值越接近表示相似性越高。但是,由于您只对这两个图像的不同之处感兴趣,因此diff我们将重点关注图像。具体来说,diff图像包含实际图像差异,较暗区域具有更大的差异。较大的差异区域以黑色突出显示,而较小的差异以灰色突出。

灰色嘈杂区域可能是由于 .jpg 有损压缩。如果我们使用无损压缩图像格式,我们将获得更清晰的结果。比较两张图像后的 SSIM 分数表明它们非常相似。

图片相似度 0.9198863419190031

现在我们过滤diff图像,因为我们只想找到图像之间的巨大差异。我们遍历每个轮廓,使用最小阈值区域进行过滤以去除灰色噪声,并使用边界框突出显示差异。这是结果。

为了可视化确切的差异,我们将轮廓填充到蒙版和原始图像上。

from skimage.metrics import structural_similarity
import cv2
import numpy as np

before = cv2.imread('left.jpg')
after = cv2.imread('right.jpg')

# Convert images to grayscale
before_gray = cv2.cvtColor(before, cv2.COLOR_BGR2GRAY)
after_gray = cv2.cvtColor(after, cv2.COLOR_BGR2GRAY)

# Compute SSIM between two images
(score, diff) = structural_similarity(before_gray, after_gray, full=True)
print("Image similarity", score)

# The diff image contains the actual image differences between the two images
# and is represented as a floating point data type in the range [0,1] 
# so we must convert the array to 8-bit unsigned integers in the range
# [0,255] before we can use it with OpenCV
diff = (diff * 255).astype("uint8")

# Threshold the difference image, followed by finding contours to
# obtain the regions of the two input images that differ
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 = contours[0] if len(contours) == 2 else contours[1]

mask = np.zeros(before.shape, dtype='uint8')
filled_after = after.copy()

for c in contours:
    area = cv2.contourArea(c)
    if area > 40:
        x,y,w,h = cv2.boundingRect(c)
        cv2.rectangle(before, (x, y), (x + w, y + h), (36,255,12), 2)
        cv2.rectangle(after, (x, y), (x + w, y + h), (36,255,12), 2)
        cv2.drawContours(mask, [c], 0, (0,255,0), -1)
        cv2.drawContours(filled_after, [c], 0, (0,255,0), -1)

cv2.imshow('before', before)
cv2.imshow('after', after)
cv2.imshow('diff',diff)
cv2.imshow('mask',mask)
cv2.imshow('filled after',filled_after)
cv2.waitKey(0)

注意:使用的 scikit-image 版本是0.18.1. 在以前的版本中,该功能skimage.measure.compare_ssim0.18.1. 根据文档,该功能仍然存在,但现在位于skimage.metrics不同名称的新子模块下。新更新的功能是skimage.metrics.structural_similarity


推荐阅读