Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIvan Perevala <ivpe>2020-09-30 16:12:14 +0300
committerSergey Sharybin <sergey@blender.org>2020-09-30 16:54:24 +0300
commit3a7d62cd1f5e06e22af1642fc5f4aab59bace585 (patch)
treed2832d6dacf16938c709e395a3220f2c64ee18e7 /intern/libmv
parent5ac477805637f20b8ac5e742457fa8f304066d83 (diff)
Tracking: Implement Brown-Conrady distortion model
Implemented Brown-Conrady lens distortion model with 4 radial and 2 tangential coefficients to improve compatibility with other software, such as Agisoft Photoscan/Metashapes, 3DF Zephir, RealityCapture, Bentley ContextCapture, Alisevision Meshroom(opensource). Also older programs: Bundler, CPMVS. In general terms, most photogrammetric software. The new model is available under the distortion model menu in Lens settings. For tests and demos check the original patch. Reviewed By: sergey Differential Revision: https://developer.blender.org/D9037
Diffstat (limited to 'intern/libmv')
-rw-r--r--intern/libmv/intern/camera_intrinsics.cc73
-rw-r--r--intern/libmv/intern/camera_intrinsics.h5
-rw-r--r--intern/libmv/libmv/simple_pipeline/bundle.cc25
-rw-r--r--intern/libmv/libmv/simple_pipeline/camera_intrinsics.cc78
-rw-r--r--intern/libmv/libmv/simple_pipeline/camera_intrinsics.h65
-rw-r--r--intern/libmv/libmv/simple_pipeline/distortion_models.cc90
-rw-r--r--intern/libmv/libmv/simple_pipeline/distortion_models.h55
7 files changed, 389 insertions, 2 deletions
diff --git a/intern/libmv/intern/camera_intrinsics.cc b/intern/libmv/intern/camera_intrinsics.cc
index 554c4350b0a..628637e12cc 100644
--- a/intern/libmv/intern/camera_intrinsics.cc
+++ b/intern/libmv/intern/camera_intrinsics.cc
@@ -25,6 +25,7 @@ using libmv::CameraIntrinsics;
using libmv::DivisionCameraIntrinsics;
using libmv::PolynomialCameraIntrinsics;
using libmv::NukeCameraIntrinsics;
+using libmv::BrownCameraIntrinsics;
libmv_CameraIntrinsics *libmv_cameraIntrinsicsNew(
const libmv_CameraIntrinsicsOptions* libmv_camera_intrinsics_options) {
@@ -64,6 +65,14 @@ libmv_CameraIntrinsics *libmv_cameraIntrinsicsCopy(
*nuke_intrinsics);
break;
}
+ case libmv::DISTORTION_MODEL_BROWN:
+ {
+ const BrownCameraIntrinsics *brown_intrinsics =
+ static_cast<const BrownCameraIntrinsics*>(orig_intrinsics);
+ new_intrinsics = LIBMV_OBJECT_NEW(BrownCameraIntrinsics,
+ *brown_intrinsics);
+ break;
+ }
default:
assert(!"Unknown distortion model");
}
@@ -164,6 +173,35 @@ void libmv_cameraIntrinsicsUpdate(
break;
}
+ case LIBMV_DISTORTION_MODEL_BROWN:
+ {
+ assert(camera_intrinsics->GetDistortionModelType() ==
+ libmv::DISTORTION_MODEL_BROWN);
+
+ BrownCameraIntrinsics *brown_intrinsics =
+ (BrownCameraIntrinsics *) camera_intrinsics;
+
+ double k1 = libmv_camera_intrinsics_options->brown_k1;
+ double k2 = libmv_camera_intrinsics_options->brown_k2;
+ double k3 = libmv_camera_intrinsics_options->brown_k3;
+ double k4 = libmv_camera_intrinsics_options->brown_k4;
+
+ if (brown_intrinsics->k1() != k1 ||
+ brown_intrinsics->k2() != k2 ||
+ brown_intrinsics->k3() != k3 ||
+ brown_intrinsics->k4() != k4) {
+ brown_intrinsics->SetRadialDistortion(k1, k2, k3, k4);
+ }
+
+ double p1 = libmv_camera_intrinsics_options->brown_p1;
+ double p2 = libmv_camera_intrinsics_options->brown_p2;
+
+ if (brown_intrinsics->p1() != p1 || brown_intrinsics->p2() != p2) {
+ brown_intrinsics->SetTangentialDistortion(p1, p2);
+ }
+ break;
+ }
+
default:
assert(!"Unknown distortion model");
}
@@ -228,6 +266,21 @@ void libmv_cameraIntrinsicsExtractOptions(
break;
}
+ case libmv::DISTORTION_MODEL_BROWN:
+ {
+ const BrownCameraIntrinsics *brown_intrinsics =
+ static_cast<const BrownCameraIntrinsics *>(camera_intrinsics);
+ camera_intrinsics_options->distortion_model =
+ LIBMV_DISTORTION_MODEL_BROWN;
+ camera_intrinsics_options->brown_k1 = brown_intrinsics->k1();
+ camera_intrinsics_options->brown_k2 = brown_intrinsics->k2();
+ camera_intrinsics_options->brown_k3 = brown_intrinsics->k3();
+ camera_intrinsics_options->brown_k4 = brown_intrinsics->k4();
+ camera_intrinsics_options->brown_p1 = brown_intrinsics->p1();
+ camera_intrinsics_options->brown_p2 = brown_intrinsics->p2();
+ break;
+ }
+
default:
assert(!"Unknown distortion model");
}
@@ -366,6 +419,23 @@ static void libmv_cameraIntrinsicsFillFromOptions(
break;
}
+ case LIBMV_DISTORTION_MODEL_BROWN:
+ {
+ BrownCameraIntrinsics *brown_intrinsics =
+ static_cast<BrownCameraIntrinsics*>(camera_intrinsics);
+
+ brown_intrinsics->SetRadialDistortion(
+ camera_intrinsics_options->brown_k1,
+ camera_intrinsics_options->brown_k2,
+ camera_intrinsics_options->brown_k3,
+ camera_intrinsics_options->brown_k4);
+ brown_intrinsics->SetTangentialDistortion(
+ camera_intrinsics_options->brown_p1,
+ camera_intrinsics_options->brown_p2);
+
+ break;
+ }
+
default:
assert(!"Unknown distortion model");
}
@@ -384,6 +454,9 @@ CameraIntrinsics* libmv_cameraIntrinsicsCreateFromOptions(
case LIBMV_DISTORTION_MODEL_NUKE:
camera_intrinsics = LIBMV_OBJECT_NEW(NukeCameraIntrinsics);
break;
+ case LIBMV_DISTORTION_MODEL_BROWN:
+ camera_intrinsics = LIBMV_OBJECT_NEW(BrownCameraIntrinsics);
+ break;
default:
assert(!"Unknown distortion model");
}
diff --git a/intern/libmv/intern/camera_intrinsics.h b/intern/libmv/intern/camera_intrinsics.h
index b3d259893bd..eb6176770ec 100644
--- a/intern/libmv/intern/camera_intrinsics.h
+++ b/intern/libmv/intern/camera_intrinsics.h
@@ -30,6 +30,7 @@ enum {
LIBMV_DISTORTION_MODEL_POLYNOMIAL = 0,
LIBMV_DISTORTION_MODEL_DIVISION = 1,
LIBMV_DISTORTION_MODEL_NUKE = 2,
+ LIBMV_DISTORTION_MODEL_BROWN = 3,
};
typedef struct libmv_CameraIntrinsicsOptions {
@@ -49,6 +50,10 @@ typedef struct libmv_CameraIntrinsicsOptions {
// Nuke distortion model.
double nuke_k1, nuke_k2;
+
+ // Brown-Conrady distortion model.
+ double brown_k1, brown_k2, brown_k3, brown_k4;
+ double brown_p1, brown_p2;
} 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 22ab0cdf864..c055846318a 100644
--- a/intern/libmv/libmv/simple_pipeline/bundle.cc
+++ b/intern/libmv/libmv/simple_pipeline/bundle.cc
@@ -50,6 +50,7 @@ enum {
OFFSET_K1,
OFFSET_K2,
OFFSET_K3,
+ OFFSET_K4,
OFFSET_P1,
OFFSET_P2,
@@ -135,6 +136,26 @@ void ApplyDistortionModelUsingIntrinsicsBlock(
LOG(FATAL) << "Unsupported distortion model.";
return;
}
+
+ case DISTORTION_MODEL_BROWN:
+ {
+ const T& k1 = intrinsics_block[OFFSET_K1];
+ const T& k2 = intrinsics_block[OFFSET_K2];
+ const T& k3 = intrinsics_block[OFFSET_K3];
+ const T& k4 = intrinsics_block[OFFSET_K4];
+ const T& p1 = intrinsics_block[OFFSET_P1];
+ const T& p2 = intrinsics_block[OFFSET_P2];
+
+ ApplyBrownDistortionModel(focal_length,
+ focal_length,
+ principal_point_x,
+ principal_point_y,
+ k1, k2, k3, k4,
+ p1, p2,
+ normalized_x, normalized_y,
+ distorted_x, distorted_y);
+ return;
+ }
}
LOG(FATAL) << "Unknown distortion model.";
@@ -168,6 +189,7 @@ void InvertDistortionModelUsingIntrinsicsBlock(
switch (invariant_intrinsics->GetDistortionModelType()) {
case DISTORTION_MODEL_POLYNOMIAL:
case DISTORTION_MODEL_DIVISION:
+ case DISTORTION_MODEL_BROWN:
LOG(FATAL) << "Unsupported distortion model.";
return;
@@ -783,8 +805,9 @@ void EuclideanBundleCommonIntrinsics(
MAYBE_SET_CONSTANT(BUNDLE_TANGENTIAL_P2, OFFSET_P2);
#undef MAYBE_SET_CONSTANT
- // Always set K3 constant, it's not used at the moment.
+ // Always set K3 and K4 constant, it's not used at the moment.
constant_intrinsics.push_back(OFFSET_K3);
+ constant_intrinsics.push_back(OFFSET_K4);
ceres::SubsetParameterization *subset_parameterization =
new ceres::SubsetParameterization(OFFSET_MAX, constant_intrinsics);
diff --git a/intern/libmv/libmv/simple_pipeline/camera_intrinsics.cc b/intern/libmv/libmv/simple_pipeline/camera_intrinsics.cc
index c7c827fcd66..052714bbb3e 100644
--- a/intern/libmv/libmv/simple_pipeline/camera_intrinsics.cc
+++ b/intern/libmv/libmv/simple_pipeline/camera_intrinsics.cc
@@ -296,6 +296,72 @@ void NukeCameraIntrinsics::InvertIntrinsics(double image_x,
normalized_y);
}
+// Brown model.
+
+BrownCameraIntrinsics::BrownCameraIntrinsics()
+ : CameraIntrinsics() {
+ SetRadialDistortion(0.0, 0.0, 0.0, 0.0);
+ SetTangentialDistortion(0.0, 0.0);
+}
+
+BrownCameraIntrinsics::BrownCameraIntrinsics(
+ const BrownCameraIntrinsics &from)
+ : CameraIntrinsics(from) {
+ SetRadialDistortion(from.k1(), from.k2(), from.k3(), from.k4());
+ SetTangentialDistortion(from.p1(), from.p2());
+}
+
+void BrownCameraIntrinsics::SetRadialDistortion(double k1,
+ double k2,
+ double k3,
+ double k4) {
+ parameters_[OFFSET_K1] = k1;
+ parameters_[OFFSET_K2] = k2;
+ parameters_[OFFSET_K3] = k3;
+ parameters_[OFFSET_K4] = k4;
+ ResetLookupGrids();
+}
+
+void BrownCameraIntrinsics::SetTangentialDistortion(double p1,
+ double p2) {
+ parameters_[OFFSET_P1] = p1;
+ parameters_[OFFSET_P2] = p2;
+ ResetLookupGrids();
+}
+
+void BrownCameraIntrinsics::ApplyIntrinsics(double normalized_x,
+ double normalized_y,
+ double *image_x,
+ double *image_y) const {
+ ApplyBrownDistortionModel(focal_length_x(),
+ focal_length_y(),
+ principal_point_x(),
+ principal_point_y(),
+ k1(), k2(), k3(), k4(),
+ p1(), p2(),
+ normalized_x,
+ normalized_y,
+ image_x,
+ image_y);
+}
+
+void BrownCameraIntrinsics::InvertIntrinsics(
+ double image_x,
+ double image_y,
+ double *normalized_x,
+ double *normalized_y) const {
+ InvertBrownDistortionModel(focal_length_x(),
+ focal_length_y(),
+ principal_point_x(),
+ principal_point_y(),
+ k1(), k2(), k3(), k4(),
+ p1(), p2(),
+ image_x,
+ image_y,
+ normalized_x,
+ normalized_y);
+}
+
std::ostream& operator <<(std::ostream &os,
const CameraIntrinsics &intrinsics) {
if (intrinsics.focal_length_x() == intrinsics.focal_length_x()) {
@@ -344,6 +410,18 @@ std::ostream& operator <<(std::ostream &os,
PRINT_NONZERO_COEFFICIENT(nuke_intrinsics, k2);
break;
}
+ case DISTORTION_MODEL_BROWN:
+ {
+ const BrownCameraIntrinsics *brown_intrinsics =
+ static_cast<const BrownCameraIntrinsics *>(&intrinsics);
+ PRINT_NONZERO_COEFFICIENT(brown_intrinsics, k1);
+ PRINT_NONZERO_COEFFICIENT(brown_intrinsics, k2);
+ PRINT_NONZERO_COEFFICIENT(brown_intrinsics, k3);
+ PRINT_NONZERO_COEFFICIENT(brown_intrinsics, k4);
+ PRINT_NONZERO_COEFFICIENT(brown_intrinsics, p1);
+ PRINT_NONZERO_COEFFICIENT(brown_intrinsics, p2);
+ break;
+ }
default:
LOG(FATAL) << "Unknown distortion model.";
}
diff --git a/intern/libmv/libmv/simple_pipeline/camera_intrinsics.h b/intern/libmv/libmv/simple_pipeline/camera_intrinsics.h
index 782fd56c54c..cf0bdb76ccb 100644
--- a/intern/libmv/libmv/simple_pipeline/camera_intrinsics.h
+++ b/intern/libmv/libmv/simple_pipeline/camera_intrinsics.h
@@ -447,6 +447,71 @@ class NukeCameraIntrinsics : public CameraIntrinsics {
double parameters_[NUM_PARAMETERS];
};
+class BrownCameraIntrinsics : public CameraIntrinsics {
+ public:
+ // This constants defines an offset of corresponding coefficients
+ // in the parameters_ array.
+ enum {
+ OFFSET_K1,
+ OFFSET_K2,
+ OFFSET_K3,
+ OFFSET_K4,
+ OFFSET_P1,
+ OFFSET_P2,
+
+ // This defines the size of array which we need to have in order
+ // to store all the coefficients.
+ NUM_PARAMETERS,
+ };
+
+ BrownCameraIntrinsics();
+ BrownCameraIntrinsics(const BrownCameraIntrinsics &from);
+
+ DistortionModelType GetDistortionModelType() const {
+ return DISTORTION_MODEL_BROWN;
+ }
+
+ int num_distortion_parameters() const { return NUM_PARAMETERS; }
+ double *distortion_parameters() { return parameters_; };
+ const double *distortion_parameters() const { return parameters_; };
+
+ double k1() const { return parameters_[OFFSET_K1]; }
+ double k2() const { return parameters_[OFFSET_K2]; }
+ double k3() const { return parameters_[OFFSET_K3]; }
+ double k4() const { return parameters_[OFFSET_K4]; }
+ double p1() const { return parameters_[OFFSET_P1]; }
+ double p2() const { return parameters_[OFFSET_P2]; }
+
+ // Set radial distortion coeffcients.
+ void SetRadialDistortion(double k1, double k2, double k3, double k4);
+
+ // Set tangential distortion coeffcients.
+ void SetTangentialDistortion(double p1, double p2);
+
+ // Apply camera intrinsics to the normalized point to get image coordinates.
+ //
+ // This applies the lens distortion to a point which is in normalized
+ // camera coordinates (i.e. the principal point is at (0, 0)) to get image
+ // coordinates in pixels.
+ void ApplyIntrinsics(double normalized_x,
+ double normalized_y,
+ double *image_x,
+ double *image_y) const;
+
+ // Invert camera intrinsics on the image point to get normalized coordinates.
+ //
+ // This reverses the effect of lens distortion on a point which is in image
+ // coordinates to get normalized camera coordinates.
+ void InvertIntrinsics(double image_x,
+ double image_y,
+ double *normalized_x,
+ double *normalized_y) const;
+
+ private:
+ double parameters_[NUM_PARAMETERS];
+};
+
+
/// A human-readable representation of the camera intrinsic parameters.
std::ostream& operator <<(std::ostream &os,
const CameraIntrinsics &intrinsics);
diff --git a/intern/libmv/libmv/simple_pipeline/distortion_models.cc b/intern/libmv/libmv/simple_pipeline/distortion_models.cc
index c069fc6f623..f602234b630 100644
--- a/intern/libmv/libmv/simple_pipeline/distortion_models.cc
+++ b/intern/libmv/libmv/simple_pipeline/distortion_models.cc
@@ -117,6 +117,56 @@ struct InvertDivisionIntrinsicsCostFunction {
double x_, y_;
};
+struct InvertBrownIntrinsicsCostFunction {
+ public:
+ typedef Vec2 FMatrixType;
+ typedef Vec2 XMatrixType;
+
+ InvertBrownIntrinsicsCostFunction(const double focal_length_x,
+ const double focal_length_y,
+ const double principal_point_x,
+ const double principal_point_y,
+ const double k1,
+ const double k2,
+ const double k3,
+ const double k4,
+ const double p1,
+ const double p2,
+ const double image_x,
+ const double image_y)
+ : focal_length_x_(focal_length_x),
+ focal_length_y_(focal_length_y),
+ principal_point_x_(principal_point_x),
+ principal_point_y_(principal_point_y),
+ k1_(k1), k2_(k2), k3_(k3), k4_(k4),
+ p1_(p1), p2_(p2),
+ x_(image_x), y_(image_y) {}
+
+ Vec2 operator()(const Vec2 &u) const {
+ double xx, yy;
+
+ ApplyBrownDistortionModel(focal_length_x_,
+ focal_length_y_,
+ principal_point_x_,
+ principal_point_y_,
+ k1_, k2_, k3_, k4_,
+ p1_, p2_,
+ u(0), u(1),
+ &xx, &yy);
+
+ Vec2 fx;
+ fx << (xx - x_), (yy - y_);
+ return fx;
+ }
+ double focal_length_x_;
+ double focal_length_y_;
+ double principal_point_x_;
+ double principal_point_y_;
+ double k1_, k2_, k3_, k4_;
+ double p1_, p2_;
+ double x_, y_;
+};
+
} // namespace
void InvertPolynomialDistortionModel(const double focal_length_x,
@@ -194,6 +244,46 @@ void InvertDivisionDistortionModel(const double focal_length_x,
*normalized_y = normalized(1);
}
+void InvertBrownDistortionModel(const double focal_length_x,
+ const double focal_length_y,
+ const double principal_point_x,
+ const double principal_point_y,
+ const double k1,
+ const double k2,
+ const double k3,
+ const double k4,
+ const double p1,
+ const double p2,
+ const double image_x,
+ const double image_y,
+ double *normalized_x,
+ double *normalized_y) {
+ // Compute the initial guess. For a camera with no distortion, this will also
+ // be the final answer; the LM iteration will terminate immediately.
+ Vec2 normalized;
+ normalized(0) = (image_x - principal_point_x) / focal_length_x;
+ normalized(1) = (image_y - principal_point_y) / focal_length_y;
+
+ typedef LevenbergMarquardt<InvertBrownIntrinsicsCostFunction> Solver;
+
+ InvertBrownIntrinsicsCostFunction intrinsics_cost(focal_length_x,
+ focal_length_y,
+ principal_point_x,
+ principal_point_y,
+ k1, k2, k3, k4,
+ p1, p2,
+ image_x, image_y);
+ Solver::SolverParameters params;
+ Solver solver(intrinsics_cost);
+
+ /*Solver::Results results =*/ solver.minimize(params, &normalized);
+
+ // TODO(keir): Better error handling.
+
+ *normalized_x = normalized(0);
+ *normalized_y = normalized(1);
+}
+
struct ApplyNukeIntrinsicsCostFunction {
public:
typedef Vec2 FMatrixType;
diff --git a/intern/libmv/libmv/simple_pipeline/distortion_models.h b/intern/libmv/libmv/simple_pipeline/distortion_models.h
index 6ba351d729d..51300477956 100644
--- a/intern/libmv/libmv/simple_pipeline/distortion_models.h
+++ b/intern/libmv/libmv/simple_pipeline/distortion_models.h
@@ -29,6 +29,7 @@ enum DistortionModelType {
DISTORTION_MODEL_POLYNOMIAL,
DISTORTION_MODEL_DIVISION,
DISTORTION_MODEL_NUKE,
+ DISTORTION_MODEL_BROWN,
};
// Invert camera intrinsics on the image point to get normalized coordinates.
@@ -202,6 +203,58 @@ void ApplyNukeDistortionModel(const double focal_length_x,
double *image_x,
double *image_y);
-} // namespace libmv
+// Invert camera intrinsics on the image point to get normalized coordinates.
+// This inverts the radial lens distortion to a point which is in image pixel
+// coordinates to get normalized coordinates.
+void InvertBrownDistortionModel(const double focal_length_x,
+ const double focal_length_y,
+ const double principal_point_x,
+ const double principal_point_y,
+ const double k1,
+ const double k2,
+ const double k3,
+ const double k4,
+ const double p1,
+ const double p2,
+ const double image_x,
+ const double image_y,
+ double *normalized_x,
+ double *normalized_y);
+
+template <typename T>
+inline void ApplyBrownDistortionModel(const T &focal_length_x,
+ const T &focal_length_y,
+ const T &principal_point_x,
+ const T &principal_point_y,
+ const T &k1,
+ const T &k2,
+ const T &k3,
+ const T &k4,
+ const T &p1,
+ const T &p2,
+ const T &normalized_x,
+ const T &normalized_y,
+ T *image_x,
+ T *image_y) {
+ T x = normalized_x;
+ T y = normalized_y;
+
+ // Apply distortion to the normalized points to get (xd, yd).
+ T x2 = x * x;
+ T y2 = y * y;
+ T xy2 = T(2) * x * y;
+ T r2 = x2 + y2;
+ T r_coeff = T(1) + (((k4 * r2 + k3) * r2 + k2) * r2 + k1) * r2;
+ T tx = p1 * (r2 + T(2) * x2) + p2 * xy2;
+ T ty = p2 * (r2 + T(2) * y2) + p1 * xy2;
+ T xd = x * r_coeff + tx;
+ T yd = y * r_coeff + ty;
+
+ // Apply focal length and principal point to get the final image coordinates.
+ *image_x = focal_length_x * xd + principal_point_x;
+ *image_y = focal_length_y * yd + principal_point_y;
+} // namespace libmv
+
+}
#endif // LIBMV_SIMPLE_PIPELINE_DISTORTION_MODELS_H_