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() ````
Asked By: Shivam Singh

||

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.

Circles

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)

Cirlces_masked

Answered By: Claudio
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.