I'm new to image processing and I'm struggling a bit, I'm making my own diy security software and I made a function to detect some movement in order to start recording and notify me.
The idea of this function is to take two images and diff them in order to find some movement, the problem I have is that either :
- The detection is working really fine but at night there's some noise on the image and even daily in the shadows which trigger a positive detection wrongly
- The function is not wrongly triggered but it miss some detections
- divide gray images and blur
- replace the basic threshold by an adaptative one (gaussian and mean)
Код: Выделить всё
import cv2
import numpy as np
from skimage.metrics import structural_similarity as ssim
def count_diff_nb(img_1, img_2):
# resize images
img_1_height, img_1_width = img_1.shape[:2]
new_height = int((600 / img_1_width) * img_1_height)
img_1 = cv2.resize(img_1, (600,new_height))
img_2 = cv2.resize(img_2, (600,new_height))
# convert to gray scale
gray_image1 = cv2.cvtColor(img_1, cv2.COLOR_BGR2GRAY)
gray_image2 = cv2.cvtColor(img_2, cv2.COLOR_BGR2GRAY)
# Gaussian blur in order to remove some noise
blur1 = cv2.GaussianBlur(gray_image1, (5,5), 0)
blur2 = cv2.GaussianBlur(gray_image2, (5,5), 0)
# divide (bad idea)
#divide1 = cv2.divide(gray_image1, blur1, scale=255)
#divide2 = cv2.divide(gray_image2, blur2, scale=255)
# Compute SSIM between two images
#ssim_value, diff = ssim(gray_image1, gray_image2, full=True)
ssim_value, diff = ssim(blur1, blur2, full=True)
#ssim_value, diff = ssim(divide1, divide2, full=True)
diff_percent = (1 - ssim_value) * 100
# The diff image contains the actual image differences between the two images
# and is represented as a floating point data type 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")
# Adaptative threshold (bad idea too)
#thresh = cv2.adaptiveThreshold(diff, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 11, 2)
#thresh = cv2.adaptiveThreshold(diff, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY_INV, 3, 10)
# Threshold the difference image
thresh = cv2.threshold(diff, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]
# followed by finding contours to
# obtain the regions that differ between the two images
contours = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]
# Highlight differences
mask = np.zeros(img_1.shape, dtype='uint8')
filled = img_2.copy()
contours_nb = 0
for c in contours:
# limit is an area so sqrt of size
area = cv2.contourArea(c)
# 72000 is 1/3 of global img area
if area > 2000 and area < 72000:
contours_nb = contours_nb + 1
x,y,w,h = cv2.boundingRect(c)
cv2.rectangle(img_1, (x, y), (x + w, y + h), (36,255,12), 2)
cv2.rectangle(img_2, (x, y), (x + w, y + h), (36,255,12), 2)
cv2.drawContours(mask, [c], 0, (0,255,0), -1)
cv2.drawContours(filled, [c], 0, (0,255,0), -1)
return contours_nb, diff_percent, img_2, filled
I thought to ignore the dark colors before converting to grayscale but if the moving thing is black then .. it's a bad idea I think.
Thanks a lot !
Edit :
I changed the whole thing by implementing this solution suggested by @pippo1980. I use BackgroundSubtractorMOG2 which works the best in my case. (I tested the different options).
So it works almost perfectly, the last pain point is now at the sunrise and sunset, when my cheap webcam is struggling with noise and the image is a little blur / randomly noised.
I'm searching how to deal with this but I'm not sure.
Here's when it's working fine, you can see that the mask is really sharp :


And at sunset with the blur / noise on image :






Источник: https://stackoverflow.com/questions/781 ... ndom-noise