diff options
Diffstat (limited to 'extern/libmv/intern')
-rw-r--r-- | extern/libmv/intern/camera_intrinsics.cc | 354 | ||||
-rw-r--r-- | extern/libmv/intern/camera_intrinsics.h | 138 | ||||
-rw-r--r-- | extern/libmv/intern/detector.cc | 148 | ||||
-rw-r--r-- | extern/libmv/intern/detector.h | 77 | ||||
-rw-r--r-- | extern/libmv/intern/homography.cc | 59 | ||||
-rw-r--r-- | extern/libmv/intern/homography.h | 43 | ||||
-rw-r--r-- | extern/libmv/intern/image.cc | 272 | ||||
-rw-r--r-- | extern/libmv/intern/image.h | 99 | ||||
-rw-r--r-- | extern/libmv/intern/logging.cc | 55 | ||||
-rw-r--r-- | extern/libmv/intern/logging.h | 47 | ||||
-rw-r--r-- | extern/libmv/intern/reconstruction.cc | 530 | ||||
-rw-r--r-- | extern/libmv/intern/reconstruction.h | 99 | ||||
-rw-r--r-- | extern/libmv/intern/region.h | 43 | ||||
-rw-r--r-- | extern/libmv/intern/stub.cc | 330 | ||||
-rw-r--r-- | extern/libmv/intern/track_region.cc | 177 | ||||
-rw-r--r-- | extern/libmv/intern/track_region.h | 81 | ||||
-rw-r--r-- | extern/libmv/intern/tracks.cc | 52 | ||||
-rw-r--r-- | extern/libmv/intern/tracks.h | 51 | ||||
-rw-r--r-- | extern/libmv/intern/utildefines.h | 62 |
19 files changed, 2717 insertions, 0 deletions
diff --git a/extern/libmv/intern/camera_intrinsics.cc b/extern/libmv/intern/camera_intrinsics.cc new file mode 100644 index 00000000000..e8b99970ff7 --- /dev/null +++ b/extern/libmv/intern/camera_intrinsics.cc @@ -0,0 +1,354 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2011 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Blender Foundation, + * Sergey Sharybin + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "intern/camera_intrinsics.h" +#include "intern/utildefines.h" +#include "libmv/simple_pipeline/camera_intrinsics.h" + +using libmv::CameraIntrinsics; +using libmv::DivisionCameraIntrinsics; +using libmv::PolynomialCameraIntrinsics; + +libmv_CameraIntrinsics *libmv_cameraIntrinsicsNew( + const libmv_CameraIntrinsicsOptions* libmv_camera_intrinsics_options) { + CameraIntrinsics *camera_intrinsics = + libmv_cameraIntrinsicsCreateFromOptions(libmv_camera_intrinsics_options); + return (libmv_CameraIntrinsics *) camera_intrinsics; +} + +libmv_CameraIntrinsics *libmv_cameraIntrinsicsCopy( + const libmv_CameraIntrinsics* libmv_intrinsics) { + const CameraIntrinsics *orig_intrinsics = + (const CameraIntrinsics *) libmv_intrinsics; + + CameraIntrinsics *new_intrinsics = NULL; + switch (orig_intrinsics->GetDistortionModelType()) { + case libmv::DISTORTION_MODEL_POLYNOMIAL: + { + const PolynomialCameraIntrinsics *polynomial_intrinsics = + static_cast<const PolynomialCameraIntrinsics*>(orig_intrinsics); + new_intrinsics = LIBMV_OBJECT_NEW(PolynomialCameraIntrinsics, + *polynomial_intrinsics); + break; + } + case libmv::DISTORTION_MODEL_DIVISION: + { + const DivisionCameraIntrinsics *division_intrinsics = + static_cast<const DivisionCameraIntrinsics*>(orig_intrinsics); + new_intrinsics = LIBMV_OBJECT_NEW(DivisionCameraIntrinsics, + *division_intrinsics); + break; + } + default: + assert(!"Unknown distortion model"); + } + return (libmv_CameraIntrinsics *) new_intrinsics; +} + +void libmv_cameraIntrinsicsDestroy(libmv_CameraIntrinsics* libmv_intrinsics) { + LIBMV_OBJECT_DELETE(libmv_intrinsics, CameraIntrinsics); +} + +void libmv_cameraIntrinsicsUpdate( + const libmv_CameraIntrinsicsOptions* libmv_camera_intrinsics_options, + libmv_CameraIntrinsics* libmv_intrinsics) { + CameraIntrinsics *camera_intrinsics = (CameraIntrinsics *) libmv_intrinsics; + + double focal_length = libmv_camera_intrinsics_options->focal_length; + double principal_x = libmv_camera_intrinsics_options->principal_point_x; + double principal_y = libmv_camera_intrinsics_options->principal_point_y; + int image_width = libmv_camera_intrinsics_options->image_width; + int image_height = libmv_camera_intrinsics_options->image_height; + + /* Try avoid unnecessary updates, so pre-computed distortion grids + * are not freed. + */ + + if (camera_intrinsics->focal_length() != focal_length) { + camera_intrinsics->SetFocalLength(focal_length, focal_length); + } + + if (camera_intrinsics->principal_point_x() != principal_x || + camera_intrinsics->principal_point_y() != principal_y) { + camera_intrinsics->SetPrincipalPoint(principal_x, principal_y); + } + + if (camera_intrinsics->image_width() != image_width || + camera_intrinsics->image_height() != image_height) { + camera_intrinsics->SetImageSize(image_width, image_height); + } + + switch (libmv_camera_intrinsics_options->distortion_model) { + case LIBMV_DISTORTION_MODEL_POLYNOMIAL: + { + assert(camera_intrinsics->GetDistortionModelType() == + libmv::DISTORTION_MODEL_POLYNOMIAL); + + PolynomialCameraIntrinsics *polynomial_intrinsics = + (PolynomialCameraIntrinsics *) camera_intrinsics; + + double k1 = libmv_camera_intrinsics_options->polynomial_k1; + double k2 = libmv_camera_intrinsics_options->polynomial_k2; + double k3 = libmv_camera_intrinsics_options->polynomial_k3; + + if (polynomial_intrinsics->k1() != k1 || + polynomial_intrinsics->k2() != k2 || + polynomial_intrinsics->k3() != k3) { + polynomial_intrinsics->SetRadialDistortion(k1, k2, k3); + } + break; + } + + case LIBMV_DISTORTION_MODEL_DIVISION: + { + assert(camera_intrinsics->GetDistortionModelType() == + libmv::DISTORTION_MODEL_DIVISION); + + DivisionCameraIntrinsics *division_intrinsics = + (DivisionCameraIntrinsics *) camera_intrinsics; + + double k1 = libmv_camera_intrinsics_options->division_k1; + double k2 = libmv_camera_intrinsics_options->division_k2; + + if (division_intrinsics->k1() != k1 || + division_intrinsics->k2() != k2) { + division_intrinsics->SetDistortion(k1, k2); + } + + break; + } + + default: + assert(!"Unknown distortion model"); + } +} + +void libmv_cameraIntrinsicsSetThreads(libmv_CameraIntrinsics* libmv_intrinsics, + int threads) { + CameraIntrinsics *camera_intrinsics = (CameraIntrinsics *) libmv_intrinsics; + camera_intrinsics->SetThreads(threads); +} + +void libmv_cameraIntrinsicsExtractOptions( + const libmv_CameraIntrinsics* libmv_intrinsics, + libmv_CameraIntrinsicsOptions* camera_intrinsics_options) { + const CameraIntrinsics *camera_intrinsics = + (const CameraIntrinsics *) libmv_intrinsics; + + // Fill in options which are common for all distortion models. + camera_intrinsics_options->focal_length = camera_intrinsics->focal_length(); + camera_intrinsics_options->principal_point_x = + camera_intrinsics->principal_point_x(); + camera_intrinsics_options->principal_point_y = + camera_intrinsics->principal_point_y(); + + camera_intrinsics_options->image_width = camera_intrinsics->image_width(); + camera_intrinsics_options->image_height = camera_intrinsics->image_height(); + + switch (camera_intrinsics->GetDistortionModelType()) { + case libmv::DISTORTION_MODEL_POLYNOMIAL: + { + const PolynomialCameraIntrinsics *polynomial_intrinsics = + static_cast<const PolynomialCameraIntrinsics *>(camera_intrinsics); + camera_intrinsics_options->distortion_model = + LIBMV_DISTORTION_MODEL_POLYNOMIAL; + camera_intrinsics_options->polynomial_k1 = polynomial_intrinsics->k1(); + camera_intrinsics_options->polynomial_k2 = polynomial_intrinsics->k2(); + camera_intrinsics_options->polynomial_k3 = polynomial_intrinsics->k3(); + camera_intrinsics_options->polynomial_p1 = polynomial_intrinsics->p1(); + camera_intrinsics_options->polynomial_p1 = polynomial_intrinsics->p2(); + break; + } + + case libmv::DISTORTION_MODEL_DIVISION: + { + const DivisionCameraIntrinsics *division_intrinsics = + static_cast<const DivisionCameraIntrinsics *>(camera_intrinsics); + camera_intrinsics_options->distortion_model = + LIBMV_DISTORTION_MODEL_DIVISION; + camera_intrinsics_options->division_k1 = division_intrinsics->k1(); + camera_intrinsics_options->division_k2 = division_intrinsics->k2(); + break; + } + + default: + assert(!"Uknown distortion model"); + } +} + +void libmv_cameraIntrinsicsUndistortByte( + const libmv_CameraIntrinsics* libmv_intrinsics, + const unsigned char *source_image, + int width, + int height, + float overscan, + int channels, + unsigned char* destination_image) { + CameraIntrinsics *camera_intrinsics = (CameraIntrinsics *) libmv_intrinsics; + camera_intrinsics->UndistortBuffer(source_image, + width, height, + overscan, + channels, + destination_image); +} + +void libmv_cameraIntrinsicsUndistortFloat( + const libmv_CameraIntrinsics* libmv_intrinsics, + const float* source_image, + int width, + int height, + float overscan, + int channels, + float* destination_image) { + CameraIntrinsics *intrinsics = (CameraIntrinsics *) libmv_intrinsics; + intrinsics->UndistortBuffer(source_image, + width, height, + overscan, + channels, + destination_image); +} + +void libmv_cameraIntrinsicsDistortByte( + const struct libmv_CameraIntrinsics* libmv_intrinsics, + const unsigned char *source_image, + int width, + int height, + float overscan, + int channels, + unsigned char *destination_image) { + CameraIntrinsics *intrinsics = (CameraIntrinsics *) libmv_intrinsics; + intrinsics->DistortBuffer(source_image, + width, height, + overscan, + channels, + destination_image); +} + +void libmv_cameraIntrinsicsDistortFloat( + const libmv_CameraIntrinsics* libmv_intrinsics, + float* source_image, + int width, + int height, + float overscan, + int channels, + float* destination_image) { + CameraIntrinsics *intrinsics = (CameraIntrinsics *) libmv_intrinsics; + intrinsics->DistortBuffer(source_image, + width, height, + overscan, + channels, + destination_image); +} + +void libmv_cameraIntrinsicsApply( + const libmv_CameraIntrinsicsOptions* libmv_camera_intrinsics_options, + double x, + double y, + double* x1, + double* y1) { + /* Do a lens distortion if focal length is non-zero only. */ + if (libmv_camera_intrinsics_options->focal_length) { + CameraIntrinsics* camera_intrinsics = + libmv_cameraIntrinsicsCreateFromOptions(libmv_camera_intrinsics_options); + camera_intrinsics->ApplyIntrinsics(x, y, x1, y1); + LIBMV_OBJECT_DELETE(camera_intrinsics, CameraIntrinsics); + } +} + +void libmv_cameraIntrinsicsInvert( + const libmv_CameraIntrinsicsOptions* libmv_camera_intrinsics_options, + double x, + double y, + double* x1, + double* y1) { + /* Do a lens un-distortion if focal length is non-zero only/ */ + if (libmv_camera_intrinsics_options->focal_length) { + CameraIntrinsics *camera_intrinsics = + libmv_cameraIntrinsicsCreateFromOptions(libmv_camera_intrinsics_options); + camera_intrinsics->InvertIntrinsics(x, y, x1, y1); + LIBMV_OBJECT_DELETE(camera_intrinsics, CameraIntrinsics); + } +} + +static void libmv_cameraIntrinsicsFillFromOptions( + const libmv_CameraIntrinsicsOptions* camera_intrinsics_options, + CameraIntrinsics* camera_intrinsics) { + camera_intrinsics->SetFocalLength(camera_intrinsics_options->focal_length, + camera_intrinsics_options->focal_length); + + camera_intrinsics->SetPrincipalPoint( + camera_intrinsics_options->principal_point_x, + camera_intrinsics_options->principal_point_y); + + camera_intrinsics->SetImageSize(camera_intrinsics_options->image_width, + camera_intrinsics_options->image_height); + + switch (camera_intrinsics_options->distortion_model) { + case LIBMV_DISTORTION_MODEL_POLYNOMIAL: + { + PolynomialCameraIntrinsics *polynomial_intrinsics = + static_cast<PolynomialCameraIntrinsics*>(camera_intrinsics); + + polynomial_intrinsics->SetRadialDistortion( + camera_intrinsics_options->polynomial_k1, + camera_intrinsics_options->polynomial_k2, + camera_intrinsics_options->polynomial_k3); + + break; + } + + case LIBMV_DISTORTION_MODEL_DIVISION: + { + DivisionCameraIntrinsics *division_intrinsics = + static_cast<DivisionCameraIntrinsics*>(camera_intrinsics); + + division_intrinsics->SetDistortion( + camera_intrinsics_options->division_k1, + camera_intrinsics_options->division_k2); + break; + } + + default: + assert(!"Unknown distortion model"); + } +} + +CameraIntrinsics* libmv_cameraIntrinsicsCreateFromOptions( + const libmv_CameraIntrinsicsOptions* camera_intrinsics_options) { + CameraIntrinsics *camera_intrinsics = NULL; + switch (camera_intrinsics_options->distortion_model) { + case LIBMV_DISTORTION_MODEL_POLYNOMIAL: + camera_intrinsics = LIBMV_OBJECT_NEW(PolynomialCameraIntrinsics); + break; + case LIBMV_DISTORTION_MODEL_DIVISION: + camera_intrinsics = LIBMV_OBJECT_NEW(DivisionCameraIntrinsics); + break; + default: + assert(!"Unknown distortion model"); + } + libmv_cameraIntrinsicsFillFromOptions(camera_intrinsics_options, camera_intrinsics); + return camera_intrinsics; +} diff --git a/extern/libmv/intern/camera_intrinsics.h b/extern/libmv/intern/camera_intrinsics.h new file mode 100644 index 00000000000..9910d16a108 --- /dev/null +++ b/extern/libmv/intern/camera_intrinsics.h @@ -0,0 +1,138 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2011 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Blender Foundation, + * Sergey Sharybin + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef LIBMV_C_API_CAMERA_INTRINSICS_H_ +#define LIBMV_C_API_CAMERA_INTRINSICS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct libmv_CameraIntrinsics libmv_CameraIntrinsics; + +enum { + LIBMV_DISTORTION_MODEL_POLYNOMIAL = 0, + LIBMV_DISTORTION_MODEL_DIVISION = 1, +}; + +typedef struct libmv_CameraIntrinsicsOptions { + // Common settings of all distortion models. + int distortion_model; + int image_width, image_height; + double focal_length; + double principal_point_x, principal_point_y; + + // Radial distortion model. + double polynomial_k1, polynomial_k2, polynomial_k3; + double polynomial_p1, polynomial_p2; + + // Division distortion model. + double division_k1, division_k2; +} libmv_CameraIntrinsicsOptions; + +libmv_CameraIntrinsics *libmv_cameraIntrinsicsNew( + const libmv_CameraIntrinsicsOptions* libmv_camera_intrinsics_options); + +libmv_CameraIntrinsics *libmv_cameraIntrinsicsCopy( + const libmv_CameraIntrinsics* libmv_intrinsics); + +void libmv_cameraIntrinsicsDestroy(libmv_CameraIntrinsics* libmv_intrinsics); +void libmv_cameraIntrinsicsUpdate( + const libmv_CameraIntrinsicsOptions* libmv_camera_intrinsics_options, + libmv_CameraIntrinsics* libmv_intrinsics); + +void libmv_cameraIntrinsicsSetThreads(libmv_CameraIntrinsics* libmv_intrinsics, + int threads); + +void libmv_cameraIntrinsicsExtractOptions( + const libmv_CameraIntrinsics* libmv_intrinsics, + libmv_CameraIntrinsicsOptions* camera_intrinsics_options); + +void libmv_cameraIntrinsicsUndistortByte( + const libmv_CameraIntrinsics* libmv_intrinsics, + const unsigned char *source_image, + int width, + int height, + float overscan, + int channels, + unsigned char* destination_image); + +void libmv_cameraIntrinsicsUndistortFloat( + const libmv_CameraIntrinsics* libmv_intrinsics, + const float* source_image, + int width, + int height, + float overscan, + int channels, + float* destination_image); + +void libmv_cameraIntrinsicsDistortByte( + const struct libmv_CameraIntrinsics* libmv_intrinsics, + const unsigned char *source_image, + int width, + int height, + float overscan, + int channels, + unsigned char *destination_image); + +void libmv_cameraIntrinsicsDistortFloat( + const libmv_CameraIntrinsics* libmv_intrinsics, + float* source_image, + int width, + int height, + float overscan, + int channels, + float* destination_image); + +void libmv_cameraIntrinsicsApply( + const libmv_CameraIntrinsicsOptions* libmv_camera_intrinsics_options, + double x, + double y, + double* x1, + double* y1); + +void libmv_cameraIntrinsicsInvert( + const libmv_CameraIntrinsicsOptions* libmv_camera_intrinsics_options, + double x, + double y, + double* x1, + double* y1); + +#ifdef __cplusplus +} +#endif + +#ifdef __cplusplus + +namespace libmv { + class CameraIntrinsics; +} + +libmv::CameraIntrinsics* libmv_cameraIntrinsicsCreateFromOptions( + const libmv_CameraIntrinsicsOptions* camera_intrinsics_options); +#endif + +#endif // LIBMV_C_API_CAMERA_INTRINSICS_H_ diff --git a/extern/libmv/intern/detector.cc b/extern/libmv/intern/detector.cc new file mode 100644 index 00000000000..8abc9014115 --- /dev/null +++ b/extern/libmv/intern/detector.cc @@ -0,0 +1,148 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2011 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Blender Foundation, + * Sergey Sharybin + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "intern/detector.h" +#include "intern/image.h" +#include "intern/utildefines.h" +#include "libmv/simple_pipeline/detect.h" + +using libmv::Detect; +using libmv::DetectOptions; +using libmv::Feature; +using libmv::FloatImage; + +struct libmv_Features { + int count; + Feature* features; +}; + +namespace { + +libmv_Features *libmv_featuresFromVector( + const libmv::vector<Feature>& features) { + libmv_Features* libmv_features = LIBMV_STRUCT_NEW(libmv_Features, 1); + int count = features.size(); + if (count) { + libmv_features->features = LIBMV_STRUCT_NEW(Feature, count); + for (int i = 0; i < count; i++) { + libmv_features->features[i] = features.at(i); + } + } else { + libmv_features->features = NULL; + } + libmv_features->count = count; + return libmv_features; +} + +void libmv_convertDetectorOptions(libmv_DetectOptions *options, + DetectOptions *detector_options) { + switch (options->detector) { +#define LIBMV_CONVERT(the_detector) \ + case LIBMV_DETECTOR_ ## the_detector: \ + detector_options->type = DetectOptions::the_detector; \ + break; + LIBMV_CONVERT(FAST) + LIBMV_CONVERT(MORAVEC) + LIBMV_CONVERT(HARRIS) +#undef LIBMV_CONVERT + } + detector_options->margin = options->margin; + detector_options->min_distance = options->min_distance; + detector_options->fast_min_trackness = options->fast_min_trackness; + detector_options->moravec_max_count = options->moravec_max_count; + detector_options->moravec_pattern = options->moravec_pattern; + detector_options->harris_threshold = options->harris_threshold; +} + +} // namespace + +libmv_Features *libmv_detectFeaturesByte(const unsigned char* image_buffer, + int width, + int height, + int channels, + libmv_DetectOptions* options) { + // Prepare the image. + FloatImage image; + libmv_byteBufferToFloatImage(image_buffer, width, height, channels, &image); + + // Configure detector. + DetectOptions detector_options; + libmv_convertDetectorOptions(options, &detector_options); + + // Run the detector. + libmv::vector<Feature> detected_features; + Detect(image, detector_options, &detected_features); + + // Convert result to C-API. + libmv_Features* result = libmv_featuresFromVector(detected_features); + return result; +} + +libmv_Features* libmv_detectFeaturesFloat(const float* image_buffer, + int width, + int height, + int channels, + libmv_DetectOptions* options) { + // Prepare the image. + FloatImage image; + libmv_floatBufferToFloatImage(image_buffer, width, height, channels, &image); + + // Configure detector. + DetectOptions detector_options; + libmv_convertDetectorOptions(options, &detector_options); + + // Run the detector. + libmv::vector<Feature> detected_features; + Detect(image, detector_options, &detected_features); + + // Convert result to C-API. + libmv_Features* result = libmv_featuresFromVector(detected_features); + return result; +} + +void libmv_featuresDestroy(libmv_Features* libmv_features) { + if (libmv_features->features) { + LIBMV_STRUCT_DELETE(libmv_features->features); + } + LIBMV_STRUCT_DELETE(libmv_features); +} + +int libmv_countFeatures(const libmv_Features* libmv_features) { + return libmv_features->count; +} + +void libmv_getFeature(const libmv_Features* libmv_features, + int number, + double* x, + double* y, + double* score, + double* size) { + Feature &feature = libmv_features->features[number]; + *x = feature.x; + *y = feature.y; + *score = feature.score; + *size = feature.size; +} diff --git a/extern/libmv/intern/detector.h b/extern/libmv/intern/detector.h new file mode 100644 index 00000000000..f72b0dd8d6e --- /dev/null +++ b/extern/libmv/intern/detector.h @@ -0,0 +1,77 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2011 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Blender Foundation, + * Sergey Sharybin + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef LIBMV_C_API_DETECTOR_H_ +#define LIBMV_C_API_DETECTOR_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct libmv_Features libmv_Features; + +enum { + LIBMV_DETECTOR_FAST, + LIBMV_DETECTOR_MORAVEC, + LIBMV_DETECTOR_HARRIS, +}; + +typedef struct libmv_DetectOptions { + int detector; + int margin; + int min_distance; + int fast_min_trackness; + int moravec_max_count; + unsigned char *moravec_pattern; + double harris_threshold; +} libmv_DetectOptions; + +libmv_Features* libmv_detectFeaturesByte(const unsigned char* image_buffer, + int width, + int height, + int channels, + libmv_DetectOptions* options); + +libmv_Features* libmv_detectFeaturesFloat(const float* image_buffer, + int width, + int height, + int channels, + libmv_DetectOptions* options); + +void libmv_featuresDestroy(libmv_Features* libmv_features); +int libmv_countFeatures(const libmv_Features* libmv_features); +void libmv_getFeature(const libmv_Features* libmv_features, + int number, + double* x, + double* y, + double* score, + double* size); + +#ifdef __cplusplus +} +#endif + +#endif // LIBMV_C_API_DETECTOR_H_ diff --git a/extern/libmv/intern/homography.cc b/extern/libmv/intern/homography.cc new file mode 100644 index 00000000000..6b61bd9ab42 --- /dev/null +++ b/extern/libmv/intern/homography.cc @@ -0,0 +1,59 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2011 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Blender Foundation, + * Sergey Sharybin + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "intern/homography.h" +#include "intern/utildefines.h" +#include "libmv/logging/logging.h" +#include "libmv/multiview/homography.h" + +void libmv_homography2DFromCorrespondencesEuc(/* const */ double (*x1)[2], + /* const */ double (*x2)[2], + int num_points, + double H[3][3]) { + libmv::Mat x1_mat, x2_mat; + libmv::Mat3 H_mat; + + x1_mat.resize(2, num_points); + x2_mat.resize(2, num_points); + + for (int i = 0; i < num_points; i++) { + x1_mat.col(i) = libmv::Vec2(x1[i][0], x1[i][1]); + x2_mat.col(i) = libmv::Vec2(x2[i][0], x2[i][1]); + } + + LG << "x1: " << x1_mat; + LG << "x2: " << x2_mat; + + libmv::EstimateHomographyOptions options; + libmv::EstimateHomography2DFromCorrespondences(x1_mat, + x2_mat, + options, + &H_mat); + + LG << "H: " << H_mat; + + memcpy(H, H_mat.data(), 9 * sizeof(double)); +} diff --git a/extern/libmv/intern/homography.h b/extern/libmv/intern/homography.h new file mode 100644 index 00000000000..175108e8171 --- /dev/null +++ b/extern/libmv/intern/homography.h @@ -0,0 +1,43 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2011 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Blender Foundation, + * Sergey Sharybin + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef LIBMV_C_API_HOMOGRAPHY_H_ +#define LIBMV_C_API_HOMOGRAPHY_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +void libmv_homography2DFromCorrespondencesEuc(/* const */ double (*x1)[2], + /* const */ double (*x2)[2], + int num_points, + double H[3][3]); + +#ifdef __cplusplus +} +#endif + +#endif // LIBMV_C_API_HOMOGRAPHY_H_ diff --git a/extern/libmv/intern/image.cc b/extern/libmv/intern/image.cc new file mode 100644 index 00000000000..7e623bdbec7 --- /dev/null +++ b/extern/libmv/intern/image.cc @@ -0,0 +1,272 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2011 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Blender Foundation, + * Sergey Sharybin + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "intern/image.h" +#include "intern/utildefines.h" +#include "libmv/tracking/track_region.h" + +#include <cassert> +#include <png.h> + +using libmv::FloatImage; +using libmv::SamplePlanarPatch; + +void libmv_floatImaheDestroy(libmv_FloatImage *image) { + delete [] image->buffer; +} + +/* Image <-> buffers conversion */ + +void libmv_byteBufferToFloatImage(const unsigned char* buffer, + int width, + int height, + int channels, + FloatImage* image) { + image->Resize(height, width, channels); + for (int y = 0, a = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + for (int k = 0; k < channels; k++) { + (*image)(y, x, k) = (float)buffer[a++] / 255.0f; + } + } + } +} + +void libmv_floatBufferToFloatImage(const float* buffer, + int width, + int height, + int channels, + FloatImage* image) { + image->Resize(height, width, channels); + for (int y = 0, a = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + for (int k = 0; k < channels; k++) { + (*image)(y, x, k) = buffer[a++]; + } + } + } +} + +void libmv_floatImageToFloatBuffer(const FloatImage &image, + float* buffer) { + for (int y = 0, a = 0; y < image.Height(); y++) { + for (int x = 0; x < image.Width(); x++) { + for (int k = 0; k < image.Depth(); k++) { + buffer[a++] = image(y, x, k); + } + } + } +} + +void libmv_floatImageToByteBuffer(const libmv::FloatImage &image, + unsigned char* buffer) { + for (int y = 0, a= 0; y < image.Height(); y++) { + for (int x = 0; x < image.Width(); x++) { + for (int k = 0; k < image.Depth(); k++) { + buffer[a++] = image(y, x, k) * 255.0f; + } + } + } +} + +static bool savePNGImage(png_bytep* row_pointers, + int width, + int height, + int depth, + int color_type, + const char* file_name) { + png_infop info_ptr; + png_structp png_ptr; + FILE *fp = fopen(file_name, "wb"); + + if (fp == NULL) { + return false; + } + + /* Initialize stuff */ + png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + info_ptr = png_create_info_struct(png_ptr); + + if (setjmp(png_jmpbuf(png_ptr))) { + fclose(fp); + return false; + } + + png_init_io(png_ptr, fp); + + /* Write PNG header. */ + if (setjmp(png_jmpbuf(png_ptr))) { + fclose(fp); + return false; + } + + png_set_IHDR(png_ptr, + info_ptr, + width, + height, + depth, + color_type, + PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_BASE, + PNG_FILTER_TYPE_BASE); + + png_write_info(png_ptr, info_ptr); + + /* Write bytes/ */ + if (setjmp(png_jmpbuf(png_ptr))) { + fclose(fp); + return false; + } + + png_write_image(png_ptr, row_pointers); + + /* End write/ */ + if (setjmp(png_jmpbuf(png_ptr))) { + fclose(fp); + return false; + } + + png_write_end(png_ptr, NULL); + fclose(fp); + + return true; +} + +bool libmv_saveImage(const FloatImage& image, + const char* prefix, + int x0, + int y0) { + int x, y; + png_bytep *row_pointers; + + assert(image.Depth() == 1); + + row_pointers = new png_bytep[image.Height()]; + + for (y = 0; y < image.Height(); y++) { + row_pointers[y] = new png_byte[4 * image.Width()]; + + for (x = 0; x < image.Width(); x++) { + if (x0 == x && image.Height() - y0 - 1 == y) { + row_pointers[y][x * 4 + 0] = 255; + row_pointers[y][x * 4 + 1] = 0; + row_pointers[y][x * 4 + 2] = 0; + row_pointers[y][x * 4 + 3] = 255; + } else { + float pixel = image(image.Height() - y - 1, x, 0); + row_pointers[y][x * 4 + 0] = pixel * 255; + row_pointers[y][x * 4 + 1] = pixel * 255; + row_pointers[y][x * 4 + 2] = pixel * 255; + row_pointers[y][x * 4 + 3] = 255; + } + } + } + + static int image_counter = 0; + char file_name[128]; + snprintf(file_name, sizeof(file_name), + "%s_%02d.png", + prefix, ++image_counter); + bool result = savePNGImage(row_pointers, + image.Width(), + image.Height(), + 8, + PNG_COLOR_TYPE_RGBA, + file_name); + + for (y = 0; y < image.Height(); y++) { + delete [] row_pointers[y]; + } + delete [] row_pointers; + + return result; +} + +void libmv_samplePlanarPatchFloat(const float* image, + int width, + int height, + int channels, + const double* xs, + const double* ys, + int num_samples_x, + int num_samples_y, + const float* mask, + float* patch, + double* warped_position_x, + double* warped_position_y) { + FloatImage libmv_image, libmv_patch, libmv_mask; + FloatImage *libmv_mask_for_sample = NULL; + + libmv_floatBufferToFloatImage(image, width, height, channels, &libmv_image); + + if (mask) { + libmv_floatBufferToFloatImage(mask, width, height, 1, &libmv_mask); + libmv_mask_for_sample = &libmv_mask; + } + + SamplePlanarPatch(libmv_image, + xs, ys, + num_samples_x, num_samples_y, + libmv_mask_for_sample, + &libmv_patch, + warped_position_x, + warped_position_y); + + libmv_floatImageToFloatBuffer(libmv_patch, patch); +} + + void libmv_samplePlanarPatchByte(const unsigned char* image, + int width, + int height, + int channels, + const double* xs, + const double* ys, + int num_samples_x, + int num_samples_y, + const float* mask, + unsigned char* patch, + double* warped_position_x, + double* warped_position_y) { + libmv::FloatImage libmv_image, libmv_patch, libmv_mask; + libmv::FloatImage *libmv_mask_for_sample = NULL; + + libmv_byteBufferToFloatImage(image, width, height, channels, &libmv_image); + + if (mask) { + libmv_floatBufferToFloatImage(mask, width, height, 1, &libmv_mask); + libmv_mask_for_sample = &libmv_mask; + } + + libmv::SamplePlanarPatch(libmv_image, + xs, ys, + num_samples_x, num_samples_y, + libmv_mask_for_sample, + &libmv_patch, + warped_position_x, + warped_position_y); + + libmv_floatImageToByteBuffer(libmv_patch, patch); +} diff --git a/extern/libmv/intern/image.h b/extern/libmv/intern/image.h new file mode 100644 index 00000000000..9936e748b9d --- /dev/null +++ b/extern/libmv/intern/image.h @@ -0,0 +1,99 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2011 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Blender Foundation, + * Sergey Sharybin + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef LIBMV_IMAGE_H_ +#define LIBMV_IMAGE_H_ + +#ifdef __cplusplus +# include "libmv/image/image.h" +void libmv_byteBufferToFloatImage(const unsigned char* buffer, + int width, + int height, + int channels, + libmv::FloatImage* image); + +void libmv_floatBufferToFloatImage(const float* buffer, + int width, + int height, + int channels, + libmv::FloatImage* image); + +void libmv_floatImageToFloatBuffer(const libmv::FloatImage& image, + float *buffer); + +void libmv_floatImageToByteBuffer(const libmv::FloatImage& image, + unsigned char* buffer); + +bool libmv_saveImage(const libmv::FloatImage& image, + const char* prefix, + int x0, + int y0); +#endif // __cplusplus + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct libmv_FloatImage { + float *buffer; + int width; + int height; + int channels; +} libmv_FloatImage; + +void libmv_floatImaheDestroy(libmv_FloatImage *image); + +void libmv_samplePlanarPatchFloat(const float* image, + int width, + int height, + int channels, + const double* xs, + const double* ys, + int num_samples_x, + int num_samples_y, + const float* mask, + float* patch, + double* warped_position_x, + double* warped_position_y); + + void libmv_samplePlanarPatchByte(const unsigned char* image, + int width, + int height, + int channels, + const double* xs, + const double* ys, + int num_samples_x, + int num_samples_y, + const float* mask, + unsigned char* patch, + double* warped_position_x, + double* warped_position_y); + +#ifdef __cplusplus +} +#endif + +#endif // LIBMV_IMAGE_H_ diff --git a/extern/libmv/intern/logging.cc b/extern/libmv/intern/logging.cc new file mode 100644 index 00000000000..4ab2d91c8b4 --- /dev/null +++ b/extern/libmv/intern/logging.cc @@ -0,0 +1,55 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2011 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Blender Foundation, + * Sergey Sharybin + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "intern/logging.h" +#include "intern/utildefines.h" +#include "libmv/logging/logging.h" + +void libmv_initLogging(const char* argv0) { + // Make it so FATAL messages are always print into console. + char severity_fatal[32]; + snprintf(severity_fatal, sizeof(severity_fatal), "%d", + google::GLOG_FATAL); + + google::InitGoogleLogging(argv0); + google::SetCommandLineOption("logtostderr", "1"); + google::SetCommandLineOption("v", "0"); + google::SetCommandLineOption("stderrthreshold", severity_fatal); + google::SetCommandLineOption("minloglevel", severity_fatal); +} + +void libmv_startDebugLogging(void) { + google::SetCommandLineOption("logtostderr", "1"); + google::SetCommandLineOption("v", "2"); + google::SetCommandLineOption("stderrthreshold", "1"); + google::SetCommandLineOption("minloglevel", "0"); +} + +void libmv_setLoggingVerbosity(int verbosity) { + char val[10]; + snprintf(val, sizeof(val), "%d", verbosity); + google::SetCommandLineOption("v", val); +} diff --git a/extern/libmv/intern/logging.h b/extern/libmv/intern/logging.h new file mode 100644 index 00000000000..479ed3d6288 --- /dev/null +++ b/extern/libmv/intern/logging.h @@ -0,0 +1,47 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2011 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Blender Foundation, + * Sergey Sharybin + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef LIBMV_C_API_LOGGING_H_ +#define LIBMV_C_API_LOGGING_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +// Initialize GLog logging. +void libmv_initLogging(const char* argv0); + +// Switch Glog to debug logging level. +void libmv_startDebugLogging(void); + +// Set GLog logging verbosity level. +void libmv_setLoggingVerbosity(int verbosity); + +#ifdef __cplusplus +} +#endif + +#endif // LIBMV_C_API_LOGGING_H_ diff --git a/extern/libmv/intern/reconstruction.cc b/extern/libmv/intern/reconstruction.cc new file mode 100644 index 00000000000..eb3677fd206 --- /dev/null +++ b/extern/libmv/intern/reconstruction.cc @@ -0,0 +1,530 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2011 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Blender Foundation, + * Sergey Sharybin + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "intern/reconstruction.h" +#include "intern/camera_intrinsics.h" +#include "intern/tracks.h" +#include "intern/utildefines.h" + +#include "libmv/logging/logging.h" +#include "libmv/simple_pipeline/bundle.h" +#include "libmv/simple_pipeline/keyframe_selection.h" +#include "libmv/simple_pipeline/initialize_reconstruction.h" +#include "libmv/simple_pipeline/modal_solver.h" +#include "libmv/simple_pipeline/pipeline.h" +#include "libmv/simple_pipeline/reconstruction_scale.h" +#include "libmv/simple_pipeline/tracks.h" + +using libmv::CameraIntrinsics; +using libmv::EuclideanCamera; +using libmv::EuclideanPoint; +using libmv::EuclideanReconstruction; +using libmv::EuclideanScaleToUnity; +using libmv::Marker; +using libmv::ProgressUpdateCallback; + +using libmv::PolynomialCameraIntrinsics; +using libmv::Tracks; +using libmv::EuclideanBundle; +using libmv::EuclideanCompleteReconstruction; +using libmv::EuclideanReconstructTwoFrames; +using libmv::EuclideanReprojectionError; + +struct libmv_Reconstruction { + EuclideanReconstruction reconstruction; + + /* Used for per-track average error calculation after reconstruction */ + Tracks tracks; + CameraIntrinsics *intrinsics; + + double error; +}; + +namespace { + +class ReconstructUpdateCallback : public ProgressUpdateCallback { + public: + ReconstructUpdateCallback( + reconstruct_progress_update_cb progress_update_callback, + void *callback_customdata) { + progress_update_callback_ = progress_update_callback; + callback_customdata_ = callback_customdata; + } + + void invoke(double progress, const char* message) { + if (progress_update_callback_) { + progress_update_callback_(callback_customdata_, progress, message); + } + } + protected: + reconstruct_progress_update_cb progress_update_callback_; + void* callback_customdata_; +}; + +void libmv_solveRefineIntrinsics( + const Tracks &tracks, + const int refine_intrinsics, + const int bundle_constraints, + reconstruct_progress_update_cb progress_update_callback, + void* callback_customdata, + EuclideanReconstruction* reconstruction, + CameraIntrinsics* intrinsics) { + /* only a few combinations are supported but trust the caller/ */ + int bundle_intrinsics = 0; + + if (refine_intrinsics & LIBMV_REFINE_FOCAL_LENGTH) { + bundle_intrinsics |= libmv::BUNDLE_FOCAL_LENGTH; + } + if (refine_intrinsics & LIBMV_REFINE_PRINCIPAL_POINT) { + bundle_intrinsics |= libmv::BUNDLE_PRINCIPAL_POINT; + } + if (refine_intrinsics & LIBMV_REFINE_RADIAL_DISTORTION_K1) { + bundle_intrinsics |= libmv::BUNDLE_RADIAL_K1; + } + if (refine_intrinsics & LIBMV_REFINE_RADIAL_DISTORTION_K2) { + bundle_intrinsics |= libmv::BUNDLE_RADIAL_K2; + } + + progress_update_callback(callback_customdata, 1.0, "Refining solution"); + + EuclideanBundleCommonIntrinsics(tracks, + bundle_intrinsics, + bundle_constraints, + reconstruction, + intrinsics); +} + +void finishReconstruction( + const Tracks &tracks, + const CameraIntrinsics &camera_intrinsics, + libmv_Reconstruction *libmv_reconstruction, + reconstruct_progress_update_cb progress_update_callback, + void *callback_customdata) { + EuclideanReconstruction &reconstruction = + libmv_reconstruction->reconstruction; + + /* Reprojection error calculation. */ + progress_update_callback(callback_customdata, 1.0, "Finishing solution"); + libmv_reconstruction->tracks = tracks; + libmv_reconstruction->error = EuclideanReprojectionError(tracks, + reconstruction, + camera_intrinsics); +} + +bool selectTwoKeyframesBasedOnGRICAndVariance( + Tracks& tracks, + Tracks& normalized_tracks, + CameraIntrinsics& camera_intrinsics, + int& keyframe1, + int& keyframe2) { + libmv::vector<int> keyframes; + + /* Get list of all keyframe candidates first. */ + SelectKeyframesBasedOnGRICAndVariance(normalized_tracks, + camera_intrinsics, + keyframes); + + if (keyframes.size() < 2) { + LG << "Not enough keyframes detected by GRIC"; + return false; + } else if (keyframes.size() == 2) { + keyframe1 = keyframes[0]; + keyframe2 = keyframes[1]; + return true; + } + + /* Now choose two keyframes with minimal reprojection error after initial + * reconstruction choose keyframes with the least reprojection error after + * solving from two candidate keyframes. + * + * In fact, currently libmv returns single pair only, so this code will + * not actually run. But in the future this could change, so let's stay + * prepared. + */ + int previous_keyframe = keyframes[0]; + double best_error = std::numeric_limits<double>::max(); + for (int i = 1; i < keyframes.size(); i++) { + EuclideanReconstruction reconstruction; + int current_keyframe = keyframes[i]; + libmv::vector<Marker> keyframe_markers = + normalized_tracks.MarkersForTracksInBothImages(previous_keyframe, + current_keyframe); + + Tracks keyframe_tracks(keyframe_markers); + + /* get a solution from two keyframes only */ + EuclideanReconstructTwoFrames(keyframe_markers, &reconstruction); + EuclideanBundle(keyframe_tracks, &reconstruction); + EuclideanCompleteReconstruction(keyframe_tracks, + &reconstruction, + NULL); + + double current_error = EuclideanReprojectionError(tracks, + reconstruction, + camera_intrinsics); + + LG << "Error between " << previous_keyframe + << " and " << current_keyframe + << ": " << current_error; + + if (current_error < best_error) { + best_error = current_error; + keyframe1 = previous_keyframe; + keyframe2 = current_keyframe; + } + + previous_keyframe = current_keyframe; + } + + return true; +} + +Marker libmv_projectMarker(const EuclideanPoint& point, + const EuclideanCamera& camera, + const CameraIntrinsics& intrinsics) { + libmv::Vec3 projected = camera.R * point.X + camera.t; + projected /= projected(2); + + libmv::Marker reprojected_marker; + intrinsics.ApplyIntrinsics(projected(0), projected(1), + &reprojected_marker.x, + &reprojected_marker.y); + + reprojected_marker.image = camera.image; + reprojected_marker.track = point.track; + return reprojected_marker; +} + +void libmv_getNormalizedTracks(const Tracks &tracks, + const CameraIntrinsics &camera_intrinsics, + Tracks *normalized_tracks) +{ + libmv::vector<Marker> markers = tracks.AllMarkers(); + for (int i = 0; i < markers.size(); ++i) { + Marker &marker = markers[i]; + camera_intrinsics.InvertIntrinsics(marker.x, marker.y, + &marker.x, &marker.y); + normalized_tracks->Insert(marker.image, + marker.track, + marker.x, marker.y, + marker.weight); + } +} + +} // namespace + +libmv_Reconstruction *libmv_solveReconstruction( + const libmv_Tracks* libmv_tracks, + const libmv_CameraIntrinsicsOptions* libmv_camera_intrinsics_options, + libmv_ReconstructionOptions* libmv_reconstruction_options, + reconstruct_progress_update_cb progress_update_callback, + void* callback_customdata) { + libmv_Reconstruction *libmv_reconstruction = + LIBMV_OBJECT_NEW(libmv_Reconstruction); + + Tracks &tracks = *((Tracks *) libmv_tracks); + EuclideanReconstruction &reconstruction = + libmv_reconstruction->reconstruction; + + ReconstructUpdateCallback update_callback = + ReconstructUpdateCallback(progress_update_callback, + callback_customdata); + + /* Retrieve reconstruction options from C-API to libmv API. */ + CameraIntrinsics *camera_intrinsics; + camera_intrinsics = libmv_reconstruction->intrinsics = + libmv_cameraIntrinsicsCreateFromOptions(libmv_camera_intrinsics_options); + + /* Invert the camera intrinsics/ */ + Tracks normalized_tracks; + libmv_getNormalizedTracks(tracks, *camera_intrinsics, &normalized_tracks); + + /* keyframe selection. */ + int keyframe1 = libmv_reconstruction_options->keyframe1, + keyframe2 = libmv_reconstruction_options->keyframe2; + + if (libmv_reconstruction_options->select_keyframes) { + LG << "Using automatic keyframe selection"; + + update_callback.invoke(0, "Selecting keyframes"); + + selectTwoKeyframesBasedOnGRICAndVariance(tracks, + normalized_tracks, + *camera_intrinsics, + keyframe1, + keyframe2); + + /* so keyframes in the interface would be updated */ + libmv_reconstruction_options->keyframe1 = keyframe1; + libmv_reconstruction_options->keyframe2 = keyframe2; + } + + /* Actual reconstruction. */ + LG << "frames to init from: " << keyframe1 << " " << keyframe2; + + libmv::vector<Marker> keyframe_markers = + normalized_tracks.MarkersForTracksInBothImages(keyframe1, keyframe2); + + LG << "number of markers for init: " << keyframe_markers.size(); + + update_callback.invoke(0, "Initial reconstruction"); + + EuclideanReconstructTwoFrames(keyframe_markers, &reconstruction); + EuclideanBundle(normalized_tracks, &reconstruction); + EuclideanCompleteReconstruction(normalized_tracks, + &reconstruction, + &update_callback); + + /* Refinement/ */ + if (libmv_reconstruction_options->refine_intrinsics) { + libmv_solveRefineIntrinsics( + tracks, + libmv_reconstruction_options->refine_intrinsics, + libmv::BUNDLE_NO_CONSTRAINTS, + progress_update_callback, + callback_customdata, + &reconstruction, + camera_intrinsics); + } + + /* Set reconstruction scale to unity. */ + EuclideanScaleToUnity(&reconstruction); + + /* Finish reconstruction. */ + finishReconstruction(tracks, + *camera_intrinsics, + libmv_reconstruction, + progress_update_callback, + callback_customdata); + + return (libmv_Reconstruction *) libmv_reconstruction; +} + +libmv_Reconstruction *libmv_solveModal( + const libmv_Tracks *libmv_tracks, + const libmv_CameraIntrinsicsOptions *libmv_camera_intrinsics_options, + const libmv_ReconstructionOptions *libmv_reconstruction_options, + reconstruct_progress_update_cb progress_update_callback, + void *callback_customdata) { + libmv_Reconstruction *libmv_reconstruction = + LIBMV_OBJECT_NEW(libmv_Reconstruction); + + Tracks &tracks = *((Tracks *) libmv_tracks); + EuclideanReconstruction &reconstruction = + libmv_reconstruction->reconstruction; + + ReconstructUpdateCallback update_callback = + ReconstructUpdateCallback(progress_update_callback, + callback_customdata); + + /* Retrieve reconstruction options from C-API to libmv API. */ + CameraIntrinsics *camera_intrinsics; + camera_intrinsics = libmv_reconstruction->intrinsics = + libmv_cameraIntrinsicsCreateFromOptions( + libmv_camera_intrinsics_options); + + /* Invert the camera intrinsics. */ + Tracks normalized_tracks; + libmv_getNormalizedTracks(tracks, *camera_intrinsics, &normalized_tracks); + + /* Actual reconstruction. */ + ModalSolver(normalized_tracks, &reconstruction, &update_callback); + + PolynomialCameraIntrinsics empty_intrinsics; + EuclideanBundleCommonIntrinsics(normalized_tracks, + libmv::BUNDLE_NO_INTRINSICS, + libmv::BUNDLE_NO_TRANSLATION, + &reconstruction, + &empty_intrinsics); + + /* Refinement. */ + if (libmv_reconstruction_options->refine_intrinsics) { + libmv_solveRefineIntrinsics( + tracks, + libmv_reconstruction_options->refine_intrinsics, + libmv::BUNDLE_NO_TRANSLATION, + progress_update_callback, callback_customdata, + &reconstruction, + camera_intrinsics); + } + + /* Finish reconstruction. */ + finishReconstruction(tracks, + *camera_intrinsics, + libmv_reconstruction, + progress_update_callback, + callback_customdata); + + return (libmv_Reconstruction *) libmv_reconstruction; +} + +void libmv_reconstructionDestroy(libmv_Reconstruction *libmv_reconstruction) { + LIBMV_OBJECT_DELETE(libmv_reconstruction->intrinsics, CameraIntrinsics); + LIBMV_OBJECT_DELETE(libmv_reconstruction, libmv_Reconstruction); +} + +int libmv_reprojectionPointForTrack( + const libmv_Reconstruction *libmv_reconstruction, + int track, + double pos[3]) { + const EuclideanReconstruction *reconstruction = + &libmv_reconstruction->reconstruction; + const EuclideanPoint *point = + reconstruction->PointForTrack(track); + if (point) { + pos[0] = point->X[0]; + pos[1] = point->X[2]; + pos[2] = point->X[1]; + return 1; + } + return 0; +} + +double libmv_reprojectionErrorForTrack( + const libmv_Reconstruction *libmv_reconstruction, + int track) { + const EuclideanReconstruction *reconstruction = + &libmv_reconstruction->reconstruction; + const CameraIntrinsics *intrinsics = libmv_reconstruction->intrinsics; + libmv::vector<Marker> markers = + libmv_reconstruction->tracks.MarkersForTrack(track); + + int num_reprojected = 0; + double total_error = 0.0; + + for (int i = 0; i < markers.size(); ++i) { + double weight = markers[i].weight; + const EuclideanCamera *camera = + reconstruction->CameraForImage(markers[i].image); + const EuclideanPoint *point = + reconstruction->PointForTrack(markers[i].track); + + if (!camera || !point || weight == 0.0) { + continue; + } + + num_reprojected++; + + Marker reprojected_marker = + libmv_projectMarker(*point, *camera, *intrinsics); + double ex = (reprojected_marker.x - markers[i].x) * weight; + double ey = (reprojected_marker.y - markers[i].y) * weight; + + total_error += sqrt(ex * ex + ey * ey); + } + + return total_error / num_reprojected; +} + +double libmv_reprojectionErrorForImage( + const libmv_Reconstruction *libmv_reconstruction, + int image) { + const EuclideanReconstruction *reconstruction = + &libmv_reconstruction->reconstruction; + const CameraIntrinsics *intrinsics = libmv_reconstruction->intrinsics; + libmv::vector<Marker> markers = + libmv_reconstruction->tracks.MarkersInImage(image); + const EuclideanCamera *camera = reconstruction->CameraForImage(image); + int num_reprojected = 0; + double total_error = 0.0; + + if (!camera) { + return 0.0; + } + + for (int i = 0; i < markers.size(); ++i) { + const EuclideanPoint *point = + reconstruction->PointForTrack(markers[i].track); + + if (!point) { + continue; + } + + num_reprojected++; + + Marker reprojected_marker = + libmv_projectMarker(*point, *camera, *intrinsics); + double ex = (reprojected_marker.x - markers[i].x) * markers[i].weight; + double ey = (reprojected_marker.y - markers[i].y) * markers[i].weight; + + total_error += sqrt(ex * ex + ey * ey); + } + + return total_error / num_reprojected; +} + +int libmv_reprojectionCameraForImage( + const libmv_Reconstruction *libmv_reconstruction, + int image, + double mat[4][4]) { + const EuclideanReconstruction *reconstruction = + &libmv_reconstruction->reconstruction; + const EuclideanCamera *camera = + reconstruction->CameraForImage(image); + + if (camera) { + for (int j = 0; j < 3; ++j) { + for (int k = 0; k < 3; ++k) { + int l = k; + + if (k == 1) { + l = 2; + } else if (k == 2) { + l = 1; + } + + if (j == 2) { + mat[j][l] = -camera->R(j, k); + } else { + mat[j][l] = camera->R(j, k); + } + } + mat[j][3] = 0.0; + } + + libmv::Vec3 optical_center = -camera->R.transpose() * camera->t; + + mat[3][0] = optical_center(0); + mat[3][1] = optical_center(2); + mat[3][2] = optical_center(1); + + mat[3][3] = 1.0; + + return 1; + } + + return 0; +} + +double libmv_reprojectionError( + const libmv_Reconstruction *libmv_reconstruction) { + return libmv_reconstruction->error; +} + +libmv_CameraIntrinsics *libmv_reconstructionExtractIntrinsics( + libmv_Reconstruction *libmv_reconstruction) { + return (libmv_CameraIntrinsics *) libmv_reconstruction->intrinsics; +} diff --git a/extern/libmv/intern/reconstruction.h b/extern/libmv/intern/reconstruction.h new file mode 100644 index 00000000000..744f4bafb0b --- /dev/null +++ b/extern/libmv/intern/reconstruction.h @@ -0,0 +1,99 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2011 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Blender Foundation, + * Sergey Sharybin + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef LIBMV_C_API_RECONSTRUCTION_H_ +#define LIBMV_C_API_RECONSTRUCTION_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct libmv_CameraIntrinsics libmv_CameraIntrinsics; +typedef struct libmv_CameraIntrinsicsOptions libmv_CameraIntrinsicsOptions; +typedef struct libmv_Reconstruction libmv_Reconstruction; +typedef struct libmv_Tracks libmv_Tracks; + +enum { + LIBMV_REFINE_FOCAL_LENGTH = (1 << 0), + LIBMV_REFINE_PRINCIPAL_POINT = (1 << 1), + LIBMV_REFINE_RADIAL_DISTORTION_K1 = (1 << 2), + LIBMV_REFINE_RADIAL_DISTORTION_K2 = (1 << 4), +}; + +typedef struct libmv_ReconstructionOptions { + int select_keyframes; + int keyframe1, keyframe2; + int refine_intrinsics; +} libmv_ReconstructionOptions; + +typedef void (*reconstruct_progress_update_cb) (void* customdata, + double progress, + const char* message); + +libmv_Reconstruction* libmv_solveReconstruction( + const libmv_Tracks* libmv_tracks, + const libmv_CameraIntrinsicsOptions* libmv_camera_intrinsics_options, + libmv_ReconstructionOptions* libmv_reconstruction_options, + reconstruct_progress_update_cb progress_update_callback, + void* callback_customdata); + +libmv_Reconstruction* libmv_solveModal( + const libmv_Tracks* libmv_tracks, + const libmv_CameraIntrinsicsOptions* libmv_camera_intrinsics_options, + const libmv_ReconstructionOptions* libmv_reconstruction_options, + reconstruct_progress_update_cb progress_update_callback, + void* callback_customdata); + +void libmv_reconstructionDestroy(libmv_Reconstruction* libmv_reconstruction); + +int libmv_reprojectionPointForTrack( + const libmv_Reconstruction* libmv_reconstruction, + int track, + double pos[3]); + +double libmv_reprojectionErrorForTrack( + const libmv_Reconstruction* libmv_reconstruction, + int track); + +double libmv_reprojectionErrorForImage( + const libmv_Reconstruction* libmv_reconstruction, + int image); + +int libmv_reprojectionCameraForImage( + const libmv_Reconstruction* libmv_reconstruction, + int image, + double mat[4][4]); + +double libmv_reprojectionError(const libmv_Reconstruction* libmv_reconstruction); + +libmv_CameraIntrinsics* libmv_reconstructionExtractIntrinsics( + libmv_Reconstruction *libmv_Reconstruction); + +#ifdef __cplusplus +} +#endif + +#endif // LIBMV_C_API_RECONSTRUCTION_H_ diff --git a/extern/libmv/intern/region.h b/extern/libmv/intern/region.h new file mode 100644 index 00000000000..9f114bbad3b --- /dev/null +++ b/extern/libmv/intern/region.h @@ -0,0 +1,43 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2014 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Blender Foundation, + * Sergey Sharybin + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef LIBMV_C_API_REGION_H_ +#define LIBMV_C_API_REGION_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct libmv_Region { + float min[2]; + float max[2]; +} libmv_Region; + +#ifdef __cplusplus +} +#endif + +#endif // LIBMV_C_API_REGION_H_ diff --git a/extern/libmv/intern/stub.cc b/extern/libmv/intern/stub.cc new file mode 100644 index 00000000000..cd8bb8ab841 --- /dev/null +++ b/extern/libmv/intern/stub.cc @@ -0,0 +1,330 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2013 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Blender Foundation, + * Sergey Sharybin + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "libmv-capi.h" + +#include <cstdlib> +#include <cstring> + +/* ************ Logging ************ */ + +void libmv_initLogging(const char * /*argv0*/) { +} + +void libmv_startDebugLogging(void) { +} + +void libmv_setLoggingVerbosity(int /*verbosity*/) { +} + +/* ************ Planar tracker ************ */ + +/* TrackRegion (new planar tracker) */ +int libmv_trackRegion(const libmv_TrackRegionOptions * /*options*/, + const float * /*image1*/, + int /*image1_width*/, + int /*image1_height*/, + const float * /*image2*/, + int /*image2_width*/, + int /*image2_height*/, + const double *x1, + const double *y1, + libmv_TrackRegionResult *result, + double *x2, + double *y2) { + /* Convert to doubles for the libmv api. The four corners and the center. */ + for (int i = 0; i < 5; ++i) { + x2[i] = x1[i]; + y2[i] = y1[i]; + } + + result->termination = -1; + result->termination_reason = "Built without libmv support"; + result->correlation = 0.0; + + return false; +} + +void libmv_samplePlanarPatchFloat(const float * /*image*/, + int /*width*/, + int /*height*/, + int /*channels*/, + const double * /*xs*/, + const double * /*ys*/, + int /*num_samples_x*/, + int /*num_samples_y*/, + const float * /*mask*/, + float * /*patch*/, + double * /*warped_position_x*/, + double * /*warped_position_y*/) { + /* TODO(sergey): implement */ +} + +void libmv_samplePlanarPatchByte(const unsigned char * /*image*/, + int /*width*/, + int /*height*/, + int /*channels*/, + const double * /*xs*/, + const double * /*ys*/, + int /*num_samples_x*/, int /*num_samples_y*/, + const float * /*mask*/, + unsigned char * /*patch*/, + double * /*warped_position_x*/, + double * /*warped_position_y*/) { + /* TODO(sergey): implement */ +} + +/* ************ Tracks ************ */ + +libmv_Tracks *libmv_tracksNew(void) { + return NULL; +} + +void libmv_tracksInsert(libmv_Tracks * /*libmv_tracks*/, + int /*image*/, + int /*track*/, + double /*x*/, + double /*y*/, + double /*weight*/) { +} + +void libmv_tracksDestroy(libmv_Tracks * /*libmv_tracks*/) { +} + +/* ************ Reconstruction solver ************ */ + +libmv_Reconstruction *libmv_solveReconstruction( + const libmv_Tracks * /*libmv_tracks*/, + const libmv_CameraIntrinsicsOptions * /*libmv_camera_intrinsics_options*/, + libmv_ReconstructionOptions * /*libmv_reconstruction_options*/, + reconstruct_progress_update_cb /*progress_update_callback*/, + void * /*callback_customdata*/) { + return NULL; +} + +libmv_Reconstruction *libmv_solveModal( + const libmv_Tracks * /*libmv_tracks*/, + const libmv_CameraIntrinsicsOptions * /*libmv_camera_intrinsics_options*/, + const libmv_ReconstructionOptions * /*libmv_reconstruction_options*/, + reconstruct_progress_update_cb /*progress_update_callback*/, + void * /*callback_customdata*/) { + return NULL; +} + +int libmv_reprojectionPointForTrack( + const libmv_Reconstruction * /*libmv_reconstruction*/, + int /*track*/, + double /*pos*/[3]) { + return 0; +} + +double libmv_reprojectionErrorForTrack( + const libmv_Reconstruction * /*libmv_reconstruction*/, + int /*track*/) { + return 0.0; +} + +double libmv_reprojectionErrorForImage( + const libmv_Reconstruction * /*libmv_reconstruction*/, + int /*image*/) { + return 0.0; +} + +int libmv_reprojectionCameraForImage( + const libmv_Reconstruction * /*libmv_reconstruction*/, + int /*image*/, + double /*mat*/[4][4]) { + return 0; +} + +double libmv_reprojectionError( + const libmv_Reconstruction * /*libmv_reconstruction*/) { + return 0.0; +} + +void libmv_reconstructionDestroy( + struct libmv_Reconstruction * /*libmv_reconstruction*/) { +} + +/* ************ Feature detector ************ */ + +libmv_Features *libmv_detectFeaturesByte(const unsigned char */*image_buffer*/, + int /*width*/, + int /*height*/, + int /*channels*/, + libmv_DetectOptions */*options*/) { + return NULL; +} + +struct libmv_Features *libmv_detectFeaturesFloat( + const float */*image_buffer*/, + int /*width*/, + int /*height*/, + int /*channels*/, + libmv_DetectOptions */*options*/) { + return NULL; +} + +int libmv_countFeatures(const libmv_Features * /*libmv_features*/) { + return 0; +} + +void libmv_getFeature(const libmv_Features * /*libmv_features*/, + int /*number*/, + double *x, + double *y, + double *score, + double *size) { + *x = 0.0; + *y = 0.0; + *score = 0.0; + *size = 0.0; +} + +void libmv_featuresDestroy(struct libmv_Features * /*libmv_features*/) { +} + +/* ************ Camera intrinsics ************ */ + +libmv_CameraIntrinsics *libmv_reconstructionExtractIntrinsics( + libmv_Reconstruction * /*libmv_reconstruction*/) { + return NULL; +} + +libmv_CameraIntrinsics *libmv_cameraIntrinsicsNew( + const libmv_CameraIntrinsicsOptions * /*libmv_camera_intrinsics_options*/) { + return NULL; +} + +libmv_CameraIntrinsics *libmv_cameraIntrinsicsCopy( + const libmv_CameraIntrinsics * /*libmvIntrinsics*/) { + return NULL; +} + +void libmv_cameraIntrinsicsDestroy( + libmv_CameraIntrinsics * /*libmvIntrinsics*/) { +} + +void libmv_cameraIntrinsicsUpdate( + const libmv_CameraIntrinsicsOptions * /*libmv_camera_intrinsics_options*/, + libmv_CameraIntrinsics * /*libmv_intrinsics*/) { +} + +void libmv_cameraIntrinsicsSetThreads( + libmv_CameraIntrinsics * /*libmv_intrinsics*/, + int /*threads*/) { +} + +void libmv_cameraIntrinsicsExtractOptions( + const libmv_CameraIntrinsics */*libmv_intrinsics*/, + libmv_CameraIntrinsicsOptions *camera_intrinsics_options) { + memset(camera_intrinsics_options, 0, sizeof(libmv_CameraIntrinsicsOptions)); + camera_intrinsics_options->focal_length = 1.0; +} + +void libmv_cameraIntrinsicsUndistortByte( + const libmv_CameraIntrinsics * /*libmv_intrinsics*/, + const unsigned char *source_image, + int width, int height, + float overscan, int channels, + unsigned char *destination_image) { + memcpy(destination_image, source_image, + channels * width * height * sizeof(unsigned char)); +} + +void libmv_cameraIntrinsicsUndistortFloat( + const libmv_CameraIntrinsics* /*libmv_intrinsics*/, + const float* source_image, + int width, + int height, + float overscan, + int channels, + float* destination_image) { + memcpy(destination_image, source_image, + channels * width * height * sizeof(float)); +} + +void libmv_cameraIntrinsicsDistortByte( + const struct libmv_CameraIntrinsics* /*libmv_intrinsics*/, + const unsigned char *source_image, + int width, + int height, + float overscan, + int channels, + unsigned char *destination_image) { + memcpy(destination_image, source_image, + channels * width * height * sizeof(unsigned char)); +} + +void libmv_cameraIntrinsicsDistortFloat( + const libmv_CameraIntrinsics* /*libmv_intrinsics*/, + float* source_image, + int width, + int height, + float overscan, + int channels, + float* destination_image) { + memcpy(destination_image, source_image, + channels * width * height * sizeof(float)); +} + +/* ************ utils ************ */ + +void libmv_cameraIntrinsicsApply( + const libmv_CameraIntrinsicsOptions* libmv_camera_intrinsics_options, + double x, + double y, + double* x1, + double* y1) { + double focal_length = libmv_camera_intrinsics_options->focal_length; + double principal_x = libmv_camera_intrinsics_options->principal_point_x; + double principal_y = libmv_camera_intrinsics_options->principal_point_y; + *x1 = x * focal_length + principal_x; + *y1 = y * focal_length + principal_y; +} + +void libmv_cameraIntrinsicsInvert( + const libmv_CameraIntrinsicsOptions* libmv_camera_intrinsics_options, + double x, + double y, + double* x1, + double* y1) { + double focal_length = libmv_camera_intrinsics_options->focal_length; + double principal_x = libmv_camera_intrinsics_options->principal_point_x; + double principal_y = libmv_camera_intrinsics_options->principal_point_y; + *x1 = (x - principal_x) / focal_length; + *y1 = (y - principal_y) / focal_length; +} + +void libmv_homography2DFromCorrespondencesEuc(/* const */ double (*x1)[2], + /* const */ double (*x2)[2], + int num_points, + double H[3][3]) { + memset(H, 0, sizeof(double[3][3])); + H[0][0] = 1.0f; + H[1][1] = 1.0f; + H[2][2] = 1.0f; +} diff --git a/extern/libmv/intern/track_region.cc b/extern/libmv/intern/track_region.cc new file mode 100644 index 00000000000..24fbc78c1a1 --- /dev/null +++ b/extern/libmv/intern/track_region.cc @@ -0,0 +1,177 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2011 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Blender Foundation, + * Sergey Sharybin + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "intern/track_region.h" +#include "intern/image.h" +#include "intern/utildefines.h" +#include "libmv/image/image.h" +#include "libmv/tracking/track_region.h" + +/* define this to generate PNG images with content of search areas + tracking between which failed */ +#undef DUMP_FAILURE + +/* define this to generate PNG images with content of search areas + on every itteration of tracking */ +#undef DUMP_ALWAYS + +using libmv::FloatImage; +using libmv::TrackRegionOptions; +using libmv::TrackRegionResult; +using libmv::TrackRegion; + +void libmv_configureTrackRegionOptions( + const libmv_TrackRegionOptions& options, + TrackRegionOptions* track_region_options) { + switch (options.motion_model) { +#define LIBMV_CONVERT(the_model) \ + case TrackRegionOptions::the_model: \ + track_region_options->mode = TrackRegionOptions::the_model; \ + break; + LIBMV_CONVERT(TRANSLATION) + LIBMV_CONVERT(TRANSLATION_ROTATION) + LIBMV_CONVERT(TRANSLATION_SCALE) + LIBMV_CONVERT(TRANSLATION_ROTATION_SCALE) + LIBMV_CONVERT(AFFINE) + LIBMV_CONVERT(HOMOGRAPHY) +#undef LIBMV_CONVERT + } + + track_region_options->minimum_correlation = options.minimum_correlation; + track_region_options->max_iterations = options.num_iterations; + track_region_options->sigma = options.sigma; + track_region_options->num_extra_points = 1; + track_region_options->image1_mask = NULL; + track_region_options->use_brute_initialization = options.use_brute; + /* TODO(keir): This will make some cases better, but may be a regression until + * the motion model is in. Since this is on trunk, enable it for now. + * + * TODO(sergey): This gives much worse results on mango footage (see 04_2e) + * so disabling for now for until proper prediction model is landed. + * + * The thing is, currently blender sends input coordinates as the guess to + * region tracker and in case of fast motion such an early out ruins the track. + */ + track_region_options->attempt_refine_before_brute = false; + track_region_options->use_normalized_intensities = options.use_normalization; +} + +void libmv_regionTrackergetResult(const TrackRegionResult& track_region_result, + libmv_TrackRegionResult* result) { + result->termination = (int) track_region_result.termination; + result->termination_reason = ""; + result->correlation = track_region_result.correlation; +} + +int libmv_trackRegion(const libmv_TrackRegionOptions* options, + const float* image1, + int image1_width, + int image1_height, + const float* image2, + int image2_width, + int image2_height, + const double* x1, + const double* y1, + libmv_TrackRegionResult* result, + double* x2, + double* y2) { + double xx1[5], yy1[5]; + double xx2[5], yy2[5]; + bool tracking_result = false; + + // Convert to doubles for the libmv api. The four corners and the center. + for (int i = 0; i < 5; ++i) { + xx1[i] = x1[i]; + yy1[i] = y1[i]; + xx2[i] = x2[i]; + yy2[i] = y2[i]; + } + + TrackRegionOptions track_region_options; + FloatImage image1_mask; + + libmv_configureTrackRegionOptions(*options, &track_region_options); + if (options->image1_mask) { + libmv_floatBufferToFloatImage(options->image1_mask, + image1_width, + image1_height, + 1, + &image1_mask); + + track_region_options.image1_mask = &image1_mask; + } + + // Convert from raw float buffers to libmv's FloatImage. + FloatImage old_patch, new_patch; + libmv_floatBufferToFloatImage(image1, + image1_width, + image1_height, + 1, + &old_patch); + libmv_floatBufferToFloatImage(image2, + image2_width, + image2_height, + 1, + &new_patch); + + TrackRegionResult track_region_result; + TrackRegion(old_patch, new_patch, + xx1, yy1, + track_region_options, + xx2, yy2, + &track_region_result); + + // Convert to floats for the blender api. + for (int i = 0; i < 5; ++i) { + x2[i] = xx2[i]; + y2[i] = yy2[i]; + } + + // TODO(keir): Update the termination string with failure details. + if (track_region_result.termination == TrackRegionResult::CONVERGENCE || + track_region_result.termination == TrackRegionResult::NO_CONVERGENCE) { + tracking_result = true; + } + + // Debug dump of patches. +#if defined(DUMP_FAILURE) || defined(DUMP_ALWAYS) + bool need_dump = !tracking_result; + +# ifdef DUMP_ALWAYS + need_dump = true; +# endif + + if (need_dump) { + libmv_saveImage(old_patch, "old_patch", x1[4], y1[4]); + libmv_saveImage(new_patch, "new_patch", x2[4], y2[4]); + if (options->image1_mask) { + libmv_saveImage(image1_mask, "mask", x2[4], y2[4]); + } + } +#endif + + return tracking_result; +} diff --git a/extern/libmv/intern/track_region.h b/extern/libmv/intern/track_region.h new file mode 100644 index 00000000000..95ec124c3e1 --- /dev/null +++ b/extern/libmv/intern/track_region.h @@ -0,0 +1,81 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2011 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Blender Foundation, + * Sergey Sharybin + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef LIBMV_C_API_TRACK_REGION_H_ +#define LIBMV_C_API_TRACK_REGION_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct libmv_TrackRegionOptions { + int motion_model; + int num_iterations; + int use_brute; + int use_normalization; + double minimum_correlation; + double sigma; + float *image1_mask; +} libmv_TrackRegionOptions; + +typedef struct libmv_TrackRegionResult { + int termination; + const char* termination_reason; + double correlation; +} libmv_TrackRegionResult; + +#ifdef __cplusplus +namespace libmv { + class TrackRegionOptions; + class TrackRegionResult; +} +void libmv_configureTrackRegionOptions( + const libmv_TrackRegionOptions& options, + libmv::TrackRegionOptions* track_region_options); + +void libmv_regionTrackergetResult( + const libmv::TrackRegionResult& track_region_result, + libmv_TrackRegionResult* result); +#endif + +int libmv_trackRegion(const libmv_TrackRegionOptions* options, + const float* image1, + int image1_width, + int image1_height, + const float* image2, + int image2_width, + int image2_height, + const double* x1, + const double* y1, + libmv_TrackRegionResult* result, + double* x2, + double* y2); + +#ifdef __cplusplus +} +#endif + +#endif // LIBMV_C_API_PLANAR_TRACKER_H_ diff --git a/extern/libmv/intern/tracks.cc b/extern/libmv/intern/tracks.cc new file mode 100644 index 00000000000..9b032b0760a --- /dev/null +++ b/extern/libmv/intern/tracks.cc @@ -0,0 +1,52 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2011 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Blender Foundation, + * Sergey Sharybin + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "intern/tracks.h" +#include "intern/utildefines.h" + +#include "libmv/simple_pipeline/tracks.h" + +using libmv::Marker; +using libmv::Tracks; + +libmv_Tracks* libmv_tracksNew(void) { + Tracks* tracks = LIBMV_OBJECT_NEW(Tracks); + + return (libmv_Tracks*) tracks; +} + +void libmv_tracksDestroy(libmv_Tracks* libmv_tracks) { + LIBMV_OBJECT_DELETE(libmv_tracks, Tracks); +} + +void libmv_tracksInsert(libmv_Tracks *libmv_tracks, + int image, + int track, + double x, + double y, + double weight) { + ((Tracks *) libmv_tracks)->Insert(image, track, x, y, weight); +} diff --git a/extern/libmv/intern/tracks.h b/extern/libmv/intern/tracks.h new file mode 100644 index 00000000000..79f6cc99579 --- /dev/null +++ b/extern/libmv/intern/tracks.h @@ -0,0 +1,51 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2011 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Blender Foundation, + * Sergey Sharybin + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef LIBMV_C_API_TRACKS_H_ +#define LIBMV_C_API_TRACKS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct libmv_Tracks libmv_Tracks; + +libmv_Tracks* libmv_tracksNew(void); + +void libmv_tracksDestroy(libmv_Tracks* libmv_tracks); + +void libmv_tracksInsert(libmv_Tracks* libmv_tracks, + int image, + int track, + double x, + double y, + double weight); + +#ifdef __cplusplus +} +#endif + +#endif // LIBMV_C_API_TRACKS_H_ diff --git a/extern/libmv/intern/utildefines.h b/extern/libmv/intern/utildefines.h new file mode 100644 index 00000000000..7366b242cf7 --- /dev/null +++ b/extern/libmv/intern/utildefines.h @@ -0,0 +1,62 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2013 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Sergey Sharybin + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef LIBMV_C_API_UTILDEFINES_H_ +#define LIBMV_C_API_UTILDEFINES_H_ + +#if defined(_MSC_VER) +# define __func__ __FUNCTION__ +# define snprintf _snprintf +#endif + +#ifdef WITH_LIBMV_GUARDED_ALLOC +# include "MEM_guardedalloc.h" +# define LIBMV_OBJECT_NEW OBJECT_GUARDED_NEW +# define LIBMV_OBJECT_DELETE OBJECT_GUARDED_DELETE +# define LIBMV_OBJECT_DELETE OBJECT_GUARDED_DELETE +# define LIBMV_STRUCT_NEW(type, count) \ + (type*)MEM_mallocN(sizeof(type) * count, __func__) +# define LIBMV_STRUCT_DELETE(what) MEM_freeN(what) +#else +// Need this to keep libmv-capi potentially standalone. +# if defined __GNUC__ || defined __sun +# define LIBMV_OBJECT_NEW(type, args ...) \ + new(malloc(sizeof(type))) type(args) +# else +# define LIBMV_OBJECT_NEW(type, ...) \ + new(malloc(sizeof(type))) type(__VA_ARGS__) +#endif +# define LIBMV_OBJECT_DELETE(what, type) \ + { \ + if (what) { \ + ((type*)(what))->~type(); \ + free(what); \ + } \ + } (void)0 +# define LIBMV_STRUCT_NEW(type, count) (type*)malloc(sizeof(type) * count) +# define LIBMV_STRUCT_DELETE(what) { if (what) free(what); } (void)0 +#endif + +#endif // LIBMV_C_API_UTILDEFINES_H_ |