Since the boxes are touching each other, watershed algorithm works well in this cases to extract the box contours. Then the x coordinates position of the rectangle contours can be used to say whether they are aligned or not.
Steps:
- Watershed algorithm to get markers.
- Filter out boxes(rectangles)
- To see if its aligned or not using standard deviation of all the boxes x coordinates. (the threshold can be set accordingly)
Code:
import cv2
import numpy as np
def watershed_algorithm(image):
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY + cv2.THRESH_OTSU)
# noise removal
kernel = np.ones((5,5),np.uint8)
opening = cv2.morphologyEx(thresh,cv2.MORPH_OPEN,kernel, iterations = 2)
# sure background area
sure_bg = cv2.dilate(opening,kernel,iterations=3)
# Finding sure foreground area
dist_transform = cv2.distanceTransform(opening,cv2.DIST_L2,5)
ret, sure_fg = cv2.threshold(dist_transform,0.7*dist_transform.max(),255,0)
# Finding unknown regio3
sure_fg = np.uint8(sure_fg)
unknown = cv2.subtract(sure_bg,sure_fg)
# Marker labelling
ret, markers = cv2.connectedComponents(sure_fg)
# Add one to all labels so that sure background is not 0, but 1
markers = markers+1
# Now, mark the region of unknown with zero
markers[unknown==255] = 0
markers = cv2.watershed(image,markers)
return markers
def is_rect_contour(contour):
peri = cv2.arcLength(contour, True)
approx = cv2.approxPolyDP(contour, 0.04 * peri, True)
if len(approx) == 4:
return True
else:
return False
def get_rectangle_contours(markers, shape):
rectangle_contours = []
for marker in np.unique(markers):
if marker == 0 or marker==-1:
continue
mask = np.zeros(shape, dtype="uint8")
mask[markers == marker] = 255
cnts = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
c = max(cnts[0], key=cv2.contourArea)
if is_rect_contour(c):
rectangle_contours.append(c)
return rectangle_contours
def draw_and_display_contours(contours, image):
for i,c in enumerate(contours):
(x, y, w, h) = cv2.boundingRect(c)
cv2.drawContours(image, [c], -1, (0, 255, 0), 2)
cv2.putText(image, "#{}".format(i+1), (int(x) - 10, int(y)),
cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2)
cv2.imshow('Contours', image)
cv2.waitKey(0)
cv2.destroyAllWindows()
def is_boxes_aligned(rectangle_contours):
x_coord_list = []
for c in rectangle_contours:
(x, y, w, h) = cv2.boundingRect(c)
x_coord_list.append(x)
threshold_std_deviation_in_X_coordinates = 10
if np.std(x_coord_list) < threshold_std_deviation_in_X_coordinates:
print("Box are aligned in same column with a standard deviation of {}".format(np.std(x_coord_list)))
else:
print("Box are not aligned in same column")
image = cv2.imread("./cubes.jpg")
markers = watershed_algorithm(image)
rectangle_contours = get_rectangle_contours(markers, image.shape[:2])
draw_and_display_contours(rectangle_contours,image)
is_boxes_aligned(rectangle_contours)
Output:
Box are aligned in same column with a standard deviation of 4.027681991198191
