Jad Gift
Jad Gift

Reputation: 315

How to obtain combined convex Hull of multiple separate shapes

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

enter image description here

Pic 2

enter image description here

Upvotes: 3

Views: 3846

Answers (3)

Eric Biagioli
Eric Biagioli

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

focog77269
focog77269

Reputation: 154

enter image description here

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

Jad Gift
Jad Gift

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:

enter image description here

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

Related Questions