diff options
Diffstat (limited to 'extern/libmv/libmv-util.cc')
-rw-r--r-- | extern/libmv/libmv-util.cc | 309 |
1 files changed, 309 insertions, 0 deletions
diff --git a/extern/libmv/libmv-util.cc b/extern/libmv/libmv-util.cc new file mode 100644 index 00000000000..f969417d6c1 --- /dev/null +++ b/extern/libmv/libmv-util.cc @@ -0,0 +1,309 @@ +/* + * ***** 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 ***** + */ + +#include "libmv-util.h" +#include "libmv-capi_intern.h" + +#include <cassert> +#include <png.h> + +using libmv::CameraIntrinsics; +using libmv::DivisionCameraIntrinsics; +using libmv::EuclideanCamera; +using libmv::EuclideanPoint; +using libmv::FloatImage; +using libmv::Marker; +using libmv::PolynomialCameraIntrinsics; +using libmv::Tracks; + +/* Image <-> buffers conversion */ + +void libmv_byteBufferToImage(const unsigned char *buf, + int width, int height, int channels, + FloatImage *image) +{ + int x, y, k, a = 0; + + image->Resize(height, width, channels); + + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) { + for (k = 0; k < channels; k++) { + (*image)(y, x, k) = (float)buf[a++] / 255.0f; + } + } + } +} + +void libmv_floatBufferToImage(const float *buf, + 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) = buf[a++]; + } + } + } +} + +void libmv_imageToFloatBuffer(const FloatImage &image, + float *buf) +{ + 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++) { + buf[a++] = image(y, x, k); + } + } + } +} + +void libmv_imageToByteBuffer(const libmv::FloatImage &image, + unsigned char *buf) +{ + 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++) { + buf[a++] = image(y, x, k) * 255.0f; + } + } + } +} + +/* Debugging */ + +static void 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) { + return; + } + + /* 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; + } + + png_init_io(png_ptr, fp); + + /* write header */ + if (setjmp(png_jmpbuf(png_ptr))) { + fclose(fp); + return; + } + + 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; + } + + png_write_image(png_ptr, row_pointers); + + /* end write */ + if (setjmp(png_jmpbuf(png_ptr))) { + fclose(fp); + return; + } + + png_write_end(png_ptr, NULL); + + fclose(fp); +} + +void 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 a = 0; + char buf[128]; + snprintf(buf, sizeof(buf), "%s_%02d.png", prefix, ++a); + savePNGImage(row_pointers, + image.Width(), image.Height(), 8, + PNG_COLOR_TYPE_RGBA, + buf); + } + + for (y = 0; y < image.Height(); y++) { + delete [] row_pointers[y]; + } + delete [] row_pointers; +} + +/* Camera intrinsics utility functions */ + +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; +} + +/* Reconstruction utilities */ + +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); + } +} + +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; +} |