text:
/********************************************************************************
* Copyright 2017 DigitalGlobe, Inc.
* Author: Aleksey Vitebskiy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*    http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
********************************************************************************/
#include "CliProcessor.h"

#include <boost/algorithm/string.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/make_shared.hpp>
#include <boost/make_unique.hpp>
#include <boost/range/adaptor/reversed.hpp>
#include <boost/tokenizer.hpp>
#include <classification/Classification.h>
#include <classification/GbdxModelReader.h>
#include <fstream>
#include <geometry/cv_program_options.hpp>
#include <iomanip>
#include <utility/Console.h>
#include <utility/ConsoleProgressDisplay.h>
#include <utility/Memory.h>
#include <utility/program_options.hpp>
#include <vector/FileFeatureSet.h>

namespace dg { namespace osn {

namespace po = boost::program_options;

using namespace deepcore;

using boost::program_options::variables_map;
using boost::program_options::name_with_default;
using boost::adaptors::reverse;
using boost::bad_lexical_cast;
using boost::filesystem::exists;
using boost::filesystem::path;
using boost::iequals;
using boost::join;
using boost::lexical_cast;
using boost::make_unique;
using boost::tokenizer;
using boost::escaped_list_separator;
using boost::to_lower;
using boost::to_lower_copy;
using dg::deepcore::level_t;
using std::cout;
using std::find;
using std::function;
using std::end;
using std::endl;
using std::move;
using std::ofstream;
using std::string;
using std::unique_ptr;
using geometry::GeometryType;
using dg::deepcore::ConsoleProgressDisplay;
using dg::deepcore::ProgressCategory;
using dg::deepcore::classification::GbdxModelReader;
using dg::deepcore::imagery::RasterToPolygonDP;
using dg::deepcore::vector::FileFeatureSet;

static const string OSN_USAGE =
    "Usage:\n"
        "  OpenSpaceNet <options>\n"
        "  OpenSpaceNet --config <configuration file> [other options]\n\n";

CliProcessor::CliProcessor() :
    localOptions_("Local Image Input Options"),
    webOptions_("Web Service Input Options"),
    outputOptions_("Output Options"),
    processingOptions_("Processing Options"),
    detectOptions_("Feature Detection Options"),
    segmentationOptions_("Segmentation Options"),
    filterOptions_("Filtering Options"),
    loggingOptions_("Logging Options"),
    generalOptions_("General Options"),
    supportedFormats_(FileFeatureSet::supportedFormats())
{
    classification::init();

    detectOptions_.add_options()
        ("confidence", po::value<float>()->value_name(name_with_default("PERCENT", osnArgs.confidence)),
         "Minimum percent score for results to be included in the output.")
        ("nms", po::bounded_value<std::vector<float>>()->min_tokens(0)->max_tokens(1)->value_name(name_with_default("PERCENT", osnArgs.overlap)),
         "Perform non-maximum suppression on the output. You can optionally specify the overlap threshold percentage "
         "for non-maximum suppression calculation.")
        ;

    localOptions_.add_options()
        ("image", po::value<string>()->value_name("PATH"),
         "If this is specified, the input will be taken from a local image.")
        ;

    webOptions_.add_options()
        ("service", po::value<string>()->value_name("SERVICE"),
         "Web service that will be the source of input. Valid values are: dgcs, evwhs, maps-api, and tile-json.")
        ("token", po::value<string>()->value_name("TOKEN"),
         "API token used for licensing. This is the connectId for WMTS services or the API key for the Web Maps API.")
        ("credentials", po::value<string>()->value_name("USERNAME[:PASSWORD]"),
         "Credentials for the map service. Not required for Web Maps API, optional for TileJSON. If password is not specified, you will be "
         "prompted to enter it. The credentials can also be set by setting the OSN_CREDENTIALS environment variable.")
        ("url", po::value<string>()->value_name("URL"),
         "TileJSON server URL. This is only required for the tile-json service.")
        ("use-tiles",
         "If set, the \"tiles\" field in TileJSON metadata will be used as the tile service address. The default behavior"
         "is to derive the service address from the provided URL.")
        ("zoom", po::value<int>()->value_name(name_with_default("ZOOM", osnArgs.zoom)), "Zoom level.")
        ("map-id", po::value<string>()->value_name(name_with_default("MAPID", osnArgs.mapId)), "MapsAPI map id to use.")
        ("max-connections", po::value<int>()->value_name(name_with_default("NUM", osnArgs.maxConnections)),
         "Used to speed up downloads by allowing multiple concurrent downloads to happen at once.")
        ;

    string outputDescription = "Output file format for the results. Valid values are: ";
    outputDescription += join(supportedFormats_, ", ") + ".";

    auto formatNotifier = function<void(const string&)>([this](const string& format) {
        DG_CHECK(find(supportedFormats_.begin(), supportedFormats_.end(), to_lower_copy(format)) != end(supportedFormats_),
            "Invalid output format: %s.", format.c_str());
    });

    outputOptions_.add_options()
        ("format", po::value<string>()->value_name(name_with_default("FORMAT", osnArgs.outputFormat))->notifier(formatNotifier),
         outputDescription.c_str())
        ("output", po::value<string>()->value_name("PATH"),
         "Output location with file name and path or URL.")
        ("output-layer", po::value<string>()->value_name(name_with_default("NAME", "osndetects")),
         "The output layer name, index name, or table name.")
        ("type", po::value<string>()->value_name(name_with_default("TYPE", "polygon")),
         "Output geometry type.  Currently only point and polygon are valid.")
        ("producer-info", "Add user name, application name, and application version to the output feature set.")
        ("dgcs-catalog-id", "Add catalog_id property to detected features, by finding the most intersected legacyId from DGCS WFS data source DigitalGlobe:FinishedFeature")
        ("evwhs-catalog-id", "Add catalog_id property to detected features, by finding the most intersected legacyId from EVWHS WFS data source DigitalGlobe:FinishedFeature")
        ("wfs-credentials", po::value<string>()->value_name("USERNAME[:PASSWORD]"),
         "Credentials for the WFS service, if appending legacyId. If not specified, credentials from the credentials option will be used.")
        ("append", "Append to an existing vector set. If the output does not exist, it will be created.")
        ("extra-fields",po::value<std::vector<string> >()->multitoken()->value_name("KEY VALUE [KEY VALUE...]"), "A set of key-value string pairs that will be added to the output feature set.")
        ;

    processingOptions_.add_options()
        ("cpu", "Use the CPU for processing, the default is to use the GPU.")
        ("max-utilization", po::value<float>()->value_name(name_with_default("PERCENT", osnArgs.maxUtilization)),
         "Maximum GPU utilization %. Minimum is 5, and maximum is 100. Not used if processing on CPU")
        ("model", po::value<string>()->value_name("PATH"), "Path to the the trained model.")
        ("window-size", po::value<std::vector<int>>()->multitoken()->value_name("SIZE [SIZE...]"),
         "Sliding window detection box sizes.  The source image is chipped with boxes of the given sizes.  "
         "If resampled-size is not specified, all windows must fit within the model."
         "Default is the model size.")
        ("window-step", po::value<std::vector<int>>()->multitoken()->value_name("STEP [STEP...]"),
         "Sliding window step.  Either a single step or a step for each window size may be given.  Default "
         "is 20% of the model size.")
        ("resampled-size", po::value<int>()->value_name("SIZE"),
         "Resample window chips to a fixed size.  This must fit within the model.")
        ("max-cache-size", po::value<std::string>()->value_name("SIZE"),
         "Maximum raster cache size. This can be specified as a memory amount, "
         "e.g. 16G, or as a percentage, e.g. 50%. Specifying 0 turns off raster "
         "cache size limiting. The default is 25% of the total physical RAM.")
        ;

    segmentationOptions_.add_options()
        ("r2p-method", po::value<std::string>()->value_name(name_with_default("METHOD", "simple")),
         "Raster-to-polygon approximation method. Valid values are: none, simple, tc89-l1, tc89-kcos.")
        ("r2p-accuracy", po::value<double>()->value_name(name_with_default("EPSILON", 3.0)),
         "Approximation accuracy for the raster-to-polygon operation.")
        ("r2p-min-area", po::value<double>()->value_name(name_with_default("AREA", 0.0)),
         "Minimum polygon area (in pixels).")
        ;

    filterOptions_.add_options()
        ("include-labels", po::value<std::vector<string>>()->multitoken()->value_name("LABEL [LABEL...]"),
         "Filter results to only include specified labels.")
        ("exclude-labels", po::value<std::vector<string>>()->multitoken()->value_name("LABEL [LABEL...]"),
         "Filter results to exclude specified labels.")
        ("include-region", po::value<string>()->value_name("PATH [PATH...]"), "Path to a file prescribing regions to include when filtering.")
        ("exclude-region", po::value<string>()->value_name("PATH [PATH...]"), "Path to a file prescribing regions to exclude when filtering.")
        ("region", po::value<std::vector<string>>()->multitoken()->value_name("(include/exclude) PATH [PATH...] [(include/exclude) PATH [PATH...]...]"),
         "Paths to files including and excluding regions.")
        ;

    loggingOptions_.add_options()
        ("log", po::bounded_value<std::vector<string>>()->min_tokens(1)->max_tokens(2)->value_name("[LEVEL (=debug)] PATH"),
         "Log to a file, a file name preceded by an optional log level must be specified. Permitted values for log "
         "level are: trace, debug, info, warning, error, fatal.")
        ("quiet", "If set, no output will be sent to console, only a log file, if specified.")
        ;

    generalOptions_.add_options()
        ("config", po::value<std::vector<string>>()->value_name("PATH")->multitoken(),
         "Use options from a configuration file.")
        ("help", "Show this help message")
        ;

    // Build the options used for processing
    optionsDescription_.add(detectOptions_);
    optionsDescription_.add(localOptions_);
    optionsDescription_.add(webOptions_);
    optionsDescription_.add(outputOptions_);
    optionsDescription_.add(processingOptions_);
    optionsDescription_.add(segmentationOptions_);
    optionsDescription_.add(filterOptions_);
    optionsDescription_.add(loggingOptions_);
    optionsDescription_.add(generalOptions_);

    optionsDescription_.add_options()
        ("action", po::value<string>()->value_name("ACTION"), "Action to perform.")
        ("debug", "Switch console output to \"debug\" log level.")
        ("trace", "Switch console output to \"trace\" log level.")
        ("log-format", po::value<string>()->value_name("FORMAT"), "Log format. Valid values are: short, long, debug. Default value: short")
        // This bbox argument works for both local and web options, but we have duplicated bbox argument
        // description in the usage display
        ("bbox", po::cvRect2d_value())
        ;

    // Add the bbox argumet to both local and web options (duplication is not allowed when parsing the arguments)
    localOptions_.add_options()
        ("bbox", po::cvRect2d_value()->value_name("WEST SOUTH EAST NORTH"),
         "Optional bounding box for image subset, optional for local images. Coordinates are specified in the "
         "following order: west longitude, south latitude, east longitude, and north latitude.");

    webOptions_.add_options()
        ("bbox", po::cvRect2d_value()->value_name("WEST SOUTH EAST NORTH"),
         "Bounding box for determining tiles specified in WGS84 Lat/Lon coordinate system. Coordinates are "
         "specified in the following order: west longitude, south latitude, east longitude, and north latitude.");

    visibleOptions_.add(detectOptions_);
    visibleOptions_.add(localOptions_);
    visibleOptions_.add(webOptions_);
    visibleOptions_.add(outputOptions_);
    visibleOptions_.add(processingOptions_);
    visibleOptions_.add(segmentationOptions_);
    visibleOptions_.add(filterOptions_);
    visibleOptions_.add(loggingOptions_);
    visibleOptions_.add(generalOptions_);
}

void CliProcessor::setupArgParsing(int argc, const char* const* argv)
{
    setupInitialLogging();

    try {
        parseArgs(argc, argv);
        validateArgs();
    } catch (...) {
        if (displayHelp) {
            printUsage();
        }
        throw;
    }

    if (displayHelp) {
        printUsage();
        return;
    }

    setupLogging();
}

void CliProcessor::startOSNProcessing()
{
    OpenSpaceNet osn(std::move(osnArgs));

    auto pd = boost::make_shared<ConsoleProgressDisplay>();
    osn.setProgressDisplay(pd);
    pd->enableTiming("Detecting");

    osn.process();
}

void CliProcessor::setupInitialLogging()
{
    log::init();

    cerrSink_ = log::addCerrSink(dg::deepcore::level_t::warning, dg::deepcore::level_t::fatal,
                                 dg::deepcore::log::dg_log_format::dg_short_log);

    coutSink_ = log::addCoutSink(dg::deepcore::level_t::info, dg::deepcore::level_t::info,
                                 dg::deepcore::log::dg_log_format::dg_short_log);
}

void CliProcessor::setupLogging() {
    osnArgs.quiet = consoleLogLevel > level_t::info;

    // If no file is specified, assert that warning and above goes to the console
    if (fileLogPath.empty() && consoleLogLevel > level_t::warning) {
        consoleLogLevel = level_t::warning;
    }

    // If we have all the arguments parsed correctly, now is the time to turn off console logging
    if(consoleLogLevel > level_t::info || logFormat > log::dg_short_log) {
        log::removeSink(coutSink_);
        log::removeSink(cerrSink_);
        cerrSink_ = log::addCerrSink(consoleLogLevel, level_t::fatal, logFormat);
    } else if(consoleLogLevel < level_t::info) {
        log::removeSink(coutSink_);
        coutSink_ = log::addCoutSink(consoleLogLevel, level_t::info, logFormat);
    }

    // Setup a file logger
    if (!fileLogPath.empty()) {
        auto ofs = boost::make_shared<ofstream>(fileLogPath);
        DG_CHECK(!ofs->fail(), "Error opening log file %s for writing", fileLogPath.c_str());
        log::addStreamSink(ofs, fileLogLevel, level_t::fatal,
            logFormat > log::dg_log_format::dg_long_log ? logFormat : log::dg_log_format::dg_long_log);
    }
}

template<class T>
static bool readVariable(const char* param, const variables_map& vm, T& ret)
{
    auto it = vm.find(param);
    if(it != end(vm)) {
        ret = it->second.as<T>();
        return true;
    }

    return false;
}

template <typename T>
static unique_ptr<T> readVariable(const char* param, const variables_map& vm)
{
    auto it = vm.find(param);
    if(it != end(vm)) {
        return make_unique<T>(it->second.as<T>());
    } else {
        return unique_ptr<T>();
    }
}

template<typename T>
static bool readVariable(const char* param, variables_map& vm, std::vector<T>& ret, bool splitArgs)
{
    auto it = vm.find(param);
    if(it != end(vm)) {
        if(splitArgs) {
            auto args = it->second.as<std::vector<string>>();
            ret.clear();
            for(const auto& arg : args) {
                using so_tokenizer = tokenizer<escaped_list_separator<char> >;
                so_tokenizer tok(arg, escaped_list_separator<char>('\\', ' ', '\"'));
                for(const auto& a : tok) {
                    try {
                        ret.push_back(lexical_cast<T>(a));
                    } catch(bad_lexical_cast&) {
                        DG_ERROR_THROW("Invalid --%s parameter: %s", param, arg.c_str());
                    }
                }
            }
        } else {
            ret = it->second.as<std::vector<T>>();
        }

        return true;
    }

    return false;
}

static Action parseAction(string str)
{
    to_lower(str);
    if(str == "help") {
        return Action::HELP;
    } else if(str == "detect") {
        return Action::DETECT;
    }

    return Action::UNKNOWN;
}

// Order of precedence: config files from env, env, config files from cli, cli.
void CliProcessor::parseArgs(int argc, const char* const* argv)
{
    if(argc > 1) {
        osnArgs.action = parseAction(argv[1]);
        if(osnArgs.action == Action::HELP) {
            displayHelp = true;
            return;
        } else if(osnArgs.action == Action::DETECT) {
            --argc;
            ++argv;
        } else {
            osnArgs.action = Action::DETECT;
        }

        for (int i = 1; i < argc;  ++i) {
            if(iequals(argv[i], "--help")) {
                displayHelp = true;
                if(argc == 2) {
                    return;
                }
            }
        }
    }

    // parse environment variable options
    variables_map environment_vm;
    po::store(po::parse_environment(optionsDescription_, "OSN_"), environment_vm);
    po::notify(environment_vm);
    readArgs(environment_vm, true);

    // parse regular options
    variables_map command_line_vm;
    po::store(po::command_line_parser(argc, argv)
                  .extra_style_parser(po::combine_style_parsers(
                      { &po::ignore_numbers, po::postfix_argument("region") }))
                  .options(optionsDescription_)
                  .run(), command_line_vm);
    po::notify(command_line_vm);
    readArgs(command_line_vm);
}

static Source parseService(string service)
{
    to_lower(service);
    if(service == "dgcs") {
        return Source::DGCS;
    } else if(service == "evwhs") {
        return Source::EVWHS;
    } else if(service == "maps-api") {
        return Source::MAPS_API;
    } else if(service == "tile-json") {
        return Source::TILE_JSON;
    }

    DG_ERROR_THROW("Invalid --service parameter: %s", service.c_str());
}

void CliProcessor::printUsage() const
{
    cout << OSN_USAGE << visibleOptions_ << endl;
}

enum ArgUse {
    IGNORED = 1,
    MAY_USE_ONE = 2,
    OPTIONAL = 3,
    REQUIRED = 4
};

inline void checkArgument(const char* argumentName, ArgUse expectedUse, bool set, const char* cause = "processing")
{
    if (expectedUse == REQUIRED && !set) {
        DG_ERROR_THROW("Argument --%s is required when %s", argumentName, cause);
    } else if (expectedUse == IGNORED && set) {
        OSN_LOG(warning) << "Argument --" << argumentName << " is ignored when " << cause;
    }
}

inline void checkArgument(const char* argumentName, ArgUse expectedUse, const std::string& set, const char* cause = "processing")
{
    checkArgument(argumentName, expectedUse, !set.empty(), cause);
}

template<class T>
inline void checkArgument(const char* argumentName, ArgUse expectedUse, const std::vector<T>& set, const char* cause = "processing")
{
    if (expectedUse == REQUIRED && set.empty()) {
        DG_ERROR_THROW("Argument --%s is required for %s", argumentName, cause);
    } else if (expectedUse == MAY_USE_ONE && set.size() > 1) {
        OSN_LOG(warning) << "Argument --" << argumentName << " has ignored additional parameters when " << cause;
    } else if (expectedUse == IGNORED && !set.empty()) {
        OSN_LOG(warning) << "Argument --" << argumentName << " is ignored when " << cause;
    }
}

void CliProcessor::readModelPackage()
{
    GbdxModelReader modelReader(osnArgs.modelPath);

    OSN_LOG(info) << "Reading model package..." ;

    osnArgs.modelPackage = modelReader.readModel();
    DG_CHECK(osnArgs.modelPackage, "Unable to open the model package");
}

void CliProcessor::validateArgs()
{
    if (osnArgs.action == Action::HELP || displayHelp) {
        return;
    }

    DG_CHECK(osnArgs.action == Action::DETECT, "Try 'OpenSpaceNet --help' for more information.");

    //
    // Validate action args.
    //
    ArgUse windowStepUse(OPTIONAL);
    ArgUse windowSizeUse(OPTIONAL);
    ArgUse nmsUse(OPTIONAL);
    ArgUse confidenceUse(OPTIONAL);

    checkArgument("window-step", windowStepUse, osnArgs.windowStep);
    checkArgument("window-size", windowSizeUse, osnArgs.windowSize);
    checkArgument("nms", nmsUse, osnArgs.nms);
    checkArgument("confidence", confidenceUse, confidenceSet);

    //
    // Validate source args.
    //
    ArgUse tokenUse(IGNORED);
    ArgUse credentialsUse(IGNORED);
    ArgUse mapIdUse(IGNORED);
    ArgUse zoomUse(IGNORED);
    ArgUse bboxUse(IGNORED);
    ArgUse maxConnectionsUse(IGNORED);
    ArgUse urlUse(IGNORED);
    ArgUse useTilesUse(IGNORED);
    const char * sourceDescription;

    switch (osnArgs.source) {
        case Source::LOCAL:
            bboxUse = OPTIONAL;
            sourceDescription = "using a local image";
            break;

        case Source::MAPS_API:
            tokenUse = REQUIRED;
            mapIdUse = OPTIONAL;
            zoomUse = OPTIONAL;
            bboxUse = REQUIRED;
            maxConnectionsUse = OPTIONAL;
            sourceDescription = "using maps-api";
            break;

        case Source::DGCS:
        case Source::EVWHS:
            tokenUse = REQUIRED;
            credentialsUse = REQUIRED;
            mapIdUse = OPTIONAL;
            zoomUse = OPTIONAL;
            bboxUse = REQUIRED;
            maxConnectionsUse = OPTIONAL;
            sourceDescription = "using dgcs or evwhs";
            break;

        case Source::TILE_JSON:
            credentialsUse = OPTIONAL;
            zoomUse = OPTIONAL;
            bboxUse = REQUIRED;
            maxConnectionsUse = OPTIONAL;
            urlUse = REQUIRED;
            useTilesUse = OPTIONAL;
            sourceDescription = "using tile-json";
            break;

        default:
            DG_ERROR_THROW("Source is unknown or unspecified");
    }

    if (osnArgs.dgcsCatalogID || osnArgs.evwhsCatalogID) {
        tokenUse = REQUIRED;
    }

    checkArgument("token", tokenUse, osnArgs.token, sourceDescription);
    checkArgument("credentials", credentialsUse, osnArgs.credentials, sourceDescription);
    checkArgument("map-id", mapIdUse, mapIdSet, sourceDescription);
    checkArgument("zoom", zoomUse, zoomSet, sourceDescription);
    checkArgument("bbox", bboxUse, (bool) osnArgs.bbox, sourceDescription);
    checkArgument("max-connections", maxConnectionsUse, maxConnectionsSet, sourceDescription);
    checkArgument("url", urlUse, osnArgs.url, sourceDescription);
    checkArgument("use-tiles", useTilesUse, osnArgs.useTiles, sourceDescription);

    //
    // Validate model and detection
    //
    checkArgument("model", REQUIRED, osnArgs.modelPath);

    DG_CHECK(osnArgs.includeLabels.empty() || osnArgs.excludeLabels.empty(),
             "Arguments --include-labels and --exclude-labels may not be specified at the same time");

    if(windowSizeUse > MAY_USE_ONE || windowStepUse > MAY_USE_ONE) {
        DG_CHECK(osnArgs.windowSize.size() < 2 || osnArgs.windowStep.size() < 2 ||
                 osnArgs.windowSize.size() == osnArgs.windowStep.size(),
                 "Arguments --window-size and --window-step must match in length");
    }

    //
    // Validate output
    //
    checkArgument("output", REQUIRED, osnArgs.outputPath);
    if(osnArgs.outputFormat  == "shp") {
        checkArgument("output-layer", IGNORED, osnArgs.layerName, "the output format is a shapefile");
        osnArgs.layerName = path(osnArgs.outputPath).stem().filename().string();
    } else if(osnArgs.layerName.empty()) {
        osnArgs.layerName = "osndetects";
    }

    //
    // Validate filtering
    //
    if (osnArgs.filterDefinition.size()) {
        for (const auto& action : osnArgs.filterDefinition) {
            for (const auto& file : action.second) {
                path filePath = path(file);
                if (!exists(filePath)) {
                    DG_ERROR_THROW("Argument to %s region using file \"%s\" invalid, file does not exist",
                                   action.first.c_str(), file.c_str());
                } else {
                    string fileExtension = filePath.extension().string();
                    fileExtension.erase(0,1);
                    if (find(supportedFormats_.begin(), supportedFormats_.end(), fileExtension) == supportedFormats_.end()) {
                        DG_ERROR_THROW("Argument to %s region using file \"%s\" invalid, format \"%s\" is unsupported",
                                       action.first.c_str(), file.c_str(), fileExtension.c_str());
                    }
                }
            }
        }
    }

    // Ask for password, if not specified
    if (credentialsUse > IGNORED && !displayHelp && !osnArgs.credentials.empty() && osnArgs.credentials.find(':') == string::npos) {
        promptForPassword();
    }
}

void CliProcessor::promptForPassword()
{
    cout << "Enter your web service password: ";
    auto password = readMaskedInputFromConsole();
    osnArgs.credentials += ":";
    osnArgs.credentials += password;
}

void CliProcessor::readArgs(variables_map vm, bool splitArgs) {
    // See if we have --config option(s), parse it if we do
    std::vector<string> configFiles;
    if (readVariable("config", vm, configFiles, splitArgs)) {
        // Parse config files in reverse order because parse_config_file will not override existing options. This way
        // options apply as "last one wins". The arguments specified on the command line always win.
        for (const auto &configFile : reverse(configFiles)) {
            variables_map config_vm;
            po::store(po::parse_config_file<char>(configFile.c_str(), optionsDescription_), config_vm);
            po::notify(config_vm);
            readArgs(config_vm, true);
        }
    }

    osnArgs.bbox = readVariable<cv::Rect2d>("bbox", vm);

    string service;
    bool serviceSet  = readVariable("service", vm, service);
    if (serviceSet) {
        osnArgs.source = parseService(service);
        readWebServiceArgs(vm, splitArgs);
    }

    bool imageSet = readVariable("image", vm, osnArgs.image);
    if (imageSet) {
        osnArgs.source = Source::LOCAL;
    }

    DG_CHECK(!imageSet || !serviceSet, "Arguments --image and --service may not be specified at the same time");

    readWebServiceArgs(vm, splitArgs);
    readProcessingArgs(vm, splitArgs);
    readOutputArgs(vm, splitArgs);
    readFeatureDetectionArgs(vm, splitArgs);
    readLoggingArgs(vm, splitArgs);

    if(!osnArgs.modelPath.empty()) {
        readModelPackage();
    }

    readSegmentationArgs(vm, splitArgs);
}

void CliProcessor::readWebServiceArgs(variables_map vm, bool splitArgs)
{
    mapIdSet |= readVariable("map-id", vm, osnArgs.mapId);
    readVariable("token", vm, osnArgs.token);
    readVariable("credentials", vm, osnArgs.credentials);
    readVariable("url", vm, osnArgs.url);
    osnArgs.useTiles = vm.find("use-tiles") != vm.end();
    zoomSet |= readVariable("zoom", vm, osnArgs.zoom);
    maxConnectionsSet |= readVariable("max-connections", vm, osnArgs.maxConnections);
}

void CliProcessor::readOutputArgs(variables_map vm, bool splitArgs)
{
    readVariable("format", vm, osnArgs.outputFormat);
    to_lower(osnArgs.outputFormat);

    readVariable("output", vm, osnArgs.outputPath);
    readVariable("output-layer", vm, osnArgs.layerName);

    string typeStr = "polygon";
    readVariable("type", vm, typeStr);
    to_lower(typeStr);
    if(typeStr == "polygon") {
        osnArgs.geometryType = GeometryType::POLYGON;
    } else if(typeStr == "point") {
        osnArgs.geometryType = GeometryType::POINT;
    } else {
        DG_ERROR_THROW("Invalid geometry type: %s", typeStr.c_str());
    }
    osnArgs.append = vm.find("append") != end(vm);
    osnArgs.producerInfo = vm.find("producer-info") != end(vm);

    osnArgs.dgcsCatalogID = vm.find("dgcs-catalog-id") != end(vm);
    osnArgs.evwhsCatalogID = vm.find("evwhs-catalog-id") != end(vm);
    readVariable("wfs-credentials", vm, osnArgs.wfsCredentials);
    readVariable("extra-fields", vm, osnArgs.extraFields, true);
    if (!osnArgs.extraFields.empty() && osnArgs.extraFields.size() % 2 != 0){
        DG_ERROR_THROW("Invalid number of fields: Fields must be supplied pairs of strings for key and value.");
    }
}

void CliProcessor::readProcessingArgs(variables_map vm, bool splitArgs)
{
    osnArgs.useCpu = vm.find("cpu") != end(vm);
    readVariable("max-utilization", vm, osnArgs.maxUtilization);
    readVariable("model", vm, osnArgs.modelPath);

    readVariable("window-size", vm, osnArgs.windowSize, splitArgs);
    readVariable("window-step", vm, osnArgs.windowStep, splitArgs);
    osnArgs.resampledSize = readVariable<int>("resampled-size", vm);

    readVariable("include-labels", vm, osnArgs.includeLabels, splitArgs);
    readVariable("exclude-labels", vm, osnArgs.excludeLabels, splitArgs);
    if (vm.find("region") != end(vm)) {
        parseFilterArgs(vm["region"].as<std::vector<std::string>>());
    }

    string sizeString("25%");
    readVariable("max-cache-size", vm, sizeString);
    try {
        osnArgs.maxCacheSize = memory::stringToRam(sizeString);
    } catch(...) {
        DG_ERROR_THROW("Argument --max-cache-size is invalid");
    }
}

void CliProcessor::readFeatureDetectionArgs(variables_map vm, bool /* splitArgs */)
{
    confidenceSet |= readVariable("confidence", vm, osnArgs.confidence);

    if(vm.find("nms") != end(vm)) {
        osnArgs.nms = true;
        std::vector<float> args;
        readVariable("nms", vm, args);
        if(args.size()) {
            osnArgs.overlap = args[0];
        }
    }
}

void CliProcessor::readSegmentationArgs(boost::program_options::variables_map vm, bool /* splitArgs */)
{
    bool isSegmentation = (osnArgs.modelPackage && osnArgs.modelPackage->metadata().category() == "segmentation");
    static const char* CAUSE = "input model is not a segmentation model.";

    string method;
    if(readVariable("r2p-method", vm, method)) {
        if(iequals(method, "none")) {
            osnArgs.method = RasterToPolygonDP::NONE;
        } else if(iequals(method, "simple")) {
            osnArgs.method = RasterToPolygonDP::SIMPLE;
        } else if(iequals(method, "tc89-l1")) {
            osnArgs.method = RasterToPolygonDP::TC89_L1;
        } else if(iequals(method, "tc89-kcos")) {
            osnArgs.method = RasterToPolygonDP::TC89_KCOS;
        } else {
            DG_ERROR_THROW("Invalid --r2p-method parameter: '%s'", method.c_str());
        }

        if(!isSegmentation) {
            checkArgument("r2p-method", IGNORED, true, CAUSE);
        }
    }

    if(readVariable("r2p-accuracy", vm, osnArgs.epsilon) && !isSegmentation) {
        checkArgument("r2p-accuracy", IGNORED, true, CAUSE);
    }

    if(readVariable("r2p-min-area", vm, osnArgs.minArea) && !isSegmentation) {
        checkArgument("r2p-min-area", IGNORED, true, CAUSE);
    }
}

void CliProcessor::readLoggingArgs(variables_map vm, bool splitArgs)
{
    if(vm.find("quiet") != end(vm)) {
        consoleLogLevel = level_t::fatal;
    } if(vm.find("trace") != end(vm)) {
        consoleLogLevel = level_t::trace;
    } else if(vm.find("debug") != end(vm)) {
        consoleLogLevel = level_t::debug;
    }

    string strLogFormat;
    if(readVariable("log-format", vm, strLogFormat)) {
        to_lower(strLogFormat);
        if(strLogFormat == "short") {
            logFormat = log::dg_log_format::dg_short_log;
        } else if(strLogFormat == "long") {
            logFormat = log::dg_log_format::dg_long_log;
        } else if(strLogFormat == "debug") {
            logFormat = log::dg_log_format::dg_debug_log;
        } else {
            DG_ERROR_THROW("Invalid --log-format parameter: %s", strLogFormat.c_str());
        }
    }

    std::vector<string> logArgs;
    if(readVariable("log", vm, logArgs, splitArgs)) {
        DG_CHECK(!logArgs.empty(), "Log path must be specified");
        fileLogLevel = level_t::debug;

        if(logArgs.size() == 1) {
            fileLogPath = logArgs[0];
        } else {
            fileLogLevel = log::stringToLevel(logArgs[0]);
            fileLogPath = logArgs[1];
        }
    }
}

void CliProcessor::parseFilterArgs(const std::vector<string>& filterList)
{
    string filterAction = "";
    string finalEntry = "";
    std::vector<string> filterActionFileSet;
    for (auto entry : filterList) {
        if (entry == filterAction) {
            finalEntry = entry;
            continue;
        }
        else if (entry == "include" ||
                 entry == "exclude") {
            if (filterAction != "") {
                if (filterActionFileSet.empty()) {
                    DG_ERROR_THROW("Argument to %s region without file input", filterAction.c_str());
                }
                osnArgs.filterDefinition.push_back(std::make_pair(filterAction, move(filterActionFileSet)));
            }

            filterActionFileSet.clear();
            filterAction = entry.c_str();
        } else {
            filterActionFileSet.push_back(entry);
        }

        finalEntry = entry;
    }
    if (finalEntry == "include" || finalEntry == "exclude") {
        DG_ERROR_THROW("Argument to %s region without file input", finalEntry.c_str());
    }
    if (!filterActionFileSet.empty()) {
        osnArgs.filterDefinition.push_back(std::make_pair(filterAction, move(filterActionFileSet)));
    }
}

bool CliProcessor::showHelp()
{
    return displayHelp;
}

} } // namespace dg { namespace osn {

max_stars_repo_name: DigitalGlobe/GGD-OpenSpaceNet

max_issues_repo_name: DigitalGlobe/OpenSpaceNet

max_forks_repo_name: DigitalGlobe/GGD-OpenSpaceNet


text:
#include <bitset>
#include <boost/dynamic_bitset.hpp>
#include <chrono>
#include <vector>

#include <stdio.h>

bool verbose = true;
const int bits = 30;
const int64_t mask = (1<<30) - 1;

void sieve(int64_t n)
{
  auto start = std::chrono::system_clock::now();
  std::vector<boost::dynamic_bitset<>> notprime(1+(n>>bits), boost::dynamic_bitset<>((1LL<<bits)+1));
  printf("constructed %lld %lld\n", 1+(n>>bits), (1LL<<bits)+1);
  for (int64_t p = 2; p*p <= n; p++) {
    if (notprime[p>>bits][p&mask] == 0) {
      for (int64_t q = p*2; q <= n; q += p)
	notprime[q>>bits][q&mask] = 1;
    }
  }
  auto end = std::chrono::system_clock::now();
  std::chrono::duration<double> elapsed_seconds = end-start;
  printf("Computation took %f sec\n", elapsed_seconds.count());

  int64_t k = 0;
  printf("Primes <= %lld\n", n);
  for (int64_t p = 2; p <= n; p++)
    if (notprime[p>>bits][p&mask] == 0) {
      ++k;
      if (verbose) {
	printf("%lld ", p);
      }
    }
  if (verbose)
    printf("\n");
  printf("%lld primes\n", k);
}

int main(int argc, char* argv[]) {
  if (argc < 2) {
    printf("era [-quiet] <n>: computes primes <= n\n");
    return -1;
  }
  if (!strcmp(argv[1], "-quiet")) {
    verbose = false;
  }
  int64_t n = std::stoll(argv[argc-1]);
  sieve(n);
  return 0;
}

ext: cc

max_stars_repo_name: maxpoletto/primes

max_issues_repo_name: maxpoletto/primes

max_forks_repo_name: maxpoletto/primes


text:
#pragma once

#include <boost/iterator/iterator_facade.hpp>

#include "object.hpp"

#include "detail/type_traits.hpp"
#include "detail/object.hpp"
#include "detail/object_cache.hpp"

namespace distant::wow::entities
{
	template <typename T>
	class object_iterator
		: public boost::iterator_facade<
			object_iterator<T>,				// CRTP Derivation
			T,								// Value type
			std::input_iterator_tag,		// Traversal category
			T&								// Reference type
		>
	{
	public: // {ctor}
		object_iterator() noexcept
			: base_(0) {}

		explicit object_iterator(const memory::address base) noexcept
			: base_(base)
		{
			if (!derives_from(detail::load_object_type(this->base_), detail::type_to_enum<std::decay_t<T>>()))
				this->increment();
			else
				detail::update_cache(this->base_);
		}

		template <typename OtherObject>
		object_iterator(const object_iterator<OtherObject>& other)
			: base_(other.base_) {}

	private: // boost::iterator_facade implementation:
		T& dereference() const
		{
			return *reinterpret_cast<T*>(detail::object_cache()[base_].get());
		}

		template <class OtherObject>
		bool equal(const object_iterator<OtherObject>& other) const noexcept
		{ return base_ == other.base_; }

		void increment()
		{
			memory::address next = base_;
			// Push forward until we hit a cacheable object.
			do
			{
				base_ = next;
				next = detail::next_object_base(base_);

				// If the address is invalid, then we've reached the end.
				if (!detail::valid_base_address(base_))
				{
					next = 0;
					break;
				}

				// We found an object that derives from T.
				if (derives_from(detail::load_object_type(next), detail::type_to_enum<std::decay_t<T>>()))
				{
					detail::update_cache(next);
					break;
				}

			} while (next != base_);

			base_ = next;
		}

	private:
		struct enabler {};

		friend class boost::iterator_core_access;
		template <class> friend class object_iterator;

	private: // data
		memory::address base_;
	};

	template <typename T>
	using const_object_iterator = object_iterator<const T>;

} // namespace distant::wow::entities

ext: hpp


text:
#ifndef _GRL_VREP_ROBOT_ARM_JACOBIAN_HPP_
#define _GRL_VREP_ROBOT_ARM_JACOBIAN_HPP_

#include <iostream>
#include <memory>
#include <array>

#include <boost/exception/all.hpp>
#include <boost/algorithm/string.hpp>

#include <spdlog/spdlog.h>

#include <Eigen/Core>
#include <Eigen/Geometry>

#include "grl/vrep/Vrep.hpp"
#include "grl/vrep/VrepRobotArmDriver.hpp"
#include "grl/vrep/Eigen.hpp"

#include "v_repLib.h"

namespace grl { namespace vrep {

/// @brief get the Jacobian as calculated by vrep in an Eigen::MatrixXf in column major format
/// @param driver the vrep arm driver object that provides access to vrep simulation state for a specific arm
/// @param jacobianOnly true calls simComputeJacobian, false uses simCheckIKGroup which incidentally calculates the Jacobian
///
/// The jacobianOnly option is provided because some irregularities were seen with
/// simComputeJacobian (jacobianOnly == true). Thus (jacobianOnly == false) falls
/// back on using the full vrep provided inverse kinematics calculation which is
/// slower but didn't have the previously seen irregularities. The jacobianOnly option
/// should be eliminated in favor of the simComputeJacobian (jacobianOnly == true) case
/// once all issues are fully resolved.
///
/// @return jacobian in ColumnMajor format where each row is a joint from base to tip, first 3 columns are translation component, last 3 columns are rotation component
Eigen::MatrixXf getJacobian(vrep::VrepRobotArmDriver& driver, bool jacobianOnly = false)
{

        // Initialize Variables for update
        auto jointHandles_ = driver.getJointHandles();
        int numJoints =jointHandles_.size();
        std::vector<float> ikCalculatedJointValues(numJoints,0);
        vrep::VrepRobotArmDriver::State currentArmState_;
        driver.getState(currentArmState_);

        /// @todo get target position, probably relative to base
        const auto& handleParams = driver.getVrepHandleParams();
        auto ikGroupHandle_ = std::get<vrep::VrepRobotArmDriver::RobotIkGroup>(handleParams);

        if (jacobianOnly)
        {
            // http://www.coppeliarobotics.com/helpFiles/en/apiFunctions.htm#simComputeJacobian
            auto jacobianResult = simComputeJacobian(ikGroupHandle_,NULL,NULL);

            if(jacobianResult == -1)
            {
                spdlog::get("console")->error("VrepInverseKinematicsController: couldn't compute Jacobian");
                return Eigen::MatrixXf();
            }

        }
        else
        {

            auto target = std::get<vrep::VrepRobotArmDriver::RobotTargetName>(handleParams);
            auto tip = std::get<vrep::VrepRobotArmDriver::RobotTipName>(handleParams);
            // save the current tip to target transform
            Eigen::Affine3d tipToTarget =getObjectTransform( target,tip);

            // set the current transform to the identity so simCheckIkGroup won't fail
            // @see http://www.forum.coppeliarobotics.com/viewtopic.php?f=9&t=3967
            // for details about this issue.
            setObjectTransform( target,tip,Eigen::Affine3d::Identity());

            // debug:
            // std::cout << "TipToTargetTransform:\n" << tipToTarget.matrix() << "\n";

            /// Run inverse kinematics, but all we really want is the jacobian
            /// @see http://www.coppeliarobotics.com/helpFiles/en/apiFunctions.htm#simCheckIkGroup
            auto ikcalcResult =
            simCheckIkGroup(ikGroupHandle_
                           ,numJoints
                           ,&jointHandles_[0]
                           ,&ikCalculatedJointValues[0]
                           ,NULL /// @todo do we need to use these options?
                           );
            /// @see http://www.coppeliarobotics.com/helpFiles/en/apiConstants.htm#ikCalculationResults
            if(ikcalcResult!=sim_ikresult_success && ikcalcResult != sim_ikresult_not_performed)
            {
                spdlog::get("console")->error("VrepInverseKinematicsController: didn't run inverse kinematics");
                return Eigen::MatrixXf();
            }

            setObjectTransform( target,tip,tipToTarget);
        }

        // debug verifying that get and set object transform don't corrupt underlying data
//        Eigen::Affine3d tipToTarget2 =getObjectTransform( target,tip);
//        std::cout << "\ntiptotarget\n" << tipToTarget.matrix();
//        std::cout << "\ntiptotarget2\n" << tipToTarget2.matrix();

        // Get the Jacobian
        int jacobianSize[2];
        float* jacobian=simGetIkGroupMatrix(ikGroupHandle_,0,jacobianSize);
        /// @todo FIX HACK jacobianSize include orientation component, should be 7x6 instead of 7x3

#ifdef IGNORE_ROTATION
        jacobianSize[1] = 3;
#endif

        // Transfer the Jacobian to cisst

        // jacobianSize[1] represents the row count of the Jacobian
        // (i.e. the number of equations or the number of joints involved
        // in the IK resolution of the given kinematic chain)
        // Joints appear from tip to base.

        // jacobianSize[0] represents the column count of the Jacobian
        // (i.e. the number of constraints, e.g. x,y,z,alpha,beta,gamma,jointDependency)

        // The Jacobian data is in RowMajor order, i.e.:
        // https://en.wikipedia.org/wiki/Row-major_order

        std::string str;

        // jacobianSize[1] == eigen ColMajor "rows" , jacobianSize[0] == eigen ColMajor "cols"

        Eigen::Map<Eigen::Matrix<float,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor> > mtestjacobian(jacobian,jacobianSize[1],jacobianSize[0]);
        Eigen::MatrixXf eigentestJacobian = mtestjacobian.rowwise().reverse().transpose();

        return eigentestJacobian;
}

}} // grl::vrep

#endif // _GRL_VREP_ROBOT_ARM_JACOBIAN_HPP_


text:
/*
 * lbp.cpp
 *
 * Author: F.Struck (florian.struck@cased.de), E. Pschernig (epschern@cosy.sbg.ac.at), P. Wild (pwild@cosy.sbg.ac.at)
 *
 * Generates an iris code from iris texture using the uniform LBP algorithm
 *
 */
#include <cstdio>
#include <map>
#include <vector>
#include <string>
#include <cstring>
#include <ctime>
#include <fstream>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <boost/regex.hpp>
#include <boost/filesystem.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>

using namespace std;
using namespace cv;

#define FILTER_SIZE 9
#define CELL_WIDTH 16
#define CELL_HEIGHT 16
#define SCALING_WIDTH 512
#define SCALING_HEIGHT 64
#define DELTA_SHIFT 8

/** no globbing in win32 mode **/
int _CRT_glob = 0;

/** Program modes **/
static const int MODE_MAIN = 1, MODE_HELP = 2;

/*
 * Print command line usage for this program
 */
void printUsage() {
    printf("+-----------------------------------------------------------------------------+\n");
    printf("| LBP - Iris-code generation (feature extraction) using the uniform LBP       |\n");
    printf("| algorithm with a 9x9 filter                                                 |\n");
    printf("|                                                                             |\n");
    printf("| MODES                                                                       |\n");
    printf("|                                                                             |\n");
    printf("| (# 1) Uniform LBP iris code extraction from iris textures                   |\n");
    printf("| (# 2) usage                                                                 |\n");
    printf("|                                                                             |\n");
    printf("| ARGUMENTS                                                                   |\n");
    printf("|                                                                             |\n");
    printf("+------+------------+---+---+-------------------------------------------------+\n");
    printf("| Name | Parameters | # | ? | Description                                     |\n");
    printf("+------+------------+---+---+-------------------------------------------------+\n");
    printf("| -i   | infile     | 1 | N | input iris texture (use * as wildcard, all other|\n");
    printf("|      |            |   |   | file parameters may refer to n-th * with ?n)    |\n");
    printf("| -o   | outfile    | 1 | N | output iris code image                          |\n");
    printf("| -q   |            | 1 | Y | quiet mode on (off)                             |\n");
    printf("| -t   |            | 1 | Y | time progress on (off)                          |\n");
    printf("| -h   |            | 2 | N | prints usage                                    |\n");
    printf("+------+------------+---+---+-------------------------------------------------+\n");
    printf("|                                                                             |\n");
    printf("| EXAMPLE USAGE                                                               |\n");
    printf("|                                                                             |\n");
    printf("| -i s1.tiff -o s1.png                                                        |\n");
    printf("| -i *.tiff -o ?1.png -q -t                                                   |\n");
    printf("|                                                                             |\n");
    printf("| AUTHORS                                                                     |\n");
    printf("|                                                                             |\n");
    printf("| Florian Struck (florian.struck@cased.de)                                    |\n");
    printf("| Elias Pschernig (epschern@cosy.sbg.ac.at)                                   |\n");
    printf("| Peter Wild (pwild@cosy.sbg.ac.at)                                           |\n");
    printf("|                                                                             |\n");
    printf("| COPYRIGHT                                                                   |\n");
    printf("|                                                                             |\n");
    printf("| (C) 2016 All rights reserved. Do not distribute without written permission. |\n");
    printf("+-----------------------------------------------------------------------------+\n");
}

/** ------------------------------- image processing functions ------------------------------- **/

struct Cell {
    int startX, startY;
    int endX, endY;
    int width, height;
};

/**
 * calculates the new index of a shifted pixel
 * @param index         the old index
 * @param indexWidth    the row length of this pixel
 * @param shift         the shift
 * @return              the new index
 */
int shiftIndex(const int index, const int indexWidth, const int shift) {
    int indexInRow = index % indexWidth;
    if (indexInRow + shift >= indexWidth) return index + shift - indexWidth;
    else if (indexInRow + shift < 0) return index + shift + indexWidth;
    else return index + shift;
}

uchar getAverageValue(const int centerX, const int centerY, const Cell& cell, const int filterSize, const Mat& texture) {
    int averageValue = 0;
    int mod_x, mod_y;
    const int halfCellSize = filterSize / 2;

    for (int y = centerY - halfCellSize; y <= centerY + halfCellSize; y++) {

        mod_y = y;
        if (mod_y < cell.startY) mod_y += cell.height;
        else if (mod_y >= cell.endY) mod_y -= cell.height;

        for (int x = centerX - halfCellSize; x <= centerX + halfCellSize; x++) {

            mod_x = x;
            if (mod_x < cell.startX) mod_x += cell.width;
            else if (mod_x >= cell.endX) mod_x -= cell.width;

            averageValue += *texture.ptr<uchar>(mod_y, mod_x);
        }
    }

    return (uchar) (averageValue / pow(filterSize, 2));
}

/**
 * Calculate the LBP-Value clockwise of a pixel
 * @param x             the x-coordinate of the pixel in the texture
 * @param y             the y-coordinate of the pixel in the texture
 * @param filterSize    the filter-size of the MB-LBP algorithm (has to be a multiple of 3)
 * @param texture       the iris texture
 * @return              the clockwise LBP-Value of this pixel
 */
uchar calculateLBPValue(const int centerY, const int centerX, const Cell& cellSize, const int filterSize, const Mat& texture) {
    const int filterCellSize = filterSize / 3;
    const uchar centerValue = getAverageValue(centerX, centerY, cellSize, filterCellSize, texture);

    uchar LBPValue = 0x00;
    const uchar bitMask = 0x01;

    //----------------------Top-Neighbours--------------------------------------
    for (int x = centerX - filterCellSize; x <= centerX + filterCellSize; x += filterCellSize) {
        if (getAverageValue(x, centerY - filterCellSize, cellSize, filterCellSize, texture) >= centerValue) LBPValue |= bitMask;
        LBPValue = LBPValue << 1; //*2
    }
    //----------------------Right-Neighbour------------------------------------
    if (getAverageValue(centerX + filterCellSize, centerY, cellSize, filterCellSize, texture) >= centerValue) LBPValue |= bitMask;
    LBPValue = LBPValue << 1; //*2
    //----------------------Bottom-Neighbours----------------------------------
    for (int x = centerX + filterCellSize; x >= centerX - filterCellSize; x -= filterCellSize) {
        if (getAverageValue(x, centerY + filterCellSize, cellSize, filterCellSize, texture) >= centerValue) LBPValue |= bitMask;
        LBPValue = LBPValue << 1; //*2
    }
    //-----------------------Left-Neighbours-----------------------------------
    if (getAverageValue(centerX - filterCellSize, centerY, cellSize, filterCellSize, texture) >= centerValue) LBPValue |= bitMask;

    return LBPValue;
}

/**
 * Extracts the features of the complete iris texture with the lbp algorithm
 * @param extractedData     the destination for the extracted data
 * @param cell              the start- and end-positions of this cell in the texture
 * @param texture           the source iris-texture
 */
void extractTexture(Mat& extractedData, const int filterSize, const Mat& texture) {
    Cell cell;
    cell.startX = 0;
    cell.startY = 0;
    cell.width = texture.cols;
    cell.height = texture.rows;
    cell.endX = cell.startX + cell.width;
    cell.endY = cell.startY + cell.height;

    for (int row = 0; row < texture.rows; row++) {
        for (int col = 0; col < texture.cols; col++) {
            *extractedData.ptr<uchar>(row, col) = calculateLBPValue(row, col, cell, filterSize, texture);
        }
    }
}

/**
 * Tests if a lbp-value is uniform
 * @param lbp_value the lbp-value wich should be tested
 * @return true if uniform und false if the value is not uniform
 */
bool isUniform(const unsigned char lbpValue) {
    unsigned char transmissions = 0;
    unsigned char bitmask = 64;
    unsigned char shifter = 6;
    unsigned char lastValue = (lbpValue & 128) >> 7; //initialisation of the first bit

    for (char index = 1; index < 8; index++) { //analyse every bit
        unsigned char value = (lbpValue & bitmask) >> shifter;
        if (lastValue != value) {
            lastValue = value;
            transmissions++;
        }
        shifter--;
        bitmask = bitmask >> 1;
    }
    return (transmissions <= 2);
}

/**
 * Translate a histogram to an uniformed histogram
 * @param uniformHistogram  a pointer of a uniformed histogram
 * @param extractedData     a pointer of a filled ununiformed histogram
 * @param size              the size of the ununiformed histogram
 */
void toUniformHistogram(uint16_t *uniformHistogram, const uint16_t *extractedData, const int size) {
    int uniformIndex = 0;
    uniformHistogram[58] = 0; //reset the last field

    for (int index = 0; index < size; index++) {
        if (isUniform(index)) {
            uniformHistogram[uniformIndex] = extractedData[index];
            uniformIndex++;
        }
        else {
            uniformHistogram[58] += extractedData[index];
        }
    }
}

/**
 * Transforms a part of a texture to a histogram
 * @param histogram     the destination of the histogram
 * @param cell          the part of the texture
 * @param sourceTexture the source texture
 * @param shift         the alignment of pixels for shifting
 */
void toHistogram(uint16_t *histogram, const Cell& cell, const Mat& sourceTexture, const int shift) {
    for (int row = cell.startY; row < cell.endY; row++) {
        for (int col = cell.startX; col < cell.endX; col++) {
            histogram[*sourceTexture.ptr<uchar>(row, shiftIndex(col, sourceTexture.cols, shift))]++;
        }
    }
}

/*
 * The LBP feature extraction algorithm
 *
 * code: Code matrix
 * texture: texture matrix
 */
/**
 * Creates normalized histograms of the extracted features
 * @param code          the destination for the feature data
 * @param extractedData the extracted feature of the iris
 * @param shift         the alignment of pixels for shifting
 */
void extractHistograms(Mat& code, const Mat& extractedData, const int shift) {
    const int verticalCellNumber = extractedData.cols / CELL_WIDTH;
    const int horizontalCellNumber = extractedData.rows / CELL_HEIGHT;
    const int histogramLength = 256;

    uint16_t *histogram = new uint16_t[histogramLength];
    uint16_t *uniformHistogram = new uint16_t[59]; //58 values of 255 are uniform plus rest

    Cell cell;
    cell.width = CELL_WIDTH;
    cell.height = CELL_HEIGHT;

    int cellIndex = 0;
    for (int cellRow = 0; cellRow < horizontalCellNumber; cellRow++) {
        for (int cellCol = 0; cellCol < verticalCellNumber; cellCol++, cellIndex++) {

            cell.startX = cellCol * cell.width;
            cell.startY = cellRow * cell.height;
            cell.endX = cell.startX + cell.width;
            cell.endY = cell.startY + cell.height;

            for (int i = 0; i < histogramLength; i++) histogram[i] = 0; //set all values to 0
            toHistogram(histogram, cell, extractedData, shift); //calculate Histogramm
            toUniformHistogram(uniformHistogram, histogram, histogramLength); //calculate uniform Histogramm

            int colIndex = 0;
            for (int arrayIndex = 0; arrayIndex < 59; arrayIndex++, colIndex += 2) { //translate 16-Bit integer array to 8-Bit-Image
                code.at<uchar>(cellIndex, colIndex) = (uniformHistogram[arrayIndex] & 0xFF00) >> 8;
                code.at<uchar>(cellIndex, colIndex + 1) = (uniformHistogram[arrayIndex] & 0x00FF);
            }
        }
    }

    delete[] histogram;
    delete[] uniformHistogram;
}

/**
 * Extracts the iris texture with 3 diffrent alignments and saves these in one big code map
 * @param code          the big code mat for the extraction data
 * @param texture       the iris texture which should be extracted
 * @param deltaShift    the maximum alignment for shifting
 */
void multipleExtract(Mat& code, const Mat& texture, const int deltaShift) {
    const int verticalCellNumber = texture.cols / CELL_WIDTH;
    const int horizontalCellNumber = texture.rows / CELL_HEIGHT;
    const int histogrammLength = 59; //58 uniform histograms + rest

    Mat extractedData(texture.rows, texture.cols, CV_8UC1);
    extractTexture(extractedData, FILTER_SIZE, texture);     //extract all features of this texture

    Mat singleCode(verticalCellNumber*horizontalCellNumber, 2 * histogrammLength, CV_8UC1);

    int counter = 0;
    for (int shift = -deltaShift; shift <= deltaShift; shift += deltaShift, counter++) {
        singleCode.setTo(0);
        extractHistograms(singleCode, extractedData, shift);
        singleCode.copyTo(code(Rect(0, counter*singleCode.rows, singleCode.cols, singleCode.rows)));
    }
}

/**
 * Scales a texuture
 * @param scaledTexture
 * @param orginalTexture
 */
void scaleImage(Mat& scaledTexture, const Mat& orginalTexture){
    resize(orginalTexture, scaledTexture, Size(SCALING_WIDTH,SCALING_HEIGHT), 0, 0);
}

/** ------------------------------- commandline functions ------------------------------- **/

/**
 * Parses a command line
 * This routine should be called for parsing command lines for executables.
 * Note, that all options require '-' as prefix and may contain an arbitrary
 * number of optional arguments.
 *
 * cmd: commandline representation
 * argc: number of parameters
 * argv: string array of argument values
 */
void cmdRead(map<string, vector<string> >& cmd, int argc, char *argv[]) {
    for (int i = 1; i < argc; i++) {
        char * argument = argv[i];
        if (strlen(argument) > 1 && argument[0] == '-' && (argument[1] < '0' || argument[1] > '9')) {
            cmd[argument]; // insert
            char * argument2;
            while (i + 1 < argc && (strlen(argument2 = argv[i + 1]) <= 1 || argument2[0] != '-' || (argument2[1] >= '0' && argument2[1] <= '9'))) {
                cmd[argument].push_back(argument2);
                i++;
            }
        }
        else {
            CV_Error(CV_StsBadArg, "Invalid command line format");
        }
    }
}

/**
 * Checks, if each command line option is valid, i.e. exists in the options array
 *
 * cmd: commandline representation
 * validOptions: list of valid options separated by pipe (i.e. |) character
 */
void cmdCheckOpts(map<string, vector<string> >& cmd, const string validOptions) {
    vector<string> tokens;
    const string delimiters = "|";
    string::size_type lastPos = validOptions.find_first_not_of(delimiters, 0); // skip delimiters at beginning
    string::size_type pos = validOptions.find_first_of(delimiters, lastPos); // find first non-delimiter
    while (string::npos != pos || string::npos != lastPos) {
        tokens.push_back(validOptions.substr(lastPos, pos - lastPos)); // add found token to vector
        lastPos = validOptions.find_first_not_of(delimiters, pos); // skip delimiters
        pos = validOptions.find_first_of(delimiters, lastPos); // find next non-delimiter
    }
    sort(tokens.begin(), tokens.end());
    for (map<string, vector<string> >::iterator it = cmd.begin(); it != cmd.end(); it++) {
        if (!binary_search(tokens.begin(), tokens.end(), it->first)) {
            CV_Error(CV_StsBadArg, "Command line parameter '" + it->first + "' not allowed.");
            tokens.clear();
            return;
        }
    }
    tokens.clear();
}

/*
 * Checks, if a specific required option exists in the command line
 *
 * cmd: commandline representation
 * option: option name
 */
void cmdCheckOptExists(map<string, vector<string> >& cmd, const string option) {
    map<string, vector<string> >::iterator it = cmd.find(option);
    if (it == cmd.end()) CV_Error(CV_StsBadArg, "Command line parameter '" + option + "' is required, but does not exist.");
}

/*
 * Checks, if a specific option has the appropriate number of parameters
 *
 * cmd: commandline representation
 * option: option name
 * size: appropriate number of parameters for the option
 */
void cmdCheckOptSize(map<string, vector<string> >& cmd, const string option, const unsigned int size = 1) {
    map<string, vector<string> >::iterator it = cmd.find(option);
    if (it->second.size() != size) CV_Error(CV_StsBadArg, "Command line parameter '" + option + "' has unexpected size.");
}

/*
 * Checks, if a specific option has the appropriate number of parameters
 *
 * cmd: commandline representation
 * option: option name
 * min: minimum appropriate number of parameters for the option
 * max: maximum appropriate number of parameters for the option
 */
void cmdCheckOptRange(map<string, vector<string> >& cmd, string option, unsigned int min = 0, unsigned int max = 1) {
    map<string, vector<string> >::iterator it = cmd.find(option);
    unsigned int size = it->second.size();
    if (size < min || size > max) CV_Error(CV_StsBadArg, "Command line parameter '" + option + "' is out of range.");
}

/*
 * Returns the list of parameters for a given option
 *
 * cmd: commandline representation
 * option: name of the option
 */
vector<string> * cmdGetOpt(map<string, vector<string> >& cmd, const string option) {
    map<string, vector<string> >::iterator it = cmd.find(option);
    return (it != cmd.end()) ? &(it->second) : 0;
}

/*
 * Returns number of parameters in an option
 *
 * cmd: commandline representation
 * option: name of the option
 */
unsigned int cmdSizePars(map<string, vector<string> >& cmd, const string option) {
    map<string, vector<string> >::iterator it = cmd.find(option);
    return (it != cmd.end()) ? it->second.size() : 0;
}

/*
 * Returns a specific parameter type (int) given an option and parameter index
 *
 * cmd: commandline representation
 * option: name of option
 * param: name of parameter
 */
int cmdGetParInt(map<string, vector<string> >& cmd, string option, unsigned int param = 0) {
    map<string, vector<string> >::iterator it = cmd.find(option);
    if (it != cmd.end()) {
        if (param < it->second.size()) {
            return atoi(it->second[param].c_str());
        }
    }
    return 0;
}

/*
 * Returns a specific parameter type (float) given an option and parameter index
 *
 * cmd: commandline representation
 * option: name of option
 * param: name of parameter
 */
float cmdGetParFloat(map<string, vector<string> >& cmd, const string option, const unsigned int param = 0) {
    map<string, vector<string> >::iterator it = cmd.find(option);
    if (it != cmd.end()) {
        if (param < it->second.size()) {
            return atof(it->second[param].c_str());
        }
    }
    return 0;
}

/*
 * Returns a specific parameter type (string) given an option and parameter index
 *
 * cmd: commandline representation
 * option: name of option
 * param: name of parameter
 */
string cmdGetPar(map<string, vector<string> >& cmd, const string option, const unsigned int param = 0) {
    map<string, vector<string> >::iterator it = cmd.find(option);
    if (it != cmd.end()) {
        if (param < it->second.size()) {
            return it->second[param];
        }
    }
    return 0;
}

/** ------------------------------- timing functions ------------------------------- **/

/**
 * Class for handling timing progress information
 */
class Timing {
public:
    /** integer indicating progress with respect tot total **/
    int progress;
    /** total count for progress **/
    int total;

    /*
     * Default constructor for timing initializing time.
     * Automatically calls init()
     *
     * seconds: update interval in seconds
     * eraseMode: if true, outputs sends erase characters at each print command
     */
    Timing(long seconds, bool eraseMode) {
        updateInterval = seconds;
        progress = 1;
        total = 100;
        eraseCount = 0;
        erase = eraseMode;
        init();
    }

    /*
     * Destructor
     */
    ~Timing() {
    }

    /*
     * Initializes timing variables
     */
    void init(void) {
        start = boost::posix_time::microsec_clock::universal_time();
        lastPrint = start - boost::posix_time::seconds(updateInterval);
    }

    /*
     * Clears printing (for erase option only)
     */
    void clear(void) {
        string erase(eraseCount, '\r');
        erase.append(eraseCount, ' ');
        erase.append(eraseCount, '\r');
        printf("%s", erase.c_str());
        eraseCount = 0;
    }

    /*
     * Updates current time and returns true, if output should be printed
     */
    bool update(void) {
        current = boost::posix_time::microsec_clock::universal_time();
        return ((current - lastPrint > boost::posix_time::seconds(updateInterval)) || (progress == total));
    }

    /*
     * Prints timing object to STDOUT
     */
    void print(void) {
        lastPrint = current;
        float percent = 100.f * progress / total;
        boost::posix_time::time_duration passed = (current - start);
        boost::posix_time::time_duration togo = passed * (total - progress) / max(1, progress);
        if (erase) {
            string erase(eraseCount, '\r');
            printf("%s", erase.c_str());
            int newEraseCount = (progress != total) ? printf("Progress ... %3.2f%% (%i/%i Total %i:%02i:%02i.%03i Remaining ca. %i:%02i:%02i.%03i)", percent, progress, total, passed.hours(), passed.minutes(), passed.seconds(), (int) (passed.total_milliseconds() % 1000), togo.hours(), togo.minutes(), togo.seconds(), (int) (togo.total_milliseconds() % 1000)) : printf("Progress ... %3.2f%% (%i/%i Total %i:%02i:%02i.%03d)", percent, progress, total, passed.hours(), passed.minutes(), passed.seconds(), (int) (passed.total_milliseconds() % 1000));
            if (newEraseCount < eraseCount) {
                string erase(newEraseCount - eraseCount, ' ');
                erase.append(newEraseCount - eraseCount, '\r');
                printf("%s", erase.c_str());
            }
            eraseCount = newEraseCount;
        }
        else {
            eraseCount = (progress != total) ? printf("Progress ... %3.2f%% (%i/%i Total %i:%02i:%02i.%03i Remaining ca. %i:%02i:%02i.%03i)\n", percent, progress, total, passed.hours(), passed.minutes(), passed.seconds(), (int) (passed.total_milliseconds() % 1000), togo.hours(), togo.minutes(), togo.seconds(), (int) (togo.total_milliseconds() % 1000)) : printf("Progress ... %3.2f%% (%i/%i Total %i:%02i:%02i.%03d)\n", percent, progress, total, passed.hours(), passed.minutes(), passed.seconds(), (int) (passed.total_milliseconds() % 1000));
        }
    }
private:
    long updateInterval;
    boost::posix_time::ptime start;
    boost::posix_time::ptime current;
    boost::posix_time::ptime lastPrint;
    int eraseCount;
    bool erase;
};

/** ------------------------------- file pattern matching functions ------------------------------- **/

/*
 * Formats a given string, such that it can be used as a regular expression
 * I.e. escapes special characters and uses * and ? as wildcards
 *
 * pattern: regular expression path pattern
 * pos: substring starting index
 * n: substring size
 *
 * returning: escaped substring
 */
string patternSubstrRegex(string& pattern, size_t pos, size_t n) {
    string result;
    for (size_t i = pos, e = pos + n; i < e; i++) {
        char c = pattern[i];
        if (c == '\\' || c == '.' || c == '+' || c == '[' || c == '{' || c == '|' || c == '(' || c == ')' || c == '^' || c == '$' || c == '}' || c == ']') {
            result.append(1, '\\');
            result.append(1, c);
        }
        else if (c == '*') {
            result.append("([^/\\\\]*)");
        }
        else if (c == '?') {
            result.append("([^/\\\\])");
        }
        else {
            result.append(1, c);
        }
    }
    return result;
}

/*
 * Converts a regular expression path pattern into a list of files matching with this pattern by replacing wildcards
 * starting in position pos assuming that all prior wildcards have been resolved yielding intermediate directory path.
 * I.e. this function appends the files in the specified path according to yet unresolved pattern by recursive calling.
 *
 * pattern: regular expression path pattern
 * files: the list to which new files can be applied
 * pos: an index such that positions 0...pos-1 of pattern are already considered/matched yielding path
 * path: the current directory (or empty)
 */
void patternToFiles(string& pattern, vector<string>& files, const size_t& pos, const string& path) {
    size_t first_unknown = pattern.find_first_of("*?", pos); // find unknown * in pattern
    if (first_unknown != string::npos) {
        size_t last_dirpath = pattern.find_last_of("/\\", first_unknown);
        size_t next_dirpath = pattern.find_first_of("/\\", first_unknown);
        if (next_dirpath != string::npos) {
            boost::regex expr((last_dirpath != string::npos && last_dirpath > pos) ? patternSubstrRegex(pattern, last_dirpath + 1, next_dirpath - last_dirpath - 1) : patternSubstrRegex(pattern, pos, next_dirpath - pos));
            boost::filesystem::directory_iterator end_itr; // default construction yields past-the-end
            try {
                for (boost::filesystem::directory_iterator itr(((path.length() > 0) ? path + pattern[pos - 1] : (last_dirpath != string::npos && last_dirpath > pos) ? "" : "./") + ((last_dirpath != string::npos && last_dirpath > pos) ? pattern.substr(pos, last_dirpath - pos) : "")); itr != end_itr; ++itr) {
                    if (boost::filesystem::is_directory(itr->path())) {
                        boost::filesystem::path p = itr->path().filename();
                        string s = p.string();
                        if (boost::regex_match(s.c_str(), expr)) {
                            patternToFiles(pattern, files, (int) (next_dirpath + 1), ((path.length() > 0) ? path + pattern[pos - 1] : "") + ((last_dirpath != string::npos && last_dirpath > pos) ? pattern.substr(pos, last_dirpath - pos) + pattern[last_dirpath] : "") + s);
                        }
                    }
                }
            } catch (boost::filesystem::filesystem_error &e) {
            }
        }
        else {
            boost::regex expr((last_dirpath != string::npos && last_dirpath > pos) ? patternSubstrRegex(pattern, last_dirpath + 1, pattern.length() - last_dirpath - 1) : patternSubstrRegex(pattern, pos, pattern.length() - pos));
            boost::filesystem::directory_iterator end_itr; // default construction yields past-the-end
            try {
                for (boost::filesystem::directory_iterator itr(((path.length() > 0) ? path + pattern[pos - 1] : (last_dirpath != string::npos && last_dirpath > pos) ? "" : "./") + ((last_dirpath != string::npos && last_dirpath > pos) ? pattern.substr(pos, last_dirpath - pos) : "")); itr != end_itr; ++itr) {
                    boost::filesystem::path p = itr->path().filename();
                    string s = p.string();
                    if (boost::regex_match(s.c_str(), expr)) {
                        files.push_back(((path.length() > 0) ? path + pattern[pos - 1] : "") + ((last_dirpath != string::npos && last_dirpath > pos) ? pattern.substr(pos, last_dirpath - pos) + pattern[last_dirpath] : "") + s);
                    }
                }
            } catch (boost::filesystem::filesystem_error &e) {
            }
        }
    }
    else { // no unknown symbols
        boost::filesystem::path file(((path.length() > 0) ? path + "/" : "") + pattern.substr(pos, pattern.length() - pos));
        if (boost::filesystem::exists(file)) {
            files.push_back(file.string());
        }
    }
}

/**
 * Converts a regular expression path pattern into a list of files matching with this pattern
 *
 * pattern: regular expression path pattern
 * files: the list to which new files can be applied
 */
void patternToFiles(string& pattern, vector<string>& files) {
    patternToFiles(pattern, files, 0, "");
}

/*
 * Renames a given filename corresponding to the actual file pattern using a renaming pattern.
 * Wildcards can be referred to as ?1, ?2, ... in the order they appeared in the file pattern.
 *
 * pattern: regular expression path pattern
 * renamePattern: renaming pattern using ?1, ?2, ... as placeholders for wildcards
 * infile: path of the file (matching with pattern) to be renamed
 * outfile: path of the renamed file
 * par: used parameter (default: '?')
 */
void patternFileRename(string& pattern, const string& renamePattern, const string& infile, string& outfile, const char par = '?') {
    size_t first_unknown = renamePattern.find_first_of(par, 0); // find unknown ? in renamePattern
    if (first_unknown != string::npos) {
        string formatOut = "";
        for (size_t i = 0, e = renamePattern.length(); i < e; i++) {
            char c = renamePattern[i];
            if (c == par && i + 1 < e) {
                c = renamePattern[i + 1];
                if (c > '0' && c <= '9') {
                    formatOut.append(1, '$');
                    formatOut.append(1, c);
                }
                else {
                    formatOut.append(1, par);
                    formatOut.append(1, c);
                }
                i++;
            }
            else {
                formatOut.append(1, c);
            }
        }
        boost::regex patternOut(patternSubstrRegex(pattern, 0, pattern.length()));
        outfile = boost::regex_replace(infile, patternOut, formatOut, boost::match_default | boost::format_perl);
    }
    else {
        outfile = renamePattern;
    }
}

/** ------------------------------- Program ------------------------------- **/

/*
 * Main program
 */
int main(int argc, char *argv[]) {
    int mode = MODE_HELP;
    map<string, vector<string> > cmd;
    try {
        cmdRead(cmd, argc, argv);
        if (cmd.size() == 0 || cmdGetOpt(cmd, "-h") != 0) mode = MODE_HELP;
        else mode = MODE_MAIN;
        if (mode == MODE_MAIN) {
            // validate command line
            cmdCheckOpts(cmd, "-i|-o|-m|-q|-t");

            cmdCheckOptExists(cmd, "-i");
            cmdCheckOptSize(cmd, "-i", 1);
            string inFiles = cmdGetPar(cmd, "-i");

            cmdCheckOptExists(cmd, "-o");
            cmdCheckOptSize(cmd, "-o", 1);
            string outFiles = cmdGetPar(cmd, "-o");

            string imaskFiles, omaskFiles;

            if (cmdGetOpt(cmd, "-m") != 0) {
                cmdCheckOptSize(cmd, "-m", 2);
                imaskFiles = cmdGetPar(cmd, "-m", 0);
                omaskFiles = cmdGetPar(cmd, "-m", 1);
            }
            bool quiet = false;
            if (cmdGetOpt(cmd, "-q") != 0) {
                cmdCheckOptSize(cmd, "-q", 0);
                quiet = true;
            }
            bool time = false;
            if (cmdGetOpt(cmd, "-t") != 0) {
                cmdCheckOptSize(cmd, "-t", 0);
                time = true;
            }
            // starting routine
            Timing timing(1, quiet);
            vector<string> files;
            patternToFiles(inFiles, files);
            CV_Assert(files.size() > 0);
            timing.total = files.size();
            for (vector<string>::iterator inFile = files.begin(); inFile != files.end(); ++inFile, timing.progress++) {
                if (!quiet) printf("Loading texture '%s' ...\n", (*inFile).c_str());

                Mat imgOrginal = imread(*inFile, CV_LOAD_IMAGE_GRAYSCALE);
                CV_Assert(imgOrginal.data != 0);
                Mat out;
                if (imgOrginal.rows != 64 || imgOrginal.cols != 512) {
                    printf("Input texture has to be of size 512 x 64.\n");
                    exit(EXIT_FAILURE);
                }

                Mat img;
                scaleImage(img, imgOrginal);

                int verticalCellNumber = img.cols / CELL_WIDTH; //width
                int horizontalCellNumber = img.rows / CELL_HEIGHT; //height

                if (!quiet) printf("Creating %d x %d iris-code ...\n", 118, verticalCellNumber * horizontalCellNumber*3);
                Mat code(verticalCellNumber*horizontalCellNumber*3, 118, CV_8UC1);
                code.setTo(0);
                multipleExtract(code, img, DELTA_SHIFT);
                out = code;
                string outfile;
                patternFileRename(inFiles, outFiles, *inFile, outfile);
                if (!quiet) printf("Storing code '%s' ...\n", outfile.c_str());
                if (!imwrite(outfile, out)) CV_Error(CV_StsError, "Could not save image '" + outfile + "'");
                if (time && timing.update()) timing.print();
            }
            if (time && quiet) timing.clear();
        }
        else if (mode == MODE_HELP) {
            // validate command line
            cmdCheckOpts(cmd, "-h");
            if (cmdGetOpt(cmd, "-h") != 0) cmdCheckOptSize(cmd, "-h", 0);
            // starting routine
            printUsage();
        }
    } catch (...) {
        printf("Exit with errors.\n");
        exit(EXIT_FAILURE);
    }
    return EXIT_SUCCESS;
}

ext: cpp


text: #include <boost/bimap/relation/support/get_pair_functor.hpp>

max_stars_repo_name: miathedev/BoostForArduino

max_issues_repo_name: miathedev/BoostForArduino

max_forks_repo_name: miathedev/BoostForArduino


text:
#include "stdafx.h"
#include <boost/test/output/compiler_log_formatter.hpp>

class SpecLogFormatter :
	public boost::unit_test::output::compiler_log_formatter
{
	virtual void test_unit_start(std::ostream &os, boost::unit_test::test_unit const& tu) override
	{
		os << std::string(m_indent, ' ') << boost::replace_all_copy(tu.p_name.get(), "_", " ") << std::endl;
		m_indent += 2;
	}

	virtual void test_unit_finish(std::ostream &/*os*/, boost::unit_test::test_unit const& /*tu*/, unsigned long /*elapsed*/) override
	{
		m_indent -= 2;
	}

	int m_indent = 0;
};

boost::unit_test::test_suite* init_unit_test_suite(int /*argc*/, char* /*argv*/[])
{
	boost::unit_test::unit_test_log.set_formatter(new SpecLogFormatter);
	boost::unit_test::framework::master_test_suite().p_name.value = "All tests";
	return 0;
}

int main(int argc, char* argv[])
{
	return boost::unit_test::unit_test_main(&init_unit_test_suite, argc, argv);
}

max_stars_repo_name: AlexanderChibirev/OOP

max_issues_repo_name: AlexanderChibirev/OOP

max_forks_repo_name: AlexanderChibirev/OOP