-
Notifications
You must be signed in to change notification settings - Fork 251
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[FIX][MOTION ESTIMATION] Fix error on homography calculation #278
Merged
Merged
Changes from 10 commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
2049fe2
prevent homography opencv error
gfugante c847bef
prevent error on _get_sparse_flow
gfugante e9c0e46
handle None points and update operations
gfugante 8c92fa0
best working version
gfugante a1a8547
Added warning message when homography couldn't be computed
8e5c2fd
If not enough points and we have no previous transformation, return None
6cde4b2
homography calculation warning
gfugante 6311640
Add small number whenever the third column of the transformed points …
18920ae
Use new drawing functions in camera_modetion demo
c6d1f43
Remove repeated import
b38fb36
Run black on camera_motion.py
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,7 @@ | ||
"Camera motion stimation module." | ||
import copy | ||
from abc import ABC, abstractmethod | ||
from logging import warning | ||
from typing import Optional, Tuple | ||
|
||
import numpy as np | ||
|
@@ -148,16 +150,21 @@ def abs_to_rel(self, points: np.ndarray): | |
ones = np.ones((len(points), 1)) | ||
points_with_ones = np.hstack((points, ones)) | ||
points_transformed = points_with_ones @ self.homography_matrix.T | ||
points_transformed = points_transformed / points_transformed[:, -1].reshape( | ||
last_column = points_transformed[:, -1] | ||
last_column[last_column == 0] = 0.0000001 | ||
points_transformed = points_transformed / last_column.reshape( | ||
-1, 1 | ||
) | ||
return points_transformed[:, :2] | ||
new_points_transformed = points_transformed[:, :2] | ||
return new_points_transformed | ||
|
||
def rel_to_abs(self, points: np.ndarray): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess the same error that happened in |
||
ones = np.ones((len(points), 1)) | ||
points_with_ones = np.hstack((points, ones)) | ||
points_transformed = points_with_ones @ self.inverse_homography_matrix.T | ||
points_transformed = points_transformed / points_transformed[:, -1].reshape( | ||
last_column = points_transformed[:, -1] | ||
last_column[last_column == 0] = 0.0000001 | ||
points_transformed = points_transformed / last_column.reshape( | ||
-1, 1 | ||
) | ||
return points_transformed[:, :2] | ||
|
@@ -212,7 +219,17 @@ def __init__( | |
|
||
def __call__( | ||
self, curr_pts: np.ndarray, prev_pts: np.ndarray | ||
) -> Tuple[bool, HomographyTransformation]: | ||
) -> Tuple[bool, Optional[HomographyTransformation]]: | ||
|
||
if not (isinstance(prev_pts, np.ndarray) and prev_pts.shape[0] >= 4 | ||
and isinstance(curr_pts, np.ndarray) and curr_pts.shape[0] >= 4): | ||
warning("The homography couldn't be computed in this frame " | ||
"due to low amount of points") | ||
if isinstance(self.data, np.ndarray): | ||
return True, HomographyTransformation(self.data) | ||
else: | ||
return True, None | ||
|
||
homography_matrix, points_used = cv2.findHomography( | ||
prev_pts, | ||
curr_pts, | ||
|
@@ -340,13 +357,15 @@ def __init__( | |
transformations_getter = HomographyTransformationGetter() | ||
|
||
self.transformations_getter = transformations_getter | ||
self.transformations_getter_copy = copy.deepcopy(transformations_getter) | ||
|
||
self.prev_mask = None | ||
self.gray_next = None | ||
self.quality_level = quality_level | ||
|
||
def update( | ||
self, frame: np.ndarray, mask: np.ndarray = None | ||
) -> CoordinatesTransformation: | ||
) -> Optional[CoordinatesTransformation]: | ||
""" | ||
Estimate camera motion for each frame | ||
|
||
|
@@ -371,36 +390,48 @@ def update( | |
The CoordinatesTransformation that can transform coordinates on this frame to absolute coordinates | ||
or vice versa. | ||
""" | ||
|
||
self.gray_next = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) | ||
if self.gray_prvs is None: | ||
self.gray_prvs = self.gray_next | ||
self.prev_mask = mask | ||
|
||
curr_pts, self.prev_pts = _get_sparse_flow( | ||
self.gray_next, | ||
self.gray_prvs, | ||
self.prev_pts, | ||
self.max_points, | ||
self.min_distance, | ||
self.block_size, | ||
self.prev_mask, | ||
quality_level=self.quality_level, | ||
) | ||
if self.draw_flow: | ||
for (curr, prev) in zip(curr_pts, self.prev_pts): | ||
c = tuple(curr.astype(int).ravel()) | ||
p = tuple(prev.astype(int).ravel()) | ||
cv2.line(frame, c, p, self.flow_color, 2) | ||
cv2.circle(frame, c, 3, self.flow_color, -1) | ||
|
||
update_prvs, coord_transformations = self.transformations_getter( | ||
curr_pts, | ||
self.prev_pts, | ||
) | ||
curr_pts, prev_pts = None, None | ||
try: | ||
curr_pts, prev_pts = _get_sparse_flow( | ||
self.gray_next, | ||
self.gray_prvs, | ||
self.prev_pts, | ||
self.max_points, | ||
self.min_distance, | ||
self.block_size, | ||
self.prev_mask, | ||
quality_level=self.quality_level, | ||
) | ||
if self.draw_flow: | ||
for (curr, prev) in zip(curr_pts, prev_pts): | ||
c = tuple(curr.astype(int).ravel()) | ||
p = tuple(prev.astype(int).ravel()) | ||
cv2.line(frame, c, p, self.flow_color, 2) | ||
cv2.circle(frame, c, 3, self.flow_color, -1) | ||
except Exception as e: | ||
warning(e) | ||
|
||
update_prvs, coord_transformations = True, None | ||
try: | ||
update_prvs, coord_transformations = self.transformations_getter( | ||
curr_pts, prev_pts | ||
) | ||
except Exception as e: | ||
warning(e) | ||
del self.transformations_getter | ||
self.transformations_getter = copy.deepcopy(self.transformations_getter_copy) | ||
|
||
if update_prvs: | ||
self.gray_prvs = self.gray_next | ||
self.prev_pts = None | ||
self.prev_mask = mask | ||
else: | ||
self.prev_pts = prev_pts | ||
|
||
return coord_transformations |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great catch. I assume this is happening when dividing by the last column of the
points_transformed
array, since it might contain zero values (really weird case, but sure, can happen). Tell me if you think the source of the problem might be other, because I actually couldn't reproduce the nan or infs error.Anyway, I'm not exactly convinced that this is the best way of fixing it if you get infinite values. The two main reasons I say that are
points_transformed
array whenever it has some zero entry, so that when we compute the quotient we are not getting a division by zero. I think at least that feels somewhat less arbitrary than just returning the zero point.Could you please try the suggestion of my second point and check if you still can reproduce the nan/inf error or if that would also solve it?