#include #include #include #include #include #include "sample_common.h" static const std::string keys = "{ @left_img | | path to input left image }" "{ @right_img | | path to input right image }" "{ disp_size | 256 | maximum possible disparity value }" "{ P1 | 10 | penalty on the disparity change by plus or minus 1 between neighbor pixels }" "{ P2 | 120 | penalty on the disparity change by more than 1 between neighbor pixels }" "{ uniqueness | 0.80 | margin in ratio by which the best cost function value should be at least second one }" "{ num_paths | 8 | number of scanlines used in cost aggregation }" "{ min_disp | -160 | minimum disparity value }" "{ LR_max_diff | 1 | maximum allowed difference between left and right disparity }" "{ census_type | 1 | type of census transform (0:CENSUS_9x7 1:SYMMETRIC_CENSUS_9x7) }" "{ output_dir | . | directory to save disparity.xml and disparity_color.png }" "{ no_display | 0 | set to 1 to skip interactive display window (for pipeline/headless use) }" "{ help h | | display this help and exit }"; int main(int argc, char* argv[]) { double start_time = cv::getTickCount(); // Start total execution time cv::CommandLineParser parser(argc, argv, keys); if (parser.has("help")) { parser.printMessage(); return 0; } double load_start = cv::getTickCount(); // Start loading time cv::Mat I1 = cv::imread(parser.get("@left_img"), cv::IMREAD_UNCHANGED); cv::Mat I2 = cv::imread(parser.get("@right_img"), cv::IMREAD_UNCHANGED); double load_end = cv::getTickCount(); double load_time_s = (load_end - load_start) / cv::getTickFrequency(); // Seconds double load_time_ms = load_time_s * 1000.0; // Milliseconds std::cout << "Image Loading Time: " << load_time_s << " s (" << load_time_ms << " ms)" << std::endl; if (I1.channels() > 1) cv::cvtColor(I1, I1, cv::COLOR_BGR2GRAY); if (I2.channels() > 1) cv::cvtColor(I2, I2, cv::COLOR_BGR2GRAY); const int disp_size = parser.get("disp_size"); const int P1 = parser.get("P1"); const int P2 = parser.get("P2"); const float uniqueness = parser.get("uniqueness"); const int num_paths = parser.get("num_paths"); const int min_disp = parser.get("min_disp"); const int LR_max_diff = parser.get("LR_max_diff"); const auto census_type = static_cast(parser.get("census_type")); if (!parser.check()) { parser.printErrors(); parser.printMessage(); std::exit(EXIT_FAILURE); } ASSERT_MSG(!I1.empty() && !I2.empty(), "imread failed."); ASSERT_MSG(I1.size() == I2.size() && I1.type() == I2.type(), "input images must be same size and type."); ASSERT_MSG(I1.type() == CV_8U || I1.type() == CV_16U, "input image format must be CV_8U or CV_16U."); ASSERT_MSG(disp_size == 64 || disp_size == 128 || disp_size == 256, "disparity size must be 64, 128 or 256."); ASSERT_MSG(num_paths == 4 || num_paths == 8, "number of scanlines must be 4 or 8."); ASSERT_MSG(census_type == sgm::CensusType::CENSUS_9x7 || census_type == sgm::CensusType::SYMMETRIC_CENSUS_9x7, "census type must be 0 or 1."); const int src_depth = I1.type() == CV_8U ? 8 : 16; const int dst_depth = 16; const sgm::PathType path_type = num_paths == 8 ? sgm::PathType::SCAN_8PATH : sgm::PathType::SCAN_4PATH; const sgm::StereoSGM::Parameters param(P1, P2, uniqueness, false, path_type, min_disp, LR_max_diff, census_type); sgm::StereoSGM ssgm(I1.cols, I1.rows, disp_size, src_depth, dst_depth, sgm::EXECUTE_INOUT_HOST2HOST, param); cv::Mat disparity(I1.size(), CV_16S); double disparity_start = cv::getTickCount(); // Start disparity computation time ssgm.execute(I1.data, I2.data, disparity.data); double disparity_end = cv::getTickCount(); double disparity_time_s = (disparity_end - disparity_start) / cv::getTickFrequency(); // Seconds double disparity_time_ms = disparity_time_s * 1000.0; // Milliseconds std::cout << "Disparity Computation Time: " << disparity_time_s << " s (" << disparity_time_ms << " ms)" << std::endl; const std::string output_dir = parser.get("output_dir"); // Save disparity cv::FileStorage fs(output_dir + "/disparity.xml", cv::FileStorage::WRITE); fs << "disparity" << disparity; fs.release(); // Convert disparity to 8-bit for visualization cv::Mat disparity_8u, disparity_color; disparity.convertTo(disparity_8u, CV_8U, 255.0 / disp_size); cv::applyColorMap(disparity_8u, disparity_color, cv::COLORMAP_TURBO); // Save colored disparity image cv::imwrite(output_dir + "/disparity_color.png", disparity_color); double total_end = cv::getTickCount(); double total_time_s = (total_end - start_time) / cv::getTickFrequency(); // Seconds double total_time_ms = total_time_s * 1000.0; // Milliseconds std::cout << "Total Execution Time: " << total_time_s << " s (" << total_time_ms << " ms)" << std::endl; // Display images const std::vector images = { disparity_8u, disparity_color, I1 }; const std::vector titles = { "Disparity", "Colored Disparity", "Input Image" }; if (!parser.get("no_display")) { std::cout << "Hot keys:\n"; std::cout << "\tESC - Quit the program\n"; std::cout << "\ts - Switch display (Disparity | Colored Disparity | Input Image)\n"; int mode = 0; while (true) { cv::setWindowTitle("Image", titles[mode]); cv::imshow("Image", images[mode]); const char c = cv::waitKey(0); if (c == 's') mode = (mode < 2 ? mode + 1 : 0); if (c == 27) break; } } return 0; }