Skip to content

Instantly share code, notes, and snippets.

@kyleingraham
Created August 23, 2020 16:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kyleingraham/fde1ea36f9e33a5ac53b067d60ba8ce1 to your computer and use it in GitHub Desktop.
Save kyleingraham/fde1ea36f9e33a5ac53b067d60ba8ce1 to your computer and use it in GitHub Desktop.
Calculate/Export Radiometric Response Function with OpenCV
#include <fstream>
#include <iostream>
#include <opencv2/core/utility.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/photo.hpp>
void load_exposure_data(std::ifstream& list_file,
std::vector<cv::Mat>& exposures,
std::vector<float>& exposure_times);
bool response_monotonic(const cv::Mat& response);
void write_response_csv(std::ofstream& csv, const cv::Mat& response);
int main(int argc, const char* argv[]) {
const std::string keys{
"{l list |list.txt| list file of images and inverse exposure times}"
"{o output |response.csv| file path at which to save response CSV}"};
cv::CommandLineParser parser(argc, argv, keys);
std::string list_file_name{parser.get<std::string>("list")};
std::ifstream list_file(list_file_name);
std::vector<cv::Mat> exposures;
std::vector<float> exposure_times;
load_exposure_data(list_file, exposures, exposure_times);
std::cout << "Loaded exposure data from: " << list_file_name << "\n";
cv::Ptr<cv::CalibrateDebevec> calibrator = cv::createCalibrateDebevec();
cv::Mat response;
calibrator->process(exposures, response, exposure_times);
if (response_monotonic(response)) {
std::cout << "Calculated response is monotonic.\n";
} else {
std::cout << "Calculated response is not monotonic.\n";
}
std::string output_file_name{parser.get<std::string>("output")};
std::ofstream csv(output_file_name);
write_response_csv(csv, response);
std::cout << "Wrote response to: " << output_file_name << "\n";
return 0;
}
void load_exposure_data(std::ifstream& list_file,
std::vector<cv::Mat>& exposures,
std::vector<float>& exposure_times) {
std::string exposure_file_name;
float inverse_exposure_time;
while (list_file >> exposure_file_name >> inverse_exposure_time) {
cv::Mat exposure{cv::imread(exposure_file_name)};
exposures.push_back(exposure);
exposure_times.push_back(1 / inverse_exposure_time);
}
list_file.close();
}
bool response_monotonic(const cv::Mat& response) {
bool at_start{true}, is_monotonic{true};
float blue_before{0}, green_before{0}, red_before{0};
cv::MatConstIterator_<cv::Vec3f> response_iter{response.begin<cv::Vec3f>()};
for (; response_iter != response.end<cv::Vec3f>(); ++response_iter) {
float blue_now{(*response_iter)[0]}, green_now{(*response_iter)[1]},
red_now{(*response_iter)[2]};
if (at_start) {
blue_now = blue_before;
green_now = green_before;
red_now = red_before;
at_start = false;
continue;
}
if (!(blue_before <= blue_now || green_before <= green_now ||
red_before <= red_now)) {
std::cout << blue_before << blue_now << green_before << green_now
<< red_before << red_now;
is_monotonic = false;
break;
}
}
return is_monotonic;
}
void write_response_csv(std::ofstream& csv, const cv::Mat& response) {
csv << "blue_input,blue_response,green_input,green_response,"
"red_input,red_response\n";
int pixel_value{0};
cv::MatConstIterator_<cv::Vec3f> response_iter = response.begin<cv::Vec3f>();
for (; response_iter != response.end<cv::Vec3f>(); ++response_iter) {
csv << (*response_iter)[0] << "," << pixel_value << ","
<< (*response_iter)[1] << "," << pixel_value << ","
<< (*response_iter)[2] << "," << pixel_value << "\n";
++pixel_value;
}
csv.close();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment