Drawing several circles in an additive way
Hello ! I'm using cv2 in python to draw circles (representing stars) into a CV_8U
image. I'm drawing on average 5k small circles, radius goes from 1px
to 6px
with antialiasing.
Im taking ~80ms for drawing ~5k or few circles and (e.g.) ~3200ms for ~80k circles. Because each circle has a different size and color, I'm actually calling cv2.circle
each time I want to draw a circle which is for sure slowing the program down but no big deal (is there any other alternative to this anyway for different radius and colors?).
The issue is where some circles, for example, two red circles overlap:
circle A with radius=5px and color rgb=(200,10,30) at xy=(200, 300)
circle B with radius=2px and color rgb=( 20, 2, 1) at xy=(200, 300)
If circle A is drawn before and circle B later, because circle B's brightness is so low I will be left with a circumference in red and a very dark interior instead of the ideal of making the second circle values add to the already existing values at that position (like adding two light sources).
My current solution which makes my program run an order of magnitude slower compared to the timing I wrote before is to draw the circles to a buffer the size of the biggest possible circle and then add that buffer to the specific position in the final image. But I'm wondering if is there a parameter in OpenCV to define how the drawings to the image are made? (to make it additive) and prevent the need for that buffer.
Thanks.
EDIT : ( added by @sturkmen to be more clear ) EDIT2: Update on the edit
import numpy as np
import cv2 as cv
img0 = np.zeros((12, 12, 3), np.uint8)
cv.circle(img0, (5, 5), 5, (30, 10, 200), -1, cv.LINE_AA) # Big bright
cv.circle(img0, (5, 5), 2, (1, 2, 30), -1, cv.LINE_AA) # Small dim
img0 = cv.resize(img0, (240, 240), interpolation=cv.INTER_AREA)
cv.imshow('current', img0)
img1 = np.zeros((12, 12, 3), np.uint8)
img2 = np.zeros((12, 12, 3), np.uint8)
cv.circle(img1, (5, 5), 5, (30, 10, 200), -1, cv.LINE_AA) # Big bright
cv.circle(img2, (5, 5), 2, (1, 2, 20), -1, cv.LINE_AA) # Small dim
img2 = cv.resize(img1 + img2, (240, 240), interpolation=cv.INTER_AREA) # Img needs to be clipped [0,255]
cv.imshow('desired', img2)
cv.waitKey()
cv.destroyAllWindows()
current code result:
desired result:
You could do blending over ROIs, maintaining a total light image. So rather than call
cv::circle()
directly on the image, call it on a small image that fits the circle and then add that small image to the appropriate ROI in the model/additive image. Normalize the additive image when done for viewing.@Ediolot i edited your question according to my understanding. let us know if it is correct.
Thanks for the comments ! @sturkmen I made a small edit to your addition to show my current result and desired result. Also, I'm already doing what @der-luftmensch suggested but it gets one order of magnitude slower. I'm wondering if there is another way to write a circle that is not destructive
just wonder,what is your image size?
Around 1000x500 pixels
i guess you have have all coordinates and color values before drawing. if so, maybe sorting them and making a function drawing merged two of them at once etc..