Example: kitti_dataset2rawlog

C++ example source code:

/* +------------------------------------------------------------------------+
   |                     Mobile Robot Programming Toolkit (MRPT)            |
   |                          https://www.mrpt.org/                         |
   |                                                                        |
   | Copyright (c) 2005-2024, Individual contributors, see AUTHORS file     |
   | See: https://www.mrpt.org/Authors - All rights reserved.               |
   | Released under BSD License. See: https://www.mrpt.org/License          |
   +------------------------------------------------------------------------+ */

/* ------------------------------------------------------
                  kitti_dataset2rawlog
    A small tool to translate the KITTI datasets and
    the karlsruhe sequences
    http://www.cvlibs.net/datasets/karlsruhe_sequences/

    into MRPT rawlog binary format, ready to be parsed
    by RawLogViewer or user programs.

Usage:
 * Karlsruhe seqs:
        kitti_dataset2rawlog  [PATH_TO_DIR_WITH_IMAGES] [CALIB_FILE]
[OUTPUT_NAME]

 * KITTI seqs:
        kitti_dataset2rawlog  [PATH_TO_IMAGE_00] [PATH_TO_IMAGE_01] [CALIB_FILE]
[OUTPUT_NAME]

Output files:
    - OUTPUT_NAME.rawlog: The output rawlog file.

  ------------------------------------------------------ */

#include <mrpt/img/TCamera.h>
#include <mrpt/io/CFileGZOutputStream.h>
#include <mrpt/io/CTextFileLinesParser.h>
#include <mrpt/obs/CObservationStereoImages.h>
#include <mrpt/serialization/CArchive.h>
#include <mrpt/system/filesystem.h>
#include <mrpt/system/string_utils.h>

#include <iostream>

using namespace std;
using namespace mrpt;
using namespace mrpt::obs;
using namespace mrpt::serialization;

const double STEREO_FPS = 10.0;

void stereo2rawlog(
    bool is_kitti_dataset, const string& src_path0, const string& src_path1,
    const string& calib_file, const string& out_name)
{
    /* Camera params:
    Left (1):
    6.790081e+02 0.000000e+00 6.598034e+02 0.000000e+00
    0.000000e+00 6.790081e+02 1.865724e+02 0.000000e+00
    0.000000e+00 0.000000e+00 1.000000e+00 0.000000e+00

    Right (2):

    6.790081e+02 0.000000e+00 6.598034e+02 -3.887481e+02
    0.000000e+00 6.790081e+02 1.865724e+02 0.000000e+00
    0.000000e+00 0.000000e+00 1.000000e+00 0.000000e+00

    base = 3.887481e+02  / 6.790081e+02 = 0.57252351 m
    */

    // Parse calib file:
    mrpt::math::CMatrixDouble P1_roi, P2_roi;
    bool p1_ok = false, p2_ok = false;

    const string name_P0 = is_kitti_dataset ? "P0:" : "P1_roi:";
    const string name_P1 = is_kitti_dataset ? "P1:" : "P2_roi:";

    std::istringstream ss;
    mrpt::io::CTextFileLinesParser fp;
    fp.open(calib_file);
    while (fp.getNextLine(ss))
    {
        string sStart;
        ss >> sStart;
        if (mrpt::system::strStartsI(sStart, name_P0))
        {
            P1_roi.loadFromTextFile(ss);
            ASSERT_(P1_roi.cols() == 12 && P1_roi.rows() == 1);
            p1_ok = true;
        }
        if (mrpt::system::strStartsI(sStart, name_P1))
        {
            P2_roi.loadFromTextFile(ss);
            ASSERT_(P2_roi.cols() == 12 && P2_roi.rows() == 1);
            p2_ok = true;
        }
    }

    if (!p1_ok || !p2_ok)
        throw std::runtime_error("Couldn't load P*_ROI calib matrices!");

    mrpt::img::TCamera cam_params_l;
    cam_params_l.ncols = 1344;
    cam_params_l.nrows = 391;
    cam_params_l.fx(P2_roi(0, 0));
    cam_params_l.fy(P2_roi(0, 5));
    cam_params_l.cx(P2_roi(0, 2));
    cam_params_l.cy(P2_roi(0, 6));

    mrpt::img::TCamera cam_params_r = cam_params_l;

    // base = -P2_roi(1,4)/P2_roi(1,1)
    const double baseline = -P2_roi(0, 3) / P2_roi(0, 0);
    const mrpt::poses::CPose3DQuat l2r_pose(
        baseline, 0.0, 0.0, mrpt::math::CQuaternionDouble());

    cout << "baseline: " << baseline << endl;

    // Create rawlog file ----------------------------------------------
    const string out_rawlog_fil = out_name + string(".rawlog");
    const string out_imgs_dir = out_name + string("_Images");
    cout << "Creating rawlog: " << out_rawlog_fil << endl;
    mrpt::io::CFileGZOutputStream f_out(out_rawlog_fil);

    if (is_kitti_dataset)
    {
        cout << "Creating imgs dir: " << out_imgs_dir << endl;
        mrpt::system::createDirectory(out_imgs_dir);
    }

    mrpt::system::TTimeStamp tim0 = mrpt::Clock::now();

    // For each image:
    for (int i = 0;; i++)
    {
        string sImgFile_L, sImgFile_R;
        string sImg_L, sImg_R;
        string sTrgImgFile_L, sTrgImgFile_R;
        string sTrgImg_L, sTrgImg_R;  // If !="", will copy the file.

        if (is_kitti_dataset)
        {
            // 0000000000.png
            // 1234567890
            sImgFile_L = mrpt::format("%010i.png", i);
            sImgFile_R = mrpt::format("%010i.png", i);
            sImg_L =
                mrpt::format("%s/%s", src_path0.c_str(), sImgFile_L.c_str());
            sImg_R =
                mrpt::format("%s/%s", src_path1.c_str(), sImgFile_R.c_str());

            sTrgImgFile_L = mrpt::format("I0_%s", sImgFile_L.c_str());
            sTrgImgFile_R = mrpt::format("I1_%s", sImgFile_R.c_str());

            sTrgImg_L = mrpt::format(
                "%s/%s", out_imgs_dir.c_str(), sTrgImgFile_L.c_str());
            sTrgImg_R = mrpt::format(
                "%s/%s", out_imgs_dir.c_str(), sTrgImgFile_R.c_str());
        }
        else
        {
            // I1_000000.png
            // I2_002570.png
            sImgFile_L = mrpt::format("I1_%06i.png", i);
            sImgFile_R = mrpt::format("I2_%06i.png", i);
            sTrgImgFile_L = sImgFile_L;
            sTrgImgFile_R = sImgFile_R;
            sImg_L =
                mrpt::format("%s/%s", src_path0.c_str(), sImgFile_L.c_str());
            sImg_R =
                mrpt::format("%s/%s", src_path0.c_str(), sImgFile_R.c_str());
        }

        if (!mrpt::system::fileExists(sImg_L) ||
            !mrpt::system::fileExists(sImg_R))
        {
            cout << "Couldn't detect image pair " << sImg_L << " | " << sImg_R
                 << "  -> ending.\n";
            break;
        }

        CObservationStereoImages obs;
        obs.timestamp = mrpt::Clock::fromDouble(
            mrpt::Clock::toDouble(tim0) + i / STEREO_FPS);
        obs.cameraPose = mrpt::poses::CPose3DQuat(mrpt::poses::CPose3D(
            0, 0, 0, -90.0_deg, 0.0_deg, DEG2RAD(-90.0 - 4.6)));

        obs.leftCamera = cam_params_l;
        obs.rightCamera = cam_params_r;
        obs.rightCameraPose = l2r_pose;

        obs.imageLeft.setExternalStorage(sTrgImgFile_L);
        obs.imageRight.setExternalStorage(sTrgImgFile_R);

        obs.sensorLabel = "CAMERA1";

        // save:
        archiveFrom(f_out) << obs;

        // Copy img:
        if (is_kitti_dataset)
        {
            if (!mrpt::system::copyFile(sImg_L, sTrgImg_L))
            {
                cerr << "Error copying file: " << sImg_L << " => " << sTrgImg_L
                     << endl;
                return;
            }
            if (!mrpt::system::copyFile(sImg_R, sTrgImg_R))
            {
                cerr << "Error copying file: " << sImg_R << " => " << sTrgImg_R
                     << endl;
                return;
            }
        }

        // cout << "Writing entry #" << i << endl;
    }

    cout << "\nAll done!\n";
}

// ------------------------------------------------------
//                      MAIN
// ------------------------------------------------------
int main(int argc, char** argv)
{
    try
    {
        if (argc != 4 && argc != 5)
        {
            cerr << "Usage:\n"
                    "Karlsruhe seqs:\n"
                    " kitti_dataset2rawlog  [PATH_TO_DIR_WITH_IMAGES] "
                    "[CALIB_FILE] [OUTPUT_NAME]\n"
                    "KITTI seqs:\n"
                    " kitti_dataset2rawlog  [PATH_TO_IMAGE_00] "
                    "[PATH_TO_IMAGE_01] [CALIB_FILE] [OUTPUT_NAME]\n";
            return 1;
        }

        if (argc == 4)
        {
            // "Karlsruhe seqs":
            stereo2rawlog(false, argv[1], "", argv[2], argv[3]);
        }
        else
        {
            // "KITTI":
            stereo2rawlog(true, argv[1], argv[2], argv[3], argv[4]);
        }

        return 0;
    }
    catch (const std::exception& e)
    {
        std::cerr << "MRPT error: " << mrpt::exception_to_str(e) << std::endl;
        return -1;
    }
}