libmv_bundle_adjuster.cc 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852
  1. // Copyright (c) 2013 libmv authors.
  2. //
  3. // Permission is hereby granted, free of charge, to any person obtaining a copy
  4. // of this software and associated documentation files (the "Software"), to
  5. // deal in the Software without restriction, including without limitation the
  6. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  7. // sell copies of the Software, and to permit persons to whom the Software is
  8. // furnished to do so, subject to the following conditions:
  9. //
  10. // The above copyright notice and this permission notice shall be included in
  11. // all copies or substantial portions of the Software.
  12. //
  13. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  18. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  19. // IN THE SOFTWARE.
  20. //
  21. // Author: mierle@gmail.com (Keir Mierle)
  22. // sergey.vfx@gmail.com (Sergey Sharybin)
  23. //
  24. // This is an example application which contains bundle adjustment code used
  25. // in the Libmv library and Blender. It reads problems from files passed via
  26. // the command line and runs the bundle adjuster on the problem.
  27. //
  28. // File with problem a binary file, for which it is crucial to know in which
  29. // order bytes of float values are stored in. This information is provided
  30. // by a single character in the beginning of the file. There're two possible
  31. // values of this byte:
  32. // - V, which means values in the file are stored with big endian type
  33. // - v, which means values in the file are stored with little endian type
  34. //
  35. // The rest of the file contains data in the following order:
  36. // - Space in which markers' coordinates are stored in
  37. // - Camera intrinsics
  38. // - Number of cameras
  39. // - Cameras
  40. // - Number of 3D points
  41. // - 3D points
  42. // - Number of markers
  43. // - Markers
  44. //
  45. // Markers' space could either be normalized or image (pixels). This is defined
  46. // by the single character in the file. P means markers in the file is in image
  47. // space, and N means markers are in normalized space.
  48. //
  49. // Camera intrinsics are 8 described by 8 float 8.
  50. // This values goes in the following order:
  51. //
  52. // - Focal length, principal point X, principal point Y, k1, k2, k3, p1, p2
  53. //
  54. // Every camera is described by:
  55. //
  56. // - Image for which camera belongs to (single 4 bytes integer value).
  57. // - Column-major camera rotation matrix, 9 float values.
  58. // - Camera translation, 3-component vector of float values.
  59. //
  60. // Image number shall be greater or equal to zero. Order of cameras does not
  61. // matter and gaps are possible.
  62. //
  63. // Every 3D point is described by:
  64. //
  65. // - Track number point belongs to (single 4 bytes integer value).
  66. // - 3D position vector, 3-component vector of float values.
  67. //
  68. // Track number shall be greater or equal to zero. Order of tracks does not
  69. // matter and gaps are possible.
  70. //
  71. // Finally every marker is described by:
  72. //
  73. // - Image marker belongs to single 4 bytes integer value).
  74. // - Track marker belongs to single 4 bytes integer value).
  75. // - 2D marker position vector, (two float values).
  76. //
  77. // Marker's space is used a default value for refine_intrinsics command line
  78. // flag. This means if there's no refine_intrinsics flag passed via command
  79. // line, camera intrinsics will be refined if markers in the problem are
  80. // stored in image space and camera intrinsics will not be refined if markers
  81. // are in normalized space.
  82. //
  83. // Passing refine_intrinsics command line flag defines explicitly whether
  84. // refinement of intrinsics will happen. Currently, only none and all
  85. // intrinsics refinement is supported.
  86. //
  87. // There're existing problem files dumped from blender stored in folder
  88. // ../data/libmv-ba-problems.
  89. #include <fcntl.h>
  90. #include <cstdio>
  91. #include <sstream>
  92. #include <string>
  93. #include <vector>
  94. #ifdef _MSC_VER
  95. #include <io.h>
  96. #define open _open
  97. #define close _close
  98. typedef unsigned __int32 uint32_t;
  99. #else
  100. #include <unistd.h>
  101. #include <cstdint>
  102. // NOTE MinGW does define the macro.
  103. #ifndef O_BINARY
  104. // O_BINARY is not defined on unix like platforms, as there is no
  105. // difference between binary and text files.
  106. #define O_BINARY 0
  107. #endif
  108. #endif
  109. #include "ceres/ceres.h"
  110. #include "ceres/rotation.h"
  111. #include "gflags/gflags.h"
  112. #include "glog/logging.h"
  113. using Mat3 = Eigen::Matrix<double, 3, 3>;
  114. using Vec6 = Eigen::Matrix<double, 6, 1>;
  115. using Vec3 = Eigen::Vector3d;
  116. using Vec4 = Eigen::Vector4d;
  117. DEFINE_string(input, "", "Input File name");
  118. DEFINE_string(refine_intrinsics,
  119. "",
  120. "Camera intrinsics to be refined. Options are: none, radial.");
  121. namespace {
  122. // A EuclideanCamera is the location and rotation of the camera
  123. // viewing an image.
  124. //
  125. // image identifies which image this camera represents.
  126. // R is a 3x3 matrix representing the rotation of the camera.
  127. // t is a translation vector representing its positions.
  128. struct EuclideanCamera {
  129. EuclideanCamera() = default;
  130. EuclideanCamera(const EuclideanCamera& c) = default;
  131. int image{-1};
  132. Mat3 R;
  133. Vec3 t;
  134. };
  135. // A Point is the 3D location of a track.
  136. //
  137. // track identifies which track this point corresponds to.
  138. // X represents the 3D position of the track.
  139. struct EuclideanPoint {
  140. EuclideanPoint() = default;
  141. EuclideanPoint(const EuclideanPoint& p) = default;
  142. int track{-1};
  143. Vec3 X;
  144. };
  145. // A Marker is the 2D location of a tracked point in an image.
  146. //
  147. // x and y is the position of the marker in pixels from the top left corner
  148. // in the image identified by an image. All markers for to the same target
  149. // form a track identified by a common track number.
  150. struct Marker {
  151. int image;
  152. int track;
  153. double x, y;
  154. };
  155. // Cameras intrinsics to be bundled.
  156. //
  157. // BUNDLE_RADIAL actually implies bundling of k1 and k2 coefficients only,
  158. // no bundling of k3 is possible at this moment.
  159. enum BundleIntrinsics {
  160. BUNDLE_NO_INTRINSICS = 0,
  161. BUNDLE_FOCAL_LENGTH = 1,
  162. BUNDLE_PRINCIPAL_POINT = 2,
  163. BUNDLE_RADIAL_K1 = 4,
  164. BUNDLE_RADIAL_K2 = 8,
  165. BUNDLE_RADIAL = 12,
  166. BUNDLE_TANGENTIAL_P1 = 16,
  167. BUNDLE_TANGENTIAL_P2 = 32,
  168. BUNDLE_TANGENTIAL = 48,
  169. };
  170. // Denotes which blocks to keep constant during bundling.
  171. // For example it is useful to keep camera translations constant
  172. // when bundling tripod motions.
  173. enum BundleConstraints {
  174. BUNDLE_NO_CONSTRAINTS = 0,
  175. BUNDLE_NO_TRANSLATION = 1,
  176. };
  177. // The intrinsics need to get combined into a single parameter block; use these
  178. // enums to index instead of numeric constants.
  179. enum {
  180. OFFSET_FOCAL_LENGTH,
  181. OFFSET_PRINCIPAL_POINT_X,
  182. OFFSET_PRINCIPAL_POINT_Y,
  183. OFFSET_K1,
  184. OFFSET_K2,
  185. OFFSET_K3,
  186. OFFSET_P1,
  187. OFFSET_P2,
  188. };
  189. // Returns a pointer to the camera corresponding to a image.
  190. EuclideanCamera* CameraForImage(std::vector<EuclideanCamera>* all_cameras,
  191. const int image) {
  192. if (image < 0 || image >= all_cameras->size()) {
  193. return nullptr;
  194. }
  195. EuclideanCamera* camera = &(*all_cameras)[image];
  196. if (camera->image == -1) {
  197. return nullptr;
  198. }
  199. return camera;
  200. }
  201. const EuclideanCamera* CameraForImage(
  202. const std::vector<EuclideanCamera>& all_cameras, const int image) {
  203. if (image < 0 || image >= all_cameras.size()) {
  204. return nullptr;
  205. }
  206. const EuclideanCamera* camera = &all_cameras[image];
  207. if (camera->image == -1) {
  208. return nullptr;
  209. }
  210. return camera;
  211. }
  212. // Returns maximal image number at which marker exists.
  213. int MaxImage(const std::vector<Marker>& all_markers) {
  214. if (all_markers.size() == 0) {
  215. return -1;
  216. }
  217. int max_image = all_markers[0].image;
  218. for (int i = 1; i < all_markers.size(); i++) {
  219. max_image = std::max(max_image, all_markers[i].image);
  220. }
  221. return max_image;
  222. }
  223. // Returns a pointer to the point corresponding to a track.
  224. EuclideanPoint* PointForTrack(std::vector<EuclideanPoint>* all_points,
  225. const int track) {
  226. if (track < 0 || track >= all_points->size()) {
  227. return nullptr;
  228. }
  229. EuclideanPoint* point = &(*all_points)[track];
  230. if (point->track == -1) {
  231. return nullptr;
  232. }
  233. return point;
  234. }
  235. // Reader of binary file which makes sure possibly needed endian
  236. // conversion happens when loading values like floats and integers.
  237. //
  238. // File's endian type is reading from a first character of file, which
  239. // could either be V for big endian or v for little endian. This
  240. // means you need to design file format assuming first character
  241. // denotes file endianness in this way.
  242. class EndianAwareFileReader {
  243. public:
  244. EndianAwareFileReader() {
  245. // Get an endian type of the host machine.
  246. union {
  247. unsigned char bytes[4];
  248. uint32_t value;
  249. } endian_test = {{0, 1, 2, 3}};
  250. host_endian_type_ = endian_test.value;
  251. file_endian_type_ = host_endian_type_;
  252. }
  253. ~EndianAwareFileReader() {
  254. if (file_descriptor_ > 0) {
  255. close(file_descriptor_);
  256. }
  257. }
  258. bool OpenFile(const std::string& file_name) {
  259. file_descriptor_ = open(file_name.c_str(), O_RDONLY | O_BINARY);
  260. if (file_descriptor_ < 0) {
  261. return false;
  262. }
  263. // Get an endian tpye of data in the file.
  264. auto file_endian_type_flag = Read<unsigned char>();
  265. if (file_endian_type_flag == 'V') {
  266. file_endian_type_ = kBigEndian;
  267. } else if (file_endian_type_flag == 'v') {
  268. file_endian_type_ = kLittleEndian;
  269. } else {
  270. LOG(FATAL) << "Problem file is stored in unknown endian type.";
  271. }
  272. return true;
  273. }
  274. // Read value from the file, will switch endian if needed.
  275. template <typename T>
  276. T Read() const {
  277. T value;
  278. CHECK_GT(read(file_descriptor_, &value, sizeof(value)), 0);
  279. // Switch endian type if file contains data in different type
  280. // that current machine.
  281. if (file_endian_type_ != host_endian_type_) {
  282. value = SwitchEndian<T>(value);
  283. }
  284. return value;
  285. }
  286. private:
  287. static constexpr long int kLittleEndian = 0x03020100ul;
  288. static constexpr long int kBigEndian = 0x00010203ul;
  289. // Switch endian type between big to little.
  290. template <typename T>
  291. T SwitchEndian(const T value) const {
  292. if (sizeof(T) == 4) {
  293. auto temp_value = static_cast<unsigned int>(value);
  294. // clang-format off
  295. return ((temp_value >> 24)) |
  296. ((temp_value << 8) & 0x00ff0000) |
  297. ((temp_value >> 8) & 0x0000ff00) |
  298. ((temp_value << 24));
  299. // clang-format on
  300. } else if (sizeof(T) == 1) {
  301. return value;
  302. } else {
  303. LOG(FATAL) << "Entered non-implemented part of endian "
  304. "switching function.";
  305. }
  306. }
  307. int host_endian_type_;
  308. int file_endian_type_;
  309. int file_descriptor_{-1};
  310. };
  311. // Read 3x3 column-major matrix from the file
  312. void ReadMatrix3x3(const EndianAwareFileReader& file_reader, Mat3* matrix) {
  313. for (int i = 0; i < 9; i++) {
  314. (*matrix)(i % 3, i / 3) = file_reader.Read<float>();
  315. }
  316. }
  317. // Read 3-vector from file
  318. void ReadVector3(const EndianAwareFileReader& file_reader, Vec3* vector) {
  319. for (int i = 0; i < 3; i++) {
  320. (*vector)(i) = file_reader.Read<float>();
  321. }
  322. }
  323. // Reads a bundle adjustment problem from the file.
  324. //
  325. // file_name denotes from which file to read the problem.
  326. // camera_intrinsics will contain initial camera intrinsics values.
  327. //
  328. // all_cameras is a vector of all reconstructed cameras to be optimized,
  329. // vector element with number i will contain camera for image i.
  330. //
  331. // all_points is a vector of all reconstructed 3D points to be optimized,
  332. // vector element with number i will contain point for track i.
  333. //
  334. // all_markers is a vector of all tracked markers existing in
  335. // the problem. Only used for reprojection error calculation, stay
  336. // unchanged during optimization.
  337. //
  338. // Returns false if any kind of error happened during
  339. // reading.
  340. bool ReadProblemFromFile(const std::string& file_name,
  341. double camera_intrinsics[8],
  342. std::vector<EuclideanCamera>* all_cameras,
  343. std::vector<EuclideanPoint>* all_points,
  344. bool* is_image_space,
  345. std::vector<Marker>* all_markers) {
  346. EndianAwareFileReader file_reader;
  347. if (!file_reader.OpenFile(file_name)) {
  348. return false;
  349. }
  350. // Read markers' space flag.
  351. auto is_image_space_flag = file_reader.Read<unsigned char>();
  352. if (is_image_space_flag == 'P') {
  353. *is_image_space = true;
  354. } else if (is_image_space_flag == 'N') {
  355. *is_image_space = false;
  356. } else {
  357. LOG(FATAL) << "Problem file contains markers stored in unknown space.";
  358. }
  359. // Read camera intrinsics.
  360. for (int i = 0; i < 8; i++) {
  361. camera_intrinsics[i] = file_reader.Read<float>();
  362. }
  363. // Read all cameras.
  364. int number_of_cameras = file_reader.Read<int>();
  365. for (int i = 0; i < number_of_cameras; i++) {
  366. EuclideanCamera camera;
  367. camera.image = file_reader.Read<int>();
  368. ReadMatrix3x3(file_reader, &camera.R);
  369. ReadVector3(file_reader, &camera.t);
  370. if (camera.image >= all_cameras->size()) {
  371. all_cameras->resize(camera.image + 1);
  372. }
  373. (*all_cameras)[camera.image].image = camera.image;
  374. (*all_cameras)[camera.image].R = camera.R;
  375. (*all_cameras)[camera.image].t = camera.t;
  376. }
  377. LOG(INFO) << "Read " << number_of_cameras << " cameras.";
  378. // Read all reconstructed 3D points.
  379. int number_of_points = file_reader.Read<int>();
  380. for (int i = 0; i < number_of_points; i++) {
  381. EuclideanPoint point;
  382. point.track = file_reader.Read<int>();
  383. ReadVector3(file_reader, &point.X);
  384. if (point.track >= all_points->size()) {
  385. all_points->resize(point.track + 1);
  386. }
  387. (*all_points)[point.track].track = point.track;
  388. (*all_points)[point.track].X = point.X;
  389. }
  390. LOG(INFO) << "Read " << number_of_points << " points.";
  391. // And finally read all markers.
  392. int number_of_markers = file_reader.Read<int>();
  393. for (int i = 0; i < number_of_markers; i++) {
  394. Marker marker;
  395. marker.image = file_reader.Read<int>();
  396. marker.track = file_reader.Read<int>();
  397. marker.x = file_reader.Read<float>();
  398. marker.y = file_reader.Read<float>();
  399. all_markers->push_back(marker);
  400. }
  401. LOG(INFO) << "Read " << number_of_markers << " markers.";
  402. return true;
  403. }
  404. // Apply camera intrinsics to the normalized point to get image coordinates.
  405. // This applies the radial lens distortion to a point which is in normalized
  406. // camera coordinates (i.e. the principal point is at (0, 0)) to get image
  407. // coordinates in pixels. Templated for use with autodifferentiation.
  408. template <typename T>
  409. inline void ApplyRadialDistortionCameraIntrinsics(const T& focal_length_x,
  410. const T& focal_length_y,
  411. const T& principal_point_x,
  412. const T& principal_point_y,
  413. const T& k1,
  414. const T& k2,
  415. const T& k3,
  416. const T& p1,
  417. const T& p2,
  418. const T& normalized_x,
  419. const T& normalized_y,
  420. T* image_x,
  421. T* image_y) {
  422. T x = normalized_x;
  423. T y = normalized_y;
  424. // Apply distortion to the normalized points to get (xd, yd).
  425. T r2 = x * x + y * y;
  426. T r4 = r2 * r2;
  427. T r6 = r4 * r2;
  428. T r_coeff = 1.0 + k1 * r2 + k2 * r4 + k3 * r6;
  429. T xd = x * r_coeff + 2.0 * p1 * x * y + p2 * (r2 + 2.0 * x * x);
  430. T yd = y * r_coeff + 2.0 * p2 * x * y + p1 * (r2 + 2.0 * y * y);
  431. // Apply focal length and principal point to get the final image coordinates.
  432. *image_x = focal_length_x * xd + principal_point_x;
  433. *image_y = focal_length_y * yd + principal_point_y;
  434. }
  435. // Cost functor which computes reprojection error of 3D point X
  436. // on camera defined by angle-axis rotation and it's translation
  437. // (which are in the same block due to optimization reasons).
  438. //
  439. // This functor uses a radial distortion model.
  440. struct OpenCVReprojectionError {
  441. OpenCVReprojectionError(const double observed_x, const double observed_y)
  442. : observed_x(observed_x), observed_y(observed_y) {}
  443. template <typename T>
  444. bool operator()(const T* const intrinsics,
  445. const T* const R_t, // Rotation denoted by angle axis
  446. // followed with translation
  447. const T* const X, // Point coordinates 3x1.
  448. T* residuals) const {
  449. // Unpack the intrinsics.
  450. const T& focal_length = intrinsics[OFFSET_FOCAL_LENGTH];
  451. const T& principal_point_x = intrinsics[OFFSET_PRINCIPAL_POINT_X];
  452. const T& principal_point_y = intrinsics[OFFSET_PRINCIPAL_POINT_Y];
  453. const T& k1 = intrinsics[OFFSET_K1];
  454. const T& k2 = intrinsics[OFFSET_K2];
  455. const T& k3 = intrinsics[OFFSET_K3];
  456. const T& p1 = intrinsics[OFFSET_P1];
  457. const T& p2 = intrinsics[OFFSET_P2];
  458. // Compute projective coordinates: x = RX + t.
  459. T x[3];
  460. ceres::AngleAxisRotatePoint(R_t, X, x);
  461. x[0] += R_t[3];
  462. x[1] += R_t[4];
  463. x[2] += R_t[5];
  464. // Compute normalized coordinates: x /= x[2].
  465. T xn = x[0] / x[2];
  466. T yn = x[1] / x[2];
  467. T predicted_x, predicted_y;
  468. // Apply distortion to the normalized points to get (xd, yd).
  469. // TODO(keir): Do early bailouts for zero distortion; these are expensive
  470. // jet operations.
  471. ApplyRadialDistortionCameraIntrinsics(focal_length,
  472. focal_length,
  473. principal_point_x,
  474. principal_point_y,
  475. k1,
  476. k2,
  477. k3,
  478. p1,
  479. p2,
  480. xn,
  481. yn,
  482. &predicted_x,
  483. &predicted_y);
  484. // The error is the difference between the predicted and observed position.
  485. residuals[0] = predicted_x - observed_x;
  486. residuals[1] = predicted_y - observed_y;
  487. return true;
  488. }
  489. const double observed_x;
  490. const double observed_y;
  491. };
  492. // Print a message to the log which camera intrinsics are gonna to be optimized.
  493. void BundleIntrinsicsLogMessage(const int bundle_intrinsics) {
  494. if (bundle_intrinsics == BUNDLE_NO_INTRINSICS) {
  495. LOG(INFO) << "Bundling only camera positions.";
  496. } else {
  497. std::string bundling_message = "";
  498. #define APPEND_BUNDLING_INTRINSICS(name, flag) \
  499. if (bundle_intrinsics & flag) { \
  500. if (!bundling_message.empty()) { \
  501. bundling_message += ", "; \
  502. } \
  503. bundling_message += name; \
  504. } \
  505. (void)0
  506. APPEND_BUNDLING_INTRINSICS("f", BUNDLE_FOCAL_LENGTH);
  507. APPEND_BUNDLING_INTRINSICS("px, py", BUNDLE_PRINCIPAL_POINT);
  508. APPEND_BUNDLING_INTRINSICS("k1", BUNDLE_RADIAL_K1);
  509. APPEND_BUNDLING_INTRINSICS("k2", BUNDLE_RADIAL_K2);
  510. APPEND_BUNDLING_INTRINSICS("p1", BUNDLE_TANGENTIAL_P1);
  511. APPEND_BUNDLING_INTRINSICS("p2", BUNDLE_TANGENTIAL_P2);
  512. LOG(INFO) << "Bundling " << bundling_message << ".";
  513. }
  514. }
  515. // Print a message to the log containing all the camera intriniscs values.
  516. void PrintCameraIntrinsics(const char* text, const double* camera_intrinsics) {
  517. std::ostringstream intrinsics_output;
  518. intrinsics_output << "f=" << camera_intrinsics[OFFSET_FOCAL_LENGTH];
  519. intrinsics_output << " cx=" << camera_intrinsics[OFFSET_PRINCIPAL_POINT_X]
  520. << " cy=" << camera_intrinsics[OFFSET_PRINCIPAL_POINT_Y];
  521. #define APPEND_DISTORTION_COEFFICIENT(name, offset) \
  522. { \
  523. if (camera_intrinsics[offset] != 0.0) { \
  524. intrinsics_output << " " name "=" << camera_intrinsics[offset]; \
  525. } \
  526. } \
  527. (void)0
  528. APPEND_DISTORTION_COEFFICIENT("k1", OFFSET_K1);
  529. APPEND_DISTORTION_COEFFICIENT("k2", OFFSET_K2);
  530. APPEND_DISTORTION_COEFFICIENT("k3", OFFSET_K3);
  531. APPEND_DISTORTION_COEFFICIENT("p1", OFFSET_P1);
  532. APPEND_DISTORTION_COEFFICIENT("p2", OFFSET_P2);
  533. #undef APPEND_DISTORTION_COEFFICIENT
  534. LOG(INFO) << text << intrinsics_output.str();
  535. }
  536. // Get a vector of camera's rotations denoted by angle axis
  537. // conjuncted with translations into single block
  538. //
  539. // Element with index i matches to a rotation+translation for
  540. // camera at image i.
  541. std::vector<Vec6> PackCamerasRotationAndTranslation(
  542. const std::vector<Marker>& all_markers,
  543. const std::vector<EuclideanCamera>& all_cameras) {
  544. std::vector<Vec6> all_cameras_R_t;
  545. int max_image = MaxImage(all_markers);
  546. all_cameras_R_t.resize(max_image + 1);
  547. for (int i = 0; i <= max_image; i++) {
  548. const EuclideanCamera* camera = CameraForImage(all_cameras, i);
  549. if (!camera) {
  550. continue;
  551. }
  552. ceres::RotationMatrixToAngleAxis(&camera->R(0, 0), &all_cameras_R_t[i](0));
  553. all_cameras_R_t[i].tail<3>() = camera->t;
  554. }
  555. return all_cameras_R_t;
  556. }
  557. // Convert cameras rotations fro mangle axis back to rotation matrix.
  558. void UnpackCamerasRotationAndTranslation(
  559. const std::vector<Marker>& all_markers,
  560. const std::vector<Vec6>& all_cameras_R_t,
  561. std::vector<EuclideanCamera>* all_cameras) {
  562. int max_image = MaxImage(all_markers);
  563. for (int i = 0; i <= max_image; i++) {
  564. EuclideanCamera* camera = CameraForImage(all_cameras, i);
  565. if (!camera) {
  566. continue;
  567. }
  568. ceres::AngleAxisToRotationMatrix(&all_cameras_R_t[i](0), &camera->R(0, 0));
  569. camera->t = all_cameras_R_t[i].tail<3>();
  570. }
  571. }
  572. void EuclideanBundleCommonIntrinsics(const std::vector<Marker>& all_markers,
  573. const int bundle_intrinsics,
  574. const int bundle_constraints,
  575. double* camera_intrinsics,
  576. std::vector<EuclideanCamera>* all_cameras,
  577. std::vector<EuclideanPoint>* all_points) {
  578. PrintCameraIntrinsics("Original intrinsics: ", camera_intrinsics);
  579. ceres::Problem::Options problem_options;
  580. problem_options.cost_function_ownership = ceres::DO_NOT_TAKE_OWNERSHIP;
  581. ceres::Problem problem(problem_options);
  582. // Convert cameras rotations to angle axis and merge with translation
  583. // into single parameter block for maximal minimization speed
  584. //
  585. // Block for minimization has got the following structure:
  586. // <3 elements for angle-axis> <3 elements for translation>
  587. std::vector<Vec6> all_cameras_R_t =
  588. PackCamerasRotationAndTranslation(all_markers, *all_cameras);
  589. // Manifold used to restrict camera motion for modal solvers.
  590. ceres::SubsetManifold* constant_transform_manifold = nullptr;
  591. if (bundle_constraints & BUNDLE_NO_TRANSLATION) {
  592. std::vector<int> constant_translation;
  593. // First three elements are rotation, last three are translation.
  594. constant_translation.push_back(3);
  595. constant_translation.push_back(4);
  596. constant_translation.push_back(5);
  597. constant_transform_manifold =
  598. new ceres::SubsetManifold(6, constant_translation);
  599. }
  600. std::vector<OpenCVReprojectionError> errors;
  601. std::vector<ceres::AutoDiffCostFunction<OpenCVReprojectionError, 2, 8, 6, 3>>
  602. costFunctions;
  603. errors.reserve(all_markers.size());
  604. costFunctions.reserve(all_markers.size());
  605. int num_residuals = 0;
  606. bool have_locked_camera = false;
  607. for (const auto& marker : all_markers) {
  608. EuclideanCamera* camera = CameraForImage(all_cameras, marker.image);
  609. EuclideanPoint* point = PointForTrack(all_points, marker.track);
  610. if (camera == nullptr || point == nullptr) {
  611. continue;
  612. }
  613. // Rotation of camera denoted in angle axis followed with
  614. // camera translaiton.
  615. double* current_camera_R_t = &all_cameras_R_t[camera->image](0);
  616. errors.emplace_back(marker.x, marker.y);
  617. costFunctions.emplace_back(&errors.back(), ceres::DO_NOT_TAKE_OWNERSHIP);
  618. problem.AddResidualBlock(&costFunctions.back(),
  619. nullptr,
  620. camera_intrinsics,
  621. current_camera_R_t,
  622. &point->X(0));
  623. // We lock the first camera to better deal with scene orientation ambiguity.
  624. if (!have_locked_camera) {
  625. problem.SetParameterBlockConstant(current_camera_R_t);
  626. have_locked_camera = true;
  627. }
  628. if (bundle_constraints & BUNDLE_NO_TRANSLATION) {
  629. problem.SetManifold(current_camera_R_t, constant_transform_manifold);
  630. }
  631. num_residuals++;
  632. }
  633. LOG(INFO) << "Number of residuals: " << num_residuals;
  634. if (!num_residuals) {
  635. LOG(INFO) << "Skipping running minimizer with zero residuals";
  636. return;
  637. }
  638. BundleIntrinsicsLogMessage(bundle_intrinsics);
  639. if (bundle_intrinsics == BUNDLE_NO_INTRINSICS) {
  640. // No camera intrinsics are being refined,
  641. // set the whole parameter block as constant for best performance.
  642. problem.SetParameterBlockConstant(camera_intrinsics);
  643. } else {
  644. // Set the camera intrinsics that are not to be bundled as
  645. // constant using some macro trickery.
  646. std::vector<int> constant_intrinsics;
  647. #define MAYBE_SET_CONSTANT(bundle_enum, offset) \
  648. if (!(bundle_intrinsics & bundle_enum)) { \
  649. constant_intrinsics.push_back(offset); \
  650. }
  651. MAYBE_SET_CONSTANT(BUNDLE_FOCAL_LENGTH, OFFSET_FOCAL_LENGTH);
  652. MAYBE_SET_CONSTANT(BUNDLE_PRINCIPAL_POINT, OFFSET_PRINCIPAL_POINT_X);
  653. MAYBE_SET_CONSTANT(BUNDLE_PRINCIPAL_POINT, OFFSET_PRINCIPAL_POINT_Y);
  654. MAYBE_SET_CONSTANT(BUNDLE_RADIAL_K1, OFFSET_K1);
  655. MAYBE_SET_CONSTANT(BUNDLE_RADIAL_K2, OFFSET_K2);
  656. MAYBE_SET_CONSTANT(BUNDLE_TANGENTIAL_P1, OFFSET_P1);
  657. MAYBE_SET_CONSTANT(BUNDLE_TANGENTIAL_P2, OFFSET_P2);
  658. #undef MAYBE_SET_CONSTANT
  659. // Always set K3 constant, it's not used at the moment.
  660. constant_intrinsics.push_back(OFFSET_K3);
  661. auto* subset_manifold = new ceres::SubsetManifold(8, constant_intrinsics);
  662. problem.SetManifold(camera_intrinsics, subset_manifold);
  663. }
  664. // Configure the solver.
  665. ceres::Solver::Options options;
  666. options.use_nonmonotonic_steps = true;
  667. options.preconditioner_type = ceres::SCHUR_JACOBI;
  668. options.linear_solver_type = ceres::ITERATIVE_SCHUR;
  669. options.use_inner_iterations = true;
  670. options.max_num_iterations = 100;
  671. options.minimizer_progress_to_stdout = true;
  672. // Solve!
  673. ceres::Solver::Summary summary;
  674. ceres::Solve(options, &problem, &summary);
  675. std::cout << "Final report:\n" << summary.FullReport();
  676. // Copy rotations and translations back.
  677. UnpackCamerasRotationAndTranslation(
  678. all_markers, all_cameras_R_t, all_cameras);
  679. PrintCameraIntrinsics("Final intrinsics: ", camera_intrinsics);
  680. }
  681. } // namespace
  682. int main(int argc, char** argv) {
  683. GFLAGS_NAMESPACE::ParseCommandLineFlags(&argc, &argv, true);
  684. google::InitGoogleLogging(argv[0]);
  685. if (CERES_GET_FLAG(FLAGS_input).empty()) {
  686. LOG(ERROR) << "Usage: libmv_bundle_adjuster --input=blender_problem";
  687. return EXIT_FAILURE;
  688. }
  689. double camera_intrinsics[8];
  690. std::vector<EuclideanCamera> all_cameras;
  691. std::vector<EuclideanPoint> all_points;
  692. bool is_image_space;
  693. std::vector<Marker> all_markers;
  694. if (!ReadProblemFromFile(CERES_GET_FLAG(FLAGS_input),
  695. camera_intrinsics,
  696. &all_cameras,
  697. &all_points,
  698. &is_image_space,
  699. &all_markers)) {
  700. LOG(ERROR) << "Error reading problem file";
  701. return EXIT_FAILURE;
  702. }
  703. // If there's no refine_intrinsics passed via command line
  704. // (in this case FLAGS_refine_intrinsics will be an empty string)
  705. // we use problem's settings to detect whether intrinsics
  706. // shall be refined or not.
  707. //
  708. // Namely, if problem has got markers stored in image (pixel)
  709. // space, we do full intrinsics refinement. If markers are
  710. // stored in normalized space, and refine_intrinsics is not
  711. // set, no refining will happen.
  712. //
  713. // Using command line argument refine_intrinsics will explicitly
  714. // declare which intrinsics need to be refined and in this case
  715. // refining flags does not depend on problem at all.
  716. int bundle_intrinsics = BUNDLE_NO_INTRINSICS;
  717. if (CERES_GET_FLAG(FLAGS_refine_intrinsics).empty()) {
  718. if (is_image_space) {
  719. bundle_intrinsics = BUNDLE_FOCAL_LENGTH | BUNDLE_RADIAL;
  720. }
  721. } else {
  722. if (CERES_GET_FLAG(FLAGS_refine_intrinsics) == "radial") {
  723. bundle_intrinsics = BUNDLE_FOCAL_LENGTH | BUNDLE_RADIAL;
  724. } else if (CERES_GET_FLAG(FLAGS_refine_intrinsics) != "none") {
  725. LOG(ERROR) << "Unsupported value for refine-intrinsics";
  726. return EXIT_FAILURE;
  727. }
  728. }
  729. // Run the bundler.
  730. EuclideanBundleCommonIntrinsics(all_markers,
  731. bundle_intrinsics,
  732. BUNDLE_NO_CONSTRAINTS,
  733. camera_intrinsics,
  734. &all_cameras,
  735. &all_points);
  736. return EXIT_SUCCESS;
  737. }