I need help with this code. I want to get the RGB value of the circle only.
How do I return the RGB value of the circle?
prevCircle = None
dist = lambda x1,y1,x2,y2 : (x1-x2)**2+(y1-y2)**2
while True:
(grabbed, frame) = videoCapture.read()
grayFrame = cv.cvtColor(frame,cv.COLOR_BGR2GRAY)
blurFrame = cv.GaussianBlur(grayFrame,(11,11),0)
height, width, _ = frame.shape
circles = cv.HoughCircles(blurFrame ,cv.HOUGH_GRADIENT,1.2,50,param1=100,param2=30,minRadius=75,maxRadius=400)
if circles is not None:
circles = np.uint16(np.around(circles))
chosen=None
for i in circles[0 ,:]:
if chosen is None: chosen =i
if prevCircle is not None:
if dist(chosen[0],chosen[1],prevCircle[0],prevCircle[1]) <= dist(i[0],i[1],prevCircle[0],prevCircle[1]):chosen = i
cv.circle(frame,(chosen[0],chosen[1]),1,(0,100,100),3)
cv.circle(frame,(chosen[0],chosen[1]),chosen[2],(0,0,0),3)
prevCirlce = chosen
cv.imshow("Camera", frame)
Here is one way to do that in Python/OpenCV.
After getting the circle from HoughCircles, draw the circle as white filled on a black background as a mask. Then use cv2.mean() with the mask to get the channel colors inside the input image within the found circle.
Input:
import cv2
import numpy as np
# Read image
img = cv2.imread('yellow_circle.jpg')
hh, ww = img.shape[:2]
# Convert to grayscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# get Hough circles
min_dist = int(ww/10)
circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, 1, minDist=min_dist, param1=150, param2=20, minRadius=0, maxRadius=0)
print("circles:", circles)
# draw circles
img_circle = img.copy()
mask = np.zeros_like(gray)
for circle in circles[0]:
# draw the circle in the output image, then draw a rectangle
# corresponding to the center of the circle
(x,y,r) = circle
x = int(x)
y = int(y)
r = int(r)
cv2.circle(img_circle, (x, y), r, (0, 0, 255), 2)
cv2.circle(mask, (x, y), r, 255, -1)
# get average color with mask
ave_color = cv2.mean(img, mask=mask)[:3]
print("average circle color:", ave_color)
# save results
cv2.imwrite('yellow_circle_circle.jpg', img_circle)
cv2.imwrite('yellow_circle_mask.jpg', mask)
# show images
cv2.imshow('circle', img_circle)
cv2.imshow('mask', mask)
cv2.waitKey(0)
cv2.destroyAllWindows()
Circle Found:
Mask Image:
Data:
circles: [[[596.5 516.5 367.1]]]
average circle color: (1.1791196817751013, 254.96112948094645, 254.88615376615763)
Related
I have tried some variations in the parameters, read a detailed description of their meaning, but I can't seem to detect a simple circle in an image. This is a simplified function I have tried:
def get_a_circles(image):
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
circles = cv2.HoughCircles(gray, # input grayscale image
cv2.HOUGH_GRADIENT,
2,
minDist=5,
param1=10, param2=200,
minRadius=0,
maxRadius=0)
return circles
which, when run on this image:
img = cv2.imread("step2.jpg")
get_a_circle(img.copy())
returns none.
It does however detect the circles in this image:
image
circles found & highlighted
I tried to add some blur to the image that fails, with either
gray = cv2.medianBlur(gray, 5) or gray = cv2.GaussianBlur(gray,(5,5),0) but it does not improve the results.
Any suggestions on what to try with that image? (It would seem it's an obvious circle)
You need to lower param2 in HoughCircles in Python/OpenCV.
Input:
import cv2
import numpy as np
# Read image
img = cv2.imread('dot.jpg')
hh, ww = img.shape[:2]
# Convert to grayscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# median filter
gray = cv2.medianBlur(gray, 5)
# get Hough circles
min_dist = int(ww/20)
circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, 1, minDist=min_dist, param1=150, param2=10, minRadius=0, maxRadius=0)
print(circles)
# draw circles
result = img.copy()
for circle in circles[0]:
# draw the circle in the output image, then draw a rectangle
# corresponding to the center of the circle
(x,y,r) = circle
x = int(x)
y = int(y)
cv2.circle(result, (x, y), r, (0, 0, 255), 1)
# save results
cv2.imwrite('dot_circle.jpg', result)
# show images
cv2.imshow('result', result)
cv2.waitKey(0)
cv2.destroyAllWindows()
Result:
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);
I want to crop the image only inside the box or rectangle. I tried so many approaches but nothing worked.
import cv2
import numpy as np
img = cv2.imread("C:/Users/hp/Desktop/segmentation/add.jpeg", 0);
h, w = img.shape[:2]
# print(img.shape)
kernel = np.ones((3,3),np.uint8)
img2 = img.copy()
img2 = cv2.medianBlur(img2,5)
img2 = cv2.adaptiveThreshold(img2,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,\
cv2.THRESH_BINARY,11,2)
img2 = 255 - img2
img2 = cv2.dilate(img2, kernel)
img2 = cv2.medianBlur(img2, 9)
img2 = cv2.medianBlur(img2, 9)
cv2.imshow('anything', img2)
cv2.waitKey(0)
cv2.destroyAllWindows()
position = np.where(img2 !=0)
x0 = position[0].min()
x1 = position[0].max()
y0 = position[1].min()
y1 = position[1].max()
print(x0,x1,y0,y1)
result = img[x0:x1,y0:y1]
cv2.imshow('anything', result)
cv2.waitKey(0)
cv2.destroyAllWindows()
Output should be the image inside the sqaure.
You can use contour detection for this. If your image has basically only a hand drawn rectangle in it, I think it's good enough to assume it's the largest closed contour in the image. From that contour, we can figure out a polygon/quadrilateral approximation and then finally get an approximate rectangle. I'll define some utilities at the beginning which I generally use to make my time easier when messing around with images:
def load_image(filename):
return cv2.imread(filename)
def bnw(image):
return cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
def col(image):
return cv2.cvtColor(image, cv2.COLOR_GRAY2RGB)
def fixrgb(image):
return cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
def show_image(image, figsize=(7,7), cmap=None):
cmap = cmap if len(image.shape)==3 else 'gray'
plt.figure(figsize=figsize)
plt.imshow(image, cmap=cmap)
plt.show()
def AdaptiveThresh(gray):
blur = cv2.medianBlur(gray, 5)
adapt_type = cv2.ADAPTIVE_THRESH_GAUSSIAN_C
thresh_type = cv2.THRESH_BINARY_INV
return cv2.adaptiveThreshold(blur, 255, adapt_type, thresh_type, 11, 2)
def get_rect(pts):
xmin = pts[:,0,1].min()
ymin = pts[:,0,0].min()
xmax = pts[:,0,1].max()
ymax = pts[:,0,0].max()
return (ymin,xmin), (ymax,xmax)
Let's load the image and convert it to grayscale:
image_name = 'test.jpg'
image_original = fixrgb(load_image(image_name))
image_gray = 255-bnw(image_original)
show_image(image_gray)
Use some morph ops to enhance the image:
kernel = np.ones((3,3),np.uint8)
d = 255-cv2.dilate(image_gray,kernel,iterations = 1)
show_image(d)
Find the edges and enhance/denoise:
e = AdaptiveThresh(d)
show_image(e)
m = cv2.dilate(e,kernel,iterations = 1)
m = cv2.medianBlur(m,11)
m = cv2.dilate(m,kernel,iterations = 1)
show_image(m)
Contour detection:
contours, hierarchy = cv2.findContours(m, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
total_area = np.prod(image_gray.shape)
max_area = 0
for cnt in contours:
# Simplify contour
perimeter = cv2.arcLength(cnt, True)
approx = cv2.approxPolyDP(cnt, 0.03 * perimeter, True)
area = cv2.contourArea(approx)
# Shape is recrangular, so 4 points approximately and it's convex
if (len(approx) == 4 and cv2.isContourConvex(approx) and max_area<area<total_area):
max_area = cv2.contourArea(approx)
quad_polygon = approx
img1 = image_original.copy()
img2 = image_original.copy()
cv2.polylines(img1,[quad_polygon],True,(0,255,0),10)
show_image(img1)
tl, br = get_rect(quad_polygon)
cv2.rectangle(img2, tl, br, (0,255,0), 10)
show_image(img2)
So you can see the approximate polygon and the corresponding rectangle, using which you can get your crop. I suggest you play around with median blur and morphological ops like erosion, dilation, opening, closing etc and see which set of operations suits your images the best; I can't really say what's good from just one image. You can crop using the top left and bottom right coordinates:
show_image(image_original[tl[1]:br[1],tl[0]:br[0],:])
Draw the square with a different color (e.g red) so it can be distinguishable from other writing and background. Then threshold it so you get a black and white image: the red line will be white in this image. Get the coordinates of white pixels: from this set, select only the two pairs (minX, minY)(maxX,maxY). They are the top-left and bottom-right points of the box (remember that in an image the 0,0 point is on the top left of the image) and you can use them to crop the image.
guys,
I have written a program where I recognize circles with cv2.HoughCircles(). The code works too. Unfortunately I need the area of the circles for my project. But I don't know how to calculate this and my search on the internet was unsuccessful.
Thank you.
https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_imgproc/py_houghcircles/py_houghcircles.html
import cv2
import numpy as np
img = cv2.imread('opencv_logo.png',0)
img = cv2.medianBlur(img,5)
cimg = cv2.cvtColor(img,cv2.COLOR_GRAY2BGR)
circles = cv2.HoughCircles(img,cv2.HOUGH_GRADIENT,1,20,
param1=50,param2=30,minRadius=0,maxRadius=0)
circles = np.uint16(np.around(circles))
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.imshow('detected circles',cimg)
cv2.waitKey(0)
cv2.destroyAllWindows()
i[0] is the x position
i[1] is the y position
i[2] is the radius
Area is calculated with the formula pi * r²
So the area of each detected circle would be:
for i in circles[0,:]:
area = 3.14159 * i[2] * i[2]
From HoughCircles() you get a list of 'circles' which contains x, y, r of the circle. x, y are coordinates of the center and r is the radius.
From the radius you can calculate the area of the circle with:
A = PI * r^2
Thank you guys,
#Tin Nguyen
if i use:
for i in circles[0,:]:
area = 3.14159 * i[2] * i[2]
then i get the following error: "TypeError: 'NoneType' object is not subscriptable"
This is my code, i want to detect circles in realtime and calculate the area.
import pypylon.pylon as py # wrapper to control Basler camera with python
import cv2 # openCV
import numpy as np
first_device = py.TlFactory.GetInstance().CreateFirstDevice()
icam = py.InstantCamera(first_device)
icam.Open()
# set parameters
icam.PixelFormat = "RGB8"
# if only a part of image sensor is used an offset is required or centering
'''icam.Width = 640
icam.Height = 480
icam.CenterX = False
icam.CenterY = False'''
# Demonstration of setting parameters - properties can be found on Pylon Viewer
# Auto property values are 'Off', 'Once', 'Continuous'
icam.GainAuto = 'Off'
icam.ExposureAuto = 'Continuous'
icam.BalanceWhiteAuto = 'Off'
icam.Gain = 0 # minimum gain value
# icam.ExposureTime = 50000 # exposure time or use ExposureAuto
icam.StartGrabbing(py.GrabStrategy_LatestImages)
while True:
res = icam.RetrieveResult(1000) # 1000 = time constant for time-out
frame = cv2.cvtColor(res.Array, cv2.COLOR_RGB2BGR)
output = frame.copy()
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray,(5,5),0)
gray = cv2.medianBlur(gray, 5)
gray = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,\
cv2.THRESH_BINARY,11,3.5)
kernel = np.ones((2,3),np.uint8)
gray = cv2.erode(gray,kernel)
gray = cv2.dilate(gray, kernel)
# detect circles in the image
circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, 1, 200, param1=30, param2=45,
minRadius=0, maxRadius=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 in the image
# 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)
# time.sleep(0.5)
print
"Column Number: "
print
x
print
"Row Number: "
print
y
print
"Radius is: "
print
r
# Display the resulting frame
cv2.imshow('gray', gray)
cv2.imshow('frame', output)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
for i in circles[0, :]:
area = 3.14159 * i[2] * i[2]
print(area)
icam.StopGrabbing()
icam.Close()
cv2.destroyAllWindows()
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()