python - 使用 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 个图像:两个输入图像,但突出显示了差异(以可配置的颜色清楚地突出显示),以及仅包含差异的第三个图像(掩码)。
解决方案
为了可视化两个图像之间的差异,我们可以采用定量方法来确定图像之间的确切差异,使用图像质量评估中引入的结构相似性指数(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_ssim
在0.18.1
. 根据文档,该功能仍然存在,但现在位于skimage.metrics
不同名称的新子模块下。新更新的功能是skimage.metrics.structural_similarity
推荐阅读
- nginx - NGinx 发送 307 而不是 401
- perl - 试图从动态 NF 文件中获取最后 4 个不同的值
- ios - iOS / Swift 中的 3D 动画文本,就好像它是写在一个看不见的旋转卫生纸卷上一样
- python-3.x - 将 pynacl 中的 45 字节共享密钥转换为 32 字节密钥,以便与 25 字节 IV 的 AES-CBC 一起使用
- android - Android 应用程序在完成活动时冻结,runOnUiThread() 停止工作
- internet-explorer - 如何使用VBScript点击页面上的链接
- python - 在 Python 中将数据放入数据结构(列表、字典等)中
- opengl - 在OpenGL中,为什么我们在世界空间中默认位于(0,0,0)?
- phppgadmin - phpPgAdmin - 登录失败 - 虚拟类 - 无法实例化
- javascript - 在javascript中计算放大的图像分辨率