Reputation: 315
I have 2 shapes (pic 1) and need to find one convexHull of both of them combined (pic2). More precisely I am interested in obtaining external corners (purple circles pic 2). The shapes are detached. The shape I trace is a square sheet of transparent plastic with two color stripes on the side. Stripes are very easy to trace (inRange).
One quick and dirty method I am thinking is to connect centers of the stripes with a white line and then obtain convexHull. I am also thinking on concatenating lists of vertexes of both shapes and obtain combined convexHull but I am not certain if this method will crash the convexHull function.
Is there any more elegant way to resolve this problem?
Please help
Pic 1
Pic 2
Upvotes: 3
Views: 3846
Reputation: 36
This answer refers to a small mistake in a previous answer. I have not enough reputation to add the comment there. In the selected answer, in the line
cont = np.vstack(contours[i] for i in range(length))
there is a type. It should be:
cont = np.vstack([contours[i] for i in range(length)])
Otherwise you will get the following error: TypeError: arrays to stack must be passed as a "sequence" type such as list or tuple.
.
Upvotes: 0
Reputation: 154
import numpy as np
import cv2
img = cv2.imread('in1.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
(_, thresh) = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)
thresh = ~thresh
points = np.column_stack(np.where(thresh.transpose() > 0))
hull1 = cv2.convexHull(points)
result1 = cv2.polylines(img.copy(), [hull1], True, (0,0,255), 2)
cv2.imshow('result1', result1)
points2 = np.fliplr(np.transpose(np.nonzero(thresh)))
approx = cv2.convexHull(points2)
result2 = cv2.polylines(img.copy(), [approx], True, (255,255,0), 2)
cv2.imshow('result2', result2)
(contours, _) = cv2.findContours(thresh, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)
points3 = [pt[0] for ctr in contours for pt in ctr]
points3 = np.array(points3).reshape((-1,1,2)).astype(np.int32)
hull3 = cv2.convexHull(points3)
result3 = cv2.drawContours(img.copy(), [hull3], -1, (0,255,0), 1, cv2.LINE_AA)
cv2.imshow('result3', result3)
points4 = list(set(zip(*np.where(img >= 128)[1::-1])))
points4 = np.array(points4).reshape((-1,1,2)).astype(np.int32)
hull4 = cv2.convexHull(points4)
result4 = cv2.drawContours(img.copy(), [hull4], -1, (0,255,255), 1, cv2.LINE_AA)
cv2.imshow('result4', result4)
result = np.hstack([result1, result2, result3, result4])
cv2.imwrite('result.jpg', result)
Upvotes: -1
Reputation: 315
Issue resolved.
Works like a charm. Concatenating points of separate shapes don't crash convexHull.
I posted the code on GitHub https://github.com/wojciechkrukar/OpenCV/blob/master/RectangleDetector/RectangleDetector.ipynb
This is the result:
Here is the most important chunk of code:
_ , contours,hier = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
#size of contour points
length = len(contours)
#concatinate poits form all shapes into one array
cont = np.vstack(contours[i] for i in range(length))
hull = cv2.convexHull(cont)
uni_hull = []
uni_hull.append(hull) # <- array as first element of list
cv2.drawContours(image,uni_hull,-1,255,2);
Upvotes: 6