highlights:
- Hough is generally useful, but OpenCV’s HoughCircles is a war crime
- your circles are actually ellipses
the first big one has an aspect ratio of 645 : 640. that can throw canny off, unless you make its accumulator array sufficiently coarse (dp).
OpenCV’s HoughCircles is a terrible API.
in the case of HoughCircles, you need to feed it the uncannied data, because it runs a Canny on the data obligatorily.
for your data, I’d not want any Canny step at all. but you can’t have that, not with OpenCV.
only HoughCircles does that. the other Hough APIs in OpenCV don’t do that.
it seems to be made to detect filled circles only, not outlined circles (yours are outlined).
that’s why I say it’s a bad API.
honestly, I have no idea how to make OpenCV’s HoughCircles reliably find circles in data such as yours. it is incredibly sensitive to parameter choices. a good algorithm should not be that sensitive.
I wasted minutes on HOUGH_GRADIENT.
eventually I gave HOUGH_GRADIENT_ALT a try. that seems a LOT less fiddly.
also it’s more tolerant of ellipses. that might the an issue here. ellipses smear the peak they should leave in the accumulator array. you might get better results if your scans (photos?) are stretched right.
im = cv.imread("LunarSketch_0001.jpg", cv.IMREAD_GRAYSCALE)
(h, w) = im.shape[:2]
ar = 642 / 637 # measure the w/h of some circle
im = cv.resize(src=im, dsize=None, fx=1, fy=ar, interpolation=cv.INTER_AREA)
k = 11; im = cv.stackBlur(im, (k,k))
# https://docs.opencv.org/4.13.0/dd/d1a/group__imgproc__feature.html#ga47849c3be0d0406ad3ca45db65a25d2d
# read carefully what param1 and param2 do depending on method
circles = cv.HoughCircles(
im,
method=cv.HOUGH_GRADIENT_ALT,
dp=1.5,
minDist=100,
param1=300,
param2=0.90,
minRadius=80,
maxRadius=400,
)
assert circles is not None, circles
print(len(circles))
canvas = cv.cvtColor(im, cv.COLOR_GRAY2BGR) >> 1
for (x, y, r) in circles[0]: # (opencv-python 5 puts these in a row, not a column...)
cv.circle(canvas, center=(int(x), int(y)), radius=int(r), color=(0, 255, 0), thickness=2, lineType=cv.LINE_AA)
cv.circle(canvas, center=(int(x), int(y)), radius=2, color=(0, 0, 255), thickness=-1)
Even with all that, I can’t get the detections to be accurate. they are off. that should not be so, but thanks to whoever designed HoughCircles and everyone who didn’t fix it nor point it out since then, it is what it is.