From c4197cbd22784b8c002df8a02bb95764dc589b50 Mon Sep 17 00:00:00 2001 From: Peter Corke Date: Mon, 17 Aug 2026 20:58:08 +1000 Subject: [PATCH] fix: catch cv2.error in points2F(), not just F/mask=None cv2.findFundamentalMat() doesn't always fail cleanly on degenerate point configurations -- sometimes it raises a raw C++ assertion (a Mat rowRange error) instead of returning (None, None). Both are the same underlying condition (points too degenerate to estimate F), so catch cv2.error alongside the existing None-check and re-raise as the same descriptive ValueError. Surfaced by RVC3-python's visodom.py example, which already expects and catches ValueError from points2F() to skip degenerate frames in a temporal-matching loop -- the raw cv2.error was slipping past that except clause uncaught. Co-Authored-By: Claude Sonnet 5 --- src/machinevisiontoolbox/Camera.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/machinevisiontoolbox/Camera.py b/src/machinevisiontoolbox/Camera.py index e7c76e98..b5645b8f 100644 --- a/src/machinevisiontoolbox/Camera.py +++ b/src/machinevisiontoolbox/Camera.py @@ -2785,9 +2785,20 @@ def points2F( if seed is not None: cv2.setRNGSeed(seed) - F, mask = cv2.findFundamentalMat( - points1=p1.T, points2=p2.T, method=points2F_dict[method], **kwargs - ) + try: + F, mask = cv2.findFundamentalMat( + points1=p1.T, points2=p2.T, method=points2F_dict[method], **kwargs + ) + except cv2.error as e: + # on some degenerate point configurations cv2.findFundamentalMat + # raises a raw C++ assertion (eg. a Mat rowRange error) instead + # of returning None -- same underlying cause as the F is None + # case below, just surfaced differently by OpenCV + raise ValueError( + f"cv2.findFundamentalMat could not estimate F from " + f"{p1.shape[1]} point correspondences using method={method!r} " + f"-- points are likely too degenerate (eg. coplanar, collinear): {e}" + ) from e if F is None or mask is None: # already know p1.shape[1] >= min_points (checked above), so a