在OpenCV Python中检测/提取图像之间的最大差异

在OpenCV Python中检测/提取图像之间的最大差异,python,opencv,image-processing,Python,Opencv,Image Processing,我正在做一个射击模拟器项目,我必须从图像中检测弹孔。我正在尝试区分两幅图像,这样我就可以在图像之间检测到新的洞,但它没有按预期工作。在这两幅图像之间,由于相机帧之间的轻微移动,先前的弹孔中有微小的变化 我的第一张照片在这里 before.png 第二个在这里 after.png 我尝试了这个代码来检查差异 导入cv2 将numpy作为np导入 before=cv2.imread(“before.png”)after=cv2.imread(“after.png”) 结果=之后-之前 cv2.i

我正在做一个射击模拟器项目,我必须从图像中检测弹孔。我正在尝试区分两幅图像,这样我就可以在图像之间检测到新的洞,但它没有按预期工作。在这两幅图像之间,由于相机帧之间的轻微移动,先前的弹孔中有微小的变化

我的第一张照片在这里

before.png

第二个在这里

after.png

我尝试了这个代码来检查差异

导入cv2
将numpy作为np导入
before=cv2.imread(“before.png”)after=cv2.imread(“after.png”)
结果=之后-之前
cv2.imwrite(“result.png”,result)
我在result.png中得到的结果是下图

result.png

但这不是我所期望的,我只想探测新的洞 但它显示的是与前一幅图像的一些像素的差异。 我期待的结果是

expected.png

请帮我弄清楚,这样它只能检测出很大的差异

提前谢谢


任何新想法都将受到欢迎。

为了找出两幅图像之间的差异,您可以利用中引入的结构相似性指数(SSIM)。此方法已在图像处理库中实现。您可以使用
pip install scikit image
安装
scikit image

使用scikit图像中的
compare_ssim()
函数,它返回一个
score
和一个差分图像
diff
得分
表示两个输入图像之间的结构相似性指数,可以在[-1,1]范围内,数值更接近表示更高相似性的数值。但是,由于您只对两个图像的不同之处感兴趣,因此
diff
图像就是您要查找的内容。
diff
图像包含两个图像之间的实际图像差异

接下来,我们使用
cv2.findContours()
查找所有轮廓,并过滤最大轮廓。最大轮廓应代表新检测到的差异,因为微小差异应小于添加的项目符号

这是两幅图像之间检测到的最大差异

这是两幅图像之间的实际差异。注意所有的差异是如何被捕捉到的,但由于新的子弹很可能是最大的轮廓,我们可以过滤掉相机帧之间的所有其他轻微移动。

注意:如果我们假设新子弹在
diff
图像中具有最大的轮廓,则此方法非常有效。如果最新的孔较小,则可能必须遮罩现有区域,以及新图像中的任何新轮廓都将是新孔(假设图像将是带白孔的均匀黑色背景)

下面是另一个具有不同输入图像的示例。SSIM非常适合检测图像之间的差异


这是我的方法:在我们从另一个中减去一个之后,仍然有一些噪声,所以我只是尝试去除这些噪声。我将图像按大小的百分位数进行分割,并对图像的每个小部分进行前后比较,以便只剩下大量的白色像素。当存在遮挡时,即当新快照与现有快照重叠时,该算法缺乏精度

import cv2 
import numpy as np

# This is the percentage of the width/height we're gonna cut
# 0.99 < percent < 0.1
percent = 0.01 

before = cv2.imread("before.png")
after = cv2.imread("after.png")

result =  after - before # Here, we eliminate the biggest differences between before and after

h, w, _ = result.shape

hPercent = percent * h
wPercent = percent * w

def isBlack(crop): # Function that tells if the crop is black
    mask = np.zeros(crop.shape, dtype = int)
    return not (np.bitwise_or(crop, mask)).any()

for wFrom in range(0, w, int(wPercent)): # Here we are gonna remove that noise
    for hFrom in range(0, h, int(hPercent)):
        wTo = int(wFrom+wPercent)
        hTo = int(hFrom+hPercent)
        crop = result[wFrom:wTo,hFrom:hTo] # Crop the image

        if isBlack(crop): # If it is black, there is no shot in it
            continue    # We dont need to continue with the algorithm

        beforeCrop = before[wFrom:wTo,hFrom:hTo] # Crop the image before

        if  not isBlack(beforeCrop): # If the image before is not black, it means there was a hot already there
            result[wFrom:wTo,hFrom:hTo] = [0, 0, 0] # So, we erase it from the result

cv2.imshow("result",result )
cv2.imshow("before", before)
cv2.imshow("after", after)
cv2.waitKey(0)
导入cv2
将numpy作为np导入
#这是我们要切割的宽度/高度的百分比
#0.99<百分之<0.1
百分比=0.01
before=cv2.imread(“before.png”)
after=cv2.imread(“after.png”)
结果=之后-之前#在这里,我们消除了之前和之后的最大差异
h、 w,u=result.shape
h百分比=百分比*h
wPercent=百分比*w
def isBlack(裁剪):用于告知裁剪是否为黑色的函数
掩码=np.zero(crop.shape,dtype=int)
返回not(np.按位_或(裁剪、掩码)).any()
对于范围(0,w,int(wPercent))内的wFrom:#这里我们将消除该噪声
对于范围(0,h,int(hPercent))内的hFrom:
wTo=int(wFrom+W百分比)
hTo=int(hFrom+hPercent)
裁剪=结果[wFrom:wTo,hFrom:hTo]#裁剪图像
如果是黑色(作物):#如果是黑色,则没有子弹
继续,我们不需要继续算法
beforeCrop=before[wFrom:wTo,hFrom:hTo]#在之前裁剪图像
如果不是黑色(在裁剪之前):#如果之前的图像不是黑色,则表示那里已经有热图像
结果[wFrom:wTo,hFrom:hTo]=[0,0,0]#因此,我们将其从结果中删除
cv2.imshow(“结果”,结果)
cv2.imshow(“之前”,之前)
cv2.imshow(“之后”,之后)
cv2.等待键(0)
如您所见,它适用于您提供的用例。好的下一步是保留快照位置数组,以便您可以

我的代码:

来自skimage.measure导入比较
导入argparse
导入imutils
进口cv2
将numpy作为np导入
#加载两个输入图像
imageA=cv2.imread('./Input_1.png')
cv2.imwrite(“./org.jpg”,imageA)
#imageA=cv2.medianBlur(imageA,29)
imageB=cv2.imread('./Input_2.png')
cv2.imwrite(“./test.jpg”,imageB)
#imageB=cv2.medianBlur(imageB,29)
#将图像转换为灰度
灰度A=cv2.CVT颜色(图像A,cv2.COLOR\U BGR2GRAY)
grayB=cv2.CVT颜色(图像B,cv2.COLOR\u BGR2GRAY)
##########################################################################################################
差值=cv2。减去(灰度A、灰度B)
结果=非np.任何(差异)
如果结果为真:
打印(“图片相同”)
其他:
cv2.imwrite(“./open\u cv\u subtract.jpg”,差值)
打印(“图片不同,差异被存储。”)
##########################################################################################################
diff=cv2.absdiff(灰度A、灰度B)
cv2.imwrite(“./tabsdiff.png”,
import cv2 
import numpy as np

# This is the percentage of the width/height we're gonna cut
# 0.99 < percent < 0.1
percent = 0.01 

before = cv2.imread("before.png")
after = cv2.imread("after.png")

result =  after - before # Here, we eliminate the biggest differences between before and after

h, w, _ = result.shape

hPercent = percent * h
wPercent = percent * w

def isBlack(crop): # Function that tells if the crop is black
    mask = np.zeros(crop.shape, dtype = int)
    return not (np.bitwise_or(crop, mask)).any()

for wFrom in range(0, w, int(wPercent)): # Here we are gonna remove that noise
    for hFrom in range(0, h, int(hPercent)):
        wTo = int(wFrom+wPercent)
        hTo = int(hFrom+hPercent)
        crop = result[wFrom:wTo,hFrom:hTo] # Crop the image

        if isBlack(crop): # If it is black, there is no shot in it
            continue    # We dont need to continue with the algorithm

        beforeCrop = before[wFrom:wTo,hFrom:hTo] # Crop the image before

        if  not isBlack(beforeCrop): # If the image before is not black, it means there was a hot already there
            result[wFrom:wTo,hFrom:hTo] = [0, 0, 0] # So, we erase it from the result

cv2.imshow("result",result )
cv2.imshow("before", before)
cv2.imshow("after", after)
cv2.waitKey(0)