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