Hough Circle way too sensitive - python

I am trying to detect circles in an antibiotic susceptibility test image. with my code, it detects 7 circles however it draws way too many of them (you can find the original image and the results in the links bellow) . how can I make the detection accurate?
P.S: I know that the minRadius i want to detect is 20mm≈75pixels and maxRad is 50mm≈190pixels
import cv2
import numpy as np
image= "atbg.jpg"
img= cv2.imread(image,1)
img_orig=img.copy()
img= cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
img = cv2.GaussianBlur(img,(21,21),cv2.BORDER_DEFAULT)
all_circs=cv2.HoughCircles(img,cv2.HOUGH_GRADIENT,1,10, param1=50, param2=30, minRadius=75 , maxRadius=190)
all_circs_rounded= np.uint16(np.around(all_circs))
for (x, y ,r) in all_circs_rounded[0, :]:
cv2.circle(img_orig, (x, y), r, (0, 0, 0), 3)
cv2.circle(img_orig, (x, y), 2, (0, 255, 255), 3)
imS = cv2.resize(img_orig, (600, 540))
cv2.imshow("output", imS)
cv2.waitKey(0)
cv2.destroyAllWindows()
Original image:
Result image:

Can you first get the edges of the circles using Canny() edge detection?

Related

HoughCircles circle detection not working?

I have been trying to write a program that can detect circles on my screen.
This is my screen before code processing
As you can see on the image, there are three circles that the code should detect. I am using HoughCircles function from OpenCV library to achieve this task. My code is below.
ss = gui.screenshot()
img = cv2.cvtColor(np.array(ss), cv2.COLOR_RGB2BGR)
output = img.copy()
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, 1.2, 100)
if circles is not None:
print("circles found", len(circles))
circles = np.round(circles[0, :]).astype("int")
for (x, y, r) in circles:
cv2.circle(output, (x, y), r, (0, 255, 0), 4)
cv2.rectangle(output, (x - 5, y - 5), (x + 5, y + 5), (0, 128, 255), -1)
cv2.imshow("output", np.hstack([gray, output]))
cv2.waitKey(0)
cv2.imshow("output", gray)
cv2.waitKey(0)
I am first taking screenshot of my screen. Then, I convert it to use it for opencv.
However, this code does not detect any circles for the screenshot shown in the first picture. I know this because when ran, my program does not print "circles found". Moreover, to show that I have been taking screenshots and transforming them to grayscale properly, I have this image taken from the last two lines of my code.
picture in a gray scale
To show that my code works with other circle images, here is a picture of a regular circle:
before detection
after detection
Any help would be very appreciated!
Here's an alternative solution to detect the circles without using the Hough Transform. As your input image has a very distinct blue hue to the blobs of interest, you can try to create a segmentation mask based on their HSV values. Then, detect contours and approximate each contour using a circle. The last step can be implemented using the cv2.minEnclosingCircle, which, as its name suggest, can compute the Minimum Enclosing Circle of a contour.
Let's see the code:
# image path
path = "D://opencvImages//"
fileName = "XUzFw.png"
# Reading an image in default mode:
inputImage = cv2.imread(path + fileName)
# Create a deep copy of the input for results:
inputImageCopy = inputImage.copy()
# Convert the image to the HSV color space:
hsvImage = cv2.cvtColor(inputImage, cv2.COLOR_BGR2HSV)
# Set the HSV values:
lowRange = np.array([78, 0, 158])
uppRange = np.array([125, 255, 255])
# Create the HSV mask
mask = cv2.inRange(hsvImage, lowRange, uppRange)
This generates the following segmentation mask:
As you can see, the only blobs that remain are the circles. Now, let's compute the contours and find the minimum enclosing circle:
# Find the circle blobs on the binary mask:
contours, hierarchy = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# Use a list to store the center and radius of the target circles:
detectedCircles = []
# Look for the outer contours:
for i, c in enumerate(contours):
# Approximate the contour to a circle:
(x, y), radius = cv2.minEnclosingCircle(c)
# Compute the center and radius:
center = (int(x), int(y))
radius = int(radius)
# Draw the circles:
cv2.circle(inputImageCopy, center, radius, (0, 0, 255), 2)
# Store the center and radius:
detectedCircles.append([center, radius])
# Let's see the results:
cv2.namedWindow("Circles", cv2.WINDOW_NORMAL)
cv2.imshow("Circles", inputImageCopy)
cv2.waitKey(0)
This is the result of the detection:
Additionally, you can check out the data stored in the detectedCircles list:
# Check out the detected circles:
for i in range(len(detectedCircles)):
# Get circle data:
center, r = detectedCircles[i]
# Print it:
print("i: "+str(i)+" x: "+str(center[0])+" y: "+str(center[1])+" r: "+str(r))
Which yields:
i: 0 x: 395 y: 391 r: 35
i: 1 x: 221 y: 391 r: 36
i: 2 x: 567 y: 304 r: 35
These are the parameters of houghCircles that works for me. You should also consider running a gaussian blur over the image before trying to find the circles.
I'm not a huge fan of houghCircles. I find it to be really finicky and I don't like how much of what it does is hidden inside the function. It makes tuning it mostly trial-and-error. These parameters work for this particular image, but I wouldn't count on this continuing to work under different lighting conditions or for different colors.
import cv2
import numpy as np
# load image
img = cv2.imread("spheres.png");
# grayscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY);
gray = cv2.GaussianBlur(gray,(5,5),0);
# circles
circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, dp = 1, minDist = 100, param1=65, param2=20, minRadius=20, maxRadius=50)
# draw circles
if circles is not None:
# round to ints
circles = np.uint16(np.around(circles));
for circle in circles[0, :]:
# unpack and draw
x, y, radius = circle;
center = (x,y);
cv2.circle(img, center, radius, (255, 0, 255), 3);
# show
cv2.imshow("Image", img);
cv2.imshow("Gray", gray);
cv2.waitKey(0);

is it possible to color specific area in drawcontour in python?

I work in an image processing in python, I detect the patches using cv2.minAreaRect and draw a rotated rectangle, I achieved this.
Now I want to fill the detected patch fully in white color, which means the area inside the cv2.drawContour in cyan color inside fully in white color(desire output has been done in ms-paint for reference)
I want to achieve it in python, is it possible in OpenCV-python?
Let's say you have the contours saved in cnts. Then following snippet will fill the rotated rectangles with cyan color.
import numpy as np
import cv2
for c in cnts:
rotrect = cv2.minAreaRect(c)
box = cv2.boxPoints(rotrect)
box = np.int0(box)
cv2.drawContours(image, [box], 0, (255, 255, 0), -1) # as opencv stores in BGR format
#amras As per the above guidelines, I modified and post the code I used for all of your references
import cv2
import numpy as np
import matplotlib.pyplot as plt
image=cv2.imread("CP150036_001bw.png",0)
im2=cv2.imread("CP150036_001.png")
# convert to RGB
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
# convert to grayscale
gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
# create a binary thresholded image
_, binary = cv2.threshold(gray, 225, 255, cv2.THRESH_BINARY_INV)
# show it
plt.imshow(binary, cmap="gray")
plt.show()
# find the contours from the thresholded image
contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
#print("contours:",contours)
# draw all contours
for c in contours:
if cv2.contourArea(c)>70000:
continue
(x, y, w, h) = cv2.boundingRect(c)
#cv2.rectangle(image, (x,y), (x+w,y+h), (0, 255, 0), 2)
## BEGIN - draw rotated rectangle
rect = cv2.minAreaRect(c)
box = cv2.boxPoints(rect)
box = np.int0(box)
im=cv2.drawContours(image,[box],0,(255,255,255),-1)
#im3=cv2.drawContours(im2,[box], 0, (255, 0, 0), 2)
# show the image with the drawn contours
plt.imshow(image)
#plt.imshow(im3)
#cv2.imwrite("textDectBox.png",im3)
cv2.imwrite("detectImg.png",im)
plt.show()

drawing a disk by analyzing neighbors pixel intensity

The picture and code below is a toy example that should reflect an experiment I am running.
I would like to extract a disk corresponding to the boundary in the picture where the pixels intensities are the same or similar (in this example the bluish disk)
Using HoughCircles procedure, I can extract the center of the most probable circle of the picture.
From there I would like to probe 360° from the center at the various radius (higher or lower) from the detected center to define the boundaries (max radius and min radius) of the bluish color in the picture below.
How can I do that?
I try to analyze the histogram by applying multiple masks without success.
The green circle is the one detected with HoughCircles, the blue and red circle are the +/- 15% radius circle.
import cv2
import numpy as np
from matplotlib import pyplot as plt
image = cv2.imread("./picture.jpg")
output = image.copy()
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, 2, 800,
param1=300,
param2=1,
minRadius=100,
maxRadius=0)
if circles is not None:
# convert the (x, y) coordinates and radius of the circles to integers
circles = np.round(circles[0, :]).astype("int")
output = image.copy()
# loop over the (x, y) coordinates and radius of the circles
for (x, y, r) in circles:
# draw the circle in the output image, then draw a rectangle
# corresponding to the center of the circle
cv2.circle(output, (x, y), r, (0, 255, 0), 2)
cv2.rectangle(output, (x - 2, y - 2), (x + 2, y + 2), (0, 128, 255), -1)
# create the mask and explore histograms
# height,width,depth = output.shape
# mask = np.zeros((height,width), np.uint8)
# cv2.circle(mask, (x, y), int(round(r - (r* .15))), 1, thickness=-1)
# output = cv2.bitwise_and(output, output, mask=mask)
# hist_full = cv2.calcHist([output],[0],None,[256],[0,256])
# hist_mask = cv2.calcHist([output],[0],mask,[256],[0,256])
# plt.hist(image.ravel(),256,[0,256]); plt.show()
# plt.plot(hist_full),
# plt.plot(hist_mask)
# plt.xlim([0,256])
# plt.show()
cv2.circle(output, (x, y), int(round(r * 1.15)), (255, 0, 0), 2)
cv2.circle(output, (x, y), int(round(r - (r* .15))), (0, 0, 255), 2)
# show the output image
cv2.imshow("output", np.hstack([image, output]))
cv2.waitKey(0)
I resized the disk image, because the origin is too large. So you may modify the parameters in the function.
The source:
I found in S(HSV), the disk is more clear, so I did canny in "S".
The result:
You can reproduce the result using the code.
#!/usr/bin/python3
# 2017.11.21 21:03:09 CST
# 2017.11.22 23:21:42 CST
# 2017.11.25 16:32:46 CST
import cv2
import numpy as np
img = cv2.imread("disk2.png")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
## Canny edge in S(HSV)
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
h,s,v = cv2.split(hsv)
canny = cv2.Canny(s, 30, 200)
## The inner circle using gray
circles1 = cv2.HoughCircles(gray, method = cv2.HOUGH_GRADIENT,
dp = 2, minDist = 100,
param1=200, param2=100,
minRadius=80, maxRadius=200)
## The outer circle using canny
circles2 = cv2.HoughCircles(canny, method = cv2.HOUGH_GRADIENT,
dp = 2, minDist = 100,
param1=200, param2=100,
minRadius=200, maxRadius=0)
x1,y1, r1 = circles1[0][0]
x2,y2, r2 = circles2[0][0]
## create the mask
mask = np.zeros_like(canny)
cv2.circle(mask, (x2, y2), r2, 255, -1)
cv2.circle(mask, (x1, y1), r1, 0, -1)
## crop
imask = mask > 0
masked = np.zeros_like(img)
masked[imask] = img[imask]
cv2.imshow("canny", canny)
cv2.imshow("mask", mask)
cv2.imshow("croped", masked)
cv2.waitKey()
cv2.destroyAllWindows()

Hough Transform Not working

I'm trying to detect circles from the image using hough transform
my code :
import numpy as np
import cv2
image = cv2.imread("C:/Users/Anmol/Desktop/your_file.bmp")
output = image.copy()
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, 1.2,10)
cv2.waitKey(0)
print (circles)
# ensure at least some circles were found
if circles is not None:
# convert the (x, y) coordinates and radius of the circles to integers
circles = np.round(circles[0, :]).astype("int")
# loop over the (x, y) coordinates and radius of the circles
for (x, y, r) in circles:
# draw the circle in the output image, then draw a rectangle
# corresponding to the center of the circle
cv2.circle(output, (x, y), r, (0, 255, 0), 4)
cv2.rectangle(output, (x -5, y - 5), (x + 5, y + 5), (0, 128, 255), -1)
# show the output image
cv2.imshow("output", np.hstack([image, output]))
cv2.waitKey(0)
stops at the line
circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, 1.2,10)
I left my code running for about 5 hours but still its not going ahead of this line. It is not giving any error.
Plzz guide me what to do.
I suggest downscaling the input image if it's really large, and running a blur filter. Both of these will speed up Hough tremendously.

Circle not found

I want to detect a circle from a given image. But it just doesn't work the way I want it to. I implemented a circle detection algorithm, which works on some images with a circle but not on the one I want. I tweaked with the parameters, but couldn't get it to work.
import cv2
import numpy as np
# load the image, clone it for output, and then convert it to grayscale
image = cv2.imread("damn-circle.png")
output = image.copy()
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# detect circles in the image
blur = cv2.GaussianBlur(gray,(5,5),0)
circles = cv2.HoughCircles(blur, cv2.HOUGH_GRADIENT, 2, 120)
cv2.imshow("output", np.hstack([blur]))
cv2.waitKey(0)
print circles
# ensure at least some circles were found
if circles is not None:
# convert the (x, y) coordinates and radius of the circles to integers
circles = np.round(circles[0, :]).astype("int")
# loop over the (x, y) coordinates and radius of the circles
for (x, y, r) in circles:
# draw the circle in the output image, then draw a rectangle
# corresponding to the center of the circle
cv2.circle(output, (x, y), r, (0, 255, 0), 4)
cv2.rectangle(output, (x - 5, y - 5), (x + 5, y + 5), (0, 128, 255), -1)
# show the output image
cv2.imshow("output", np.hstack([output]))
cv2.waitKey(0)
You're code is almost perfect. It's just that the method CV_HOUGH_GRADIENT sits inside a package, cv (at least for opencv version: 2.4.13). I changed that one line to mention the package and it worked well. You'll have to put specific versions for OpenCV and NumPy if you're still not getting the right result on this simple image. Change your line to be like this:
circles = cv2.HoughCircles(blur, cv2.cv.CV_HOUGH_GRADIENT, 2, 120)
You should get a nice result. At least I just did. image with found Hough circle shown
Edited:
Ah, I didn't understand which image the question was about. I changed parameters for several items particularly the Canny detector param and the radius min/max and the accumulator resolution. I think these params will find what you want:
circles = cv2.HoughCircles(blur, method = cv2.cv.CV_HOUGH_GRADIENT, minDist = 90 , dp = 1, param1 = 3, param2 = 12 , minRadius = 30, maxRadius = 50)
My found image now looks like this: another image with found circle

Categories