I am new to python & image processing. I am working on a hobby project in which I want to find ALL circles in image and then figure out which one have cross ('X') marked inside it. I have put some code together to find circles so far (below). It works on one image but fails to recognize all circles on another one. Please guide me how i can improve performance of find_circles algorithm.
Test Image:
Result Image:
import cv2
import cv
import numpy as np
import operator
from PIL import Image
def find_circles(img):
im_gray = cv2.imread(img, cv2.CV_LOAD_IMAGE_GRAYSCALE)
(thresh, im_bw) = cv2.threshold(im_gray, 128, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)
img_bw = cv2.threshold(im_gray, thresh, 255, cv2.THRESH_BINARY)[1]
cv2.imwrite('img_bw.png',img_bw)
rows, cols =img_bw.shape
circles = cv2.HoughCircles(img_bw,cv.CV_HOUGH_GRADIENT,1,rows/32, param1=100,param2=40,minRadius=0,maxRadius=100)
circles = np.uint16(np.around(circles))
return circles
def draw_circles(img, circles):
img = cv2.imread(img,0)
cimg = cv2.cvtColor(img,cv2.COLOR_GRAY2BGR)
for i in circles[0,:]:
# draw the outer circle
cv2.circle(cimg,(i[0],i[1]),i[2],(0,255,0),2)
# draw the center of the circle
cv2.circle(cimg,(i[0],i[1]),2,(0,0,255),3)
cv2.putText(cimg,str(i[0])+str(',')+str(i[1]), (i[0],i[1]), cv2.FONT_HERSHEY_SIMPLEX, 0.4, 255)
return cimg
def main():
img = "query_circle9.png"
circles = find_circles(img)
img_circle = draw_circles(img,circles)
cv2.imwrite('cricle.png',img_circle)
if __name__=='__main__':
main()
Use the OpenCV function HoughCircles() to detect circles in an image.
Automatic circle detection is an important element of many image processing algorithms. Traditionally the Hough transform has been used to find circular objects in images but more modern approaches that make use of heuristic optimisation techniques have been developed.
cv2. HoughCircles(image, method, dp, minDist) Where Image is the image file converted to grey scale Method is the algorithm used to detct the circles. Dp is the inverse ratio of the accumulator resolution to the image resolution. minDist is the Minimum distance between the center coordinates of detected circles.
#!/usr/bin/env python
import cv2
def draw_circles(img, circles):
# img = cv2.imread(img,0)
cimg = cv2.cvtColor(img,cv2.COLOR_GRAY2BGR)
for i in circles[0,:]:
# draw the outer circle
cv2.circle(cimg,(i[0],i[1]),i[2],(0,255,0),2)
# draw the center of the circle
cv2.circle(cimg,(i[0],i[1]),2,(0,0,255),3)
cv2.putText(cimg,str(i[0])+str(',')+str(i[1]), (i[0],i[1]), cv2.FONT_HERSHEY_SIMPLEX, 0.4, 255)
return cimg
def detect_circles(image_path):
gray = cv2.imread(image_path, cv2.CV_LOAD_IMAGE_GRAYSCALE)
gray_blur = cv2.medianBlur(gray, 13) # Remove noise before laplacian
gray_lap = cv2.Laplacian(gray_blur, cv2.CV_8UC1, ksize=5)
dilate_lap = cv2.dilate(gray_lap, (3, 3)) # Fill in gaps from blurring. This helps to detect circles with broken edges.
# Furture remove noise introduced by laplacian. This removes false pos in space between the two groups of circles.
lap_blur = cv2.bilateralFilter(dilate_lap, 5, 9, 9)
# Fix the resolution to 16. This helps it find more circles. Also, set distance between circles to 55 by measuring dist in image.
# Minimum radius and max radius are also set by examining the image.
circles = cv2.HoughCircles(lap_blur, cv2.cv.CV_HOUGH_GRADIENT, 16, 55, param2=450, minRadius=20, maxRadius=40)
cimg = draw_circles(gray, circles)
print("{} circles detected.".format(circles[0].shape[0]))
# There are some false positives left in the regions containing the numbers.
# They can be filtered out based on their y-coordinates if your images are aligned to a canonical axis.
# I'll leave that to you.
return cimg
The result:
cimg = detect_circles("circles.png")
There are some left-over false detection. If your images are aligned, then you can filter these false positives based on their y-coordinates. I'll leave that to you.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With