This program demonstrates how to use most features of the pipeline, as well as allowing use of the pipeline itself through execution.
#include <armadillo>
#include <boost/program_options.hpp>
#include <boost/filesystem.hpp>
#include <opencv2/opencv.hpp>
#include <memory>
#include <chrono>
namespace po = boost::program_options;
int main(
int argc, 
char** argv)
 
{
    
    bool        show_images;
    bool        recover_illuminant;
    bool        recover_dichromatic;
    bool        process;
    bool        save = false;
    bool        keep_time;
    bool        save_refl;
    bool        nurbs;
    bool        filter;
    bool        quick_mat;
    bool        calc_error;
    int         debug;
    float       ill_alpha;
    int         ill_patch_size;
    int         dic_neigh_size;
    int         dic_gray_thres;
    int         mat_max_clust;
    int         mat_abund_num;
    float       resample;
    float       mat_temp_max;
    float       mat_temp_min;
    float       mat_cool_rate;
    float       mat_split_th;
    std::string filename;
    std::string savename;
    
    po::options_description desc("Allowed options");
    desc.add_options()
        ("help,h",           "Convey usage information")
        ("file,f",           po::value<std::string>(&filename)->default_value(""),   "Path to input file")
        ("save,o",           po::value<std::string>(&savename)->default_value(""),   "Path to output file HSZ or HDR (.hdr, .fla, .raw etc)")
        ("illuminant,i",     po::bool_switch(&recover_illuminant),                   "Perform illuminant recovery")
        ("dichromatic,d",    po::bool_switch(&recover_dichromatic),                  "Perform dichromatic decompose")
        ("material,m",       po::bool_switch(&recover_materials),                    "Perform material recovery")
        ("process,p",        po::bool_switch(&process),                              "Perform whole processing pipeline ( -i -d -m -a)")
        ("show_images,s",    po::bool_switch(&show_images),                          "Show images")
        ("print_timing,t",   po::bool_switch(&keep_time),                            "Print timing information (Walltime)")
        ("no_nurbs,n",       po::bool_switch(&nurbs),                                "Use NURBS when encoding HSZ")
        ("filter,w",         po::bool_switch(&filter),                               "Filter image before processing")
        ("quick_mat,q",      po::bool_switch(&quick_mat),                            "Use Fast material clustering method")
        ("reflectance",      po::bool_switch(&save_refl),                            "Save Reflectance Cube")
        ("calc_error,e",      po::bool_switch(&calc_error),                          "Calculate and print the RMS Error")
        ("resample,r",       po::value<float>(&resample)->default_value(1.0f),       "Resample the image by a factor ( 1 = None, 2 = /2, 4 = /4 etc.)")
        ("verbosity,v",      po::value<int>(&debug)->default_value(2),               "Quantity of output desired (0 = none, 5 = max)")
        ("ill_alpha",        po::value<float>(&ill_alpha)->default_value(50.0f),     "Illuminant Recovery Alpha value ( > 0, default = 50)")
        ("ill_patch_size",   po::value<int>(&ill_patch_size)->default_value(20),     "Illuminant patch size ( > 1, default = 20)")
        ("dic_size",         po::value<int>(&dic_neigh_size)->default_value(5),      "Dichromatic Neighbourhood Size ( > 0, default 5)")
        ("dic_gray_thres",   po::value<int>(&dic_gray_thres)->default_value(2),      "Dichromatic Gray Threshold ( > 0, default 2)")
        ("mat_max_clust",    po::value<int>(&mat_max_clust)->default_value(20),      "Material Recovery Max Clusters ( > 0, default 20)")
        ("mat_abund_num",    po::value<int>(&mat_abund_num)->default_value(5),       "Material Abundance per pixel ( > 1, default 5)")
        ("mat_temp_max",     po::value<float>(&mat_temp_max)->default_value(0.02f),  "Material Recovery Max Temperature ( > Min Temp, default 0.02)")
        ("mat_temp_min",     po::value<float>(&mat_temp_min)->default_value(0.00025f),"Material Recovery Min Temperature ( < Max Temp, default 0.00025)")
        ("mat_cool_rate",    po::value<float>(&mat_cool_rate)->default_value(0.8f),  "Material Recovery Cooling Rate ( <0, default 0.8)")
        ("mat_split_th",     po::value<float>(&mat_split_th)->default_value(-1),     "Material Recovery Cluster Split Threshold ( < 0, default cos(5pi / 180))")
        ;
    
    po::variables_map vm;
    po::store(po::parse_command_line(argc, argv, desc), vm);
    po::notify(vm);
    
    
    
    if (vm.count("help")) {
        std::cout << desc << std::endl;
        return 0;
    }
    
    std::shared_ptr<scyl::input>  input;
    std::shared_ptr<scyl::output> output;
    
    std::string file_extension  = boost::filesystem::extension(filename);
    std::string save_extension  = boost::filesystem::extension(savename);
    
    if (file_extension.compare(".hsz") == 0 ||
        file_extension.compare(".HSZ") == 0)
    {
        
        input = std::make_shared<scyl::hsz_input>(filename);
        std::cout << "Loaded " << filename << std::endl;
    } else if (!file_extension.empty())
    {
        
        
        input = std::make_shared<scyl::hdr_input>(filename);
        std::cout << "Loaded " << filename << std::endl;
    } else
    {
        std::cout << "The file you have supplied for input is not supported. Try .hsz or .hdr files." << std::endl;
        std::cout << desc << std::endl;
        return -1;
    }
    
    if (savename != "")
    {
        
        if (save_extension.compare(".hsz") == 0 ||
            save_extension.compare(".HSZ") == 0)
        {
            
            output = std::make_shared<scyl::hsz_output>();
            save = true;
        } else if (!save_extension.empty())
        {
            
            output = std::make_shared<scyl::hdr_output>(save_refl);
            save = true;
        } else
        {
            
            std::cout << "The file you have supplied for out is not supported. Try .hsz or .hdr files." << std::endl;
            std::cout << desc << std::endl;
            return -1;
        }
    }
    
    
    if (save)
    {
        
    } else
    {
        
    }
    
  
  
    if (quick_mat)
    {
    } else {
    }
    
    if (filter)
    {
        std::cout << "Filtering Image..." << std::endl;
    }
    
    if (!(resample < 1.0f + arma::Datum<float>::eps and resample > 1.0f - arma::Datum<float>::eps) and resample > 0.0f)
    {
    }
    
    if (pipeline.
height() > 1500 || pipeline.
width() > 1500)
 
    {
        std::cout << "Image is very large, may take long time and a lot of memory to process" << std::endl << "Use '-r' to resample image smaller" << std::endl;
    }
    
    
    if (process)
    {
        recover_illuminant  = true;
        recover_dichromatic = true;
        recover_materials   = true;
    }
    
    std::chrono::time_point<std::chrono::system_clock> begin, end;
    std::chrono::duration<float> time_ill = std::chrono::duration<float>(0);
    std::chrono::duration<float> time_dic = std::chrono::duration<float>(0);
    std::chrono::duration<float> time_mat = std::chrono::duration<float>(0);
    begin = std::chrono::system_clock::now();
    try
    {
        if (recover_illuminant)
        {
            
            end = std::chrono::system_clock::now();
            time_ill = end - begin;
        }
        if (recover_dichromatic)
        {
            
            end = std::chrono::system_clock::now();
            time_dic = end - begin;
        }
        if (recover_materials)
        {
            
            end = std::chrono::system_clock::now();
            time_mat = end - begin;
        }
        if (save)
        {
            
            std::cout << "Saved " << savename << std::endl;
        }
    } catch (std::exception & e)
    {
        
        std::cout << e.what() << std::endl;
        return -1;
    }
    
    if (show_images)
    {
        
        cv::Mat tmp[3];
        
        
        arma::fcube 
I = pipeline.
I();
        cv::Mat showI;
        cv::merge(tmp, 3, showI);
        cv::namedWindow("I", CV_WINDOW_FREERATIO);
        cv::imshow("I", showI);
        try
        {
           std::cout << 
"Recovered Illuminant" << std::endl << pipeline.
illuminant() << std::endl;
        } catch (std::exception & e) {}
        try
        {
            
            tmp2.convertTo(tmp2, CV_8UC1, 255.0);
            cv::Mat showM;
            cv::applyColorMap(tmp2, showM, cv::COLORMAP_RAINBOW);
            cv::namedWindow("Material Map", CV_WINDOW_FREERATIO);
            cv::imshow("Material Map", showM);
        } catch (std::exception & e) {
            std::cout << e.what() << std::endl;
        }
        try
        {
            
            cv::namedWindow("Shading", CV_WINDOW_FREERATIO);
            cv::imshow(
"Shading", showg/pipeline.
g().max());
        } catch (std::exception & e) {}
        cv::waitKey(0);
    }
    
    if(keep_time)
    {
        std::cout << ">-------------------------------------------------------<" << std::endl
                  << 
"Image:            " << filename << 
" (" << pipeline.
height() << 
"x" << pipeline.
width() << 
"x" << pipeline.
bands() << 
")" << std::endl
                  << "Illuminant Time:  " << time_ill.count() << std::endl
                  << "Dichromatic Time: " << time_dic.count() - time_ill.count() << std::endl
                  << "Material Time:    " << time_mat.count() - time_dic.count() << std::endl
                  << "Total Time:       " << time_mat.count() << std::endl
                  << ">-------------------------------------------------------<" << std::endl;
    }
    
    if (calc_error)
    {
        try
        {
            reconstructed_I -= pipeline.
I();
            float rms = arma::accu(arma::sqrt(arma::square(reconstructed_I)))/reconstructed_I.n_elem;
            std::cout << 
"RMS Error: " << rms << 
" (max = " << pipeline.
I().max() << 
"), " << rms/pipeline.
I().max()*100.0 << 
"%" << std::endl;
        } catch (std::exception & e) {}
    }
    return 0;
}