source/render/GenerateKeypointProjections.cpp (76 lines of code) (raw):

/** * Copyright 2004-present Facebook. All Rights Reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. */ #include <gflags/gflags.h> #include <glog/logging.h> #include <opencv2/opencv.hpp> #include "source/calibration/Calibration.h" #include "source/calibration/FeatureMatcher.h" #include "source/util/Camera.h" #include "source/util/CvUtil.h" #include "source/util/ImageUtil.h" #include "source/util/SystemUtil.h" using namespace fb360_dep; const std::string kUsageMessage = R"( - Reprojects a grid of keypoints to another camera at different depths. - Example: ./GenerateKeypointProjections \ --color=/path/to/video/color \ --frame=000000 \ --rig=/path/to/rigs/rig.json \ --output_dir=/path/to/output )"; DEFINE_double(height_stride, 0.125, "x grid stride in percent"); DEFINE_double(length_stride, 0.125, "y grid stride in percent"); DEFINE_string(output_dir, "", "path to output directory"); DEFINE_string(rig, "", "path to camera rig .json file"); DECLARE_int32(search_radius); int main(int argc, char* argv[]) { system_util::initDep(argc, argv, kUsageMessage); CHECK_NE(FLAGS_rig, ""); CHECK_NE(FLAGS_output_dir, ""); filesystem::create_directories(FLAGS_output_dir); // Load camera rig const Camera::Rig rig = Camera::loadRig(FLAGS_rig); const std::vector<cv::Mat_<cv::Vec4f>> images = image_util::loadImages<cv::Vec4f>(FLAGS_color, rig, FLAGS_frame, FLAGS_threads); const double height = rig[0].resolution.y(); const double width = rig[0].resolution.x(); for (int c0Idx = 0; c0Idx < int(rig.size()); ++c0Idx) { for (int c1Idx = c0Idx + 1; c1Idx < int(rig.size()); ++c1Idx) { cv::Mat_<cv::Vec4f> keypointProjection(height, width, cv::Scalar(0, 0, 0, 0)); // Project a grid of points seen by the camera at c1Idx to the camera at c0Idx at different // depths for (double width_frac = 0; width_frac <= 1; width_frac += FLAGS_length_stride) { for (double height_frac = 0; height_frac <= 1; height_frac += FLAGS_height_stride) { const Camera::Vector2 c1Point(width * width_frac, height * height_frac); if (rig[c1Idx].isOutsideImageCircle( Camera::Vector2(c1Point.x() + 0.5, c1Point.y() + 0.5))) { continue; } int depthSample = -1; double disparity = 0; cv::Rect2f box1(0, 0, 0, 0); // Unique color for this grid point (all depths will be the same color) const cv::Vec4f color = cv::Vec4f(height_frac, width_frac, (1 - height_frac), 1); while (calibration::getNextDepthSample( depthSample, disparity, box1, rig[c1Idx], c1Point, rig[c0Idx])) { const Camera::Vector3 cornerWorldProjection = rig[c1Idx].rig(c1Point, 1 / disparity); Camera::Vector2 projectedPoint; // Draw a circle centered at the reprojected point // Thickness of -1 indicates the circle is filled in if (rig[c0Idx].sees(cornerWorldProjection, projectedPoint)) { cv::rectangle( keypointProjection, cv::Point2d( projectedPoint.x() - 0.5 - FLAGS_search_radius, projectedPoint.y() - 0.5 - FLAGS_search_radius), cv::Point2d( projectedPoint.x() - 0.5 + FLAGS_search_radius, projectedPoint.y() - 0.5 + FLAGS_search_radius), color, -1); } } } } cv::Mat_<cv::Vec4f> blend; cv::addWeighted(images[c0Idx], 1, keypointProjection, 0.6, 0, blend); const std::string fn = folly::sformat("{}/{}_{}.png", FLAGS_output_dir, rig[c0Idx].id, rig[c1Idx].id); cv_util::imwriteExceptionOnFail(fn, 255.0f * blend); } } return EXIT_SUCCESS; }