最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

opencv - Drawing a bounding box around the largest contour python CV - Stack Overflow

programmeradmin3浏览0评论

I'm struggling to get the bounding box for an identified area in an image. The following code results in this image: .png. However, as might be obvious from the picture, I'd like to bounding box to enclose the (black) identified large area instead. Any suggestions on how to accomplish that?

The following image shows what the desired result should be (the red contours and the thick green bounding box):

Here is the original image:

import numpy as np
import cv2

# Load the image
image = cv2.imread("image.png")  # Update with your image path
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)

# Define refined HSV ranges for sandy ground (light brown, beige, gray)
lower_sand = np.array([10, 20, 100])  # Lower bound for sand-like colors
upper_sand = np.array([30, 100, 255])  # Upper bound for sand-like colors

# Create a mask for the sandy competition ground
mask_sand = cv2.inRange(hsv, lower_sand, upper_sand)

# Apply morphological operations to reduce noise
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (7, 7))
mask_sand = cv2.morphologyEx(mask_sand, cv2.MORPH_CLOSE, kernel)  # Close gaps
mask_sand = cv2.morphologyEx(mask_sand, cv2.MORPH_OPEN, kernel)   # Remove small noise

# Invert the mask (to highlight everything except the competition area)
mask = cv2.bitwise_not(mask_sand)

# Apply the inverted mask to the original image
output = cv2.bitwise_and(image, image, mask=mask)

# Ensure the mask is properly binarized for contour detection
ret, thresh = cv2.threshold(mask, 50, 255, cv2.THRESH_BINARY)

# Find contours
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

if contours:
    # Find the largest contour by area
    largest_contour = max(contours, key=cv2.contourArea)

    # Approximate the contour to a quadrilateral
    epsilon = 0.02 * cv2.arcLength(largest_contour, True)
    approx = cv2.approxPolyDP(largest_contour, epsilon, True)

    # If the approximation has 4 points, use it; otherwise, use convex hull
    if len(approx) == 4:
        quadrilateral = approx
    else:
        quadrilateral = cv2.convexHull(largest_contour)

    # Draw the quadrilateral in green
    cv2.polylines(output, [quadrilateral], isClosed=True, color=(0, 255, 0), thickness=3)

    # Draw all detected contours in blue
    cv2.drawContours(output, contours, -1, (255, 0, 0), 2)


# Show and save the output
cv2.imshow("Result", np.hstack([image, output]))
cv2.imwrite("output_image.png", output)

cv2.waitKey(0)
cv2.destroyAllWindows()

I'm struggling to get the bounding box for an identified area in an image. The following code results in this image: https://i.sstatic/6HX4dNrB.png. However, as might be obvious from the picture, I'd like to bounding box to enclose the (black) identified large area instead. Any suggestions on how to accomplish that?

The following image shows what the desired result should be (the red contours and the thick green bounding box):

Here is the original image:

import numpy as np
import cv2

# Load the image
image = cv2.imread("image.png")  # Update with your image path
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)

# Define refined HSV ranges for sandy ground (light brown, beige, gray)
lower_sand = np.array([10, 20, 100])  # Lower bound for sand-like colors
upper_sand = np.array([30, 100, 255])  # Upper bound for sand-like colors

# Create a mask for the sandy competition ground
mask_sand = cv2.inRange(hsv, lower_sand, upper_sand)

# Apply morphological operations to reduce noise
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (7, 7))
mask_sand = cv2.morphologyEx(mask_sand, cv2.MORPH_CLOSE, kernel)  # Close gaps
mask_sand = cv2.morphologyEx(mask_sand, cv2.MORPH_OPEN, kernel)   # Remove small noise

# Invert the mask (to highlight everything except the competition area)
mask = cv2.bitwise_not(mask_sand)

# Apply the inverted mask to the original image
output = cv2.bitwise_and(image, image, mask=mask)

# Ensure the mask is properly binarized for contour detection
ret, thresh = cv2.threshold(mask, 50, 255, cv2.THRESH_BINARY)

# Find contours
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

if contours:
    # Find the largest contour by area
    largest_contour = max(contours, key=cv2.contourArea)

    # Approximate the contour to a quadrilateral
    epsilon = 0.02 * cv2.arcLength(largest_contour, True)
    approx = cv2.approxPolyDP(largest_contour, epsilon, True)

    # If the approximation has 4 points, use it; otherwise, use convex hull
    if len(approx) == 4:
        quadrilateral = approx
    else:
        quadrilateral = cv2.convexHull(largest_contour)

    # Draw the quadrilateral in green
    cv2.polylines(output, [quadrilateral], isClosed=True, color=(0, 255, 0), thickness=3)

    # Draw all detected contours in blue
    cv2.drawContours(output, contours, -1, (255, 0, 0), 2)


# Show and save the output
cv2.imshow("Result", np.hstack([image, output]))
cv2.imwrite("output_image.png", output)

cv2.waitKey(0)
cv2.destroyAllWindows()
Share Improve this question edited Feb 17 at 13:03 Patrick Plaatje asked Feb 16 at 11:02 Patrick PlaatjePatrick Plaatje 1091 silver badge9 bronze badges 3
  • something that i noticed just now, please add the source image, without any of the drawings – Tino D Commented Feb 17 at 11:13
  • @ChristophRackwitz apologies, how can I avoid that? – Patrick Plaatje Commented Feb 17 at 13:02
  • @TinoD I have added the source image. – Patrick Plaatje Commented Feb 17 at 19:53
Add a comment  | 

1 Answer 1

Reset to default 2

To find the largest contour in Python/OpenCV, try

big_contour = max(contours, key=cv2.contourArea)

Then to get and draw the bounding box:

x1,y1,w1,h1 = cv2.boundingRect(big_contour)
cv2.rectangle(result, (x1, y1), (x1+w1, y1+h1), (0, 0, 255), 2)

If you are trying to draw color on a grayscale or binary image, you need to convert that to BGR before drawing. You can do that with cv2.cvtColor(output, cv2.COLOR_Gray2BGR) or cv2.merge([output, output, output])

发布评论

评论列表(0)

  1. 暂无评论