使用Python OpenCV进行圆检测

huangapple go评论108阅读模式
英文:

Circles detection with Python OpenCV

问题

以下是您提供的代码的翻译部分:

  1. 我目前正在面临一个我开发的程序的问题该程序旨在读取包含圆环的图像文件并识别圆环内外的两个圆此外它旨在类似于声纳一样扫描内部圆并检测其中的任何缺陷然而我遇到了一个问题即程序无法检测到圆环内部的圆我已尝试调整各种参数但这些修改都没有证明有效我非常感谢关于如何解决这个问题的任何指导或建议
  2. 这是我的代码

您提供的代码部分已经翻译完成。如果您需要更多帮助或有其他问题,请随时告诉我。

英文:

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:

  1. import cv2
  2. import numpy as np
  3. def detect_annulus(image):
  4. # Convert to grayscale
  5. gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
  6. # Denoise the image
  7. denoised = cv2.fastNlMeansDenoising(gray, None, 10, 10, 7)
  8. # Perform Canny edge detection
  9. edges = cv2.Canny(denoised, 50, 100)
  10. # Detect circles using Hough Circle Transform
  11. circles = cv2.HoughCircles(edges, cv2.HOUGH_GRADIENT, dp=1, minDist=50, param1=50, param2=25, minRadius=220,
  12. maxRadius=1000)
  13. # Check if circles are found
  14. if circles is not None:
  15. # Convert the circle parameters to integers
  16. circles = np.round(circles[0, :]).astype(int)
  17. # Filter circles based on size, aspect ratio, or position if needed
  18. # Sort circles by radius in descending order
  19. circles = sorted(circles, key=lambda x: x[2], reverse=True)
  20. # Extract the annulus circle (outer circle)
  21. x, y, r_outer = circles[0]
  22. # Extract the inside circle (smaller circle)
  23. x_inner, y_inner, r_inner = circles[1]
  24. # Calculate the radius inside the annulus
  25. r_final = r_outer - r_inner
  26. # Draw the circles on the image
  27. cv2.circle(image, (x, y), r_outer, (0, 255, 0), 2)
  28. cv2.circle(image, (x_inner, y_inner), r_inner, (0, 0, 255), 2)
  29. # Display the image with circles
  30. cv2.imshow('Circles', image)
  31. cv2.waitKey(0)
  32. cv2.destroyAllWindows()
  33. return r_final
  34. else:
  35. print("No circles detected.")
  36. return None
  37. def scan_circle_for_imperfections(image, center_x, center_y, radius, step_size):
  38. # Initialize variables to store imperfections
  39. imperfections = []
  40. # Convert to grayscale
  41. gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
  42. # Calculate the number of iterations based on step size
  43. num_iterations = int(360 / step_size)
  44. # Initialize variables to store the largest and smallest r_final values
  45. largest_r_final = None
  46. smallest_r_final = None
  47. # Iterate over angles around the circle
  48. for i in range(num_iterations):
  49. # Compute the current angle
  50. angle = i * step_size
  51. # Compute the coordinates of the point on the circle
  52. x = int(center_x + radius * np.cos(np.radians(angle)))
  53. y = int(center_y + radius * np.sin(np.radians(angle)))
  54. # Get the pixel intensity at the point
  55. intensity = gray[y, x]
  56. # Calculate the r_final value at the current point
  57. r_final = intensity / 255.0 * radius
  58. # Update the largest and smallest r_final values
  59. if largest_r_final is None or r_final > largest_r_final:
  60. largest_r_final = r_final
  61. if smallest_r_final is None or r_final < smallest_r_final:
  62. smallest_r_final = r_final
  63. # Calculate the threshold for detecting imperfections
  64. threshold = 0.5 # Adjust this value based on your requirements
  65. # Iterate over angles again to find imperfections
  66. for i in range(num_iterations):
  67. # Compute the current angle
  68. angle = i * step_size
  69. # Compute the coordinates of the point on the circle
  70. x = int(center_x + radius * np.cos(np.radians(angle)))
  71. y = int(center_y + radius * np.sin(np.radians(angle)))
  72. # Get the pixel intensity at the point
  73. intensity = gray[y, x]
  74. # Calculate the r_final value at the current point
  75. r_final = intensity / 255.0 * radius
  76. # Check if the r_final value is significantly larger than others
  77. if r_final - smallest_r_final > threshold * (largest_r_final - smallest_r_final):
  78. imperfections.append((x, y))
  79. return imperfections
  80. def main():
  81. # Load the input image
  82. image = cv2.imread('Images/1.jpg')
  83. # Detect the annulus and calculate the inside and outside radii
  84. r_final = detect_annulus(image)
  85. if r_final is not None:
  86. # Find the center coordinates of the annulus
  87. center_x = int(image.shape[1] / 2)
  88. center_y = int(image.shape[0] / 2)
  89. # Define the scanning radius from the center
  90. scan_radius = int(r_final * 1.2)
  91. # Define the step size for scanning
  92. step_size = 5
  93. # Scan the circle for imperfections
  94. imperfections = scan_circle_for_imperfections(image, center_x, center_y, scan_radius, step_size)
  95. # Print the imperfections
  96. if imperfections:
  97. print(f"Imperfections found: {len(imperfections)}")
  98. for imperfection in imperfections:
  99. print(f"Coordinate: {imperfection}")
  100. else:
  101. print("No imperfections found.")
  102. else:
  103. print("Failed to detect the annulus.")
  104. if __name__ == '__main__':
  105. main()

and the image i used is :Annulus Image

答案1

得分: 1

主要问题是外圈和内圈具有相同的中心坐标,但minDist参数限制了中心之间的最小距离。

minDist - 检测到的圆心之间的最小距离。如果参数值太小,除了一个真实的圆之外,可能还会误检测到多个相邻圆。如果参数值太大,可能会错过一些圆。

通常情况下,cv2.HoughCircles 不是设计用来检测具有相同中心坐标的多个圆的。

我们可以通过两次迭代来找到外圈和内圈:

  • 使用 cv2.HoughCircles 来找到外圈(忽略内圈)。
  • edges 中擦除外圈(在外圈上绘制黑色)。
  • 使用 cv2.HoughCircles 来找到内圈。

代码示例:

  1. import cv2
  2. import numpy as np
  3. def detect_annulus(image):
  4. # 将图像转换为灰度
  5. gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
  6. # 对图像进行去噪
  7. denoised = cv2.fastNlMeansDenoising(gray, None, 10, 10, 7)
  8. # 使用Canny边缘检测
  9. edges = cv2.Canny(denoised, 50, 100)
  10. # 使用Hough Circle Transform检测圆
  11. circles = cv2.HoughCircles(edges, cv2.HOUGH_GRADIENT, dp=1, minDist=50, param1=50, param2=25, minRadius=220,
  12. maxRadius=1000)
  13. # 检查是否检测到了圆
  14. if circles is not None:
  15. # 将圆参数转换为整数
  16. circles = np.round(circles[0, :]).astype(int)
  17. # 根据需要基于大小、宽高比或位置筛选圆
  18. # 按半径降序排序圆
  19. circles = sorted(circles, key=lambda x: x[2], reverse=True)
  20. # 提取环形圆(外圈)
  21. x, y, r_outer = circles[0]
  22. # 在图像上绘制圆
  23. cv2.circle(image, (x, y), r_outer, (0, 255, 0), 2)
  24. # 擦除外圈(大圆)
  25. cv2.circle(edges, (x, y), r_outer, 0, 5)
  26. # 使用Hough Circle Transform检测圆(检测内圈)
  27. circles = cv2.HoughCircles(edges, cv2.HOUGH_GRADIENT, dp=1, minDist=50, param1=50, param2=25, minRadius=220,
  28. maxRadius=300)
  29. if circles is not None:
  30. circles = np.round(circles[0, :]).astype(int)
  31. # 按半径降序排序圆
  32. circles = sorted(circles, key=lambda x: x[2], reverse=True)
  33. # 提取内圈(小圆)
  34. x_inner, y_inner, r_inner = circles[0]
  35. cv2.circle(image, (x_inner, y_inner), r_inner, (0, 0, 255), 2)
  36. # 计算环形内的半径
  37. r_final = r_outer - r_inner
  38. else:
  39. print("未检测到内圆。")
  40. return None
  41. # 显示带有圆的图像
  42. cv2.imshow('Circles', image)
  43. cv2.waitKey(0)
  44. cv2.destroyAllWindows()
  45. return r_final
  46. else:
  47. print("未检测到圆。")
  48. return None
  49. # 其他代码部分不翻译

输出:
使用Python OpenCV进行圆检测


注意:
总的来说,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:

  1. import cv2
  2. import numpy as np
  3. def detect_annulus(image):
  4. # Convert to grayscale
  5. gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
  6. # Denoise the image
  7. denoised = cv2.fastNlMeansDenoising(gray, None, 10, 10, 7)
  8. # Perform Canny edge detection
  9. edges = cv2.Canny(denoised, 50, 100)
  10. # Detect circles using Hough Circle Transform
  11. circles = cv2.HoughCircles(edges, cv2.HOUGH_GRADIENT, dp=1, minDist=50, param1=50, param2=25, minRadius=220,
  12. maxRadius=1000)
  13. # Check if circles are found
  14. if circles is not None:
  15. # Convert the circle parameters to integers
  16. circles = np.round(circles[0, :]).astype(int)
  17. # Filter circles based on size, aspect ratio, or position if needed
  18. # Sort circles by radius in descending order
  19. circles = sorted(circles, key=lambda x: x[2], reverse=True)
  20. # Extract the annulus circle (outer circle)
  21. x, y, r_outer = circles[0]
  22. # Draw the circles on the image
  23. cv2.circle(image, (x, y), r_outer, (0, 255, 0), 2)
  24. #cv2.circle(image, (x_inner, y_inner), r_inner, (0, 0, 255), 2)
  25. # Erase the outer (large) circle.
  26. cv2.circle(edges, (x, y), r_outer, 0, 5)
  27. #cv2.imshow('edges', edges)
  28. # Detect circles using Hough Circle Transform (detect the inner circle).
  29. circles = cv2.HoughCircles(edges, cv2.HOUGH_GRADIENT, dp=1, minDist=50, param1=50, param2=25, minRadius=220,
  30. maxRadius=300)
  31. if circles is not None:
  32. circles = np.round(circles[0, :]).astype(int)
  33. # Sort circles by radius in descending order
  34. circles = sorted(circles, key=lambda x: x[2], reverse=True)
  35. # Extract the inside circle (smaller circle)
  36. x_inner, y_inner, r_inner = circles[0]
  37. cv2.circle(image, (x_inner, y_inner), r_inner, (0, 0, 255), 2)
  38. # Calculate the radius inside the annulus
  39. r_final = r_outer - r_inner
  40. else:
  41. print("No Inner circle detected.")
  42. return None
  43. # Display the image with circles
  44. cv2.imshow('Circles', image)
  45. cv2.waitKey(0)
  46. cv2.destroyAllWindows()
  47. #cv2.imwrite('circles_image.png', image)
  48. return r_final
  49. else:
  50. print("No circles detected.")
  51. return None
  52. def scan_circle_for_imperfections(image, center_x, center_y, radius, step_size):
  53. # Initialize variables to store imperfections
  54. imperfections = []
  55. # Convert to grayscale
  56. gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
  57. # Calculate the number of iterations based on step size
  58. num_iterations = int(360 / step_size)
  59. # Initialize variables to store the largest and smallest r_final values
  60. largest_r_final = None
  61. smallest_r_final = None
  62. # Iterate over angles around the circle
  63. for i in range(num_iterations):
  64. # Compute the current angle
  65. angle = i * step_size
  66. # Compute the coordinates of the point on the circle
  67. x = int(center_x + radius * np.cos(np.radians(angle)))
  68. y = int(center_y + radius * np.sin(np.radians(angle)))
  69. # Get the pixel intensity at the point
  70. intensity = gray[y, x]
  71. # Calculate the r_final value at the current point
  72. r_final = intensity / 255.0 * radius
  73. # Update the largest and smallest r_final values
  74. if largest_r_final is None or r_final > largest_r_final:
  75. largest_r_final = r_final
  76. if smallest_r_final is None or r_final < smallest_r_final:
  77. smallest_r_final = r_final
  78. # Calculate the threshold for detecting imperfections
  79. threshold = 0.5 # Adjust this value based on your requirements
  80. # Iterate over angles again to find imperfections
  81. for i in range(num_iterations):
  82. # Compute the current angle
  83. angle = i * step_size
  84. # Compute the coordinates of the point on the circle
  85. x = int(center_x + radius * np.cos(np.radians(angle)))
  86. y = int(center_y + radius * np.sin(np.radians(angle)))
  87. # Get the pixel intensity at the point
  88. intensity = gray[y, x]
  89. # Calculate the r_final value at the current point
  90. r_final = intensity / 255.0 * radius
  91. # Check if the r_final value is significantly larger than others
  92. if r_final - smallest_r_final > threshold * (largest_r_final - smallest_r_final):
  93. imperfections.append((x, y))
  94. return imperfections
  95. def main():
  96. # Load the input image
  97. image = cv2.imread('Images/1.jpg')
  98. # Detect the annulus and calculate the inside and outside radii
  99. r_final = detect_annulus(image)
  100. if r_final is not None:
  101. # Find the center coordinates of the annulus
  102. center_x = int(image.shape[1] / 2)
  103. center_y = int(image.shape[0] / 2)
  104. # Define the scanning radius from the center
  105. scan_radius = int(r_final * 1.2)
  106. # Define the step size for scanning
  107. step_size = 5
  108. # Scan the circle for imperfections
  109. imperfections = scan_circle_for_imperfections(image, center_x, center_y, scan_radius, step_size)
  110. # Print the imperfections
  111. if imperfections:
  112. print(f"Imperfections found: {len(imperfections)}")
  113. for imperfection in imperfections:
  114. print(f"Coordinate: {imperfection}")
  115. else:
  116. print("No imperfections found.")
  117. else:
  118. print("Failed to detect the annulus.")
  119. if __name__ == '__main__':
  120. main()

Output:
使用Python OpenCV进行圆检测


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).

huangapple
  • 本文由 发表于 2023年6月8日 17:11:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/76430304.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定