I want to use the Python OpenCV library to perform image processing and detect squares in an image. The squares have a certain width, but the specific width value is unknown. Then I want to draw a circle with the center of the square as the center point and a radius equal to four times the distance from the center to the square's contour. There are two intersecting lines in the image, and their positions are not fixed. The clarity of the lines may vary in different images. You can notice that there are many noise dots on the image, and the brightness levels are also inconsistent with different images. How can I determine if the intersection point of the two lines falls within the circle? Red arrow indicates the intersection point of 2 lines in the below image.
I used 4 images for testing. Currently, I convert the color image to grayscale, apply Gaussian blur, use the Canny algorithm for edge detection, and then perform contour detection. The problem I'm facing is that due to the width of the square, some images have the square contour drawn outside the square, some have it drawn inside, and some have both inside and outside contours. How can I update the algorithm to only draw the outer contour? I have already tried adjusting the values in
cv2.Canny(blur, 50, 100)
, but it's difficult to find a set of values that work for all images. And cv2.findContours(edges, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
,if change cv2.RETR_TREE
to cv2.EXTERNAL
, it cannot find the center point and circle.
Looking forward to receiving some useful suggestions from you.
The 4 images for testing are as below.
My Python code is as below.
import cv2
import glob
import os
import numpy as np
def detect_squares(img_path):
file_name = os.path.basename(img_path)
# Read the image and create a copy for drawing results
img = cv2.imread(img_path)
image_with_rectangles = img.copy()
# Convert to grayscale
gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
# Apply Gaussian blur
blur = cv2.GaussianBlur(gray, (5, 5), 0)
# Perform edge detection
edges = cv2.Canny(blur, 50, 100)
# Find contours
contours, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
# Traverse through the detected contours
for contour in contours:
# Calculate contour perimeter
perimeter = cv2.arcLength(contour, True)
# Get the coordinates of contour vertices
approx = cv2.approxPolyDP(contour, 0.04 * perimeter, True)
# Get the coordinate values, width, and height
x, y, w, h = cv2.boundingRect(approx)
# Classify the contour
if len(approx) == 4 and perimeter >= 350 and 0.9 <= float(w) / h <= 1.1:
# Draw red contour lines
cv2.drawContours(image_with_rectangles, contour, -1, (0, 0, 255), cv2.FILLED)
# Calculate contour moments
M = cv2.moments(contour)
# Calculate the centroid coordinates of the contour
if M["m00"] != 0:
center_x = int(M["m10"] / M["m00"])
center_y = int(M["m01"] / M["m00"])
center = (center_x, center_y)
# Draw the center point on the image
cv2.circle(image_with_rectangles, center, 5, (0, 255, 255), 3)
# Calculate the distance from the center to the square contour
distance = int(cv2.pointPolygonTest(approx, center, True))
# Calculate the radius of the circle
radius = 4 * distance
# Draw the circle
cv2.circle(image_with_rectangles, (center_x, center_y), radius, (0, 255, 255), 2)
# Show the resulting image
# cv2.imshow(f"Canny Detection - {file_name}", edges)
cv2.imshow(f"Shape Detection - {file_name}", image_with_rectangles)
cv2.waitKey(0)
cv2.destroyAllWindows()
detect_squares(image_path)