imageopencvimage-processingbackgroundbackground-subtraction

How to remove the background of an image using OpenCV?


What would be the best way to remove the background from this photo?

enter image description here

I've tried converted to HSV and using inRange to get a mask, but it doesn't pick up the plant fully, and includes some of the mortar between the brickwork.


Solution

  • Since there seems to be a clear distinction between the desired plant and the background, I recommend color thresholding with a lower and upper threshold range to isolate the desired regions. The idea is to convert the image to HSV format, color threshold to obtain a mask, then bitwise-and. I think you have the right approach but had trouble determining the lower and upper ranges. Using this lower/upper range:

    hsv_lower = np.array([41,57,78])
    hsv_upper = np.array([145,255,255])
    

    enter image description here

    import cv2
    import numpy as np
    
    image = cv2.imread("1.jpg")
    original = image.copy()
    hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
    
    hsv_lower = np.array([41,57,78])
    hsv_upper = np.array([145,255,255])
    mask = cv2.inRange(hsv, hsv_lower, hsv_upper)
    result = cv2.bitwise_and(original, original, mask=mask)
    
    cv2.imshow('mask', mask)
    cv2.imshow('result', result)
    cv2.waitKey()
    

    To determine the lower and upper range, we can use a color thresholder HSV script

    import cv2
    import sys
    import numpy as np
    
    def nothing(x):
        pass
    
    # Load in image
    image = cv2.imread('1.jpg')
    
    # Create a window
    cv2.namedWindow('image')
    
    # create trackbars for color change
    cv2.createTrackbar('HMin','image',0,179,nothing) # Hue is from 0-179 for Opencv
    cv2.createTrackbar('SMin','image',0,255,nothing)
    cv2.createTrackbar('VMin','image',0,255,nothing)
    cv2.createTrackbar('HMax','image',0,179,nothing)
    cv2.createTrackbar('SMax','image',0,255,nothing)
    cv2.createTrackbar('VMax','image',0,255,nothing)
    
    # Set default value for MAX HSV trackbars.
    cv2.setTrackbarPos('HMax', 'image', 179)
    cv2.setTrackbarPos('SMax', 'image', 255)
    cv2.setTrackbarPos('VMax', 'image', 255)
    
    # Initialize to check if HSV min/max value changes
    hMin = sMin = vMin = hMax = sMax = vMax = 0
    phMin = psMin = pvMin = phMax = psMax = pvMax = 0
    
    output = image
    wait_time = 33
    
    while(1):
    
        # get current positions of all trackbars
        hMin = cv2.getTrackbarPos('HMin','image')
        sMin = cv2.getTrackbarPos('SMin','image')
        vMin = cv2.getTrackbarPos('VMin','image')
    
        hMax = cv2.getTrackbarPos('HMax','image')
        sMax = cv2.getTrackbarPos('SMax','image')
        vMax = cv2.getTrackbarPos('VMax','image')
    
        # Set minimum and max HSV values to display
        lower = np.array([hMin, sMin, vMin])
        upper = np.array([hMax, sMax, vMax])
    
        # Create HSV Image and threshold into a range.
        hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
        mask = cv2.inRange(hsv, lower, upper)
        output = cv2.bitwise_and(image,image, mask= mask)
    
        # Print if there is a change in HSV value
        if( (phMin != hMin) | (psMin != sMin) | (pvMin != vMin) | (phMax != hMax) | (psMax != sMax) | (pvMax != vMax) ):
            print("(hMin = %d , sMin = %d, vMin = %d), (hMax = %d , sMax = %d, vMax = %d)" % (hMin , sMin , vMin, hMax, sMax , vMax))
            phMin = hMin
            psMin = sMin
            pvMin = vMin
            phMax = hMax
            psMax = sMax
            pvMax = vMax
    
        # Display output image
        cv2.imshow('image',output)
    
        # Wait longer to prevent freeze for videos.
        if cv2.waitKey(wait_time) & 0xFF == ord('q'):
            break
    
    cv2.destroyAllWindows()