Skip to content
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

detect and warn collinearity of GCPs #40

Open
wants to merge 1 commit into
base: 353
Choose a base branch
from
Open
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
30 changes: 30 additions & 0 deletions opensfm/reconstruction.py
Original file line number Diff line number Diff line change
Expand Up @@ -1446,6 +1446,32 @@ def should(self) -> bool:
def done(self) -> None:
self.num_points_last = len(self.reconstruction.points)

def detect_gcp_collinear(reconstruction: types.Reconstruction, gcp: List[pymap.GroundControlPoint], epsilon_abs = 1, epsilon_ratio = 0.05) -> bool:
"""
Determine if the gcp points are collinear based on PCA analysis.
There are two criteria to determine if the points are collinear:
1. The first singular value is small, less than `epsilon_abs`. This is not collinear, but means the points are very close to each other, which is also no good for alignment)
2. The ratio of the 2nd singular value to the 1st singular value is small, less than `epsilon_ratio`. This suggests the points are collinear. The smaller the ratio, the more collinear the points are.
"""
if len(gcp) <= 2:
return True
X = []
# Convert the gcp points to ENU coordinates
for point in gcp:
point_enu = np.array(
reconstruction.reference.to_topocentric(*point.lla_vec)
)
if not point.has_altitude:
point_enu[2] = 0.0
X.append(point_enu)
# Center the points
X = np.array(X)
X = X - np.average(X, axis=0)
# Perform PCA
_, s, _ = np.linalg.svd(X)
ratio = s[1]/s[0]
is_line = s[0] < epsilon_abs or ratio < epsilon_ratio
return is_line

def grow_reconstruction(
data: DataSetBase,
Expand Down Expand Up @@ -1594,6 +1620,8 @@ def triangulation_reconstruction(
gcp = data.load_ground_control_points()

reconstruction = helpers.reconstruction_from_metadata(data, images)
if gcp and detect_gcp_collinear(reconstruction, gcp):
logger.warning("GCP points are likely collinear. The reconstruction orientation may be inaccurate.")

config = data.config
config_override = config.copy()
Expand Down Expand Up @@ -1676,6 +1704,8 @@ def incremental_reconstruction(

if reconstruction:
remaining_images -= set(reconstruction.shots)
if gcp and detect_gcp_collinear(reconstruction, gcp):
logger.warning("GCP points are likely collinear. The reconstruction orientation may be inaccurate.")
reconstruction, rec_report["grow"] = grow_reconstruction(
data,
tracks_manager,
Expand Down
Loading