Reputation: 941
I am trying to get the coordinates of the 4 vertices of minimum area rectangles constructed around some objects of similar characteristics in an image, ignore if they are equal to a certain set of values, and if they are not, add them to a list.
Here is how I get the vertices:
contours, hierarchy = cv2.findContours(mask2, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for contour in contours:
rect = cv2.minAreaRect(contour)
points = cv2.cv.BoxPoints(rect)
points = np.int0(points)
coordinate_list.append(points)
So points
contains the coordinates. I tried printing points
and here are part of the output that is printed in the console:
[[459 467]
[459 467]
[459 467]
[459 467]]
[[450 466]
[450 466]
[450 466]
[450 466]]
[[306 376]
[306 376]
[306 376]
[306 376]]
This output confuses me as I do not know how to write them in my code.
Now suppose I want to ignore rectangles with vertices of coordinates ((459, 467),(459, 467),(459, 467),(459, 467))
and ((450, 466),(450, 466),(450, 466),(450, 466))
. I tried inserting the following code before the coordinate_list.append(points)
statement:
if points in [[[459 467], [459 467], [459 467], [459 467]], [[450 466], [450 466], [450 466], [450 466]]]:
continue
I also tried a number of ways to display the vertices (like adding commas, replacing square brackets with normal brackets etc) in the hope of matching the correct format that points
store the values but I can't seem to find the right answer.
How can I write this if
statement correctly?
P/s: If anyone has a more appropriate title for this question, please help me change it. Thanks!
Upvotes: 2
Views: 5195
Reputation: 104493
cv2.boxPoints
should return only 4 coordinates which contain the minimum spanning bounding box for the contour. In your code, what is returned is a numpy
array of size 4 x 2
where each row is a rectangle coordinate of the minimum spanning bounding box. The fact that you get repeated coordinates is rather odd.
In any case, since points
is now a numpy
array, one way would be to check if the x
coordinate of the returned box coordinates are in a set of coordinates provided by you and the same for y
.
As such, something numpy
-ish would look something like this:
# Store x and y coordinates as column vectors
xcoord = np.array([[459, 450]]).T
ycoord = np.array([[467, 466]]).T
# Run contour detection code
contours, hierarchy = cv2.findContours(mask2, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
coordinate_list = []
# Go through each contour...
for contour in contours:
rect = cv2.minAreaRect(contour)
points = cv2.cv.BoxPoints(rect)
points = np.int0(points)
# Check to see if any rectangle points are in our lists
if np.any(np.logical_and(xcoords == points[:,0], ycoords == points[:,1])):
continue
coordinate_list.append(points)
What I did first was create separate numpy
arrays that contain the x
and y
coordinates of the coordinates that you don't want to see in the list. You need to make sure that you put the points in the correct order. Therefore, xcoords[0]
and ycoords[0]
belong to one (x,y)
point. Similarly, xcoords[1]
and ycoords[1]
belong to one (x,y)
point etc.
Note that I've made the column vectors (N x 1
arrays) so that I can broadcast easily. Next, for each contour that we have detected, get the minimum spanning bounding box, then check to see if any of the x
and y
coordinates in this minimum spanning bounding box xcoords == points[:,0]
checks to see if there are any x
points in our list that we don't want to include are detected in the set of x
coordinates in the detected rectangle. Similar case for ycoords == points[:,1]
for the y
coordinates. Doing np.logical_and
will now check the pairs of coordinates and see if both (x,y)
pairs that we defined in xcoord, ycoord
are seen as coordinates in the detected bounding box. Doing np.any
checks to see if any such instance occurs. If this is True
, we continue and skip this bounding box.
The output should be stored in coordinate_list
where the rectangles whose coordinates you wanted to skip over don't appear.
Upvotes: 1