~sotirisp/parallaxis

e5bd96598b2e75a18b16881c840d94be0b7b8a91 — Sotiris Papatheodorou 1 year, 6 months ago 0bbd059 master
Change the max column to 100
5 files changed, 75 insertions(+), 106 deletions(-)

M .editorconfig
M include/parallaxis.hpp
M include/strnatcmp.hpp
M src/parallaxis.cpp
M src/parallaxis_main.cpp
M .editorconfig => .editorconfig +1 -1
@@ 12,7 12,7 @@ end_of_line = lf
charset = utf-8
insert_final_newline = true
trim_trailing_whitespace = true
max_line_length = 80
max_line_length = 100

[*.{c,h,cpp,hpp,md}]
indent_style = space

M include/parallaxis.hpp => include/parallaxis.hpp +14 -21
@@ 22,10 22,9 @@
#define PARALLAXIS_VERSION_MINOR "0"
#define PARALLAXIS_VERSION_PATCH "1"
#define LICENSE_SHORT_TEXT "\nCopyright (C) 2020  Sotiris Papatheodorou\n" \
		"License GPLv3+: GNU GPL version 3 or later " \
		"<http://gnu.org/licenses/gpl.html>.\n" \
		"This is free software: you are free to change and redistribute it.\n" \
		"There is NO WARRANTY, to the extent permitted by law.\n"
        "License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.\n" \
        "This is free software: you are free to change and redistribute it.\n" \
        "There is NO WARRANTY, to the extent permitted by law.\n"





@@ 55,43 54,37 @@ void print_image_info(const cv::Mat& image, const std::string& name);



/** Load the file in the filenames vector corresponding to the index. If it
 * can't be loaded it is removed from the vector, index is incremented and the
 * process is repeated until a file is opened successfully. If not file could
 * be opened exit() is called.
/** Load the file in the filenames vector corresponding to the index. If it can't be loaded it is
 * removed from the vector, index is incremented and the process is repeated until a file is opened
 * successfully. If not file could be opened exit() is called.
 */
cv::Mat load_image(std::vector<stdfs::path>& filenames, size_t& index);



/** Compute the minimum and maximum values for all grayscale images for use with
 * common normalization. All images in options are opened in the process. The
 * computation is only performed if options.global_min > options.global_max.
/** Compute the minimum and maximum values for all grayscale images for use with common
 * normalization. All images in options are opened in the process. The computation is only performed
 * if options.global_min > options.global_max.
 */
void compute_common_normalization(Options& options);



/** Perform all operations enabled in the options on the input image and return
 * the resulting image.
/** Perform all operations enabled in the options on the input image and return the resulting image.
 */
cv::Mat process_depth_image(const cv::Mat& input_image, const Options& options);



/** Given a path to a directory return a naturally sorted list of the files it
 * contains.
/** Given a path to a directory return a naturally sorted list of the files it contains.
 */
std::vector<stdfs::path> ls_directory(const stdfs::path& dir,
                                      const bool         recursive);
std::vector<stdfs::path> ls_directory(const stdfs::path& dir, const bool recursive);



/** Given a path return the file it refers to or the files it contains if it is
 * a directory.
/** Given a path return the file it refers to or the files it contains if it is a directory.
 */
std::vector<stdfs::path> ls_path(const stdfs::path& path,
                                 const bool         recursive);
std::vector<stdfs::path> ls_path(const stdfs::path& path, const bool recursive);




M include/strnatcmp.hpp => include/strnatcmp.hpp +6 -7
@@ 39,9 39,9 @@ inline char nat_toupper(const char a) {
inline int compare_right(const char* a, const char* b) {
    int bias = 0;

    // The longest run of digits wins. That aside, the greatest value wins, but
    // we can't know that it will until we've scanned both numbers to know that
    // they have the same magnitude, so we remember it in BIAS.
    // The longest run of digits wins. That aside, the greatest value wins, but we can't know that
    // it will until we've scanned both numbers to know that they have the same magnitude, so we
    // remember it in BIAS.
    for (;; a++, b++) {
        if (not nat_isdigit(*a) and not nat_isdigit(*b)) {
            return bias;


@@ 70,8 70,7 @@ inline int compare_right(const char* a, const char* b) {


inline int compare_left(const char* a, const char* b) {
    // Compare two left-aligned numbers: the first to have a different value
    // wins.
    // Compare two left-aligned numbers: the first to have a different value wins.
    for (;; a++, b++) {
        if (not nat_isdigit(*a) and not nat_isdigit(*b))
            return 0;


@@ 124,8 123,8 @@ inline int strnatcmp0(const char* a, const char* b, int fold_case) {
        }

        if (not ca and not cb) {
            // The strings compare the same. Perhaps the caller will want to
            // call strcmp to break the tie.
            // The strings compare the same. Perhaps the caller will want to call strcmp to break
            // the tie.
            return 0;
        }


M src/parallaxis.cpp => src/parallaxis.cpp +51 -71
@@ 13,27 13,17 @@


std::ostream& operator<<(std::ostream& os, const Options& options) {
    os << "  invert colors:          "
        << (options.invert_colors ? "YES" : "NO") << "\n"
        << "  only grayscale:         "
        << (options.only_grayscale ? "YES" : "NO") << "\n"
        << "  normalize:              "
        << (options.enable_normalization ? "YES" : "NO") << "\n"
        << "  common normalization:   "
        << (options.common_normalization ? "YES" : "NO") << "\n"
        << "  recursive:              "
        << (options.recursive ? "YES" : "NO") << "\n"
        << "  use colormap:           "
        << (options.enable_colormap ? "YES" : "NO") << "\n"
        << "  colormap name:          "
        << std::to_string(options.colormap) << "\n"
    os  << "  invert colors:          " << (options.invert_colors ? "YES" : "NO") << "\n"
        << "  only grayscale:         " << (options.only_grayscale ? "YES" : "NO") << "\n"
        << "  normalize:              " << (options.enable_normalization ? "YES" : "NO") << "\n"
        << "  common normalization:   " << (options.common_normalization ? "YES" : "NO") << "\n"
        << "  recursive:              " << (options.recursive ? "YES" : "NO") << "\n"
        << "  use colormap:           " << (options.enable_colormap ? "YES" : "NO") << "\n"
        << "  colormap name:          " << std::to_string(options.colormap) << "\n"
        << "  global min and max:     "
        << std::to_string(options.global_min) << " - "
        << std::to_string(options.global_max) << "\n"
        << "  verbosity level:        "
        << std::to_string(options.verbose) << "\n"
        << "  number of input files:  "
        << options.input_files.size() << "\n";
        << std::to_string(options.global_min) << " - " << std::to_string(options.global_max) << "\n"
        << "  verbosity level:        " << std::to_string(options.verbose) << "\n"
        << "  number of input files:  " << options.input_files.size() << "\n";
    return os;
}



@@ 54,8 44,7 @@ cv::Mat load_image(std::vector<stdfs::path>& filenames, size_t& index) {
    while (not filenames.empty()) {
        const std::string image_name (filenames[index]);
        cv::Mat image;
        // Looks like cv::imread crashes when trying to read files smaller than
        // 140 B.
        // Looks like cv::imread crashes when trying to read files smaller than 140 B.
        if (stdfs::file_size(image_name) >= 140) {
            image = cv::imread(image_name.c_str(), cv::IMREAD_UNCHANGED);
        }


@@ 65,13 54,11 @@ cv::Mat load_image(std::vector<stdfs::path>& filenames, size_t& index) {
        } else {
            if (filenames.size() == 1) {
                // No files left to try, exit.
                std::cerr << "Error: could not read file " << image_name
                        << " as image\n";
                std::cerr << "Error: could not read file " << image_name << " as image\n";
                exit(EXIT_FAILURE);
            } else {
                // Invalid file, remove from the file list.
                std::cerr << "Warning: could not read file " << image_name
                        << " as image, skipping\n";
                std::cerr << "Warning: could not read file " << image_name << " as image, skipping\n";
                filenames.erase(filenames.begin() + index);
                // Wrap the index back to the beginning if needed.
                if (index >= filenames.size()) {


@@ 126,8 113,7 @@ cv::Mat process_depth_image(const cv::Mat& input_image, const Options& options) 
        // Use a mask to only invert valid depth measurements.
        cv::Mat valid_depth_mask;
        image.convertTo(valid_depth_mask, CV_8U, 1.0/UINT8_MAX);
        cv::threshold(valid_depth_mask, valid_depth_mask,
                0, UINT8_MAX, cv::THRESH_BINARY);
        cv::threshold(valid_depth_mask, valid_depth_mask, 0, UINT8_MAX, cv::THRESH_BINARY);
        cv::bitwise_not(image, image, valid_depth_mask);
    }



@@ 139,12 125,10 @@ cv::Mat process_depth_image(const cv::Mat& input_image, const Options& options) 
        cv::Mat image_c;
        cv::applyColorMap(image_8u, image_c, options.colormap);

        // Set invalid depth measurements to black. Create a mask by
        // converting the depth image into a binary image and inverting
        // it.
        // Set invalid depth measurements to black. Create a mask by converting the depth image into
        // a binary image and inverting it.
        cv::Mat invalid_depth_mask;
        cv::threshold(image_8u, invalid_depth_mask,
                0, UINT8_MAX, cv::THRESH_BINARY_INV);
        cv::threshold(image_8u, invalid_depth_mask, 0, UINT8_MAX, cv::THRESH_BINARY_INV);
        image_c.setTo(cv::Scalar(0, 0, 0), invalid_depth_mask);

        image_c.copyTo(image);


@@ 155,8 139,7 @@ cv::Mat process_depth_image(const cv::Mat& input_image, const Options& options) 



std::vector<stdfs::path> ls_directory(const stdfs::path& dir,
                                      const bool         recursive) {
std::vector<stdfs::path> ls_directory(const stdfs::path& dir, const bool recursive) {

    std::vector<stdfs::path> files;



@@ 181,8 164,7 @@ std::vector<stdfs::path> ls_directory(const stdfs::path& dir,

                // Symlink to directory
                } else if (stdfs::is_directory(pp) and recursive) {
                    std::vector<stdfs::path> f
                            = ls_directory(pp, recursive);
                    std::vector<stdfs::path> f = ls_directory(pp, recursive);
                    files.insert(files.end(), f.begin(), f.end());
                }
            }


@@ 196,8 178,7 @@ std::vector<stdfs::path> ls_directory(const stdfs::path& dir,



std::vector<stdfs::path> ls_path(const stdfs::path& path,
                                 const bool         recursive) {
std::vector<stdfs::path> ls_path(const stdfs::path& path, const bool recursive) {

    std::vector<stdfs::path> processed_path;



@@ 301,7 282,8 @@ static error_t argp_parser(int key, char* arg, struct argp_state* state) {
            std::cout << "parallaxis "
                    PARALLAXIS_VERSION_MAJOR "."
                    PARALLAXIS_VERSION_MINOR "."
                    PARALLAXIS_VERSION_PATCH LICENSE_SHORT_TEXT;
                    PARALLAXIS_VERSION_PATCH
                    LICENSE_SHORT_TEXT;
        exit(EXIT_SUCCESS);

        case ARGP_KEY_ARG:


@@ 309,16 291,14 @@ static error_t argp_parser(int key, char* arg, struct argp_state* state) {
            break;

        case ARGP_KEY_END:
            // If no files/directories were provided, open the current
            // directory.
            // If no files/directories were provided, open the current directory.
            if (state->arg_num == 0) {
                paths.push_back(".");
            }
            // Collect the input files.
            for (const auto& p : paths) {
                const stdfs::path path (p);
                const std::vector<stdfs::path> processed_path
                        = ls_path(path, options->recursive);
                const std::vector<stdfs::path> processed_path = ls_path(path, options->recursive);
                options->input_files.insert(options->input_files.end(),
                        processed_path.begin(), processed_path.end());
            }


@@ 359,33 339,33 @@ Options parse_args(int argc, char** argv) {
            "  Quit                         q";
    const char args_doc[] = "[FILE...] [DIRECTORY...]";
    const struct argp_option argp_options[] = {
        {"colormap",             'c', "NAME", 0,
                "The name of the colormap to use. The valid colormap names are"
                " listed in COLORMAPS. (default: jet)"},
        {"invert-colors",        'i', 0,      0,
                "Invert the grayscale image colors."},
        {"only-grayscale",       'g', 0,      0,
                "Only show grayscale images."},
        {"no-normalization",     'n', 0,      0,
                "Do not normalize grayscale images."},
        {"common-normalization", 'N', 0,      0,
                "Stretch the histogram of all the grayscale images by the same"
                " amount instead of stretching it for each image individually."
                " This removes any sudden changes in image intensity when"
                " scrolling through several images. CAUTION: this option will"
                " open all supplied images which can take a long time."},
        {"quiet",                'q', 0,      0,
                "Suppress all error, warning and debug messages."},
        {"recursive",            'r', 0,      0,
                "Recursively traverse all supplied directories and show all"
                " files contained until the bottom level."},
        {"verbose",              'v', 0,      0,
                "Produce more verbose output. Extra occurrences of this"
                " option, up to 4 total, increase the amount of information"
                " shown."},
        {"version",              128, 0,      0,
                "Show version and license information."},
        {0}
            {"colormap",             'c', "NAME", 0,
                    "The name of the colormap to use. The valid colormap names are"
                    " listed in COLORMAPS. (default: jet)"},
            {"invert-colors",        'i', 0,      0,
                    "Invert the grayscale image colors."},
            {"only-grayscale",       'g', 0,      0,
                    "Only show grayscale images."},
            {"no-normalization",     'n', 0,      0,
                    "Do not normalize grayscale images."},
            {"common-normalization", 'N', 0,      0,
                    "Stretch the histogram of all the grayscale images by the same"
                    " amount instead of stretching it for each image individually."
                    " This removes any sudden changes in image intensity when"
                    " scrolling through several images. CAUTION: this option will"
                    " open all supplied images which can take a long time."},
            {"quiet",                'q', 0,      0,
                    "Suppress all error, warning and debug messages."},
            {"recursive",            'r', 0,      0,
                    "Recursively traverse all supplied directories and show all"
                    " files contained until the bottom level."},
            {"verbose",              'v', 0,      0,
                    "Produce more verbose output. Extra occurrences of this"
                    " option, up to 4 total, increase the amount of information"
                    " shown."},
            {"version",              128, 0,      0,
                    "Show version and license information."},
            {0}
    };

    // Parse the command line arguments

M src/parallaxis_main.cpp => src/parallaxis_main.cpp +3 -6
@@ 13,8 13,7 @@
int main(int argc, char** argv) {

    Options options = parse_args(argc, argv);
    cv::namedWindow("parallaxis",
            cv::WINDOW_NORMAL | cv::WINDOW_KEEPRATIO | cv::WINDOW_GUI_EXPANDED);
    cv::namedWindow("parallaxis", cv::WINDOW_NORMAL | cv::WINDOW_KEEPRATIO | cv::WINDOW_GUI_EXPANDED);
    bool quit = false;
    size_t image_index = 0;



@@ 40,8 39,7 @@ int main(int argc, char** argv) {
                    image_index = 0;
                }
                if (options.input_files.empty()) {
                    std::cerr << "Error: got option -g/--only-grayscale "
                            << "but no grayscale images \n";
                    std::cerr << "Error: got option -g/--only-grayscale " << "but no grayscale images \n";
                    exit(EXIT_FAILURE);
                }
                // Load the next image


@@ 60,8 58,7 @@ int main(int argc, char** argv) {


        // Show the image.
        const std::string title = "parallaxis ["
                + std::to_string(image_index + 1) + "/"
        const std::string title = "parallaxis [" + std::to_string(image_index + 1) + "/"
                + std::to_string(options.input_files.size()) + "] " + image_name;
        cv::setWindowTitle("parallaxis", title);
        cv::imshow("parallaxis", image);