I have a task to detect Circles and Radio buttons in an Image. For this I tried Hough circles by having different parameters.
Issues : If the circles in the Image are of same radius of Radio buttons both are detected, but in our case it should only detect only one.
Is there a way to differentiate between circles and Radio buttons (when they are not checked). Right now I am limiting them by Radius with 2 different functions one for circle and one for radio button. The above code is for circles
circle_contours=[]
# Converting the image Gray scale
gray = cv2.cvtColor(image1, cv2.COLOR_BGR2GRAY)
# Blur the image to reduce noise
img_blur = cv2.medianBlur(gray, 5)
# Apply hough transform on the image
circles = cv2.HoughCircles(img_blur, cv2.HOUGH_GRADIENT, 1,20, param1=50, param2=20,
minRadius=11, maxRadius=21)
# Draw detected circles
if circles is not None:
circles = np.uint16(np.around(circles))
for i in circles[0, :]:
# Draw outer circle
cv2.circle(image1, (i[0], i[1]), i[2], (34, 255, 34), 2)
circle_contours.append(circles)
I have used a similar approach for radio buttons but with different parameters as below.
radio_buttons= cv2.HoughCircles(img_blur, cv2.HOUGH_GRADIENT, 1,20, param1=50, param2=16,
minRadius=9, maxRadius=10)
Image 1:
Image 2:
For the Image1 it detects circles correctly and when it is passed to the radio buttons function it also draws circles(Image2) for the inner part of it with a reduced radius which are also detected as radio buttons
In Image3 Image3 it has to detect Circle and Radio buttons, where my code is only able to detect circles.
I have also tried using draw contours but it had issues when the Image also has checkboxes.
Is there any other approach or a better way for detection?
HoughCircles
Step #1: We could start with finding all contours in the given answer-sheet .
contourIdx=-1
means to draw all the contours.
import cv2 import numpy as np image = cv2.imread('zip_grade_form.png') # Converting the image Gray scale gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) ret, thresh = cv2.threshold(src=gray, thresh=127, maxval=255, type=0) contours, hierarchy = cv2.findContours(image=thresh, mode=cv2.RETR_TREE, method=cv2.CHAIN_APPROX_SIMPLE) gray = cv2.drawContours(image=gray, contours=contours, contourIdx=-1, color=(255, 255, 255), thickness=2)
Result:
From above we can see that all features except circles are removed. We use the findContours
method to remove unwanted artifacts.
Step#2: Apply HoughCircles
. The same code you wrote on the question. Result:
import cv2
import numpy as np
image = cv2.imread('zip_grade_form.png')
# Converting the image Gray scale
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(src=gray, thresh=127, maxval=255, type=0)
contours, hierarchy = cv2.findContours(image=thresh,
mode=cv2.RETR_TREE,
method=cv2.CHAIN_APPROX_SIMPLE)
gray = cv2.drawContours(image=gray, contours=contours, contourIdx=-1,
color=(255, 255, 255), thickness=2)
cv2.imwrite("gray.png", gray)
img_blur = cv2.medianBlur(gray, 5)
circles = cv2.HoughCircles(img_blur, cv2.HOUGH_GRADIENT, 1, 20, param1=50, param2=16,
minRadius=9, maxRadius=10)
circle_contours = []
if circles is not None:
circles = np.uint16(np.around(circles))
for i in circles[0, :]:
# Draw outer circle
cv2.circle(image, (i[0], i[1]), i[2], (108, 105, 255), 2)
circle_contours.append(circles)
cv2.imwrite("circles.png", image)
For detecting check-boxes and radio-buttons you need to calculate the contour-perimeter
(p) and the contour-approximation
(a). source
We can separate each object using p
and a
value since each object has a unique p
and a
values.
For instance, in image-3,
p
= 73 and a
= 4p
= 64 and a
= 8.You can find the values observing the code.
Apply the 1st step again.
Now find the contours in the above image:
if len(approx) == 8 and int(p) == 64: cv2.drawContours(image, [c], -1, (180, 105, 255), 3) elif len(approx) == 4 and int(p) == 73: cv2.drawContours(image, [c], -1, (180, 105, 255), 3)
Result:
Code:
import cv2 from imutils import grab_contours as grb_cns from imutils import resize as rsz image = cv2.imread('K1Z94.png') # Converting the image Gray scale gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) ret, thresh = cv2.threshold(src=gray, thresh=127, maxval=255, type=0) contours, hierarchy = cv2.findContours(image=thresh.copy(), mode=cv2.RETR_TREE, method=cv2.CHAIN_APPROX_SIMPLE) gray = cv2.drawContours(image=gray, contours=contours, contourIdx=-1, color=(255, 255, 255), thickness=2) resized = rsz(gray, width=300) ratio = gray.shape[0] / float(gray.shape[0]) canny = cv2.Canny(gray, 50, 200) thresh = cv2.threshold(src=canny, thresh=60, maxval=255, type=cv2.THRESH_OTSU + cv2.THRESH_BINARY)[1] cns = cv2.findContours(image=thresh.copy(), mode=cv2.RETR_EXTERNAL, method=cv2.CHAIN_APPROX_SIMPLE) cns = grb_cns(cns) for c in cns: p = cv2.arcLength(c, True) # perimeter approx = cv2.approxPolyDP(c, 0.04 * p, True) M = cv2.moments(c) # check if the all values of M are 0. all_zr = all(value == 0 for value in M.values()) if not all_zr: cX = int((M["m10"] / M["m00"])) cY = int((M["m01"] / M["m00"])) c = c.astype("float") c *= ratio c = c.astype("int") # Circles: (radio-buttons) if len(approx) == 8 and int(p) == 64: cv2.drawContours(image, [c], -1, (180, 105, 255), 3) elif len(approx) == 4 and int(p) == 73: cv2.drawContours(image, [c], -1, (180, 105, 255), 3) cv2.imwrite("result.png", image)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.