Detecting Angled Shooting Target with OpenCV Python

258 Views Asked by At

I have a task to detect a shooting target with OpenCv. The shooting target is a normal shooting target, the problem is the camera is located at the bottom of the target, so that the image will be angled.

Angled Shooting Target

I already crop and change the perspective of the image with OpenCv findhomograph. But I changed the perspective manually because I cannot create a code to detect the shooting target automatically.

Changed Perspective Shooting Target

The result of the changed perspective are not exactly circle, but it is a little bit ellipse and blurry. The OpenCv code that I tried cannot detect the outer circle because the image is blurred

This is my code that I already tried

original_image = cv2.imread("ImageLocation")
original_height, original_width = original_image.shape[:2]

# Set the desired display width
display_width = 1300

# Calculate the corresponding display height while maintaining aspect ratio
aspect_ratio = original_width / original_height
display_height = int(display_width / aspect_ratio)

# Resize the image
resized_image = cv2.resize(original_image, (display_width, display_height))

# Manually define the original corners (clockwise order)

original_corners = np.array([[465, 13], [882, 3], [218, 580], [1145, 583]], dtype=np.float32)
original_corners = original_corners.astype(np.int32)

# Draw the manually defined corners on the original image (blue color)
for corner in original_corners:
    cv2.circle(resized_image, tuple(corner), 1, (255, 0, 0), -1)

target_width = 413  # Adjust this based on your desired output size
target_height = 625
new_corners = np.array([[465, 3], [882, 3], [463, 580], [882, 580]], dtype=np.float32)

# Calculate the perspective transformation matrix
original_perspective_matrix, _ = cv2.findHomography(original_corners.astype(np.float32), new_corners)
# inverse_perspective_matrix = cv2.getPerspectiveTransform(new_corners, original_corners.astype(np.float32))


# Apply the perspective transformation
corrected_image = cv2.warpPerspective(resized_image, original_perspective_matrix, (0, 0))

crop_x1, crop_y1 = 465, 3 # Top-left corner
crop_x2, crop_y2 = 882, 580  # Bottom-right corner

# Crop the transformed image
cropped_image = corrected_image[crop_y1:crop_y2, crop_x1:crop_x2]
cropped_height, cropped_width = cropped_image.shape[:2]
brightened_image = cv2.subtract(cropped_image, 200)

# Display the corrected image with original corners and main contour
cv2.imshow("Original Image with Manual Corners", resized_image)
cv2.imshow("Corrected Image with Original Corners and Main Contour", corrected_image)
cv2.imshow("cropped Image", cropped_image)
cv2.waitKey(0)
cv2.destroyAllWindows()

# hsv
hsv = cv2.cvtColor(cropped_image, cv2.COLOR_BGR2HSV)
h, s, v = cv2.split(hsv)

# find the outer ring
lower_brightness = 70  # Adjust this value as needed
upper_brightness = 216  # Adjust this value as needed

# Extract the Value channel from the HSV image
value_channel = hsv[:, :, 2]  # Value channel is the third channel

# Create a mask for the specified brightness range
brightness_mask = cv2.inRange(value_channel, lower_brightness, upper_brightness)

# Apply the mask to the original image to show only pixels within the brightness range
filtered_result  = cv2.bitwise_and(cropped_image, cropped_image, mask=brightness_mask)
gray_filtered = cv2.cvtColor(filtered_result, cv2.COLOR_BGR2GRAY)

cv2.imshow('vmask', gray_filtered)

# contours
contours, _ = cv2.findContours(gray_filtered, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

circle_centers = []
for contour in contours:
    # Calculate the center of each bullet hole
    (x, y, w, h) = cv2.boundingRect(contour)
    if w > 25:
        center_x = x + w // 2
        center_y = y + h // 2
        radius = max(w, h) // 2
        circle_centers.append((center_x, center_y, radius)) 

The result of the code above is like this.

Masked Shooting Target with HSV

Detected Circle with OpenCv

I want to change the homograph of the image to exactly circle, not an ellipse so that the OpenCv can detect each circle. I also want the outer circle to be detected.

1

There are 1 best solutions below

1
Snehil Chatterjee On

Have you tried using threshold image? Please try these codes below

gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blurred_image = cv2.GaussianBlur(gray_image, (5, 5), 0)
_, threshold_image = cv2.threshold(blurred_image, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)

kernel = np.ones((3, 3), np.uint8)
cleaned_image = cv2.morphologyEx(threshold_image, cv2.MORPH_OPEN, kernel, iterations=3)

# Find contours (assumes the bullet holes are the largest contours)
contours, _ = cv2.findContours(cleaned_image, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE)

I think you can use these code to detect the shooting range