colmap / colmap

COLMAP - Structure-from-Motion and Multi-View Stereo
https://colmap.github.io/
Other
7.53k stars 1.5k forks source link

Passing Opencv::DMatch matches and cv::Keypoints into a database? #2816

Open antithing opened 6 days ago

antithing commented 6 days ago

As above, i have a custom feature and matching step, that converts to Opencv:

std::vector<cv::KeyPoint> kp0;
std::vector<cv::KeyPoint> kp1;
std::vector<cv::DMatch> matches;

I add these to a database like this:

colmap::FeatureKeypoints ConvertKeypointsToCOLMAP(const std::vector<cv::KeyPoint>& keypoints) {
    colmap::FeatureKeypoints colmap_keypoints;
    colmap_keypoints.reserve(keypoints.size());

    // Convert each OpenCV keypoint to COLMAP FeatureKeypoint
    for (const auto& kp : keypoints) {
        colmap::FeatureKeypoint colmap_kp;
        colmap_kp.x = kp.pt.x;       // X-coordinate of the keypoint
        colmap_kp.y = kp.pt.y;       // Y-coordinate of the keypoint      

        // Add the converted keypoint to the vector
        colmap_keypoints.push_back(colmap_kp);
    }

    return colmap_keypoints;
}

colmap::FeatureMatches ConvertMatchesToCOLMAP(const std::vector<cv::DMatch> matches)
{
    colmap::FeatureMatches colmap_matches;

    // Convert each DMatch to COLMAP Match
    for (const auto& match : matches) {
        colmap::FeatureMatch colmap_match;    
        colmap_match.point2D_idx1 = match.queryIdx; // Index in the first image
        colmap_match.point2D_idx2 = match.trainIdx; // Index in the second image

        // Add the converted match to the vector
        colmap_matches.push_back(colmap_match);
    }

    return colmap_matches;
}

void colmapFunctions::CreateEmptyDatabase(const std::string& database_path) {
    // create database
    colmap::Database database(database_path);

}

// Function to add keypoints to the COLMAP database
void colmapFunctions::add_keypoints_to_database(const std::string& database_path,
    const int image_id,
    const std::vector<cv::KeyPoint>& keypoints) {
    // Convert OpenCV keypoints to COLMAP's Eigen::MatrixXf format
    colmap::FeatureKeypoints colmap_keypoints = ConvertKeypointsToCOLMAP(keypoints);

    colmap::Database database;
    database.Open(database_path);

    // Write the keypoints to the database
    database.WriteKeypoints(image_id, colmap_keypoints);

    std::cout << "Added " << keypoints.size() << " keypoints to the database for image ID " << image_id << std::endl;
}

void colmapFunctions::add_matches_to_database(const std::string& database_path,
    const int image_id1,
    const int image_id2,
    const std::vector<cv::DMatch>& matches) {
    colmap::FeatureMatches colmap_matches = ConvertMatchesToCOLMAP(matches);

    colmap::Database database;
    database.Open(database_path);

    // Write the matches to the database
    database.WriteMatches(image_id1, image_id2,colmap_matches);

    std::cout << "Added " << colmap_matches.size() << " matches between images ID " << image_id1 << " and " << image_id2 << std::endl;

    std::cout << database.NumCameras() << "  " << database.NumImages() << " " << database.NumMatchedImagePairs() << std::endl;

}

I also add cameras and images.

void colmapFunctions::import_image(const std::string& image_path,
    const std::string& database_path, cv::Mat K, cv::Mat D, int image_id ) 
{
    std::cout << "Importing image into the database..." << std::endl;

    cv::Mat temp = cv::imread(image_path);

    if (temp.rows == 0)
    {
        return;
    }

    try {
        // Open database connection
        colmap::Database database(database_path);

        // Define camera parameters (you can adjust these to fit your camera_mode)
        colmap::Camera camera;

            // Example: Simple pinhole camera model with manually set parameters
        camera.SetModelIdFromName("OPENCV");
        camera.SetWidth(temp.cols);   // Placeholder width
        camera.SetHeight(temp.rows);  // Placeholder height
        camera.SetParams({ K.at<double>(0,0), K.at<double>(1,1), K.at<double>(0,2), K.at<double>(1,2), D.at<double>(0,0),
    D.at<double>(0,1), D.at<double>(0,2), D.at<double>(0,3) });

        // Add camera to the database
        camera.SetCameraId(database.WriteCamera(camera));

        colmap::Image image;
        image.SetName(image_path);
        image.SetCameraId(camera.CameraId());
        image.SetImageId(image_id);
      //  std::cout << image.Name() << std::endl;
        database.WriteImage(image);           

        std::cout << "Image successfully imported into the database." << std::endl;

        // Close database connection
        database.Close();
    }
    catch (const std::exception& e) {
        std::cerr << "Error importing image: " << e.what() << std::endl;
    }
}

This seems to work well, but when i load the database inside the colmap GUI. it shows no matches, and i cannot view the image (cameras, number of points and images do show in database management)

What am I doing wrong here?

ahojnnes commented 3 days ago

You don't show any code that would write the features and matches into the database?

antithing commented 3 days ago

Ah, indeed. Added now above. Thanks! Does that look correct?

Also, what are all the steps for running a colmap sfm pipeline entirely in c++ code?