how to remove background of everything outside circle in opencv python
Question:
I want the color code of circle (rgb) for that I have detected circle but doesn’t know further process to dynamically mask/crop every background except inside circle
import numpy as np
import cv2
img = cv2.imread('4.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
blurred = cv2.medianBlur(gray, 25) #cv2.bilateralFilter(gray,10,50,50)
minDist = 100
param1 = 30 #500
param2 = 50 #200 #smaller value-> more false circles
minRadius = 5
maxRadius = 100 #10
# docstring of HoughCircles: HoughCircles(image, method, dp, minDist[, circles[, param1[, param2[, minRadius[, maxRadius]]]]]) -> circles
circles = cv2.HoughCircles(blurred, cv2.HOUGH_GRADIENT, 1, minDist, param1=param1, param2=param2, minRadius=minRadius, maxRadius=maxRadius)
if circles is not None:
circles = np.uint16(np.around(circles))
for i in circles[0,:]:
cv2.circle(img, (i[0], i[1]), i[2], (0, 255, 0), 2)
# Show result for testing:
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows() ````
Answers:
The code in the question finds the circles using circles=cv2.HoughCircles()
method of OpenCV which returns in case of the below shown image:
[[[226.5 211.5 111.6]
[597.5 364.5 108.2]
[498.5 145.5 95.9]]]
# ^ ^ ^
# x y r of found circles x,y == center and r == radius
Don’t be fooled by the fact that there are float values returned for specifying integer pixel coordinates of the circle center in the image. They can be used as they are to preserve their precision or turned into integer values if necessary for indexing the corresponding pixel in the image to obtain its BGR color value (OpenCV uses by default BGR color format not RGB).
With the above results it’s easy to create a mask by creating a new black image of same size as the original image mask = np.zeros_like(img)
with white filled (specify thickness of the drawn circle line as -1 to get a filled circle) circles. With known coordinates of circle centers you can extract their BGR colors from the image array by indexing it with img[y,x]
. If you want RGB just switch G and R in the color tuple.
import numpy as np
import cv2 as cv
img = cv.imread('circles.png')
cv.imshow('original image: circles.png', img)
cv.waitKey(0)
img_gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
cv.imshow('gray image', img_gray)
cv.waitKey(0)
img_gray_blurred = cv.medianBlur(img_gray, 25) # cv.bilateralFilter(gray,10,50,50)
cv.imshow('gray/blurred image', img_gray_blurred)
cv.waitKey(0)
minDist = 10
param1 = 30 #500
param2 = 70 #200 # smaller value-> more false circles
minRadius = 5
maxRadius = 150 #10
# docstring of HoughCircles: HoughCircles(image, method, dp, minDist
# [, circles[, param1[, param2[, minRadius[, maxRadius]]]]]) -> circles
circles = cv.HoughCircles( img_gray_blurred,
cv.HOUGH_GRADIENT,
1,
minDist,
param1=param1, param2=param2,
minRadius=minRadius, maxRadius=maxRadius)
"""
print(circles) # gives float values for x, y, r of the cirles
[[[226.5 211.5 111.6]
[597.5 364.5 108.2]
[498.5 145.5 95.9]]]
"""
mask = np.zeros_like(img) # create empty black image with img size
white_color = (255, 255, 255)
line_color = (255, 0, 255)
filled_circle = -1
line_thickness = 3
if circles is not None: # found a circle or more than one circle
circles = np.uint16(np.around(circles)) # <-- turn float to integer
for i, (x, y, r) in enumerate(circles[0,:]):
cv.circle(img, (x, y), r, line_color, line_thickness)
print(f' Circle {i+1} center BGR is: {img[y,x]=}')
# draw filled circle in white on black background as mask:
mask = cv.circle(mask, (x, y), r, white_color, filled_circle)
# Apply mask to image
result = cv.bitwise_and(img, mask)
# Show result for testing:
cv.imshow('image with marked circles', img)
cv.waitKey(0)
cv.imshow('mask', mask)
cv.waitKey(0)
cv.imshow('masked image', result)
cv.waitKey(0)
cv.destroyAllWindows()
gives as output:
Circle 1 center BGR is: img[y,x]=array([ 18, 239, 57], dtype=uint8)
Circle 2 center BGR is: img[y,x]=array([ 64, 236, 13], dtype=uint8)
Circle 3 center BGR is: img[y,x]=array([ 6, 240, 105], dtype=uint8)
I want the color code of circle (rgb) for that I have detected circle but doesn’t know further process to dynamically mask/crop every background except inside circle
import numpy as np
import cv2
img = cv2.imread('4.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
blurred = cv2.medianBlur(gray, 25) #cv2.bilateralFilter(gray,10,50,50)
minDist = 100
param1 = 30 #500
param2 = 50 #200 #smaller value-> more false circles
minRadius = 5
maxRadius = 100 #10
# docstring of HoughCircles: HoughCircles(image, method, dp, minDist[, circles[, param1[, param2[, minRadius[, maxRadius]]]]]) -> circles
circles = cv2.HoughCircles(blurred, cv2.HOUGH_GRADIENT, 1, minDist, param1=param1, param2=param2, minRadius=minRadius, maxRadius=maxRadius)
if circles is not None:
circles = np.uint16(np.around(circles))
for i in circles[0,:]:
cv2.circle(img, (i[0], i[1]), i[2], (0, 255, 0), 2)
# Show result for testing:
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows() ````
The code in the question finds the circles using circles=cv2.HoughCircles()
method of OpenCV which returns in case of the below shown image:
[[[226.5 211.5 111.6]
[597.5 364.5 108.2]
[498.5 145.5 95.9]]]
# ^ ^ ^
# x y r of found circles x,y == center and r == radius
Don’t be fooled by the fact that there are float values returned for specifying integer pixel coordinates of the circle center in the image. They can be used as they are to preserve their precision or turned into integer values if necessary for indexing the corresponding pixel in the image to obtain its BGR color value (OpenCV uses by default BGR color format not RGB).
With the above results it’s easy to create a mask by creating a new black image of same size as the original image mask = np.zeros_like(img)
with white filled (specify thickness of the drawn circle line as -1 to get a filled circle) circles. With known coordinates of circle centers you can extract their BGR colors from the image array by indexing it with img[y,x]
. If you want RGB just switch G and R in the color tuple.
import numpy as np
import cv2 as cv
img = cv.imread('circles.png')
cv.imshow('original image: circles.png', img)
cv.waitKey(0)
img_gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
cv.imshow('gray image', img_gray)
cv.waitKey(0)
img_gray_blurred = cv.medianBlur(img_gray, 25) # cv.bilateralFilter(gray,10,50,50)
cv.imshow('gray/blurred image', img_gray_blurred)
cv.waitKey(0)
minDist = 10
param1 = 30 #500
param2 = 70 #200 # smaller value-> more false circles
minRadius = 5
maxRadius = 150 #10
# docstring of HoughCircles: HoughCircles(image, method, dp, minDist
# [, circles[, param1[, param2[, minRadius[, maxRadius]]]]]) -> circles
circles = cv.HoughCircles( img_gray_blurred,
cv.HOUGH_GRADIENT,
1,
minDist,
param1=param1, param2=param2,
minRadius=minRadius, maxRadius=maxRadius)
"""
print(circles) # gives float values for x, y, r of the cirles
[[[226.5 211.5 111.6]
[597.5 364.5 108.2]
[498.5 145.5 95.9]]]
"""
mask = np.zeros_like(img) # create empty black image with img size
white_color = (255, 255, 255)
line_color = (255, 0, 255)
filled_circle = -1
line_thickness = 3
if circles is not None: # found a circle or more than one circle
circles = np.uint16(np.around(circles)) # <-- turn float to integer
for i, (x, y, r) in enumerate(circles[0,:]):
cv.circle(img, (x, y), r, line_color, line_thickness)
print(f' Circle {i+1} center BGR is: {img[y,x]=}')
# draw filled circle in white on black background as mask:
mask = cv.circle(mask, (x, y), r, white_color, filled_circle)
# Apply mask to image
result = cv.bitwise_and(img, mask)
# Show result for testing:
cv.imshow('image with marked circles', img)
cv.waitKey(0)
cv.imshow('mask', mask)
cv.waitKey(0)
cv.imshow('masked image', result)
cv.waitKey(0)
cv.destroyAllWindows()
gives as output:
Circle 1 center BGR is: img[y,x]=array([ 18, 239, 57], dtype=uint8)
Circle 2 center BGR is: img[y,x]=array([ 64, 236, 13], dtype=uint8)
Circle 3 center BGR is: img[y,x]=array([ 6, 240, 105], dtype=uint8)