How to detect black shaped contour on photo with OpenCV-Python


I am trying to detect black shape on photo like this.

enter image description here

So far i have picture with shape but still on there is many lines and noise and from that i cannot use the findContours() because it's also mark the line. Can You give me some advice or help with this task. I will be so grateful for help!

Original image

enter image description here

Binary image

enter image description here

import cv2
import numpy as np
import imutils

def color_seg(choice):
    if choice == 'blue':
        lower_hue = np.array([100,30,30])
        upper_hue = np.array([150,148,255])
    elif choice == 'white':
        lower_hue = np.array([0,0,0])
        upper_hue = np.array([0,0,255])
    elif choice == 'black':
        lower_hue = np.array([0,0,0])
        upper_hue = np.array([50,50,100])
    return lower_hue, upper_hue


# Take each frame
frame = cv2.imread('11.jpg')
#frame = cv2.imread('images/road_1.jpg')

frame = imutils.resize(frame, height = 500)
chosen_color = 'black'


# Convert BGR to HSV
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)

# define range of a color in HSV
lower_hue, upper_hue = color_seg(chosen_color)


# Threshold the HSV image to get only blue colors
mask = cv2.inRange(hsv, lower_hue, upper_hue)


kernel = np.ones((5,5),np.uint8)
erosion = cv2.erode(mask,kernel,iterations = 10)
erosion = cv2.filter2D(mask,-1,kernel)
erosion = cv2.GaussianBlur(mask,(5,5),cv2.BORDER_DEFAULT)




cv2.imshow('frame',frame)
cv2.imshow('mask',mask)

cv2.waitKey(0)

Answers:


You're on the right track. After obtaining your binary image you need to perform morphological operations to filter out noise and isolate the object. Afterwards, we can find contours then filter using contour approximation and contour area. We draw the detected region onto a blank mask then bitwise-and with the original image. Here's the steps:

Binary image

enter image description here

Morphological operations

enter image description here

Detected region in green

enter image description here

Isolated result after bitwise operations

enter image description here

Code

import numpy as np
import cv2

# Color threshold
image = cv2.imread('1.jpg')
original = image.copy()
blank = np.zeros(image.shape, dtype=np.uint8)
blur = cv2.GaussianBlur(image, (7,7), 0)
hsv = cv2.cvtColor(blur, cv2.COLOR_BGR2HSV)
lower = np.array([0, 0, 0])
upper = np.array([179, 93, 97])
mask = cv2.inRange(hsv, lower, upper)

# Morph operations
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (7,7))
opening = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel, iterations=1)
close = cv2.morphologyEx(opening, cv2.MORPH_CLOSE, kernel, iterations=2)

# Find contours and filter using contour approximation + contour area
cnts = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
    peri = cv2.arcLength(c, True)
    approx = cv2.approxPolyDP(c, 0.04 * peri, True)
    area = cv2.contourArea(c)
    if len(approx) > 3 and area > 1000:
        cv2.drawContours(image, [c], -1, (36,255,12), -1)
        cv2.drawContours(blank, [c], -1, (255,255,255), -1)

# Bitwise-and for result
blank = cv2.cvtColor(blank, cv2.COLOR_BGR2GRAY)
result = cv2.bitwise_and(original,original,mask=blank)
result[blank==0] = (255,255,255)

cv2.imshow('mask', mask)
cv2.imshow('opening', opening)
cv2.imshow('close', close)
cv2.imshow('result', result)
cv2.imshow('image', image)
cv2.waitKey()