Search code examples
pythonopencvimage-processingobject-detection

Compare two different images and find the differences


I have a webcam which takes pictures of a concrete slab. Now I want to check if there are objects on the slab or not. The objects could be anything and accordingly cannot be enumerated in a class. Unfortunately I cannot compare the webcam image directly with an image without objects on the concrete slab, because the image of the camera could shift minimally in x and y direction and the lighting is also not always the same. So I cannot use cv2.substract. I would prefer a foreground and background substract, where the background is just my concrete slab and the foreground is then the objects. But since the objects don´t move but lie still on the slab, I can´t use cv2.createBackgroundSubtractorMOG2() either.

The Pictures look like this:

The Concrete slap without any objects:

enter image description here

The slap with Objects:

enter image description here enter image description here


Solution

  • In Python/OpenCV, you could do division normalization to even out the illumination and make the background white. Then do your subtraction. Then use morphology to clean up small regions. Then find contours and discard any small regions that are due to noise left after the division normalization and morphology.

    Here is how to do division normalization.

    Input 1:

    enter image description here

    Input 2:

    enter image description here

    import cv2
    import numpy as np
    
    # load image
    img1 = cv2.imread("img1.jpg")
    img2 = cv2.imread("img2.jpg")
    
    # convert to grayscale
    gray1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
    gray2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)
    
    # blur
    blur1 = cv2.GaussianBlur(gray1, (0,0), sigmaX=13, sigmaY=13)
    blur2 = cv2.GaussianBlur(gray2, (0,0), sigmaX=13, sigmaY=13)
    
    # divide
    divide1 = cv2.divide(gray1, blur1, scale=255)
    divide2 = cv2.divide(gray2, blur2, scale=255)
    
    # threshold
    thresh1 = cv2.threshold(divide1, 200, 255, cv2.THRESH_BINARY)[1]
    thresh2 = cv2.threshold(divide2, 200, 255, cv2.THRESH_BINARY)[1]
    
    # morphology
    kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3,3))
    morph1 = cv2.morphologyEx(thresh1, cv2.MORPH_OPEN, kernel)
    morph2 = cv2.morphologyEx(thresh2, cv2.MORPH_OPEN, kernel)
    kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5))
    morph1 = cv2.morphologyEx(morph1, cv2.MORPH_CLOSE, kernel)
    morph2 = cv2.morphologyEx(morph2, cv2.MORPH_CLOSE, kernel)
    
    
    # write result to disk
    cv2.imwrite("img1_division_normalize.jpg", divide1)
    cv2.imwrite("img2_division_normalize.jpg", divide2)
    cv2.imwrite("img1_division_morph1.jpg", morph1)
    cv2.imwrite("img1_division_morph2.jpg", morph2)
    
    
    # display it
    cv2.imshow("img1_norm", divide1)
    cv2.imshow("img2_norm", divide2)
    cv2.imshow("img1_thresh", thresh1)
    cv2.imshow("img2_thresh", thresh2)
    cv2.imshow("img1_morph", morph1)
    cv2.imshow("img2_morph", morph2)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    

    Image 1 Normalized:

    enter image description here

    Image 2 Normalized:

    enter image description here

    Image 1 thresholded and morphology cleaned:

    enter image description here

    Image 2 thresholded and morphology cleaned:

    enter image description here

    In this case, Image 1 becomes completely white. So it (and subtraction) is not really needed. You just need to find contours for the second image result and if necessary discard tiny regions by area. The rest are your objects.