I'm trying to write a script that will identify the circles projected in concentric rings of light. I realize the image is not the best quality, but I'm hoping to still find a way to identify the circles. Once identified, I want to output a measure that tells me how "circular" the circle actually is and if it's being "pulled" in a given direction. Here are the pictures:
I've tried this so far which isn't working:
import cv2
import numpy as np
import matplotlib.pyplot as plt
# Load the image
image_path = '/mnt/data/IMG_1.JPG'
img = cv2.imread(image_path)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# Apply Gaussian blur to reduce noise
gray_blurred = cv2.GaussianBlur(gray, (9, 9), 2)
# Use the Hough Circle Transform to detect the central circle
hough_circles = cv2.HoughCircles(gray_blurred, cv2.HOUGH_GRADIENT, dp=1.2, minDist=50, param1=100, param2=30, minRadius=30, maxRadius=150)
# Draw detected Hough circles
if hough_circles is not None:
hough_circles = np.uint16(np.around(hough_circles))
for i in hough_circles[0, :]:
cv2.circle(img, (i[0], i[1]), i[2], (0, 255, 0), 2)
cv2.circle(img, (i[0], i[1]), 2, (0, 0, 255), 3)
# Use Canny edge detection
edges = cv2.Canny(gray_blurred, 50, 150)
# Find contours
contours, _ = cv2.findContours(edges, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# Filter contours based on circularity and size
def is_circle(contour, min_radius, max_radius):
# Approximate contour to polygon
approx = cv2.approxPolyDP(contour, 0.02 * cv2.arcLength(contour, True), True)
# Calculate the radius of the contour
area = cv2.contourArea(contour)
if area == 0:
return False, 0, 0, 0
perimeter = cv2.arcLength(contour, True)
circularity = (4 * np.pi * area) / (perimeter * perimeter)
(x, y), radius = cv2.minEnclosingCircle(contour)
return 0.7 < circularity < 1.3 and min_radius < radius < max_radius, int(x), int(y), int(radius)
# Draw detected contours as circles
min_radius, max_radius = 30, 150
for contour in contours:
circle, x, y, radius = is_circle(contour, min_radius, max_radius)
if circle:
cv2.circle(img, (x, y), radius, (0, 255, 0), 2)
cv2.circle(img, (x, y), 2, (0, 0, 255), 3)
# Show the result
plt.figure(figsize=(10, 10))
plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
plt.title('Detected Circles and Shadows')
plt.axis('off')
plt.show()
This outputs the following image:

]

