I have a collection of images with a circle drawn as a white outline. However, I want to fill the complete circle with white color. What is a fast way to do it? The following is the sample of the image:
I have tried using nested loops to achieve this, but it takes a lot of time, and I have around 1.5 million images. The following is my code:
roundRobinIndex = 0
new_image = np.zeros((img_w, img_h))
for row in range(540):
for column in range(800):
if image[row,column] == 255:
roundRobinIndex = (roundRobinIndex + 1) % 2
if roundRobinIndex == 1:
new_image[row, column] = 255
You can't apply an outline to part of a shape. So instead, create a half-circle with on outline but filled with your preferred color. I used Basic Shapes>Partial Circle here. Then on top of that, draw a half-circle arc using Basic Shapes>Block Arc.
Go to the tool properties panel; click on the "Fill" icon and select the "No fill" option in the color palette. In the appeared "Create Ellipse" window press the "Cancel" button. Then hold the "Shift" key on the keyboard, do a left click on the canvas and draw a circle by moving the cursor. A circle without fill has been successfully created.
You can't apply an outline to part of a shape. So instead, create a half-circle with on outline but filled with your preferred color. I used Basic Shapes>Partial Circle here.
There are many techniques used to create a circle. In our snippet, we’ll demonstrate some examples with the CSS border-radius property, as well as with the HTML <canvas> and SVG <circle> elements. The most common one is using the border-radius property.
Use cv2.fillPoly()
to fill the circle contour
import cv2
image = cv2.imread('1.png', 0)
thresh = cv2.threshold(image, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
cv2.fillPoly(image, cnts, [255,255,255])
cv2.imshow('image', image)
cv2.waitKey()
Note: The Otsu's threshold could be removed for slightly faster performance since the input image is already a binary image, you could directly find contours on the grayscale image
I tried finding the bounding box of the white outline, and getting its centre, then floodfilling with white from there outwards.
#!/usr/bin/env python3
import cv2
def findfill(image):
thresh = cv2.threshold(image, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
cv2.fillPoly(image, cnts, [255,255,255])
def me(image):
x,y,w,h = cv2.boundingRect(image)
cv2.floodFill(image,None,(int(x+w/2),int(y+h/2)),255)
return image
image = cv2.imread('BLYmz.png', 0)
%timeit findfill(image)
%timeit me(image)
This seems to give the same results and run 2.5x faster:
findfill
810 µs ± 2.94 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
me
343 µs ± 1.06 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
Of course, if you have 1.5 million to do, I would recommend some parallel processing too :-)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With