I’ll just write the code and don’t go through it, because there are many functions, and I would not like to accept what you know or don’t know, and record for a long time. If you have any questions, feel free to ask and I will add them to the message.
You asked to place the circle in the crescents, so I set the circles in the shadow. It’s important to understand that in some kind of production code, which, I believe, should handle many images of this kind, it would be necessary to improve the established circles. In particular, any structural analysis of this type simply worries about setting this shape in pixels, and not that the object in question is what you are looking for.
I intentionally left the wrong circle there. I would suggest going to a convex body or Haar detector or matching shapes depending on what interests you.
import cv2 import numpy as np img = cv2.imread("orig.png", cv2.IMREAD_GRAYSCALE) ret, thresh = cv2.threshold(img, 80, 255, cv2.THRESH_BINARY_INV) ero = cv2.erode(thresh, np.ones((5,5))) dil = cv2.dilate(ero, np.ones((5,5))) img, contours, hierarchy = cv2.findContours(dil, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) #just for drawing purposes, the cimg is not really required cimg = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR) for cnt in contours: (x, y), radius = cv2.minEnclosingCircle(cnt) center = (int(x), int(y)) radius = int(radius) cv2.circle(cimg, center, radius, (255, 0, 0), 1)
The output image I received was

Both crescents are set correctly, and the lower part corresponds to that, and not the crescent. You can do some kind of hysteresis tracking and move this circle until its outer edge, exactly on the crescent moon, is stable enough.
There is an additional circle, which can be deleted if you configure the settings only to the right, but filtering the exact circles that you need is up to you. FE if you want the top crescent to ask for the smallest y coordinate, if all the shadows are as large as you can only request circles of radii that exceed a certain threshold, etc ...