英文:
Circles detection with Python OpenCV
问题
以下是您提供的代码的翻译部分:
我目前正在面临一个我开发的程序的问题。该程序旨在读取包含圆环的图像文件,并识别圆环内外的两个圆。此外,它旨在类似于声纳一样扫描内部圆,并检测其中的任何缺陷。然而,我遇到了一个问题,即程序无法检测到圆环内部的圆。我已尝试调整各种参数,但这些修改都没有证明有效。我非常感谢关于如何解决这个问题的任何指导或建议。
这是我的代码:
您提供的代码部分已经翻译完成。如果您需要更多帮助或有其他问题,请随时告诉我。
英文:
I am currently facing an issue with a program I have developed. The program is designed to read an image file containing an annulus and identify both the circle inside the annulus and the one outside. Furthermore, it is intended to scan the inner circle similar to a sonar and detect any imperfections within it. However, I am encountering a problem where the program fails to detect the circle inside the annulus. I have attempted adjusting various parameters, but none of these modifications have proven effective. I would greatly appreciate any guidance or suggestions on how to address this issue.[text]
This is my code:
import cv2
import numpy as np
def detect_annulus(image):
# Convert to grayscale
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# Denoise the image
denoised = cv2.fastNlMeansDenoising(gray, None, 10, 10, 7)
# Perform Canny edge detection
edges = cv2.Canny(denoised, 50, 100)
# Detect circles using Hough Circle Transform
circles = cv2.HoughCircles(edges, cv2.HOUGH_GRADIENT, dp=1, minDist=50, param1=50, param2=25, minRadius=220,
maxRadius=1000)
# Check if circles are found
if circles is not None:
# Convert the circle parameters to integers
circles = np.round(circles[0, :]).astype(int)
# Filter circles based on size, aspect ratio, or position if needed
# Sort circles by radius in descending order
circles = sorted(circles, key=lambda x: x[2], reverse=True)
# Extract the annulus circle (outer circle)
x, y, r_outer = circles[0]
# Extract the inside circle (smaller circle)
x_inner, y_inner, r_inner = circles[1]
# Calculate the radius inside the annulus
r_final = r_outer - r_inner
# Draw the circles on the image
cv2.circle(image, (x, y), r_outer, (0, 255, 0), 2)
cv2.circle(image, (x_inner, y_inner), r_inner, (0, 0, 255), 2)
# Display the image with circles
cv2.imshow('Circles', image)
cv2.waitKey(0)
cv2.destroyAllWindows()
return r_final
else:
print("No circles detected.")
return None
def scan_circle_for_imperfections(image, center_x, center_y, radius, step_size):
# Initialize variables to store imperfections
imperfections = []
# Convert to grayscale
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# Calculate the number of iterations based on step size
num_iterations = int(360 / step_size)
# Initialize variables to store the largest and smallest r_final values
largest_r_final = None
smallest_r_final = None
# Iterate over angles around the circle
for i in range(num_iterations):
# Compute the current angle
angle = i * step_size
# Compute the coordinates of the point on the circle
x = int(center_x + radius * np.cos(np.radians(angle)))
y = int(center_y + radius * np.sin(np.radians(angle)))
# Get the pixel intensity at the point
intensity = gray[y, x]
# Calculate the r_final value at the current point
r_final = intensity / 255.0 * radius
# Update the largest and smallest r_final values
if largest_r_final is None or r_final > largest_r_final:
largest_r_final = r_final
if smallest_r_final is None or r_final < smallest_r_final:
smallest_r_final = r_final
# Calculate the threshold for detecting imperfections
threshold = 0.5 # Adjust this value based on your requirements
# Iterate over angles again to find imperfections
for i in range(num_iterations):
# Compute the current angle
angle = i * step_size
# Compute the coordinates of the point on the circle
x = int(center_x + radius * np.cos(np.radians(angle)))
y = int(center_y + radius * np.sin(np.radians(angle)))
# Get the pixel intensity at the point
intensity = gray[y, x]
# Calculate the r_final value at the current point
r_final = intensity / 255.0 * radius
# Check if the r_final value is significantly larger than others
if r_final - smallest_r_final > threshold * (largest_r_final - smallest_r_final):
imperfections.append((x, y))
return imperfections
def main():
# Load the input image
image = cv2.imread('Images/1.jpg')
# Detect the annulus and calculate the inside and outside radii
r_final = detect_annulus(image)
if r_final is not None:
# Find the center coordinates of the annulus
center_x = int(image.shape[1] / 2)
center_y = int(image.shape[0] / 2)
# Define the scanning radius from the center
scan_radius = int(r_final * 1.2)
# Define the step size for scanning
step_size = 5
# Scan the circle for imperfections
imperfections = scan_circle_for_imperfections(image, center_x, center_y, scan_radius, step_size)
# Print the imperfections
if imperfections:
print(f"Imperfections found: {len(imperfections)}")
for imperfection in imperfections:
print(f"Coordinate: {imperfection}")
else:
print("No imperfections found.")
else:
print("Failed to detect the annulus.")
if __name__ == '__main__':
main()
and the image i used is :Annulus Image
答案1
得分: 1
主要问题是外圈和内圈具有相同的中心坐标,但minDist
参数限制了中心之间的最小距离。
minDist - 检测到的圆心之间的最小距离。如果参数值太小,除了一个真实的圆之外,可能还会误检测到多个相邻圆。如果参数值太大,可能会错过一些圆。
通常情况下,cv2.HoughCircles 不是设计用来检测具有相同中心坐标的多个圆的。
我们可以通过两次迭代来找到外圈和内圈:
- 使用
cv2.HoughCircles
来找到外圈(忽略内圈)。 - 从
edges
中擦除外圈(在外圈上绘制黑色)。 - 使用
cv2.HoughCircles
来找到内圈。
代码示例:
import cv2
import numpy as np
def detect_annulus(image):
# 将图像转换为灰度
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 对图像进行去噪
denoised = cv2.fastNlMeansDenoising(gray, None, 10, 10, 7)
# 使用Canny边缘检测
edges = cv2.Canny(denoised, 50, 100)
# 使用Hough Circle Transform检测圆
circles = cv2.HoughCircles(edges, cv2.HOUGH_GRADIENT, dp=1, minDist=50, param1=50, param2=25, minRadius=220,
maxRadius=1000)
# 检查是否检测到了圆
if circles is not None:
# 将圆参数转换为整数
circles = np.round(circles[0, :]).astype(int)
# 根据需要基于大小、宽高比或位置筛选圆
# 按半径降序排序圆
circles = sorted(circles, key=lambda x: x[2], reverse=True)
# 提取环形圆(外圈)
x, y, r_outer = circles[0]
# 在图像上绘制圆
cv2.circle(image, (x, y), r_outer, (0, 255, 0), 2)
# 擦除外圈(大圆)
cv2.circle(edges, (x, y), r_outer, 0, 5)
# 使用Hough Circle Transform检测圆(检测内圈)
circles = cv2.HoughCircles(edges, cv2.HOUGH_GRADIENT, dp=1, minDist=50, param1=50, param2=25, minRadius=220,
maxRadius=300)
if circles is not None:
circles = np.round(circles[0, :]).astype(int)
# 按半径降序排序圆
circles = sorted(circles, key=lambda x: x[2], reverse=True)
# 提取内圈(小圆)
x_inner, y_inner, r_inner = circles[0]
cv2.circle(image, (x_inner, y_inner), r_inner, (0, 0, 255), 2)
# 计算环形内的半径
r_final = r_outer - r_inner
else:
print("未检测到内圆。")
return None
# 显示带有圆的图像
cv2.imshow('Circles', image)
cv2.waitKey(0)
cv2.destroyAllWindows()
return r_final
else:
print("未检测到圆。")
return None
# 其他代码部分不翻译
注意:
总的来说,cv2.HoughCircles
不是一个用于找到圆的强大方法。
使用 cv2.threshold
(使用 cv2.THRESH_BINARY_INV
)然后 cv2.findContours
(不使用 cv2.Canny
)是更稳健的方法,用于找到圆的轮廓。
我们可以使用 cv2.minEnclosingCircle
来找到轮廓的中心和半径。
我们还可以使用两个阶段(首先找到外圈,然后是内圈)的方法。
英文:
The main issue is that the outer circle and the inner circle have the same center coordinate, but minDist
parameter limits the minimum distance between the centers.
>minDist - Minimum distance between the centers of the detected circles. If the parameter is too small, multiple neighbor circles may be falsely detected in addition to a true one. If it is too large, some circles may be missed.
In general cv2.HoughCircles is not designed to detect multiple circles with the same center coordinate.
We may find the outer and inner circles in two iterations:
- Use
cv2.HoughCircles
for finding the outer circle (ignore the inner circle). - Erase the outer circle from
edges
(draw black color over the outer circle). - Use
cv2.HoughCircles
for finding the inner circle.
Code sample:
import cv2
import numpy as np
def detect_annulus(image):
# Convert to grayscale
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# Denoise the image
denoised = cv2.fastNlMeansDenoising(gray, None, 10, 10, 7)
# Perform Canny edge detection
edges = cv2.Canny(denoised, 50, 100)
# Detect circles using Hough Circle Transform
circles = cv2.HoughCircles(edges, cv2.HOUGH_GRADIENT, dp=1, minDist=50, param1=50, param2=25, minRadius=220,
maxRadius=1000)
# Check if circles are found
if circles is not None:
# Convert the circle parameters to integers
circles = np.round(circles[0, :]).astype(int)
# Filter circles based on size, aspect ratio, or position if needed
# Sort circles by radius in descending order
circles = sorted(circles, key=lambda x: x[2], reverse=True)
# Extract the annulus circle (outer circle)
x, y, r_outer = circles[0]
# Draw the circles on the image
cv2.circle(image, (x, y), r_outer, (0, 255, 0), 2)
#cv2.circle(image, (x_inner, y_inner), r_inner, (0, 0, 255), 2)
# Erase the outer (large) circle.
cv2.circle(edges, (x, y), r_outer, 0, 5)
#cv2.imshow('edges', edges)
# Detect circles using Hough Circle Transform (detect the inner circle).
circles = cv2.HoughCircles(edges, cv2.HOUGH_GRADIENT, dp=1, minDist=50, param1=50, param2=25, minRadius=220,
maxRadius=300)
if circles is not None:
circles = np.round(circles[0, :]).astype(int)
# Sort circles by radius in descending order
circles = sorted(circles, key=lambda x: x[2], reverse=True)
# Extract the inside circle (smaller circle)
x_inner, y_inner, r_inner = circles[0]
cv2.circle(image, (x_inner, y_inner), r_inner, (0, 0, 255), 2)
# Calculate the radius inside the annulus
r_final = r_outer - r_inner
else:
print("No Inner circle detected.")
return None
# Display the image with circles
cv2.imshow('Circles', image)
cv2.waitKey(0)
cv2.destroyAllWindows()
#cv2.imwrite('circles_image.png', image)
return r_final
else:
print("No circles detected.")
return None
def scan_circle_for_imperfections(image, center_x, center_y, radius, step_size):
# Initialize variables to store imperfections
imperfections = []
# Convert to grayscale
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# Calculate the number of iterations based on step size
num_iterations = int(360 / step_size)
# Initialize variables to store the largest and smallest r_final values
largest_r_final = None
smallest_r_final = None
# Iterate over angles around the circle
for i in range(num_iterations):
# Compute the current angle
angle = i * step_size
# Compute the coordinates of the point on the circle
x = int(center_x + radius * np.cos(np.radians(angle)))
y = int(center_y + radius * np.sin(np.radians(angle)))
# Get the pixel intensity at the point
intensity = gray[y, x]
# Calculate the r_final value at the current point
r_final = intensity / 255.0 * radius
# Update the largest and smallest r_final values
if largest_r_final is None or r_final > largest_r_final:
largest_r_final = r_final
if smallest_r_final is None or r_final < smallest_r_final:
smallest_r_final = r_final
# Calculate the threshold for detecting imperfections
threshold = 0.5 # Adjust this value based on your requirements
# Iterate over angles again to find imperfections
for i in range(num_iterations):
# Compute the current angle
angle = i * step_size
# Compute the coordinates of the point on the circle
x = int(center_x + radius * np.cos(np.radians(angle)))
y = int(center_y + radius * np.sin(np.radians(angle)))
# Get the pixel intensity at the point
intensity = gray[y, x]
# Calculate the r_final value at the current point
r_final = intensity / 255.0 * radius
# Check if the r_final value is significantly larger than others
if r_final - smallest_r_final > threshold * (largest_r_final - smallest_r_final):
imperfections.append((x, y))
return imperfections
def main():
# Load the input image
image = cv2.imread('Images/1.jpg')
# Detect the annulus and calculate the inside and outside radii
r_final = detect_annulus(image)
if r_final is not None:
# Find the center coordinates of the annulus
center_x = int(image.shape[1] / 2)
center_y = int(image.shape[0] / 2)
# Define the scanning radius from the center
scan_radius = int(r_final * 1.2)
# Define the step size for scanning
step_size = 5
# Scan the circle for imperfections
imperfections = scan_circle_for_imperfections(image, center_x, center_y, scan_radius, step_size)
# Print the imperfections
if imperfections:
print(f"Imperfections found: {len(imperfections)}")
for imperfection in imperfections:
print(f"Coordinate: {imperfection}")
else:
print("No imperfections found.")
else:
print("Failed to detect the annulus.")
if __name__ == '__main__':
main()
Note:
In general, cv2.HoughCircles
is not a robust method for finding circles.
Using cv2.threshold
(with cv2.THRESH_BINARY_INV
), and then cv2.findContours
(without cv2.Canny
) is much more robust way for finding the contours of the circles.
We may use cv2.minEnclosingCircle
for finding the center and the radius of the contours.
We may also use two stages (finding the outer circle than the inner circle).
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论