使用OpenCV Python检测并可视化两个图像之间的差异
我有两张图片,我想让大家看清楚区别在哪里。我想为这两幅图像添加颜色,这样用户就可以在一两秒钟内清楚地发现所有的差异 例如,以下是两张有一些区别的图像: leftImage.jpg: rightImage.jpg: 我目前的做法是创建一个遮罩(两幅图像之间的差异),将其涂成红色,然后将其添加到图像中。目标是用强烈的红色清楚地标记所有差异。这是我目前的代码:使用OpenCV Python检测并可视化两个图像之间的差异,python,image,opencv,image-processing,computer-vision,Python,Image,Opencv,Image Processing,Computer Vision,我有两张图片,我想让大家看清楚区别在哪里。我想为这两幅图像添加颜色,这样用户就可以在一两秒钟内清楚地发现所有的差异 例如,以下是两张有一些区别的图像: leftImage.jpg: rightImage.jpg: 我目前的做法是创建一个遮罩(两幅图像之间的差异),将其涂成红色,然后将其添加到图像中。目标是用强烈的红色清楚地标记所有差异。这是我目前的代码: import cv2 # load images image1 = cv2.imread("leftImage.jpg") image2
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)
diff.png:
diffOverImage1.png
diffOverImage2.png
当前代码有问题:
计算出的掩码显示了一些差异,但不是全部(例如,请参见右上角的小片,或蓝色数据包上的绳子)。这些差异仅在计算遮罩中显示得非常轻微,但它们应该像其他差异一样清晰地显示为红色
输入:2张图像,有些不同
预期输出:3个图像:两个输入图像,但差异突出显示(以可配置的颜色清晰突出显示),第三个图像仅包含差异(遮罩)。快速识别两个图像之间差异的一个好方法是使用如下动画GIF: 描述了该过程,代码可用。它可以很容易地适应Python。实际上,它使用的是安装在大多数Linux发行版上的、适用于macOS和Windows的ImageMagick 仅供参考,我在终端中使用了以下命令:
flicker_cmp -o result.gif -r x400 a.jpg b.jpg
假设在图像1中,点图像1[x,y]=[10,10200]。在不同的矩阵中,不同的[x,y]=[0,0255]。在“+”计算之后,新值为[10,10455],这将不起作用,因为R值超过255 我建议你试试
image1[mask != 255] = [0, 0, 255]
image2[mask != 255] = [0, 0, 255]
如果您愿意使用Imagemagick,则可以使用其比较工具。由于您的图像是JPG,因此由于每个图像的压缩,它们将显示差异。因此,我添加了-fuzz 15%以允许15%的公差,而不显示差异。结果将显示红色(默认情况下),其中图像不同。但是颜色是可以改变的 Linux附带Imagemagick。Mac OSX和Windows也有相应的版本 还有Python Wand,它使用Imagemagick
compare -metric rmse -fuzz 25% left.jpg right.jpg diff.png
另一种方法是使用较低的模糊值,并使用形态学处理来去除噪声,并填充一点 使用convert并首先复制左侧图像并将其变白。然后再次复制左侧图像并用红色填充。然后复制左侧图像,并使用10%的较低模糊值对右侧执行差分操作。这将在图像中留下更多的噪声,但可以更好地表示真实区域。所以我使用形态学平滑来去除噪声。最后,我使用最后一幅图像作为遮罩,在白色的左侧图像上合成红色
convert left.jpg \
\( -clone 0 -fill white -colorize 50% \) \
\( -clone 0 -fill red -colorize 100 \) \
\( -clone 0 right.jpg -compose difference -composite -threshold 10% -morphology smooth diamond:1 \) \
-delete 0 \
-compose over -composite \
result.png
为了直观地显示两幅图像之间的差异,我们可以采用一种定量方法,使用中引入的结构相似性指数(SSIM)来确定图像之间的精确差异。此方法已在图像处理库中实现。您可以使用
pip install scikit image
安装scikit image
使用来自scikit图像的函数,它返回一个分数
和一个差分图像diff
。得分
表示两个输入图像之间的结构相似性指数,可以介于范围[-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图像版本是
0.18.1
。在以前的版本中,该函数是skimage.measure.compare_ssim
,但在0.18.1
中已被折旧和删除。根据,该功能仍然存在,但现在位于不同名称下的新skimage.metrics
子模块下。新更新的函数是,除非使用无损格式,否则每个图像都会与压缩有很多非常微小的差异(导致噪声)。我对此不太了解,所以这只是一个猜测,但也许一些频率滤波器可以帮助平滑这些位。使用absdiff而不是减法,您将获得所有差异,但噪声可能是一个问题。有关使用的一般概念,请参见absdiff@coffeewin:现有答案缺少什么?你在寻找什么?@CrisLuengo我在寻找一种方法,可以识别两幅图像之间的差异,其中图像处于不同角度或稍微旋转,并且除了精确的差异外,还可以输出百分比差异。我已经研究了使用SIFT和ORB-bu进行特征匹配