bool MOSEK_SolveWrapper::setup(const LP_Constraints & cstraints) //cstraints <-> constraints
{
  assert(nbParams_ == cstraints.nbParams_);

  MSK_deletetask(&task);

  int NUMVAR = cstraints.constraint_mat_.cols();
  int NUMCON = cstraints.constraint_mat_.rows();
  int NUMANZ = cstraints.constraint_mat_.cols() * cstraints.constraint_mat_.rows(); //DENSE MATRIX

  MSKrescodee r = MSK_RES_OK;
  if ( r==MSK_RES_OK )
  {
    // Create the optimization task.
    r = MSK_maketask(env,NUMCON,NUMVAR,&task);

    // Directs the log task stream to the 'printstr' function.
    if ( r==MSK_RES_OK )
      MSK_linkfunctotaskstream(task,MSK_STREAM_LOG,NULL,printstr);

    // Give MOSEK an estimate of the size of the input data.
    //This is done to increase the speed of inputting data.
    // However, it is optional.
    if (r == MSK_RES_OK)
      r = MSK_putmaxnumvar(task,NUMVAR);

    if (r == MSK_RES_OK)
      r = MSK_putmaxnumcon(task,NUMCON);

    if (r == MSK_RES_OK)
      r = MSK_putmaxnumanz(task,NUMANZ);

    // Append 'NUMCON' empty constraints. The constraints will initially have no bounds.
    if ( r == MSK_RES_OK )
      r = MSK_append(task,MSK_ACC_CON,NUMCON);

    // Append 'NUMVAR' variables. The variables will initially be fixed at zero (x=0).
    if ( r == MSK_RES_OK )
      r = MSK_append(task,MSK_ACC_VAR,NUMVAR);
  }

  this->nbParams_ = NUMVAR;

  if (cstraints.bminimize_) {
    r = MSK_putobjsense(task, MSK_OBJECTIVE_SENSE_MINIMIZE);
  }
  else  {
    r = MSK_putobjsense(task, MSK_OBJECTIVE_SENSE_MAXIMIZE);
  }

  // Optionally add a constant term to the objective.
  if ( r ==MSK_RES_OK )
    r = MSK_putcfix(task,0.0);

  // Add the objective function if any
  if (!cstraints.vec_cost_.empty())  {
    // Set objective
    for (size_t i = 0; i < cstraints.vec_cost_.size(); ++i)
      MSK_putcj(task, i, cstraints.vec_cost_[i]);
  }

  //Add constraint row by row
  const Mat & A = cstraints.constraint_mat_;

  for (int i=0; i<A.rows() && r == MSK_RES_OK; ++i)
  {
    std::vector<int> vec_colno(A.cols(), 0);
    for (int ii=0; ii<A.cols(); ++ii){
      vec_colno[ii] = ii;
    }

    // Insert a row
    Vec temp = A.row(i);
    r = MSK_putavec(task,
                    MSK_ACC_CON,       // Input row of A.
                    MSKidxt (i),       // Variable row index.
                    vec_colno.size(),  // Number of non-zeros in row(i) A.
                    &vec_colno[0],     // Pointer to row indexes of row i.
                    (double*)temp.data());    // Pointer to Values of row i.
  }

  //Add bound on variables:
  if (cstraints.vec_bounds_.size() == 1) {
    for (size_t i = 0; i < NUMVAR; ++i) {
      if (r == MSK_RES_OK)
        r = MSK_putbound(task,
                         MSK_ACC_VAR, // Put bounds on variables.
                         i,           // Index of variable.
                         convertSign(cstraints.vec_sign_[0]),      // Bound key.
                         cstraints.vec_bounds_[0].first,  // Numerical value of lower bound.
                         cstraints.vec_bounds_[0].second); // Numerical value of upper bound.
    }
  }
  else{
    for (size_t i = 0; i < NUMVAR; ++i) {
    // Set the bounds on variable j.
    //    lowerbound <= x_j <= upper bound
      if (r == MSK_RES_OK)
        r = MSK_putbound(task,
                         MSK_ACC_VAR, // Put bounds on variables.
                         i,           // Index of variable.
                         convertSign(cstraints.vec_sign_[i]),      // Bound key.
                         cstraints.vec_bounds_[i].first,  // Numerical value of lower bound.
                         cstraints.vec_bounds_[i].second); // Numerical value of upper bound.
    // in order to add sparse bounds use: MSK_putboundlist
    }
  }

  // Add bounds on constraint
  for (size_t i=0; i<NUMCON && r==MSK_RES_OK; ++i)
  {
    r = MSK_putbound(task,
                     MSK_ACC_CON, // Put bounds on constraints.
                     i,           // Index of constraint.
                     convertSign(cstraints.vec_sign_[i]),      // Bound key.
                     -MSK_INFINITY,  // Numerical value of lower bound.
                     cstraints.constraint_objective_(i)); // Numerical value of upper bound.
  }

  return r == MSK_RES_OK;
}
bool OSI_X_SolverWrapper<SOLVERINTERFACE>::setup(const LP_Constraints & cstraints) //cstraints <-> constraints
{
  bool bOk = true;
  if ( si == NULL )
  {
    return false;
  }
  assert(_nbParams == cstraints._nbParams);

  
  int NUMVAR = cstraints._constraintMat.cols();
  int NUMCON = cstraints._constraintMat.rows();
  int NUMANZ = cstraints._constraintMat.cols() * cstraints._constraintMat.rows(); //DENSE MATRIX
  
  std::vector<double> col_lb(NUMVAR);//the column lower bounds
  std::vector<double> col_ub(NUMVAR);//the column upper bounds
  
  this->_nbParams = NUMVAR;

  if (cstraints._bminimize) 
  {
    si->setObjSense( 1 );
  }
  else  
  {
    si->setObjSense( -1 );
  }

  const Mat & A = cstraints._constraintMat;

  //Equality constraint will be handked by two constraintsdue to the API limitation. 
  size_t nbLine = A.rows() + std::count(cstraints._vec_sign.begin(), cstraints._vec_sign.end(), EQ);
  
  std::vector<double> row_lb(nbLine);//the row lower bounds
  std::vector<double> row_ub(nbLine);//the row upper bounds
  
  CoinPackedMatrix * matrix = new CoinPackedMatrix(false,0,0);
  matrix->setDimensions(0, NUMVAR);

  
  //-- Add row-wise constraint
  size_t indexRow = 0;
  for (int i=0; i < A.rows(); ++i) 
  {
    Vec temp = A.row(i);
    
    CoinPackedVector row;
    if ( cstraints._vec_sign[i] == EQ || cstraints._vec_sign[i] == LE )
    {
      int coef = 1;
      for ( int j = 0; j < A.cols() ; j++ )
      {
	row.insert(j, coef * temp.data()[j]);
      }
      row_lb[indexRow] = -1.0 * si->getInfinity();
      row_ub[indexRow] = coef * cstraints._Cst_objective(i);
      matrix->appendRow(row);
      indexRow++;
    }
    if ( cstraints._vec_sign[i] == EQ || cstraints._vec_sign[i] == GE )
    {
      int coef = -1;
      for ( int j = 0; j < A.cols() ; j++ )
      {
	      row.insert(j, coef * temp.data()[j]);
      }
      row_lb[indexRow] = -1.0 * si->getInfinity();
      row_ub[indexRow] = coef * cstraints._Cst_objective(i);
      matrix->appendRow(row);      
      indexRow++;
    }
  }
  
  //-- Setup bounds
  if (cstraints._vec_bounds.size() == 1) 
  {
    // Setup the same bound for all the parameter
    for (int i=0; i < this->_nbParams; ++i)
    {
      col_lb[i] = cstraints._vec_bounds[0].first;
      col_ub[i] = cstraints._vec_bounds[0].second;
    }
  }
  else  
  {

    for (int i=0; i < this->_nbParams; ++i)
    {      
      col_lb[i] = cstraints._vec_bounds[i].first;
      col_ub[i] = cstraints._vec_bounds[i].second;
    }
  }  
 
  si->loadProblem(*matrix, &col_lb[0], &col_ub[0], cstraints._vec_cost.empty() ? NULL : &cstraints._vec_cost[0], &row_lb[0], &row_ub[0] );
  
  delete matrix;
  
  return bOk;
}
예제 #3
0
bool OSI_X_SolverWrapper::setup(const LP_Constraints & cstraints) //cstraints <-> constraints
{
  if ( si == nullptr )
  {
    return false;
  }
  assert(nbParams_ == cstraints.nbParams_);

  const unsigned int NUMVAR = cstraints.constraint_mat_.cols();
  std::vector<double>
    col_lb(NUMVAR), // the column lower bounds
    col_ub(NUMVAR); // the column upper bounds

  this->nbParams_ = NUMVAR;

  si->setObjSense( ((cstraints.bminimize_) ? 1 : -1) );

  const Mat & A = cstraints.constraint_mat_;

  //Equality constraint will be done by two constraints due to the API limitation ( >= & <=).
  const size_t nbLine = A.rows() +
    std::count(cstraints.vec_sign_.begin(), cstraints.vec_sign_.end(), LP_Constraints::LP_EQUAL);

  // Define default lower and upper bound to [-inf, inf]
  std::vector<double>
    row_lb(nbLine, -si->getInfinity()), // the row lower bounds
    row_ub(nbLine, si->getInfinity()); // the row upper bounds

  std::unique_ptr<CoinPackedMatrix> matrix(new CoinPackedMatrix(false,0,0));
  matrix->setDimensions(0, NUMVAR);

  //-- Add row-wise constraint
  size_t indexRow = 0;
  for (int i=0; i < A.rows(); ++i)
  {
    const Vec temp = A.row(i);
    CoinPackedVector row;

    if (cstraints.vec_sign_[i] == LP_Constraints::LP_EQUAL ||
        cstraints.vec_sign_[i] == LP_Constraints::LP_LESS_OR_EQUAL)
    {
      const int coef = 1;
      for ( int j = 0; j < A.cols(); ++j )
      {
        row.insert(j, coef * temp.data()[j]);
      }
      row_ub[indexRow] = coef * cstraints.constraint_objective_(i);
      matrix->appendRow(row);
      ++indexRow;
    }

    if (cstraints.vec_sign_[i] == LP_Constraints::LP_EQUAL ||
        cstraints.vec_sign_[i] == LP_Constraints::LP_GREATER_OR_EQUAL)
    {
      const int coef = -1;
      for ( int j = 0; j < A.cols(); ++j )
      {
        row.insert(j, coef * temp.data()[j]);
      }
      row_ub[indexRow] = coef * cstraints.constraint_objective_(i);
      matrix->appendRow(row);
      ++indexRow;
    }
  }

  //-- Setup bounds for all the parameters
  if (cstraints.vec_bounds_.size() == 1)
  {
    // Setup the same bound for all the parameters
    std::fill(col_lb.begin(), col_lb.end(), cstraints.vec_bounds_[0].first);
    std::fill(col_ub.begin(), col_ub.end(), cstraints.vec_bounds_[0].second);
  }
  else // each parameter have its own bounds
  {
    for (int i=0; i < this->nbParams_; ++i)
    {
      col_lb[i] = cstraints.vec_bounds_[i].first;
      col_ub[i] = cstraints.vec_bounds_[i].second;
    }
  }

  si->loadProblem(*matrix, &col_lb[0], &col_ub[0], cstraints.vec_cost_.empty() ? nullptr : &cstraints.vec_cost_[0], &row_lb[0], &row_ub[0] );

  return true;
}
int main(int argc, char **argv)
{
    enum
    {
        ROBUST_RIGID_REGISTRATION = 0,
        RIGID_REGISTRATION_ALL_POINTS = 1
    };
    std::string
    sSfM_Data_Filename_In,
    sSfM_Data_Filename_Out;
    unsigned int rigid_registration_method = RIGID_REGISTRATION_ALL_POINTS;

    CmdLine cmd;
    cmd.add(make_option('i', sSfM_Data_Filename_In, "input_file"));
    cmd.add(make_option('o', sSfM_Data_Filename_Out, "output_file"));
    cmd.add(make_option('m', rigid_registration_method, "method"));

    try
    {
        if (argc == 1) throw std::string("Invalid command line parameter.");
        cmd.process(argc, argv);
    }
    catch(const std::string& s)
    {
        std::cerr
                << "Usage: " << argv[0] << '\n'
                << " GPS registration of a SfM Data scene,\n"
                << "[-i|--input_file] path to the input SfM_Data scene\n"
                << "[-o|--output_file] path to the output SfM_Data scene\n"
                << "[-m|--method] method to use for the rigid registration\n"
                << "\t0 => registration is done using a robust estimation,\n"
                << "\t1 (default)=> registration is done using all points.\n"
                << std::endl;

        std::cerr << s << std::endl;
        return EXIT_FAILURE;
    }

    if (sSfM_Data_Filename_In.empty() || sSfM_Data_Filename_Out.empty())
    {
        std::cerr << "Invalid input or output filename." << std::endl;
        return EXIT_FAILURE;
    }

    //
    // Load a SfM scene
    // For each valid view (pose & intrinsic defined)
    //  - iff a GPS position can be parsed
    //    - store corresponding camera pose & GPS position
    // - Compute the registration between the selected camera poses & GPS positions

    // Load input SfM_Data scene
    SfM_Data sfm_data;
    if (!Load(sfm_data, sSfM_Data_Filename_In, ESfM_Data(ALL)))
    {
        std::cerr
                << "\nThe input SfM_Data file \"" << sSfM_Data_Filename_In
                << "\" cannot be read." << std::endl;
        return EXIT_FAILURE;
    }

    // Init the EXIF reader (will be used for GPS data reading)
    std::unique_ptr<Exif_IO> exifReader(new Exif_IO_EasyExif);
    if (!exifReader)
    {
        std::cerr << "Cannot instantiate the EXIF metadata reader." << std::endl;
        return EXIT_FAILURE;
    }

    // List corresponding poses (SfM - GPS)
    std::vector<Vec3> vec_sfm_center, vec_gps_center;

    for (const auto & view_it : sfm_data.GetViews() )
    {
        if (!sfm_data.IsPoseAndIntrinsicDefined(view_it.second.get()))
            continue;

        const std::string view_filename =
            stlplus::create_filespec(sfm_data.s_root_path, view_it.second->s_Img_path);

        // Try to parse EXIF metada & check existence of EXIF data
        if (! (exifReader->open( view_filename ) &&
                exifReader->doesHaveExifInfo()) )
            continue;

        // Check existence of GPS coordinates
        double latitude, longitude, altitude;
        if ( exifReader->GPSLatitude( &latitude ) &&
                exifReader->GPSLongitude( &longitude ) &&
                exifReader->GPSAltitude( &altitude ) )
        {
            // Add ECEF XYZ position to the GPS position array
            vec_gps_center.push_back( lla_to_ecef( latitude, longitude, altitude ) );
            const openMVG::geometry::Pose3 pose(sfm_data.GetPoseOrDie(view_it.second.get()));
            vec_sfm_center.push_back( pose.center() );
        }
    }

    if ( vec_sfm_center.empty() )
    {
        std::cerr << "No valid corresponding GPS data found for the used views." << std::endl;
        return EXIT_FAILURE;
    }

    std::cout << std::endl
              << "Registration report:\n"
              << " #corresponding SFM - GPS data: " << vec_sfm_center.size() << "\n"
              << std::endl;

    // Export the corresponding poses (for debugging & see the transformation)
    plyHelper::exportToPly( vec_gps_center,
                            stlplus::create_filespec(stlplus::folder_part(sSfM_Data_Filename_Out), "GPS_position", "ply"));
    plyHelper::exportToPly( vec_sfm_center,
                            stlplus::create_filespec(stlplus::folder_part(sSfM_Data_Filename_Out), "SFM_position", "ply"));

    {
        // Convert positions to the appropriate data container
        const Mat X_SfM = Eigen::Map<Mat>(vec_sfm_center[0].data(), 3, vec_sfm_center.size());
        const Mat X_GPS = Eigen::Map<Mat>(vec_gps_center[0].data(), 3, vec_gps_center.size());

        openMVG::geometry::Similarity3 sim;

        // Compute the registration:
        // - using a rigid scheme (using all points)
        // - using a robust scheme (using partial points - robust estimation)
        switch (rigid_registration_method)
        {
        case ROBUST_RIGID_REGISTRATION:
        {
            using namespace openMVG::robust;
            using namespace openMVG::geometry;

            geometry::kernel::Similarity3_Kernel kernel(X_SfM, X_GPS);
            const double lmeds_median = LeastMedianOfSquares
                                        (
                                            kernel,
                                            &sim
                                        );
            std::cout << "LMeds found a model with an upper bound of: " <<  sqrt(lmeds_median) << " user units."<< std::endl;

            // Compute & display fitting errors
            {
                const Vec vec_fitting_errors_eigen(
                    geometry::kernel::Similarity3ErrorSquaredMetric::ErrorVec(sim, X_SfM, X_GPS).array().sqrt());
                std::cout << "\n3D Similarity fitting error using all points (in target coordinate system units):";
                minMaxMeanMedian<float>(
                    vec_fitting_errors_eigen.data(),
                    vec_fitting_errors_eigen.data() + vec_fitting_errors_eigen.rows() );
            }
            // INLIERS only
            {
                std::vector<float> vec_fitting_errors;
                for (Mat::Index i = 0; i < X_SfM.cols(); ++i)
                {
                    if (geometry::kernel::Similarity3ErrorSquaredMetric::Error(sim, X_SfM.col(i), X_GPS.col(i)) < lmeds_median)
                        vec_fitting_errors.push_back((X_GPS.col(i) - sim(X_SfM.col(i))).norm());
                }
                std::cout << "\nFound: " << vec_fitting_errors.size() << " inliers"
                          << " from " << X_SfM.cols() << " points." << std::endl;
                std::cout << "\n3D Similarity fitting error using only the fitted inliers (in target coordinate system units):";
                minMaxMeanMedian<float>( vec_fitting_errors.begin(), vec_fitting_errors.end() );
            }
        }
        break;
        case RIGID_REGISTRATION_ALL_POINTS:
        {
            Vec3 t;
            Mat3 R;
            double S;
            if (!openMVG::geometry::FindRTS(X_SfM, X_GPS, &S, &t, &R))
            {
                std::cerr << "Failed to comute the registration" << std::endl;
                return EXIT_FAILURE;
            }

            std::cout
                    << "Found transform:\n"
                    << " scale: " << S << "\n"
                    << " rotation:\n" << R << "\n"
                    << " translation: " << std::fixed << std::setprecision(9)
                    << t.transpose() << std::endl;

            // Encode the transformation as a 3D Similarity transformation matrix // S * R * X + t
            sim = openMVG::geometry::Similarity3(geometry::Pose3(R, -R.transpose()* t/S), S);

            // Compute & display fitting errors
            {
                const Vec vec_fitting_errors_eigen(
                    geometry::kernel::Similarity3ErrorSquaredMetric::ErrorVec(sim, X_SfM, X_GPS).array().sqrt());
                std::cout << "\n3D Similarity fitting error (in target coordinate system units):";
                minMaxMeanMedian<float>(
                    vec_fitting_errors_eigen.data(),
                    vec_fitting_errors_eigen.data() + vec_fitting_errors_eigen.rows() );
            }
        }
        break;
        default:
            std::cerr << "Unknow rigid registration method" << std::endl;
            return EXIT_FAILURE;
        }

        //--
        // Apply the found transformation to the SfM Data Scene
        //--
        openMVG::sfm::ApplySimilarity(sim, sfm_data);
    }

    // Export the SfM_Data scene in the expected format
    if (Save(
                sfm_data,
                sSfM_Data_Filename_Out.c_str(),
                ESfM_Data(ALL)))
    {
        return EXIT_SUCCESS;
    }
    else
    {
        std::cerr
                << std::endl
                << "An error occured while trying to save \""
                << sSfM_Data_Filename_Out << "\"." << std::endl;
        return EXIT_FAILURE;
    }
    return EXIT_FAILURE;
}