Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Yolov8 segmentation output giving multiple contours per bounding box. #2

Open
eumentis-madhurzanwar opened this issue Apr 26, 2024 · 3 comments

Comments

@eumentis-madhurzanwar
Copy link

Hi. I am trying to write a custom code for handling segmentation output. The problem I am facing is converting the outputs to a binary mask and the binary mask detecting multiple contours for a single bounding box coordinate.

   mask = row.reshape(160,160)
   mask = sigmoid(mask)
   mask = (mask > 0.5).astype("uint8")*255
   x1,y1,x2,y2 = box
   mask_x1 = round(x1/image_width*160)
   mask_y1 = round(y1/image_height*160)
   mask_x2 = round(x2/image_width*160)
   mask_y2 = round(y2/image_height*160)
   mask = mask[mask_y1:mask_y2,mask_x1:mask_x2]
   img_mask = Image.fromarray(mask,"L")
   img_mask = img_mask.resize((round(x2-x1),round(y2-y1)))
   mask = np.array(img_mask)
   return mask

When I save the mask and have a look, I get multiple white contours for a single bounding box. And when this mask is passed to cv2.drawContours I get multiple polygon coordinates.I should have got a single polygon shape. Moreover there is a single probability attached to per box. Per box giving 5 contours is not matching with a single probability. If anyone can pls help me with this issue

@AndreyGermanov
Copy link
Owner

AndreyGermanov commented Apr 26, 2024

In general, a single object can consist of several parts, and in this case the mask will contain several polygons. If it so, you should treat all these polygons equally related to a single object with a single probability.

What is your problem?
The problem that YOLOv8 detects incorrect contours?
Or the contours detected correctly, but you can't handle them?

To get a correct answer, please, provide more context., share the source image, the mask and the model that you used.

@eumentis-madhurzanwar
Copy link
Author

eumentis-madhurzanwar commented Apr 26, 2024

Thank you for your prompt response. The problem is my output segmentation does not match with what yolov8's predict method produces. This happens for images where multiple polygons are detected for a single bounding box. For single polygon per bounding box the output does match.

030887
This is my original image
bounding
This is the output produced by onnx process custom post processing
segmentation_bounding
And this is the output produced by yolov8's predict method for segmentation.
The onnx process is giving 2 more segmented boxes as compared to yolov8

I have used a model trained on my custom dataset using transfer learning from the yolov8l-seg model.

while len(objects)>0:
    result.append(objects[0])
    # objects = [object for object in objects if object[4] == objects[0][4] and iou(object,objects[0])<0.45]
    objects = [object for object in objects if object[4] != objects[0][4] or iou(object,objects[0])<0.45]

img = Image.open(image_path)
draw = ImageDraw.Draw(img, "RGBA")
for object in result:
    [x1, y1, x2, y2, label, prob, mask, polygon] = object
    print('polygon',len(polygon))
    if len(polygon) > 1:
        for values in polygon:
            polygon = [(round(x1+point[0]),round(y1+point[1])) for point in values]
            draw.polygon(polygon, fill=(0, 255, 0, 125))
    else:
         polygon = [(round(x1+point[0]),round(y1+point[1])) for point in polygon[0]]
         draw.polygon(polygon, fill=(0, 255, 0, 125))

And the get_polygon code

def get_polygon(mask,number):
    contours = cv2.findContours(mask, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
 polygons = []
    for contour in contours[0]:
        polygon = [(point[0][0], point[0][1]) for point in contour]
        polygons.append(polygon)
    return polygons

@AndreyGermanov
Copy link
Owner

AndreyGermanov commented Apr 26, 2024

Sometimes ONNX version of inference gives different results, than official YOLOv8 API, perhaps because of additional image preprocessing procedures and augmentations, used in the official package. You can either filter out small polygons and use only the biggest one, or learn the Ultralytics API source code to find, which way it preprocesses the source image before inference. I think, it is here: https://github.com/ultralytics/ultralytics/blob/main/ultralytics/engine/predictor.py in the .preprocess and the .pre_transform methods. I think, it uses the letter box approach when resize the source image. It can give different results, than if just resize the image directly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants