Reputation: 109
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.net/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):
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()
Upvotes: 1
Views: 86
Reputation: 53154
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])
Upvotes: 2