[Bf-blender-cvs] [b7bcd0a87c9] master: Tracking: Implement Nuke/Natron distortion model

Sergey Sharybin noreply at git.blender.org
Wed Apr 29 16:43:34 CEST 2020


Commit: b7bcd0a87c9df2f11d7249c64768e9526b2048bd
Author: Sergey Sharybin
Date:   Mon Apr 20 17:33:03 2020 +0200
Branches: master
https://developer.blender.org/rBb7bcd0a87c9df2f11d7249c64768e9526b2048bd

Tracking: Implement Nuke/Natron distortion model

Neither Nuke nor Natron support OpenCV's radial distortion model
which makes it impossible to have any kind of interoperability.

The new model is available under the distortion model menu in Lens
settings.

Differential Revision: https://developer.blender.org/D7484

===================================================================

M	intern/libmv/intern/camera_intrinsics.cc
M	intern/libmv/intern/camera_intrinsics.h
M	intern/libmv/libmv/simple_pipeline/bundle.cc
M	intern/libmv/libmv/simple_pipeline/camera_intrinsics.cc
M	intern/libmv/libmv/simple_pipeline/camera_intrinsics.h
M	intern/libmv/libmv/simple_pipeline/distortion_models.cc
M	intern/libmv/libmv/simple_pipeline/distortion_models.h
M	release/scripts/startup/bl_ui/space_clip.py
M	source/blender/blenkernel/intern/movieclip.c
M	source/blender/blenkernel/intern/tracking_util.c
M	source/blender/makesdna/DNA_tracking_types.h
M	source/blender/makesrna/intern/rna_tracking.c

===================================================================

diff --git a/intern/libmv/intern/camera_intrinsics.cc b/intern/libmv/intern/camera_intrinsics.cc
index 89e3d0d1178..554c4350b0a 100644
--- a/intern/libmv/intern/camera_intrinsics.cc
+++ b/intern/libmv/intern/camera_intrinsics.cc
@@ -24,6 +24,7 @@
 using libmv::CameraIntrinsics;
 using libmv::DivisionCameraIntrinsics;
 using libmv::PolynomialCameraIntrinsics;
+using libmv::NukeCameraIntrinsics;
 
 libmv_CameraIntrinsics *libmv_cameraIntrinsicsNew(
     const libmv_CameraIntrinsicsOptions* libmv_camera_intrinsics_options) {
@@ -55,6 +56,14 @@ libmv_CameraIntrinsics *libmv_cameraIntrinsicsCopy(
                                           *division_intrinsics);
         break;
       }
+    case libmv::DISTORTION_MODEL_NUKE:
+      {
+        const NukeCameraIntrinsics *nuke_intrinsics =
+          static_cast<const NukeCameraIntrinsics*>(orig_intrinsics);
+        new_intrinsics = LIBMV_OBJECT_NEW(NukeCameraIntrinsics,
+                                          *nuke_intrinsics);
+        break;
+      }
     default:
       assert(!"Unknown distortion model");
   }
@@ -136,6 +145,25 @@ void libmv_cameraIntrinsicsUpdate(
         break;
       }
 
+    case LIBMV_DISTORTION_MODEL_NUKE:
+      {
+        assert(camera_intrinsics->GetDistortionModelType() ==
+               libmv::DISTORTION_MODEL_NUKE);
+
+        NukeCameraIntrinsics *nuke_intrinsics =
+          (NukeCameraIntrinsics *) camera_intrinsics;
+
+        double k1 = libmv_camera_intrinsics_options->nuke_k1;
+        double k2 = libmv_camera_intrinsics_options->nuke_k2;
+
+        if (nuke_intrinsics->k1() != k1 ||
+            nuke_intrinsics->k2() != k2) {
+          nuke_intrinsics->SetDistortion(k1, k2);
+        }
+
+        break;
+      }
+
     default:
       assert(!"Unknown distortion model");
   }
@@ -189,6 +217,17 @@ void libmv_cameraIntrinsicsExtractOptions(
         break;
       }
 
+    case libmv::DISTORTION_MODEL_NUKE:
+      {
+        const NukeCameraIntrinsics *nuke_intrinsics =
+          static_cast<const NukeCameraIntrinsics *>(camera_intrinsics);
+        camera_intrinsics_options->distortion_model =
+          LIBMV_DISTORTION_MODEL_NUKE;
+        camera_intrinsics_options->nuke_k1 = nuke_intrinsics->k1();
+        camera_intrinsics_options->nuke_k2 = nuke_intrinsics->k2();
+        break;
+      }
+
     default:
       assert(!"Unknown distortion model");
   }
@@ -316,6 +355,17 @@ static void libmv_cameraIntrinsicsFillFromOptions(
         break;
       }
 
+    case LIBMV_DISTORTION_MODEL_NUKE:
+      {
+        NukeCameraIntrinsics *nuke_intrinsics =
+          static_cast<NukeCameraIntrinsics*>(camera_intrinsics);
+
+        nuke_intrinsics->SetDistortion(
+            camera_intrinsics_options->nuke_k1,
+            camera_intrinsics_options->nuke_k2);
+        break;
+      }
+
     default:
       assert(!"Unknown distortion model");
   }
@@ -331,6 +381,9 @@ CameraIntrinsics* libmv_cameraIntrinsicsCreateFromOptions(
     case LIBMV_DISTORTION_MODEL_DIVISION:
       camera_intrinsics = LIBMV_OBJECT_NEW(DivisionCameraIntrinsics);
       break;
+    case LIBMV_DISTORTION_MODEL_NUKE:
+      camera_intrinsics = LIBMV_OBJECT_NEW(NukeCameraIntrinsics);
+      break;
     default:
       assert(!"Unknown distortion model");
   }
diff --git a/intern/libmv/intern/camera_intrinsics.h b/intern/libmv/intern/camera_intrinsics.h
index 40a5826a9c4..b3d259893bd 100644
--- a/intern/libmv/intern/camera_intrinsics.h
+++ b/intern/libmv/intern/camera_intrinsics.h
@@ -29,6 +29,7 @@ typedef struct libmv_CameraIntrinsics libmv_CameraIntrinsics;
 enum {
   LIBMV_DISTORTION_MODEL_POLYNOMIAL = 0,
   LIBMV_DISTORTION_MODEL_DIVISION = 1,
+  LIBMV_DISTORTION_MODEL_NUKE = 2,
 };
 
 typedef struct libmv_CameraIntrinsicsOptions {
@@ -45,6 +46,9 @@ typedef struct libmv_CameraIntrinsicsOptions {
 
   // Division distortion model.
   double division_k1, division_k2;
+
+  // Nuke distortion model.
+  double nuke_k1, nuke_k2;
 } libmv_CameraIntrinsicsOptions;
 
 libmv_CameraIntrinsics *libmv_cameraIntrinsicsNew(
diff --git a/intern/libmv/libmv/simple_pipeline/bundle.cc b/intern/libmv/libmv/simple_pipeline/bundle.cc
index 2976dd5053f..a70fdbc9888 100644
--- a/intern/libmv/libmv/simple_pipeline/bundle.cc
+++ b/intern/libmv/libmv/simple_pipeline/bundle.cc
@@ -66,6 +66,12 @@ enum {
 
 namespace {
 
+bool NeedUseInvertIntrinsicsPipeline(const CameraIntrinsics *intrinsics) {
+  const DistortionModelType distortion_model =
+      intrinsics->GetDistortionModelType();
+  return (distortion_model == DISTORTION_MODEL_NUKE);
+}
+
 // Apply distortion model (distort the input) on the input point in the
 // normalized space to get distorted coordinate in the image space.
 //
@@ -89,8 +95,6 @@ void ApplyDistortionModelUsingIntrinsicsBlock(
   const T& principal_point_x = intrinsics_block[OFFSET_PRINCIPAL_POINT_X];
   const T& principal_point_y = intrinsics_block[OFFSET_PRINCIPAL_POINT_Y];
 
-  // Apply distortion to the normalized points to get (xd, yd).
-  //
   // TODO(keir): Do early bailouts for zero distortion; these are expensive
   // jet operations.
   switch (invariant_intrinsics->GetDistortionModelType()) {
@@ -127,11 +131,82 @@ void ApplyDistortionModelUsingIntrinsicsBlock(
                                      distorted_x, distorted_y);
         return;
       }
+
+    case DISTORTION_MODEL_NUKE:
+      {
+        LOG(FATAL) << "Unsupported distortion model.";
+        return;
+      }
+  }
+
+  LOG(FATAL) << "Unknown distortion model.";
+}
+
+// Invert distortion model (undistort the input) on the input point in the
+// image space to get undistorted coordinate in the normalized space.
+//
+// Using intrinsics values from the parameter block, which makes this function
+// suitable for use from a cost functor.
+//
+// Only use for distortion models which are analytically defined for their
+// Invert() function.
+//
+// The invariant_intrinsics are used to access intrinsics which are never
+// packed into parameter block: for example, distortion model type and image
+// dimension.
+template<typename T>
+void InvertDistortionModelUsingIntrinsicsBlock(
+    const CameraIntrinsics *invariant_intrinsics,
+    const T* const intrinsics_block,
+    const T& image_x, const T& image_y,
+    T* normalized_x, T* normalized_y) {
+  // Unpack the intrinsics.
+  const T& focal_length      = intrinsics_block[OFFSET_FOCAL_LENGTH];
+  const T& principal_point_x = intrinsics_block[OFFSET_PRINCIPAL_POINT_X];
+  const T& principal_point_y = intrinsics_block[OFFSET_PRINCIPAL_POINT_Y];
+
+  // TODO(keir): Do early bailouts for zero distortion; these are expensive
+  // jet operations.
+  switch (invariant_intrinsics->GetDistortionModelType()) {
+    case DISTORTION_MODEL_POLYNOMIAL:
+    case DISTORTION_MODEL_DIVISION:
+      LOG(FATAL) << "Unsupported distortion model.";
+      return;
+
+    case DISTORTION_MODEL_NUKE:
+      {
+        const T& k1 = intrinsics_block[OFFSET_K1];
+        const T& k2 = intrinsics_block[OFFSET_K2];
+
+        InvertNukeDistortionModel(focal_length,
+                                  focal_length,
+                                  principal_point_x,
+                                  principal_point_y,
+                                  invariant_intrinsics->image_width(),
+                                  invariant_intrinsics->image_height(),
+                                  k1, k2,
+                                  image_x, image_y,
+                                  normalized_x, normalized_y);
+        return;
+      }
   }
 
   LOG(FATAL) << "Unknown distortion model.";
 }
 
+template<typename T>
+void NormalizedToImageSpace(const T* const intrinsics_block,
+                            const T& normalized_x, const T& normalized_y,
+                            T* image_x, T* image_y) {
+  // Unpack the intrinsics.
+  const T& focal_length      = intrinsics_block[OFFSET_FOCAL_LENGTH];
+  const T& principal_point_x = intrinsics_block[OFFSET_PRINCIPAL_POINT_X];
+  const T& principal_point_y = intrinsics_block[OFFSET_PRINCIPAL_POINT_Y];
+
+  *image_x = normalized_x * focal_length + principal_point_x;
+  *image_y = normalized_y * focal_length + principal_point_y;
+}
+
 // Cost functor which computes reprojection error of 3D point X on camera
 // defined by angle-axis rotation and it's translation (which are in the same
 // block due to optimization reasons).
@@ -191,6 +266,81 @@ struct ReprojectionErrorApplyIntrinsics {
   const double weight_;
 };
 
+// Cost functor which computes reprojection error of 3D point X on camera
+// defined by angle-axis rotation and it's translation (which are in the same
+// block due to optimization reasons).
+//
+// This functor can only be used for distortion models which have analytically
+// defined Invert() function.
+struct ReprojectionErrorInvertIntrinsics {
+  ReprojectionErrorInvertIntrinsics(
+      const CameraIntrinsics *invariant_intrinsics,
+      const double observed_distorted_x,
+      const double observed_distorted_y,
+      const double weight)
+      : invariant_intrinsics_(invariant_intrinsics),
+        observed_distorted_x_(observed_distorted_x),
+        observed_distorted_y_(observed_distorted_y),
+        weight_(weight) {}
+
+  template <typename T>
+  bool operator()(const T* const intrinsics,
+                  const T* const R_t,  // Rotation denoted by angle axis
+                                       // followed with translation
+                  const T* const X,    // Point coordinates 3x1.
+                  T* residuals) const {
+    // Unpack the intrinsics.
+    const T& focal_length      = intrinsics[OFFSET_FOCAL_LENGTH];
+    const T& principal_point_x = intrinsics[OFFSET_PRINCIPAL_POINT_X];
+    const T& principal_point_y = intrinsics[OFFSET_PRINCIPAL_POINT_Y];
+
+    // Compute projective coordinates: x = RX + t.
+    T x[3];
+
+    ceres::AngleAxisRotatePoint(R_t, X, x);
+    x[0] += R_t[3];
+    x[1] += R_t[4];
+    x[2] += R_t[5];
+
+    // Prevent points from going behind the camera.
+    if (x[2] < T(0)) {
+      return false;
+    }
+
+    // Compute normalized coordinates: x /= x[2].
+    T xn = x[0] / x[2];
+    T yn = x[1] / x[2];
+
+    // Compute image space coordinate from normalized.
+    

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list