Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/machinevisiontoolbox/ImageBlobs.py
Original file line number Diff line number Diff line change
Expand Up @@ -458,7 +458,10 @@ def __init__(

## Equivalent ellipse
J = np.array([[M["mu20"], M["mu11"]], [M["mu11"], M["mu02"]]])
e, X = np.linalg.eig(J)
# J is real-symmetric, so use eigh (not eig): eig can return
# complex128 for a symmetric matrix due to floating-point
# noise even though the eigenvalues are mathematically real.
e, X = np.linalg.eigh(J)
blob_params["a"] = 2.0 * np.sqrt(e.max() / M["m00"])
blob_params["b"] = 2.0 * np.sqrt(e.min() / M["m00"])

Expand Down
17 changes: 17 additions & 0 deletions tests/test_image_blobs.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,23 @@ def test_two_blobs_different_sizes(self):
self.assertEqual(blobs[1].area, 4)
self.assertEqual(blobs[1].perimeter_length, 7)

def test_orientation_square_blob_degenerate_moments(self):
# A square (or any blob with equal mu20/mu02 and mu11≈0) has a
# moment matrix that is a scalar multiple of the identity: its two
# eigenvalues are exactly equal. np.linalg.eig (general, non-
# symmetric solver) can return complex128 for this case due to
# floating-point noise even though the matrix is real-symmetric and
# the eigenvalues are mathematically real, which then makes
# np.arctan2() raise TypeError. np.linalg.eigh (symmetric solver)
# does not have this failure mode. See ImageBlobs.py's equivalent
# ellipse / orientation calculation.
im = Image.Squares(1, size=61, fg=255, bg=0)
blobs = im.blobs()

orientation = blobs[0].orientation
self.assertIsInstance(orientation, float)
self.assertFalse(np.iscomplexobj(orientation))


# ============================================================================ #
# Fixtures
Expand Down
Loading