I have a series of horizontal lines detected in an image using OpenCV through Python.
For each line, I have a series of (x,y) points along the lines. The points go right across the image on the X axis at regular intervals.
I want to draw essentially a filled rectangle which covers the image from one line to the next and the fill will be white to hide contents on the row which is made up top and bottom of two sets of line points.
The problem is that the Y position of the lines changes by small amounts as I go across the image so a rectangle won't fit the row nicely.
I think I essentially need to draw a freeform shape using the points that I know and fill it so that the area between the points on the top and bottom line is coloured in.
I have tried creating a polygon using the points that I have with the following command:
cv2.fillPoly(image, np.array([polygon_points], np.int32), 255)
However, rather than producing a fully filled shape that covers a row of the image, I get two triangles which start at the correct point but which meet in the middle, leaving the rest of the 'rectangle' unfilled.
How can I draw a freeform shape in OpenCV which covers the points along the top and bottom lines that I have but which also fills in all the pixels inbetween the two lines?
I hope that this makes sense. Thanks for any help.
This is because your points are likely sorted in your list as the follow (attempted) picture shows
_________________________
| pt1 pt2 ... ptm |
| |
| |
| ptm+1 ptm+2 ... pt2m |
|________________________|
Because of this the polyfill function is trying to fill from ptm to ptm+1 making your triangles (Personally I would describe it as an hourglass shape). There are two solutions to your problem. Either you can flip the second set of points changing your list from
points = [pt1, pt2, ..., ptm, ptm+1, ptm+2, ..., pt2m]
to
points = [pt1, pt2, ..., ptm, pt2m, pt2m-1, ..., ptm+1]
followed by your fillPoly
call (although fillConvexPoly
is apparently much faster)
or the alternative
x1 = min(x_points)
y1 = min(y_points)
x2 = max(x_points)
y2 = max(y_points)
cv2.rectangle(img, (x1,y1), (x2,y2), thickness=-1)
EDIT: If you are looking to create a polygon of the minimum enclosing set of points, you can use the opencv function convexHull to determine the convex hull (minimum enclosing set of points) and fill that polygon instead. Documentation is listed below: