findCirclesGrid()
is intended for camera calibration. Such patterns are expected to have distortion, just like yours. It's definitely supposed to work on your data.
It just needs a little help. It uses a BlobDetector
internally, which is initialized with some defaults that work well for the usual circles grids that show well-defined circles.
For your picture, you need a BlobDetector
with custom parameters. To find all those lumpy blobs, you need to disable all the filtering it usually does.
params = cv.SimpleBlobDetector_Params()
params.filterByArea = False
params.filterByCircularity = False
params.filterByColor = False
params.filterByConvexity = False
params.filterByInertia = False
blobdet = cv.SimpleBlobDetector_create(params)
Result of keypoints = blobdet.detect(im)
and cv.drawKeypoints()
:
You also need to be careful with the flags to findCirclesGrid()
. CALIB_CB_CLUSTERING
failed in that it misassigned points to grid positions.
(rv, gridpts) = cv.findCirclesGrid(
im, (10, 7),
flags=cv.CALIB_CB_SYMMETRIC_GRID,
blobDetector=blobdet)
And that'll give you gridpts
having shape (70, 1, 2)
.
Some visualization:
im_with_grid = cv.cvtColor(cv.pyrUp(im >> 1), cv.COLOR_GRAY2BGR)
for k in range(1, len(gridpts)):
[p1] = gridpts[k-1]
[p2] = gridpts[k]
cv.line(im_with_grid, (p1 * 2.0).astype(int), (p2 * 2.0).astype(int), (0, 0, 255), 2)
for i,[pt] in enumerate(gridpts):
cv.circle(im_with_grid, (pt * 2.0).astype(int), 5, (0, 255, 0), -1)
cv.putText(
im_with_grid, f"{i}", (pt * 2.0).astype(int),
cv.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2, cv.LINE_AA )
Or if you specify the grid size as (7, 10)
, it'll be flipped along its diagonal and look like this:
Caveat
findCirclesGrid
will fail if the grid has any defects, i.e. missing points. It can't go around those defects. You need a perfect detection of all grid points.