The concept
One simple way of detecting if intersections of shapes exist in an image, given that every shape must be a different color, you can define a mask for every color, and with the image's colors all masked out except for the shape with its, detect the amount of contours found for the outline of the shape.
If more than one contour (of an area greater than a specified amount to filter out noise) is found, that means that another shape's outline intersected the shape's outline, leaving gaps in its outline and thus resulting in multiple contours.
The code
import cv2
import numpy as np
def intersected(img, masks):
img_hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
for lower, upper in masks:
mask = cv2.inRange(img_hsv, np.array(lower), np.array(upper))
blur = cv2.GaussianBlur(mask, (5, 5), 0)
canny = cv2.Canny(blur, 0, 0)
contours, _ = cv2.findContours(canny, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
count = 0
for cnt in contours:
if cv2.contourArea(cnt) > 50:
cv2.drawContours(img, [cnt], -1, (0, 255, 0), 1)
cv2.imshow("Test", img)
count += 1
if count == 2:
return True
img = cv2.imread("shapes.png")
blue_mask = [1, 0, 0], [178, 255, 255]
red_mask = [0, 1, 0], [179, 254, 255]
if intersected(img, (blue_mask, red_mask)):
print("Intersection detected!")
else:
print("No intersection detected.")
The output
Intersection detected!
The explanation
- Import the necessary libraries:
import cv2
import numpy as np
- Define a function that will take in 2 arguments; the image of which we will be detecting if there are shape intersections, and an array of the HSV masks of the color of each shape:
def intersected(img, masks):
- Get the image in its HSV form, and loop through each of the HSV masks:
img_hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
for lower, upper in masks:
mask = cv2.inRange(img_hsv, np.array(lower), np.array(upper))
- Blur the mask to remove noise, detect it edges using the canny edge detector, and find the contours of the canny edges:
blur = cv2.GaussianBlur(mask, (5, 5), 0)
canny = cv2.Canny(blur, 0, 0)
contours, _ = cv2.findContours(canny, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
- Define a variable,
count
, to store the amount of contours with area greater than, say 50
, found so far. If the count
variable reaches 2
, we'll know that at least one intersection have been found, and that is enough to confirm that there are intersections in the image:
count = 0
for cnt in contours:
if cv2.contourArea(cnt) > 50:
cv2.drawContours(img, [cnt], -1, (0, 255, 0), 1)
cv2.imshow("Test", img)
count += 1
if count == 2:
return True
- Finally, we can utilize the function on the image:
img = cv2.imread("shapes.png")
blue_mask = [1, 0, 0], [178, 255, 255]
red_mask = [0, 1, 0], [179, 254, 255]
if intersected(img, (blue_mask, red_mask)):
print("Intersection detected!")
else:
print("No intersection detected.")