Обнаружить / извлечь наибольшую разницу между изображениями в OpenCV Python - PullRequest
1 голос
/ 13 апреля 2019

Я работаю над проектом симулятора стрельбы, где я должен обнаружить пулевые отверстия на изображениях.Я пытаюсь различить два изображения, чтобы я мог обнаружить новую дыру между изображениями, но она не работает, как ожидалось.Между двумя изображениями в предыдущих пулевых отверстиях есть небольшие изменения из-за небольшого перемещения между кадрами камеры.

Мое первое изображение здесь

before.png

, а второе здесь

after.png

Я пробовал этот код для проверки различий

import cv2 
import numpy as np

before = cv2.imread("before.png") after = cv2.imread("after.png")
result = after - before
cv2.imwrite("result.png", result)

результат, который я получаю в result.png - изображение ниже

result.png

но это не то, что я ожидал, я только хочу обнаружить новую дыру, но она показывает разницу с некоторыми пикселями предыдущего изображения.Результат, который я ожидаю, равен

Ожидается. Png

Пожалуйста, помогите мне разобраться, чтобы он мог обнаруживать только большие различия.

Заранее спасибо.

Любая новая идея будет оценена.

Ответы [ 3 ]

1 голос
/ 13 апреля 2019

Это мой подход: после того, как мы вычли одно из другого, все еще остается некоторый шум, поэтому я просто попытался удалить этот шум. Я делю изображение на процентиль его размера и для каждого небольшого участка изображения сравниваю до и после, так что остаются только значимые куски белых пикселей. Этому алгоритму не хватает точности при окклюзии, то есть всякий раз, когда новый кадр перекрывает существующий.

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)

Before After Result Как видите, это сработало для предоставленного вами варианта использования. Хороший следующий шаг - сохранить массив позиций кадров, чтобы вы могли

1 голос
/ 13 апреля 2019

Чтобы найти различия между двумя изображениями, вы можете использовать Индекс структурного сходства (SSIM), который был представлен в Оценка качества изображения: от видимости ошибок до структурного сходства .Этот метод уже реализован в библиотеке scikit-image для обработки изображений.Вы можете установить scikit-image с pip install scikit-image.

Используя функцию compare_ssim() из scikit-image, он возвращает score и разностное изображение diff.score представляет индекс структурного сходства между двумя входными изображениями и может находиться в диапазоне [-1,1] со значениями, близкими к единице, представляющей более высокое сходство.Но поскольку вас интересует только то, где два изображения различаются, изображение diff - то, что вы ищете.Изображение diff содержит фактические различия между двумя изображениями.

Далее мы находим все контуры, используя cv2.findContours() и фильтруем для наибольшего контура.Наибольший контур должен представлять новую обнаруженную разницу, так как небольшие различия должны быть меньше, чем добавленный маркер.

Здесь самая большая обнаруженная разница между двумя изображениями enter image description here

enter image description here

Вот фактическаяразличия между двумя изображениями.Обратите внимание на то, как были зафиксированы все различия, но поскольку новая пуля, скорее всего, является наибольшим контуром, мы можем отфильтровать все другие незначительные движения между кадрами камеры.enter image description here

Примечание: этот метод работает довольно хорошо, если предположить, что новая пуля будет иметь самый большой контур в изображении diff.Если самая новая дыра была меньше, вам, возможно, придется замаскировать существующие области, и любые новые контуры в новом изображении будут новыми дырами (при условии, что изображение будет равномерным черным фоном с белыми дырами).

from skimage.measure import compare_ssim
import cv2

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

# 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) = compare_ssim(before_gray, after_gray, full=True)
# 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]

contour_sizes = [(cv2.contourArea(contour), contour) for contour in contours]

# The largest contour should be the new detected difference
if len(contour_sizes) > 0:
    largest_contour = max(contour_sizes, key=lambda x: x[0])[1]
    x,y,w,h = cv2.boundingRect(largest_contour)
    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.imshow('before', before)
cv2.imshow('after', after)
cv2.imshow('diff',diff)
cv2.waitKey(0)

Вот еще один пример с различными входными изображениями.SSIM довольно хорош для обнаружения различий между изображениями

enter image description here enter image description here

enter image description here enter image description here

0 голосов
/ 09 мая 2019

Мой код:

from skimage.measure import compare_ssim
import argparse
import imutils
import cv2
import numpy as np

# load the two input images
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)

# convert the images to grayscale
grayA = cv2.cvtColor(imageA, cv2.COLOR_BGR2GRAY)
grayB = cv2.cvtColor(imageB, cv2.COLOR_BGR2GRAY)

##########################################################################################################

difference = cv2.subtract(grayA,grayB)    
result = not np.any(difference)
if result is True:
    print ("Pictures are the same")
else:
    cv2.imwrite("./open_cv_subtract.jpg", difference )
    print ("Pictures are different, the difference is stored.")

##########################################################################################################

diff = cv2.absdiff(grayA, grayB)
cv2.imwrite("./tabsdiff.png", diff)

##########################################################################################################

grayB=cv2.resize(grayB,(grayA.shape[1],grayA.shape[0]))
(score, diff) = compare_ssim(grayA, grayB, full=True)
diff = (diff * 255).astype("uint8")
print("SSIM: {}".format(score))

#########################################################################################################

thresh = cv2.threshold(diff, 25, 255,cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]
cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
#s = imutils.grab_contours(cnts)
count = 0
# loop over the contours
for c in cnts:
    # images differ
    count=count+1
    (x, y, w, h) = cv2.boundingRect(c)
    cv2.rectangle(imageA, (x, y), (x + w, y + h), (0, 0, 255), 2)
    cv2.rectangle(imageB, (x, y), (x + w, y + h), (0, 0, 255), 2)

##########################################################################################################

print (count)
cv2.imwrite("./original.jpg", imageA)
# cv2.imshow("Modified", imageB)
cv2.imwrite("./test_image.jpg", imageB)
cv2.imwrite("./compare_ssim.jpg", diff)
cv2.imwrite("./thresh.jpg", thresh)
cv2.waitKey(0)

Другой код:

import subprocess

# -fuzz 5% # ignore minor difference between two images
# -density 300
# miff:- | display
# -metric phash
# -highlight-color White # by default its RED
# -lowlight-color Black
# -compose difference # src
# -threshold 0
# -separate -evaluate-sequence Add

cmd = 'compare -highlight-color black -fuzz 5% -metric AE Input_1.png ./Input_2.png -compose src ./result.png x: '

a = subprocess.call(cmd, shell=True)

Выше кода приведены различные алгоритмы сравнения изображений для различия изображений с использованием opencv, ImageMagic, numpy, skimage и т. Д.

Надеюсь, это поможет вам.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...