Calculate/Export Radiometric Response Function with OpenCV
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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