10ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Ceres Solver - A fast non-linear least squares minimizer 20ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Copyright 2012 Google Inc. All rights reserved. 30ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// http://code.google.com/p/ceres-solver/ 40ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// 50ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Redistribution and use in source and binary forms, with or without 60ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// modification, are permitted provided that the following conditions are met: 70ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// 80ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// * Redistributions of source code must retain the above copyright notice, 90ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// this list of conditions and the following disclaimer. 100ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// * Redistributions in binary form must reproduce the above copyright notice, 110ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// this list of conditions and the following disclaimer in the documentation 120ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// and/or other materials provided with the distribution. 130ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// * Neither the name of Google Inc. nor the names of its contributors may be 140ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// used to endorse or promote products derived from this software without 150ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// specific prior written permission. 160ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// 170ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 180ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 190ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 200ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 210ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 220ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 230ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 240ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 250ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 260ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 270ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// POSSIBILITY OF SUCH DAMAGE. 280ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// 290ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Author: strandmark@google.com (Petter Strandmark) 300ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// 310ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Denoising using Fields of Experts and the Ceres minimizer. 320ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// 330ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Note that for good denoising results the weighting between the data term 340ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// and the Fields of Experts term needs to be adjusted. This is discussed 350ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// in [1]. This program assumes Gaussian noise. The noise model can be changed 360ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// by substituing another function for QuadraticCostFunction. 370ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// 380ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// [1] S. Roth and M.J. Black. "Fields of Experts." International Journal of 390ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Computer Vision, 82(2):205--229, 2009. 400ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 410ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include <algorithm> 420ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include <cmath> 430ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include <iostream> 440ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include <vector> 450ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include <sstream> 460ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include <string> 470ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 480ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include "ceres/ceres.h" 490ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include "gflags/gflags.h" 500ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include "glog/logging.h" 510ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 520ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include "fields_of_experts.h" 530ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include "pgm_image.h" 540ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 550ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus KongDEFINE_string(input, "", "File to which the output image should be written"); 560ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus KongDEFINE_string(foe_file, "", "FoE file to use"); 570ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus KongDEFINE_string(output, "", "File to which the output image should be written"); 580ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus KongDEFINE_double(sigma, 20.0, "Standard deviation of noise"); 590ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus KongDEFINE_bool(verbose, false, "Prints information about the solver progress."); 601d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha HaeberlingDEFINE_bool(line_search, false, "Use a line search instead of trust region " 611d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling "algorithm."); 620ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 630ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kongnamespace ceres { 640ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kongnamespace examples { 650ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 660ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// This cost function is used to build the data term. 670ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// 680ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// f_i(x) = a * (x_i - b)^2 690ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// 700ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kongclass QuadraticCostFunction : public ceres::SizedCostFunction<1, 1> { 710ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong public: 720ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong QuadraticCostFunction(double a, double b) 730ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong : sqrta_(std::sqrt(a)), b_(b) {} 740ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong virtual bool Evaluate(double const* const* parameters, 750ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double* residuals, 760ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double** jacobians) const { 770ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong const double x = parameters[0][0]; 780ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong residuals[0] = sqrta_ * (x - b_); 790ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong if (jacobians != NULL && jacobians[0] != NULL) { 800ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong jacobians[0][0] = sqrta_; 810ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 820ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong return true; 830ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 840ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong private: 850ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double sqrta_, b_; 860ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong}; 870ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 880ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Creates a Fields of Experts MAP inference problem. 890ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kongvoid CreateProblem(const FieldsOfExperts& foe, 900ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong const PGMImage<double>& image, 910ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong Problem* problem, 920ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong PGMImage<double>* solution) { 930ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // Create the data term 940ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong CHECK_GT(FLAGS_sigma, 0.0); 950ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong const double coefficient = 1 / (2.0 * FLAGS_sigma * FLAGS_sigma); 960ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (unsigned index = 0; index < image.NumPixels(); ++index) { 970ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong ceres::CostFunction* cost_function = 980ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong new QuadraticCostFunction(coefficient, 990ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong image.PixelFromLinearIndex(index)); 1000ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong problem->AddResidualBlock(cost_function, 1010ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong NULL, 1020ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong solution->MutablePixelFromLinearIndex(index)); 1030ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 1040ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 1050ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // Create Ceres cost and loss functions for regularization. One is needed for 1060ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // each filter. 1070ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong std::vector<ceres::LossFunction*> loss_function(foe.NumFilters()); 1080ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong std::vector<ceres::CostFunction*> cost_function(foe.NumFilters()); 1090ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int alpha_index = 0; alpha_index < foe.NumFilters(); ++alpha_index) { 1100ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong loss_function[alpha_index] = foe.NewLossFunction(alpha_index); 1110ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong cost_function[alpha_index] = foe.NewCostFunction(alpha_index); 1120ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 1130ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 1140ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // Add FoE regularization for each patch in the image. 1150ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int x = 0; x < image.width() - (foe.Size() - 1); ++x) { 1160ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int y = 0; y < image.height() - (foe.Size() - 1); ++y) { 1170ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // Build a vector with the pixel indices of this patch. 1180ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong std::vector<double*> pixels; 1190ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong const std::vector<int>& x_delta_indices = foe.GetXDeltaIndices(); 1200ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong const std::vector<int>& y_delta_indices = foe.GetYDeltaIndices(); 1210ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int i = 0; i < foe.NumVariables(); ++i) { 1220ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double* pixel = solution->MutablePixel(x + x_delta_indices[i], 1230ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong y + y_delta_indices[i]); 1240ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong pixels.push_back(pixel); 1250ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 1260ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // For this patch with coordinates (x, y), we will add foe.NumFilters() 1270ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // terms to the objective function. 1280ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int alpha_index = 0; alpha_index < foe.NumFilters(); ++alpha_index) { 1290ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong problem->AddResidualBlock(cost_function[alpha_index], 1300ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong loss_function[alpha_index], 1310ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong pixels); 1320ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 1330ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 1340ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 1350ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong} 1360ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 1370ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Solves the FoE problem using Ceres and post-processes it to make sure the 1380ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// solution stays within [0, 255]. 1390ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kongvoid SolveProblem(Problem* problem, PGMImage<double>* solution) { 1400ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // These parameters may be experimented with. For example, ceres::DOGLEG tends 1410ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // to be faster for 2x2 filters, but gives solutions with slightly higher 1420ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // objective function value. 1430ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong ceres::Solver::Options options; 1440ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong options.max_num_iterations = 100; 1450ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong if (FLAGS_verbose) { 1460ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong options.minimizer_progress_to_stdout = true; 1470ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 1481d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling 1491d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling if (FLAGS_line_search) { 1501d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling options.minimizer_type = ceres::LINE_SEARCH; 1511d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling } 1521d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling 1530ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong options.linear_solver_type = ceres::SPARSE_NORMAL_CHOLESKY; 1540ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong options.function_tolerance = 1e-3; // Enough for denoising. 1550ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 1560ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong ceres::Solver::Summary summary; 1570ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong ceres::Solve(options, problem, &summary); 1580ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong if (FLAGS_verbose) { 1590ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong std::cout << summary.FullReport() << "\n"; 1600ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 1610ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 1620ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // Make the solution stay in [0, 255]. 1630ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int x = 0; x < solution->width(); ++x) { 1640ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int y = 0; y < solution->height(); ++y) { 1650ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong *solution->MutablePixel(x, y) = 1660ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong std::min(255.0, std::max(0.0, solution->Pixel(x, y))); 1670ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 1680ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 1690ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong} 1700ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong} // namespace examples 1710ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong} // namespace ceres 1720ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 1730ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kongint main(int argc, char** argv) { 1740ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong using namespace ceres::examples; 1750ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong std::string 1760ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong usage("This program denoises an image using Ceres. Sample usage:\n"); 1770ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong usage += argv[0]; 1780ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong usage += " --input=<noisy image PGM file> --foe_file=<FoE file name>"; 1790ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong google::SetUsageMessage(usage); 1800ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong google::ParseCommandLineFlags(&argc, &argv, true); 1810ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong google::InitGoogleLogging(argv[0]); 1820ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 1830ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong if (FLAGS_input.empty()) { 1840ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong std::cerr << "Please provide an image file name.\n"; 1850ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong return 1; 1860ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 1870ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 1880ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong if (FLAGS_foe_file.empty()) { 1890ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong std::cerr << "Please provide a Fields of Experts file name.\n"; 1900ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong return 1; 1910ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 1920ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 1930ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // Load the Fields of Experts filters from file. 1940ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong FieldsOfExperts foe; 1950ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong if (!foe.LoadFromFile(FLAGS_foe_file)) { 1960ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong std::cerr << "Loading \"" << FLAGS_foe_file << "\" failed.\n"; 1970ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong return 2; 1980ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 1990ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 2000ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // Read the images 2010ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong PGMImage<double> image(FLAGS_input); 2020ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong if (image.width() == 0) { 2030ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong std::cerr << "Reading \"" << FLAGS_input << "\" failed.\n"; 2040ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong return 3; 2050ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 2060ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong PGMImage<double> solution(image.width(), image.height()); 2070ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong solution.Set(0.0); 2080ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 2090ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong ceres::Problem problem; 2100ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong CreateProblem(foe, image, &problem, &solution); 2110ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 2120ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong SolveProblem(&problem, &solution); 2130ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 2140ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong if (!FLAGS_output.empty()) { 2150ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong CHECK(solution.WriteToFile(FLAGS_output)) 2160ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong << "Writing \"" << FLAGS_output << "\" failed."; 2170ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 2180ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 2190ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong return 0; 2200ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong} 221