From e57597aa527ab1741ff19066070ecd6968056da5 Mon Sep 17 00:00:00 2001 From: Peter Corke Date: Thu, 30 Jul 2026 17:05:52 +1000 Subject: [PATCH] fix: gridify() IndexError from numpy float // int staying float64 BaseFeature2D.gridify() computed grid cell indices as f.p[0] // binwidth / f.p[1] // binheight. f.p is a numpy float array (feature point coordinates, shape (2,1)), and floor-dividing a numpy float array by a Python int still yields a float64 result -- so bins[iy, ix] always raised IndexError: arrays used as indices must be of integer (or boolean) type. This affected every call to gridify() regardless of whether nbins was passed as a tuple or scalar. Fix: extract the scalar value with .item() before floor-dividing, then cast to int explicitly. Added regression tests (gridify() had zero prior coverage) that fail with the exact reported IndexError against the unfixed code and pass against the fix -- verified both directions directly before committing. --- .../ImagePointFeatures.py | 4 ++-- tests/test_image_point_features.py | 20 +++++++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/machinevisiontoolbox/ImagePointFeatures.py b/src/machinevisiontoolbox/ImagePointFeatures.py index d185ad03..b309fbd0 100644 --- a/src/machinevisiontoolbox/ImagePointFeatures.py +++ b/src/machinevisiontoolbox/ImagePointFeatures.py @@ -294,8 +294,8 @@ def gridify(self, nbins: int | tuple[int, int], nfeat: int) -> "BaseFeature2D": bins = np.zeros((nh, nw), dtype="int") for f in self: - ix = f.p[0] // binwidth - iy = f.p[1] // binheight + ix = int(f.p[0].item() // binwidth) + iy = int(f.p[1].item() // binheight) if bins[iy, ix] < nfeat: keep.append(f) diff --git a/tests/test_image_point_features.py b/tests/test_image_point_features.py index d2e19cf6..8025b586 100644 --- a/tests/test_image_point_features.py +++ b/tests/test_image_point_features.py @@ -190,6 +190,26 @@ def test_features_list_operations(self): except: pass + def test_gridify_scalar_nbins(self): + """gridify() with a scalar nbins must not raise (regression: numpy + float // int stayed float64, bins[iy, ix] then rejected as an index)""" + img = Image.Read("monalisa.png", mono=True) + sift = img.SIFT() + self.assertGreater(len(sift), 0) + + gridded = sift.gridify(nbins=4, nfeat=2) + self.assertLessEqual(len(gridded), len(sift)) + + def test_gridify_tuple_nbins(self): + """gridify() with a (nw, nh) tuple must not raise, same root cause + as the scalar case above.""" + img = Image.Read("monalisa.png", mono=True) + sift = img.SIFT() + self.assertGreater(len(sift), 0) + + gridded = sift.gridify(nbins=(4, 3), nfeat=2) + self.assertLessEqual(len(gridded), len(sift)) + def test_feature_properties(self): """Test feature properties""" img = Image.Read("monalisa.png", mono=True)