main
Matthew 6 months ago
parent 2767bab6ea
commit 38e4ef464c

@ -1,19 +1,19 @@
#include "hdrplus/hdrplus_pipeline.h" #include "hdrplus/hdrplus_pipeline.h"
int main( int argc, char** argv ) int main(int argc, char** argv)
{ {
std::vector<std::string> paths; std::vector<std::string> paths;
for (int idx = 2; idx < argc; idx++) for (int idx = 2; idx < argc; idx++)
{ {
paths.push_back(argv[idx]); paths.push_back(argv[idx]);
} }
cv::Mat rgb; cv::Mat rgb;
hdrplus::hdrplus_pipeline pipeline; hdrplus::hdrplus_pipeline pipeline;
pipeline.run_pipeline( paths, 0, rgb); pipeline.run_pipeline(paths, 0, rgb);
cv::imwrite(argv[1], rgb); cv::imwrite(argv[1], rgb);
return 0; return 0;
} }

@ -13,239 +13,242 @@
namespace hdrplus namespace hdrplus
{ {
uint16_t uGammaCompress_1pix(float x, float threshold,float gainMin,float gainMax,float exponent); uint16_t uGammaCompress_1pix(float x, float threshold, float gainMin, float gainMax, float exponent);
uint16_t uGammaDecompress_1pix(float x, float threshold,float gainMin,float gainMax,float exponent); uint16_t uGammaDecompress_1pix(float x, float threshold, float gainMin, float gainMax, float exponent);
cv::Mat uGammaCompress_(cv::Mat m,float threshold,float gainMin,float gainMax,float exponent); cv::Mat uGammaCompress_(cv::Mat m, float threshold, float gainMin, float gainMax, float exponent);
cv::Mat uGammaDecompress_(cv::Mat m,float threshold,float gainMin,float gainMax,float exponent); cv::Mat uGammaDecompress_(cv::Mat m, float threshold, float gainMin, float gainMax, float exponent);
cv::Mat gammasRGB(cv::Mat img, bool mode); cv::Mat gammasRGB(cv::Mat img, bool mode);
class finish class finish
{ {
public: public:
cv::Mat mergedBayer; // merged image from Merge Module cv::Mat mergedBayer; // merged image from Merge Module
std::string burstPath; // path to burst images std::string burstPath; // path to burst images
std::vector<std::string> rawPathList; // a list or array of the path to all burst imgs under burst Path std::vector<std::string> rawPathList; // a list or array of the path to all burst imgs under burst Path
int refIdx; // index of the reference img int refIdx; // index of the reference img
Parameters params; Parameters params;
cv::Mat rawReference; cv::Mat rawReference;
// LibRaw libraw_processor_finish; // LibRaw libraw_processor_finish;
bayer_image* refBayer; bayer_image* refBayer;
std::string mergedImgPath; std::string mergedImgPath;
finish() finish()
{ {
refBayer = NULL; refBayer = NULL;
} }
// please use this initialization after merging part finish // please use this initialization after merging part finish
finish(std::string burstPath, cv::Mat mergedBayer,int refIdx) { finish(std::string burstPath, cv::Mat mergedBayer, int refIdx) {
refBayer = NULL; refBayer = NULL;
this->refIdx = refIdx; this->refIdx = refIdx;
this->burstPath = burstPath; this->burstPath = burstPath;
this->mergedBayer = mergedBayer; this->mergedBayer = mergedBayer;
} }
// for local testing only // for local testing only
finish(std::string burstPath, std::string mergedBayerPath,int refIdx){ finish(std::string burstPath, std::string mergedBayerPath, int refIdx) {
this->refIdx = refIdx; this->refIdx = refIdx;
this->burstPath = burstPath; this->burstPath = burstPath;
this->mergedBayer = loadFromCSV(mergedBayerPath, CV_16UC1);// this->mergedBayer = loadFromCSV(mergedBayerPath, CV_16UC1);//
load_rawPathList(burstPath); load_rawPathList(burstPath);
refBayer= new bayer_image(this->rawPathList[refIdx]); refBayer = new bayer_image(this->rawPathList[refIdx]);
this->rawReference = refBayer->raw_image;//;grayscale_image this->rawReference = refBayer->raw_image;//;grayscale_image
// initialize parameters in libraw_processor_finish // initialize parameters in libraw_processor_finish
setLibRawParams(); setLibRawParams();
showParams(); showParams();
std::cout<<"Finish init() finished!"<<std::endl; std::cout << "Finish init() finished!" << std::endl;
} }
~finish() ~finish()
{ {
if (refBayer != NULL) if (refBayer != NULL)
{ {
delete refBayer; delete refBayer;
refBayer = NULL; refBayer = NULL;
} }
} }
// finish pipeline func // finish pipeline func
// void process(std::string burstPath, cv::Mat mergedBayer,int refIdx); // void process(std::string burstPath, cv::Mat mergedBayer,int refIdx);
void process(const hdrplus::burst& burst_images, cv::Mat& finalOutputImage); void process(const hdrplus::burst& burst_images, cv::Mat& finalOutputImage);
// replace Mat a with Mat b // replace Mat a with Mat b
void copy_mat_16U(cv::Mat& A, cv::Mat B); void copy_mat_16U(cv::Mat& A, cv::Mat B);
void copy_rawImg2libraw(std::shared_ptr<LibRaw>& libraw_ptr, cv::Mat B); void copy_rawImg2libraw(std::shared_ptr<LibRaw>& libraw_ptr, cv::Mat B);
// postprocess // postprocess
// cv::Mat postprocess(std::shared_ptr<LibRaw>& libraw_ptr); // cv::Mat postprocess(std::shared_ptr<LibRaw>& libraw_ptr);
void showImg(cv::Mat img) void showImg(cv::Mat img)
{ {
int ch = CV_MAT_CN(CV_8UC1); int ch = CV_MAT_CN(CV_8UC1);
// cv::Mat tmp(4208,3120,CV_16UC1); // cv::Mat tmp(4208,3120,CV_16UC1);
cv::Mat tmp(img); cv::Mat tmp(img);
// uint16_t* ptr_tmp = (uint16_t*)tmp.data; // uint16_t* ptr_tmp = (uint16_t*)tmp.data;
// uint16_t* ptr_img = (uint16_t*)img.data; // uint16_t* ptr_img = (uint16_t*)img.data;
// // col major to row major // // col major to row major
// for(int r = 0; r < tmp.rows; r++) { // for(int r = 0; r < tmp.rows; r++) {
// for(int c = 0; c < tmp.cols; c++) { // for(int c = 0; c < tmp.cols; c++) {
// *(ptr_tmp+r*tmp.cols+c) = *(ptr_img+c*tmp.rows+r)/2048.0*255.0; // *(ptr_tmp+r*tmp.cols+c) = *(ptr_img+c*tmp.rows+r)/2048.0*255.0;
// } // }
// } // }
// std::cout<<"height="<<tmp.rows<<std::endl; // std::cout<<"height="<<tmp.rows<<std::endl;
// std::cout<<"width="<<tmp.cols<<std::endl; // std::cout<<"width="<<tmp.cols<<std::endl;
// cv::transpose(tmp, tmp); // cv::transpose(tmp, tmp);
uint16_t* ptr = (uint16_t*)tmp.data; uint16_t* ptr = (uint16_t*)tmp.data;
for(int r = 0; r < tmp.rows; r++) { for (int r = 0; r < tmp.rows; r++) {
for(int c = 0; c < tmp.cols; c++) { for (int c = 0; c < tmp.cols; c++) {
*(ptr+r*tmp.cols+c) = *(ptr+r*tmp.cols+c)/2048.0*255.0; *(ptr + r * tmp.cols + c) = *(ptr + r * tmp.cols + c) / 2048.0*255.0;
} }
} }
tmp = tmp.reshape(ch); tmp = tmp.reshape(ch);
tmp.convertTo(tmp, CV_8UC1); tmp.convertTo(tmp, CV_8UC1);
cv::imshow("test",tmp); cv::imshow("test", tmp);
cv::imwrite("test2.jpg", tmp); cv::imwrite("test2.jpg", tmp);
cv::waitKey(0); cv::waitKey(0);
std::cout<< this->mergedBayer.size()<<std::endl; std::cout << this->mergedBayer.size() << std::endl;
} }
void showMat(cv::Mat img){ void showMat(cv::Mat img) {
std::cout<<"size="<<img.size()<<std::endl; std::cout << "size=" << img.size() << std::endl;
std::cout<<"type="<<img.type()<<std::endl; std::cout << "type=" << img.type() << std::endl;
} }
void showParams() void showParams()
{ {
std::cout<<"Parameters:"<<std::endl; std::cout << "Parameters:" << std::endl;
std::cout<<"tuning_ltmGain = "<<this->params.tuning.ltmGain<<std::endl; std::cout << "tuning_ltmGain = " << this->params.tuning.ltmGain << std::endl;
std::cout<<"tuning_gtmContrast = "<<this->params.tuning.gtmContrast<<std::endl; std::cout << "tuning_gtmContrast = " << this->params.tuning.gtmContrast << std::endl;
for(auto key_val:this->params.flags){ for (auto key_val : this->params.flags) {
std::cout<<key_val.first<<","<<key_val.second<<std::endl; std::cout << key_val.first << "," << key_val.second << std::endl;
} }
std::cout<<"demosaic_algorithm = "<<refBayer->libraw_processor->imgdata.params.user_qual<<std::endl; std::cout << "demosaic_algorithm = " << refBayer->libraw_processor->imgdata.params.user_qual << std::endl;
std::cout<<"half_size = "<<refBayer->libraw_processor->imgdata.params.half_size<<std::endl; std::cout << "half_size = " << refBayer->libraw_processor->imgdata.params.half_size << std::endl;
std::cout<<"use_camera_wb = "<<refBayer->libraw_processor->imgdata.params.use_camera_wb<<std::endl; std::cout << "use_camera_wb = " << refBayer->libraw_processor->imgdata.params.use_camera_wb << std::endl;
std::cout<<"use_auto_wb = "<<refBayer->libraw_processor->imgdata.params.use_auto_wb<<std::endl; std::cout << "use_auto_wb = " << refBayer->libraw_processor->imgdata.params.use_auto_wb << std::endl;
std::cout<<"no_auto_bright = "<<refBayer->libraw_processor->imgdata.params.no_auto_bright<<std::endl; std::cout << "no_auto_bright = " << refBayer->libraw_processor->imgdata.params.no_auto_bright << std::endl;
std::cout<<"output_color = "<<refBayer->libraw_processor->imgdata.params.output_color <<std::endl; std::cout << "output_color = " << refBayer->libraw_processor->imgdata.params.output_color << std::endl;
std::cout<<"gamma[0] = "<<refBayer->libraw_processor->imgdata.params.gamm[0]<<std::endl; std::cout << "gamma[0] = " << refBayer->libraw_processor->imgdata.params.gamm[0] << std::endl;
std::cout<<"gamma[1] = "<<refBayer->libraw_processor->imgdata.params.gamm[1]<<std::endl; std::cout << "gamma[1] = " << refBayer->libraw_processor->imgdata.params.gamm[1] << std::endl;
std::cout<<"output_bps = "<<refBayer->libraw_processor->imgdata.params.output_bps<<std::endl; std::cout << "output_bps = " << refBayer->libraw_processor->imgdata.params.output_bps << std::endl;
// std::cout<<"demosaic_algorithm = "<<libraw_processor_finish.imgdata.params.user_qual<<std::endl; // std::cout<<"demosaic_algorithm = "<<libraw_processor_finish.imgdata.params.user_qual<<std::endl;
// std::cout<<"half_size = "<<libraw_processor_finish.imgdata.params.half_size<<std::endl; // std::cout<<"half_size = "<<libraw_processor_finish.imgdata.params.half_size<<std::endl;
// std::cout<<"use_camera_wb = "<<libraw_processor_finish.imgdata.params.use_camera_wb<<std::endl; // std::cout<<"use_camera_wb = "<<libraw_processor_finish.imgdata.params.use_camera_wb<<std::endl;
// std::cout<<"use_auto_wb = "<<libraw_processor_finish.imgdata.params.use_auto_wb<<std::endl; // std::cout<<"use_auto_wb = "<<libraw_processor_finish.imgdata.params.use_auto_wb<<std::endl;
// std::cout<<"no_auto_bright = "<<libraw_processor_finish.imgdata.params.no_auto_bright<<std::endl; // std::cout<<"no_auto_bright = "<<libraw_processor_finish.imgdata.params.no_auto_bright<<std::endl;
// std::cout<<"output_color = "<<libraw_processor_finish.imgdata.params.output_color <<std::endl; // std::cout<<"output_color = "<<libraw_processor_finish.imgdata.params.output_color <<std::endl;
// std::cout<<"gamma[0] = "<<libraw_processor_finish.imgdata.params.gamm[0]<<std::endl; // std::cout<<"gamma[0] = "<<libraw_processor_finish.imgdata.params.gamm[0]<<std::endl;
// std::cout<<"gamma[1] = "<<libraw_processor_finish.imgdata.params.gamm[1]<<std::endl; // std::cout<<"gamma[1] = "<<libraw_processor_finish.imgdata.params.gamm[1]<<std::endl;
// std::cout<<"output_bps = "<<libraw_processor_finish.imgdata.params.output_bps<<std::endl; // std::cout<<"output_bps = "<<libraw_processor_finish.imgdata.params.output_bps<<std::endl;
std::cout<<"===================="<<std::endl; std::cout << "====================" << std::endl;
} }
void showRawPathList(){ void showRawPathList() {
std::cout<<"RawPathList:"<<std::endl; std::cout << "RawPathList:" << std::endl;
for(auto pth:this->rawPathList){ for (auto pth : this->rawPathList) {
std::cout<<pth<<std::endl; std::cout << pth << std::endl;
} }
std::cout<<"===================="<<std::endl; std::cout << "====================" << std::endl;
} }
private: private:
cv::Mat loadFromCSV(const std::string& path, int opencv_type) cv::Mat loadFromCSV(const std::string& path, int opencv_type)
{ {
cv::Mat m; cv::Mat m;
std::ifstream csvFile (path); std::ifstream csvFile(path);
std::string line; std::string line;
while (getline(csvFile, line)) while (getline(csvFile, line))
{ {
std::vector<int> dvals; std::vector<int> dvals;
std::stringstream ss(line); std::stringstream ss(line);
std::string val; std::string val;
// int count=0; // int count=0;
while (getline(ss, val, ',')) while (getline(ss, val, ','))
{ {
dvals.push_back(stod(val));//*255.0/2048.0 dvals.push_back(stod(val));//*255.0/2048.0
// count++; // count++;
} }
// std::cout<<count<<std::endl; // std::cout<<count<<std::endl;
cv::Mat mline(dvals, true); cv::Mat mline(dvals, true);
cv::transpose(mline, mline); cv::transpose(mline, mline);
m.push_back(mline); m.push_back(mline);
} }
int ch = CV_MAT_CN(opencv_type); int ch = CV_MAT_CN(opencv_type);
m = m.reshape(ch); m = m.reshape(ch);
m.convertTo(m, opencv_type); m.convertTo(m, opencv_type);
return m; return m;
} }
void load_rawPathList(std::string burstPath){ void load_rawPathList(std::string burstPath)
DIR *pDir; // pointer to root {
struct dirent *ptr; DIR *pDir; // pointer to root
if (!(pDir = opendir(burstPath.c_str()))) { struct dirent *ptr;
std::cout<<"root dir not found!"<<std::endl; if (!(pDir = opendir(burstPath.c_str())))
return; {
} std::cout << "root dir not found!" << std::endl;
while ((ptr = readdir(pDir)) != nullptr) { return;
// ptr will move to the next file automatically }
std::string sub_file = burstPath + "/" + ptr->d_name; // current filepath that ptr points to while ((ptr = readdir(pDir)) != nullptr)
if (ptr->d_type != 8 && ptr->d_type != 4) { // not normal file or dir {
return; // ptr will move to the next file automatically
} std::string sub_file = burstPath + "/" + ptr->d_name; // current filepath that ptr points to
// only need normal files if (ptr->d_type != 8 && ptr->d_type != 4) { // not normal file or dir
if (ptr->d_type == 8) { return;
if (strcmp(ptr->d_name, ".") != 0 && strcmp(ptr->d_name, "..") != 0) { }
if (strstr(ptr->d_name, ".dng")) { // only need normal files
rawPathList.emplace_back(sub_file); if (ptr->d_type == 8) {
} if (strcmp(ptr->d_name, ".") != 0 && strcmp(ptr->d_name, "..") != 0) {
} if (strstr(ptr->d_name, ".dng")) {
} rawPathList.emplace_back(sub_file);
} }
// close root dir }
closedir(pDir); }
} }
// close root dir
void setLibRawParams(){ closedir(pDir);
refBayer->libraw_processor->imgdata.params.user_qual = params.rawpyArgs.demosaic_algorithm; }
refBayer->libraw_processor->imgdata.params.half_size = params.rawpyArgs.half_size;
refBayer->libraw_processor->imgdata.params.use_camera_wb = params.rawpyArgs.use_camera_wb; void setLibRawParams() {
refBayer->libraw_processor->imgdata.params.use_auto_wb = params.rawpyArgs.use_auto_wb; refBayer->libraw_processor->imgdata.params.user_qual = params.rawpyArgs.demosaic_algorithm;
refBayer->libraw_processor->imgdata.params.no_auto_bright = params.rawpyArgs.no_auto_bright; refBayer->libraw_processor->imgdata.params.half_size = params.rawpyArgs.half_size;
refBayer->libraw_processor->imgdata.params.output_color = params.rawpyArgs.output_color; refBayer->libraw_processor->imgdata.params.use_camera_wb = params.rawpyArgs.use_camera_wb;
refBayer->libraw_processor->imgdata.params.gamm[0] = params.rawpyArgs.gamma[0]; refBayer->libraw_processor->imgdata.params.use_auto_wb = params.rawpyArgs.use_auto_wb;
refBayer->libraw_processor->imgdata.params.gamm[1] = params.rawpyArgs.gamma[1]; refBayer->libraw_processor->imgdata.params.no_auto_bright = params.rawpyArgs.no_auto_bright;
refBayer->libraw_processor->imgdata.params.output_bps = params.rawpyArgs.output_bps; refBayer->libraw_processor->imgdata.params.output_color = params.rawpyArgs.output_color;
refBayer->libraw_processor->imgdata.params.gamm[0] = params.rawpyArgs.gamma[0];
// libraw_processor_finish.imgdata.params.user_qual = params.rawpyArgs.demosaic_algorithm; refBayer->libraw_processor->imgdata.params.gamm[1] = params.rawpyArgs.gamma[1];
// libraw_processor_finish.imgdata.params.half_size = params.rawpyArgs.half_size; refBayer->libraw_processor->imgdata.params.output_bps = params.rawpyArgs.output_bps;
// libraw_processor_finish.imgdata.params.use_camera_wb = params.rawpyArgs.use_camera_wb;
// libraw_processor_finish.imgdata.params.use_auto_wb = params.rawpyArgs.use_auto_wb; // libraw_processor_finish.imgdata.params.user_qual = params.rawpyArgs.demosaic_algorithm;
// libraw_processor_finish.imgdata.params.no_auto_bright = params.rawpyArgs.no_auto_bright; // libraw_processor_finish.imgdata.params.half_size = params.rawpyArgs.half_size;
// libraw_processor_finish.imgdata.params.output_color = params.rawpyArgs.output_color; // libraw_processor_finish.imgdata.params.use_camera_wb = params.rawpyArgs.use_camera_wb;
// libraw_processor_finish.imgdata.params.gamm[0] = params.rawpyArgs.gamma[0]; // libraw_processor_finish.imgdata.params.use_auto_wb = params.rawpyArgs.use_auto_wb;
// libraw_processor_finish.imgdata.params.gamm[1] = params.rawpyArgs.gamma[1]; // libraw_processor_finish.imgdata.params.no_auto_bright = params.rawpyArgs.no_auto_bright;
// libraw_processor_finish.imgdata.params.output_bps = params.rawpyArgs.output_bps; // libraw_processor_finish.imgdata.params.output_color = params.rawpyArgs.output_color;
} // libraw_processor_finish.imgdata.params.gamm[0] = params.rawpyArgs.gamma[0];
// libraw_processor_finish.imgdata.params.gamm[1] = params.rawpyArgs.gamma[1];
// libraw_processor_finish.imgdata.params.output_bps = params.rawpyArgs.output_bps;
}; }
};
} // namespace hdrplus } // namespace hdrplus

@ -8,62 +8,62 @@
namespace hdrplus namespace hdrplus
{ {
class RawpyArgs{ class RawpyArgs {
public: public:
int demosaic_algorithm = 3;// 3 - AHD interpolation <->int user_qual int demosaic_algorithm = 3;// 3 - AHD interpolation <->int user_qual
bool half_size = false; bool half_size = false;
bool use_camera_wb = true; bool use_camera_wb = true;
bool use_auto_wb = false; bool use_auto_wb = false;
bool no_auto_bright = true; bool no_auto_bright = true;
int output_color = LIBRAW_COLORSPACE_sRGB; int output_color = LIBRAW_COLORSPACE_sRGB;
int gamma[2] = {1,1}; //# gamma correction not applied by rawpy (not quite understand) int gamma[2] = { 1,1 }; //# gamma correction not applied by rawpy (not quite understand)
int output_bps = 16; int output_bps = 16;
}; };
class Options{ class Options {
public: public:
std::string input = ""; std::string input = "";
std::string output = ""; std::string output = "";
std::string mode = "full"; //'full' 'align' 'merge' 'finish' std::string mode = "full"; //'full' 'align' 'merge' 'finish'
int reference = 0; int reference = 0;
float temporalfactor=75.0; float temporalfactor = 75.0;
float spatialfactor = 0.1; float spatialfactor = 0.1;
int ltmGain=-1; int ltmGain = -1;
double gtmContrast=0.075; double gtmContrast = 0.075;
int verbose=2; // (0, 1, 2, 3, 4, 5) int verbose = 2; // (0, 1, 2, 3, 4, 5)
}; };
class Tuning{ class Tuning {
public: public:
std::string ltmGain = "auto"; std::string ltmGain = "auto";
double gtmContrast = 0.075; double gtmContrast = 0.075;
std::vector<float> sharpenAmount{1,0.5,0.5}; std::vector<float> sharpenAmount{ 1,0.5,0.5 };
std::vector<float> sharpenSigma{1,2,4}; std::vector<float> sharpenSigma{ 1,2,4 };
std::vector<float> sharpenThreshold{0.02,0.04,0.06}; std::vector<float> sharpenThreshold{ 0.02,0.04,0.06 };
}; };
class Parameters{ class Parameters {
public: public:
std::unordered_map<std::string,bool> flags; std::unordered_map<std::string, bool> flags;
RawpyArgs rawpyArgs; RawpyArgs rawpyArgs;
Options options; Options options;
Tuning tuning; Tuning tuning;
Parameters() Parameters()
{ {
const char* keys[] = {"writeReferenceImage", "writeGammaReference", "writeMergedImage", "writeGammaMerged", const char* keys[] = { "writeReferenceImage", "writeGammaReference", "writeMergedImage", "writeGammaMerged",
"writeShortExposure", "writeLongExposure", "writeFusedExposure", "writeLTMImage", "writeShortExposure", "writeLongExposure", "writeFusedExposure", "writeLTMImage",
"writeLTMGamma", "writeGTMImage", "writeReferenceFinal", "writeFinalImage"}; "writeLTMGamma", "writeGTMImage", "writeReferenceFinal", "writeFinalImage" };
for (int idx = 0; idx < sizeof(keys) / sizeof(const char*); idx++) { for (int idx = 0; idx < sizeof(keys) / sizeof(const char*); idx++) {
flags[keys[idx]] = true; flags[keys[idx]] = true;
} }
} }
}; };
cv::Mat postprocess(std::shared_ptr<LibRaw>& libraw_ptr, RawpyArgs rawpyArgs); cv::Mat postprocess(std::shared_ptr<LibRaw>& libraw_ptr, RawpyArgs rawpyArgs);
void setParams(std::shared_ptr<LibRaw>& libraw_ptr, RawpyArgs rawpyArgs); void setParams(std::shared_ptr<LibRaw>& libraw_ptr, RawpyArgs rawpyArgs);
} // namespace hdrplus } // namespace hdrplus

File diff suppressed because it is too large Load Diff

@ -12,227 +12,227 @@
namespace hdrplus namespace hdrplus
{ {
bayer_image::bayer_image( const std::string& bayer_image_path ) bayer_image::bayer_image(const std::string& bayer_image_path)
{ {
libraw_processor = std::make_shared<LibRaw>(); libraw_processor = std::make_shared<LibRaw>();
// Open RAW image file // Open RAW image file
int return_code; int return_code;
if ( ( return_code = libraw_processor->open_file( bayer_image_path.c_str() ) ) != LIBRAW_SUCCESS ) if ((return_code = libraw_processor->open_file(bayer_image_path.c_str())) != LIBRAW_SUCCESS)
{ {
libraw_processor->recycle(); libraw_processor->recycle();
#ifdef __ANDROID__ #ifdef __ANDROID__
return; return;
#else #else
throw std::runtime_error("Error opening file " + bayer_image_path + " " + libraw_strerror( return_code )); throw std::runtime_error("Error opening file " + bayer_image_path + " " + libraw_strerror(return_code));
#endif #endif
} }
// Unpack the raw image // Unpack the raw image
if ( ( return_code = libraw_processor->unpack() ) != LIBRAW_SUCCESS ) if ((return_code = libraw_processor->unpack()) != LIBRAW_SUCCESS)
{ {
#ifdef __ANDROID__ #ifdef __ANDROID__
return; return;
#else #else
throw std::runtime_error("Error unpack file " + bayer_image_path + " " + libraw_strerror( return_code )); throw std::runtime_error("Error unpack file " + bayer_image_path + " " + libraw_strerror(return_code));
#endif #endif
} }
// Get image basic info // Get image basic info
width = int( libraw_processor->imgdata.rawdata.sizes.raw_width ); width = int(libraw_processor->imgdata.rawdata.sizes.raw_width);
height = int( libraw_processor->imgdata.rawdata.sizes.raw_height ); height = int(libraw_processor->imgdata.rawdata.sizes.raw_height);
// Read exif tags // Read exif tags
Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(bayer_image_path); Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(bayer_image_path);
assert(image.get() != 0); assert(image.get() != 0);
image->readMetadata(); image->readMetadata();
Exiv2::ExifData &exifData = image->exifData(); Exiv2::ExifData &exifData = image->exifData();
if (exifData.empty()) { if (exifData.empty()) {
std::string error(bayer_image_path); std::string error(bayer_image_path);
error += ": No Exif data found in the file"; error += ": No Exif data found in the file";
std::cout << error << std::endl; std::cout << error << std::endl;
} }
white_level = exifData["Exif.Image.WhiteLevel"].toLong(); white_level = exifData["Exif.Image.WhiteLevel"].toLong();
black_level_per_channel.resize( 4 ); black_level_per_channel.resize(4);
black_level_per_channel.at(0) = exifData["Exif.Image.BlackLevel"].toLong(0); black_level_per_channel.at(0) = exifData["Exif.Image.BlackLevel"].toLong(0);
black_level_per_channel.at(1) = exifData["Exif.Image.BlackLevel"].toLong(1); black_level_per_channel.at(1) = exifData["Exif.Image.BlackLevel"].toLong(1);
black_level_per_channel.at(2) = exifData["Exif.Image.BlackLevel"].toLong(2); black_level_per_channel.at(2) = exifData["Exif.Image.BlackLevel"].toLong(2);
black_level_per_channel.at(3) = exifData["Exif.Image.BlackLevel"].toLong(3); black_level_per_channel.at(3) = exifData["Exif.Image.BlackLevel"].toLong(3);
iso = exifData["Exif.Image.ISOSpeedRatings"].toLong(); iso = exifData["Exif.Image.ISOSpeedRatings"].toLong();
// Create CV mat // Create CV mat
// https://answers.opencv.org/question/105972/de-bayering-a-cr2-image/ // https://answers.opencv.org/question/105972/de-bayering-a-cr2-image/
// https://www.libraw.org/node/2141 // https://www.libraw.org/node/2141
raw_image = cv::Mat( height, width, CV_16U, libraw_processor->imgdata.rawdata.raw_image ).clone(); // changed the order of width and height raw_image = cv::Mat(height, width, CV_16U, libraw_processor->imgdata.rawdata.raw_image).clone(); // changed the order of width and height
// 2x2 box filter // 2x2 box filter
grayscale_image = box_filter_kxk<uint16_t, 2>( raw_image ); grayscale_image = box_filter_kxk<uint16_t, 2>(raw_image);
#ifndef NDEBUG
printf("%s::%s read bayer image %s with\n width %zu\n height %zu\n iso %.3f\n white level %d\n black level %d %d %d %d\n", \
__FILE__, __func__, bayer_image_path.c_str(), width, height, iso, white_level, \
black_level_per_channel[0], black_level_per_channel[1], black_level_per_channel[2], black_level_per_channel[3] );
fflush( stdout );
#endif
}
bayer_image::bayer_image( const std::vector<uint8_t>& bayer_image_content ) #ifndef NDEBUG
{ printf("%s::%s read bayer image %s with\n width %zu\n height %zu\n iso %.3f\n white level %d\n black level %d %d %d %d\n", \
libraw_processor = std::make_shared<LibRaw>(); __FILE__, __func__, bayer_image_path.c_str(), width, height, iso, white_level, \
black_level_per_channel[0], black_level_per_channel[1], black_level_per_channel[2], black_level_per_channel[3]);
fflush(stdout);
#endif
}
// Open RAW image file bayer_image::bayer_image(const std::vector<uint8_t>& bayer_image_content)
int return_code; {
if ( ( return_code = libraw_processor->open_buffer( (void *)(&bayer_image_content[0]), bayer_image_content.size() ) ) != LIBRAW_SUCCESS ) libraw_processor = std::make_shared<LibRaw>();
{
libraw_processor->recycle(); // Open RAW image file
int return_code;
if ((return_code = libraw_processor->open_buffer((void *)(&bayer_image_content[0]), bayer_image_content.size())) != LIBRAW_SUCCESS)
{
libraw_processor->recycle();
#ifdef __ANDROID__ || _WIN32 #ifdef __ANDROID__ || _WIN32
return; return;
#else #else
// throw std::runtime_error("Error opening file " + bayer_image_path + " " + libraw_strerror( return_code )); // throw std::runtime_error("Error opening file " + bayer_image_path + " " + libraw_strerror( return_code ));
return; return;
#endif #endif
} }
// Unpack the raw image // Unpack the raw image
if ( ( return_code = libraw_processor->unpack() ) != LIBRAW_SUCCESS ) if ((return_code = libraw_processor->unpack()) != LIBRAW_SUCCESS)
{ {
#ifdef __ANDROID__ || _WIN32 #ifdef __ANDROID__ || _WIN32
return; return;
#else #else
// throw std::runtime_error("Error unpack file " + bayer_image_path + " " + libraw_strerror( return_code )); // throw std::runtime_error("Error unpack file " + bayer_image_path + " " + libraw_strerror( return_code ));
return; return;
#endif #endif
} }
// Get image basic info // Get image basic info
width = int( libraw_processor->imgdata.rawdata.sizes.raw_width ); width = int(libraw_processor->imgdata.rawdata.sizes.raw_width);
height = int( libraw_processor->imgdata.rawdata.sizes.raw_height ); height = int(libraw_processor->imgdata.rawdata.sizes.raw_height);
// Read exif tags // Read exif tags
Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(&bayer_image_content[0], bayer_image_content.size()); Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(&bayer_image_content[0], bayer_image_content.size());
assert(image.get() != 0); assert(image.get() != 0);
image->readMetadata(); image->readMetadata();
Exiv2::ExifData &exifData = image->exifData(); Exiv2::ExifData &exifData = image->exifData();
if (exifData.empty()) { if (exifData.empty()) {
std::string error = "No Exif data found in the file"; std::string error = "No Exif data found in the file";
std::cout << error << std::endl; std::cout << error << std::endl;
} }
white_level = exifData["Exif.Image.WhiteLevel"].toLong(); white_level = exifData["Exif.Image.WhiteLevel"].toLong();
black_level_per_channel.resize( 4 ); black_level_per_channel.resize(4);
black_level_per_channel.at(0) = exifData["Exif.Image.BlackLevel"].toLong(0); black_level_per_channel.at(0) = exifData["Exif.Image.BlackLevel"].toLong(0);
black_level_per_channel.at(1) = exifData["Exif.Image.BlackLevel"].toLong(1); black_level_per_channel.at(1) = exifData["Exif.Image.BlackLevel"].toLong(1);
black_level_per_channel.at(2) = exifData["Exif.Image.BlackLevel"].toLong(2); black_level_per_channel.at(2) = exifData["Exif.Image.BlackLevel"].toLong(2);
black_level_per_channel.at(3) = exifData["Exif.Image.BlackLevel"].toLong(3); black_level_per_channel.at(3) = exifData["Exif.Image.BlackLevel"].toLong(3);
iso = exifData["Exif.Image.ISOSpeedRatings"].toLong(); iso = exifData["Exif.Image.ISOSpeedRatings"].toLong();
// Create CV mat // Create CV mat
// https://answers.opencv.org/question/105972/de-bayering-a-cr2-image/ // https://answers.opencv.org/question/105972/de-bayering-a-cr2-image/
// https://www.libraw.org/node/2141 // https://www.libraw.org/node/2141
raw_image = cv::Mat( height, width, CV_16U, libraw_processor->imgdata.rawdata.raw_image ).clone(); // changed the order of width and height raw_image = cv::Mat(height, width, CV_16U, libraw_processor->imgdata.rawdata.raw_image).clone(); // changed the order of width and height
// 2x2 box filter // 2x2 box filter
grayscale_image = box_filter_kxk<uint16_t, 2>( raw_image ); grayscale_image = box_filter_kxk<uint16_t, 2>(raw_image);
#ifndef NDEBUG #ifndef NDEBUG
printf("%s::%s read bayer image with\n width %zu\n height %zu\n iso %.3f\n white level %d\n black level %d %d %d %d\n", \ printf("%s::%s read bayer image with\n width %zu\n height %zu\n iso %.3f\n white level %d\n black level %d %d %d %d\n", \
__FILE__, __func__, width, height, iso, white_level, \ __FILE__, __func__, width, height, iso, white_level, \
black_level_per_channel[0], black_level_per_channel[1], black_level_per_channel[2], black_level_per_channel[3] ); black_level_per_channel[0], black_level_per_channel[1], black_level_per_channel[2], black_level_per_channel[3]);
fflush( stdout ); fflush(stdout);
#endif #endif
} }
bayer_image::bayer_image( std::shared_ptr<MemFile> bayer_image_file ) bayer_image::bayer_image(std::shared_ptr<MemFile> bayer_image_file)
{ {
libraw_processor = std::make_shared<LibRaw>(); libraw_processor = std::make_shared<LibRaw>();
// Open RAW image file // Open RAW image file
int return_code; int return_code;
{ {
std::vector<uint8_t>& fileData = bayer_image_file->content; std::vector<uint8_t>& fileData = bayer_image_file->content;
if ( ( return_code = libraw_processor->open_buffer( (void *)(&fileData[0]), fileData.size() ) ) != LIBRAW_SUCCESS ) if ((return_code = libraw_processor->open_buffer((void *)(&fileData[0]), fileData.size())) != LIBRAW_SUCCESS)
{ {
libraw_processor->recycle(); libraw_processor->recycle();
#ifdef __ANDROID__ #ifdef __ANDROID__
return; return;
#else #else
return; return;
// throw std::runtime_error("Error opening file " + bayer_image_path + " " + libraw_strerror( return_code )); // throw std::runtime_error("Error opening file " + bayer_image_path + " " + libraw_strerror( return_code ));
#endif #endif
} }
} }
// Unpack the raw image // Unpack the raw image
if ( ( return_code = libraw_processor->unpack() ) != LIBRAW_SUCCESS ) if ((return_code = libraw_processor->unpack()) != LIBRAW_SUCCESS)
{ {
#ifdef __ANDROID__ #ifdef __ANDROID__
return; return;
#else #else
return; return;
// throw std::runtime_error("Error unpack file " + bayer_image_path + " " + libraw_strerror( return_code )); // throw std::runtime_error("Error unpack file " + bayer_image_path + " " + libraw_strerror( return_code ));
#endif #endif
} }
// Get image basic info // Get image basic info
width = int( libraw_processor->imgdata.rawdata.sizes.raw_width ); width = int(libraw_processor->imgdata.rawdata.sizes.raw_width);
height = int( libraw_processor->imgdata.rawdata.sizes.raw_height ); height = int(libraw_processor->imgdata.rawdata.sizes.raw_height);
// Read exif tags // Read exif tags
Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(&bayer_image_file->content[0], bayer_image_file->content.size()); Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(&bayer_image_file->content[0], bayer_image_file->content.size());
assert(image.get() != 0); assert(image.get() != 0);
image->readMetadata(); image->readMetadata();
Exiv2::ExifData &exifData = image->exifData(); Exiv2::ExifData &exifData = image->exifData();
if (exifData.empty()) { if (exifData.empty()) {
std::string error = "No Exif data found in the file"; std::string error = "No Exif data found in the file";
std::cout << error << std::endl; std::cout << error << std::endl;
} }
white_level = exifData["Exif.Image.WhiteLevel"].toLong(); white_level = exifData["Exif.Image.WhiteLevel"].toLong();
black_level_per_channel.resize( 4 ); black_level_per_channel.resize(4);
black_level_per_channel.at(0) = exifData["Exif.Image.BlackLevel"].toLong(0); black_level_per_channel.at(0) = exifData["Exif.Image.BlackLevel"].toLong(0);
black_level_per_channel.at(1) = exifData["Exif.Image.BlackLevel"].toLong(1); black_level_per_channel.at(1) = exifData["Exif.Image.BlackLevel"].toLong(1);
black_level_per_channel.at(2) = exifData["Exif.Image.BlackLevel"].toLong(2); black_level_per_channel.at(2) = exifData["Exif.Image.BlackLevel"].toLong(2);
black_level_per_channel.at(3) = exifData["Exif.Image.BlackLevel"].toLong(3); black_level_per_channel.at(3) = exifData["Exif.Image.BlackLevel"].toLong(3);
iso = exifData["Exif.Image.ISOSpeedRatings"].toLong(); iso = exifData["Exif.Image.ISOSpeedRatings"].toLong();
// Create CV mat // Create CV mat
// https://answers.opencv.org/question/105972/de-bayering-a-cr2-image/ // https://answers.opencv.org/question/105972/de-bayering-a-cr2-image/
// https://www.libraw.org/node/2141 // https://www.libraw.org/node/2141
raw_image = cv::Mat( height, width, CV_16U, libraw_processor->imgdata.rawdata.raw_image ).clone(); // changed the order of width and height raw_image = cv::Mat(height, width, CV_16U, libraw_processor->imgdata.rawdata.raw_image).clone(); // changed the order of width and height
// 2x2 box filter // 2x2 box filter
grayscale_image = box_filter_kxk<uint16_t, 2>( raw_image ); grayscale_image = box_filter_kxk<uint16_t, 2>(raw_image);
#ifndef NDEBUG #ifndef NDEBUG
printf("%s::%s read bayer image with\n width %zu\n height %zu\n iso %.3f\n white level %d\n black level %d %d %d %d\n", \ printf("%s::%s read bayer image with\n width %zu\n height %zu\n iso %.3f\n white level %d\n black level %d %d %d %d\n", \
__FILE__, __func__, width, height, iso, white_level, \ __FILE__, __func__, width, height, iso, white_level, \
black_level_per_channel[0], black_level_per_channel[1], black_level_per_channel[2], black_level_per_channel[3] ); black_level_per_channel[0], black_level_per_channel[1], black_level_per_channel[2], black_level_per_channel[3]);
fflush( stdout ); fflush(stdout);
#endif #endif
} }
std::pair<double, double> bayer_image::get_noise_params() const std::pair<double, double> bayer_image::get_noise_params() const
{ {
// Set ISO to 100 if not positive // Set ISO to 100 if not positive
double iso_ = iso <= 0 ? 100 : iso; double iso_ = iso <= 0 ? 100 : iso;
// Calculate shot noise and read noise parameters w.r.t ISO 100 // Calculate shot noise and read noise parameters w.r.t ISO 100
double lambda_shot_p = iso_ / 100.0f * baseline_lambda_shot; double lambda_shot_p = iso_ / 100.0f * baseline_lambda_shot;
double lambda_read_p = (iso_ / 100.0f) * (iso_ / 100.0f) * baseline_lambda_read; double lambda_read_p = (iso_ / 100.0f) * (iso_ / 100.0f) * baseline_lambda_read;
double black_level = (black_level_per_channel[0] + \ double black_level = (black_level_per_channel[0] + \
black_level_per_channel[1] + \ black_level_per_channel[1] + \
black_level_per_channel[2] + \ black_level_per_channel[2] + \
black_level_per_channel[3]) / 4.0; black_level_per_channel[3]) / 4.0;
// Rescale shot and read noise to normal range // Rescale shot and read noise to normal range
double lambda_shot = lambda_shot_p * (white_level - black_level); double lambda_shot = lambda_shot_p * (white_level - black_level);
double lambda_read = lambda_read_p * (white_level - black_level) * (white_level - black_level); double lambda_read = lambda_read_p * (white_level - black_level) * (white_level - black_level);
// return pair // return pair
return std::make_pair(lambda_shot, lambda_read); return std::make_pair(lambda_shot, lambda_read);
} }
} }

File diff suppressed because it is too large Load Diff

@ -17,122 +17,122 @@
namespace hdrplus namespace hdrplus
{ {
void hdrplus_pipeline::run_pipeline( \ void hdrplus_pipeline::run_pipeline(\
const std::string& burst_path, \ const std::string& burst_path, \
const std::string& reference_image_path ) const std::string& reference_image_path)
{ {
// Create burst of images // Create burst of images
burst burst_images( burst_path, reference_image_path ); burst burst_images(burst_path, reference_image_path);
std::vector<std::vector<std::vector<std::pair<int, int>>>> alignments; std::vector<std::vector<std::vector<std::pair<int, int>>>> alignments;
// Run align // Run align
align_module.process( burst_images, alignments ); align_module.process(burst_images, alignments);
// Run merging // Run merging
merge_module.process( burst_images, alignments ); merge_module.process(burst_images, alignments);
// Run finishing // Run finishing
cv::Mat finalImg; cv::Mat finalImg;
finish_module.process( burst_images, finalImg); finish_module.process(burst_images, finalImg);
} }
bool hdrplus_pipeline::run_pipeline( \ bool hdrplus_pipeline::run_pipeline(\
const std::vector<std::string>& burst_paths, \ const std::vector<std::string>& burst_paths, \
int reference_image_index, cv::Mat& finalImg ) int reference_image_index, cv::Mat& finalImg)
{ {
// Create burst of images // Create burst of images
burst burst_images( burst_paths, reference_image_index ); burst burst_images(burst_paths, reference_image_index);
std::vector<std::vector<std::vector<std::pair<int, int>>>> alignments; std::vector<std::vector<std::vector<std::pair<int, int>>>> alignments;
#ifdef __ANDROID__ #ifdef __ANDROID__
// ALOGI("Finish loading images"); // ALOGI("Finish loading images");
#endif #endif
// Run align // Run align
align_module.process( burst_images, alignments ); align_module.process(burst_images, alignments);
#ifdef __ANDROID__ #ifdef __ANDROID__
// ALOGI("Finish align"); // ALOGI("Finish align");
#endif #endif
// Run merging // Run merging
merge_module.process( burst_images, alignments ); merge_module.process(burst_images, alignments);
#ifdef __ANDROID__ #ifdef __ANDROID__
// ALOGI("Finish merging"); // ALOGI("Finish merging");
#endif #endif
// Run finishing // Run finishing
finish_module.process( burst_images, finalImg); finish_module.process(burst_images, finalImg);
#ifdef __ANDROID__ #ifdef __ANDROID__
// ALOGI("Finish process"); // ALOGI("Finish process");
#endif #endif
return true; return true;
} }
bool hdrplus_pipeline::run_pipeline( \ bool hdrplus_pipeline::run_pipeline(\
const std::vector<std::vector<uint8_t> >& burst_contents, \ const std::vector<std::vector<uint8_t> >& burst_contents, \
int reference_image_index, cv::Mat& finalImg ) int reference_image_index, cv::Mat& finalImg)
{ {
// Create burst of images // Create burst of images
burst burst_images( burst_contents, reference_image_index ); burst burst_images(burst_contents, reference_image_index);
std::vector<std::vector<std::vector<std::pair<int, int>>>> alignments; std::vector<std::vector<std::vector<std::pair<int, int>>>> alignments;
#ifdef __ANDROID__ #ifdef __ANDROID__
// ALOGI("Finish loading images"); // ALOGI("Finish loading images");
#endif #endif
// Run align // Run align
align_module.process( burst_images, alignments ); align_module.process(burst_images, alignments);
#ifdef __ANDROID__ #ifdef __ANDROID__
// ALOGI("Finish align"); // ALOGI("Finish align");
#endif #endif
// Run merging // Run merging
merge_module.process( burst_images, alignments ); merge_module.process(burst_images, alignments);
#ifdef __ANDROID__ #ifdef __ANDROID__
// ALOGI("Finish merging"); // ALOGI("Finish merging");
#endif #endif
// Run finishing // Run finishing
finish_module.process( burst_images, finalImg); finish_module.process(burst_images, finalImg);
#ifdef __ANDROID__ #ifdef __ANDROID__
// ALOGI("Finish process"); // ALOGI("Finish process");
#endif #endif
return true; return true;
} }
bool hdrplus_pipeline::run_pipeline( \ bool hdrplus_pipeline::run_pipeline(\
const std::vector<std::shared_ptr<MemFile> >& burst_files, \ const std::vector<std::shared_ptr<MemFile> >& burst_files, \
int reference_image_index, cv::Mat& finalImg ) int reference_image_index, cv::Mat& finalImg)
{ {
// Create burst of images // Create burst of images
burst burst_images( burst_files, reference_image_index ); burst burst_images(burst_files, reference_image_index);
std::vector<std::vector<std::vector<std::pair<int, int>>>> alignments; std::vector<std::vector<std::vector<std::pair<int, int>>>> alignments;
#ifdef __ANDROID__ #ifdef __ANDROID__
// ALOGI("Finish loading images"); // ALOGI("Finish loading images");
#endif #endif
// Run align // Run align
align_module.process( burst_images, alignments ); align_module.process(burst_images, alignments);
#ifdef __ANDROID__ #ifdef __ANDROID__
// ALOGI("Finish align"); // ALOGI("Finish align");
#endif #endif
// Run merging // Run merging
merge_module.process( burst_images, alignments ); merge_module.process(burst_images, alignments);
#ifdef __ANDROID__ #ifdef __ANDROID__
// ALOGI("Finish merging"); // ALOGI("Finish merging");
#endif #endif
// Run finishing // Run finishing
finish_module.process( burst_images, finalImg); finish_module.process(burst_images, finalImg);
#ifdef __ANDROID__ #ifdef __ANDROID__
// ALOGI("Finish process"); // ALOGI("Finish process");
#endif #endif
return true; return true;
} }
} // namespace hdrplus } // namespace hdrplus

@ -8,345 +8,345 @@
namespace hdrplus namespace hdrplus
{ {
void merge::process(hdrplus::burst& burst_images, \ void merge::process(hdrplus::burst& burst_images, \
std::vector<std::vector<std::vector<std::pair<int, int>>>>& alignments) std::vector<std::vector<std::vector<std::pair<int, int>>>>& alignments)
{ {
// 4.1 Noise Parameters and RMS // 4.1 Noise Parameters and RMS
// Noise parameters calculated from baseline ISO noise parameters // Noise parameters calculated from baseline ISO noise parameters
double lambda_shot, lambda_read; double lambda_shot, lambda_read;
std::tie(lambda_shot, lambda_read) = burst_images.bayer_images[burst_images.reference_image_idx].get_noise_params(); std::tie(lambda_shot, lambda_read) = burst_images.bayer_images[burst_images.reference_image_idx].get_noise_params();
// 4.2-4.4 Denoising and Merging // 4.2-4.4 Denoising and Merging
// Get padded bayer image // Get padded bayer image
cv::Mat reference_image = burst_images.bayer_images_pad[burst_images.reference_image_idx]; cv::Mat reference_image = burst_images.bayer_images_pad[burst_images.reference_image_idx];
#ifndef NDEBUG #ifndef NDEBUG
// cv::imwrite("ref.jpg", reference_image); // cv::imwrite("ref.jpg", reference_image);
#endif #endif
// Get raw channels // Get raw channels
std::vector<cv::Mat> channels(4); std::vector<cv::Mat> channels(4);
hdrplus::extract_rgb_from_bayer<uint16_t>(reference_image, channels[0], channels[1], channels[2], channels[3]); hdrplus::extract_rgb_from_bayer<uint16_t>(reference_image, channels[0], channels[1], channels[2], channels[3]);
std::vector<cv::Mat> processed_channels(4); std::vector<cv::Mat> processed_channels(4);
// For each channel, perform denoising and merge // For each channel, perform denoising and merge
for (int i = 0; i < 4; ++i) { for (int i = 0; i < 4; ++i) {
// Get channel mat // Get channel mat
cv::Mat channel_i = channels[i]; cv::Mat channel_i = channels[i];
// cv::imwrite("ref" + std::to_string(i) + ".jpg", channel_i); // cv::imwrite("ref" + std::to_string(i) + ".jpg", channel_i);
//we should be getting the individual channel in the same place where we call the processChannel function with the reference channel in its arguments //we should be getting the individual channel in the same place where we call the processChannel function with the reference channel in its arguments
//possibly we could add another argument in the processChannel function which is the channel_i for the alternate image. maybe using a loop to cover all the other images //possibly we could add another argument in the processChannel function which is the channel_i for the alternate image. maybe using a loop to cover all the other images
//create list of channel_i of alternate images: //create list of channel_i of alternate images:
std::vector<cv::Mat> alternate_channel_i_list; std::vector<cv::Mat> alternate_channel_i_list;
for (int j = 0; j < burst_images.num_images; j++) { for (int j = 0; j < burst_images.num_images; j++) {
if (j != burst_images.reference_image_idx) { if (j != burst_images.reference_image_idx) {
//get alternate image //get alternate image
cv::Mat alt_image = burst_images.bayer_images_pad[j]; cv::Mat alt_image = burst_images.bayer_images_pad[j];
std::vector<cv::Mat> alt_channels(4); std::vector<cv::Mat> alt_channels(4);
hdrplus::extract_rgb_from_bayer<uint16_t>(alt_image, alt_channels[0], alt_channels[1], alt_channels[2], alt_channels[3]); hdrplus::extract_rgb_from_bayer<uint16_t>(alt_image, alt_channels[0], alt_channels[1], alt_channels[2], alt_channels[3]);
alternate_channel_i_list.push_back(alt_channels[i]); alternate_channel_i_list.push_back(alt_channels[i]);
} }
} }
// Apply merging on the channel // Apply merging on the channel
cv::Mat merged_channel = processChannel(burst_images, alignments, channel_i, alternate_channel_i_list, lambda_shot, lambda_read); cv::Mat merged_channel = processChannel(burst_images, alignments, channel_i, alternate_channel_i_list, lambda_shot, lambda_read);
// cv::imwrite("merged" + std::to_string(i) + ".jpg", merged_channel); // cv::imwrite("merged" + std::to_string(i) + ".jpg", merged_channel);
// Put channel raw data back to channels // Put channel raw data back to channels
merged_channel.convertTo(processed_channels[i], CV_16U); merged_channel.convertTo(processed_channels[i], CV_16U);
} }
// Write all channels back to a bayer mat // Write all channels back to a bayer mat
cv::Mat merged(reference_image.rows, reference_image.cols, CV_16U); cv::Mat merged(reference_image.rows, reference_image.cols, CV_16U);
int x, y; int x, y;
for (y = 0; y < reference_image.rows; ++y){ for (y = 0; y < reference_image.rows; ++y) {
uint16_t* row = merged.ptr<uint16_t>(y); uint16_t* row = merged.ptr<uint16_t>(y);
if (y % 2 == 0){ if (y % 2 == 0) {
uint16_t* i0 = processed_channels[0].ptr<uint16_t>(y / 2); uint16_t* i0 = processed_channels[0].ptr<uint16_t>(y / 2);
uint16_t* i1 = processed_channels[1].ptr<uint16_t>(y / 2); uint16_t* i1 = processed_channels[1].ptr<uint16_t>(y / 2);
for (x = 0; x < reference_image.cols;){ for (x = 0; x < reference_image.cols;) {
//R //R
row[x] = i0[x / 2]; row[x] = i0[x / 2];
x++; x++;
//G1 //G1
row[x] = i1[x / 2]; row[x] = i1[x / 2];
x++; x++;
} }
} }
else { else {
uint16_t* i2 = processed_channels[2].ptr<uint16_t>(y / 2); uint16_t* i2 = processed_channels[2].ptr<uint16_t>(y / 2);
uint16_t* i3 = processed_channels[3].ptr<uint16_t>(y / 2); uint16_t* i3 = processed_channels[3].ptr<uint16_t>(y / 2);
for(x = 0; x < reference_image.cols;){ for (x = 0; x < reference_image.cols;) {
//G2 //G2
row[x] = i2[x / 2]; row[x] = i2[x / 2];
x++; x++;
//B //B
row[x] = i3[x / 2]; row[x] = i3[x / 2];
x++; x++;
} }
} }
} }
// Remove padding // Remove padding
std::vector<int> padding = burst_images.padding_info_bayer; std::vector<int> padding = burst_images.padding_info_bayer;
cv::Range horizontal = cv::Range(padding[2], reference_image.cols - padding[3]); cv::Range horizontal = cv::Range(padding[2], reference_image.cols - padding[3]);
cv::Range vertical = cv::Range(padding[0], reference_image.rows - padding[1]); cv::Range vertical = cv::Range(padding[0], reference_image.rows - padding[1]);
burst_images.merged_bayer_image = merged(vertical, horizontal); burst_images.merged_bayer_image = merged(vertical, horizontal);
// cv::imwrite("merged.jpg", burst_images.merged_bayer_image); // cv::imwrite("merged.jpg", burst_images.merged_bayer_image);
} }
void merge::getReferenceTiles(cv::Mat reference_image, std::vector<cv::Mat>& reference_tiles) { void merge::getReferenceTiles(cv::Mat reference_image, std::vector<cv::Mat>& reference_tiles) {
for (int y = 0; y < reference_image.rows - offset; y += offset) { for (int y = 0; y < reference_image.rows - offset; y += offset) {
for (int x = 0; x < reference_image.cols - offset; x += offset) { for (int x = 0; x < reference_image.cols - offset; x += offset) {
cv::Mat tile = reference_image(cv::Rect(x, y, TILE_SIZE, TILE_SIZE)); cv::Mat tile = reference_image(cv::Rect(x, y, TILE_SIZE, TILE_SIZE));
reference_tiles.push_back(tile); reference_tiles.push_back(tile);
} }
} }
} }
cv::Mat merge::mergeTiles(std::vector<cv::Mat> tiles, int num_rows, int num_cols) { cv::Mat merge::mergeTiles(std::vector<cv::Mat> tiles, int num_rows, int num_cols) {
// 1. get all four subsets: original (evenly split), horizontal overlapped, // 1. get all four subsets: original (evenly split), horizontal overlapped,
// vertical overlapped, 2D overlapped // vertical overlapped, 2D overlapped
std::vector<std::vector<cv::Mat>> tiles_original; std::vector<std::vector<cv::Mat>> tiles_original;
std::vector<cv::Mat> row; std::vector<cv::Mat> row;
for (int y = 0; y < num_rows / offset - 1; y += 2) { for (int y = 0; y < num_rows / offset - 1; y += 2) {
row.clear(); row.clear();
for (int x = 0; x < num_cols / offset - 1; x += 2) { for (int x = 0; x < num_cols / offset - 1; x += 2) {
row.push_back(tiles[y * (num_cols / offset - 1) + x]); row.push_back(tiles[y * (num_cols / offset - 1) + x]);
} }
tiles_original.push_back(row); tiles_original.push_back(row);
} }
std::vector<std::vector<cv::Mat>> tiles_horizontal; std::vector<std::vector<cv::Mat>> tiles_horizontal;
// std::vector<cv::Mat> row; // std::vector<cv::Mat> row;
for (int y = 0; y < num_rows / offset - 1; y += 2) { for (int y = 0; y < num_rows / offset - 1; y += 2) {
row.clear(); row.clear();
for (int x = 1; x < num_cols / offset - 1; x += 2) { for (int x = 1; x < num_cols / offset - 1; x += 2) {
row.push_back(tiles[y * (num_cols / offset - 1) + x]); row.push_back(tiles[y * (num_cols / offset - 1) + x]);
} }
tiles_horizontal.push_back(row); tiles_horizontal.push_back(row);
} }
std::vector<std::vector<cv::Mat>> tiles_vertical; std::vector<std::vector<cv::Mat>> tiles_vertical;
// std::vector<cv::Mat> row; // std::vector<cv::Mat> row;
for (int y = 1; y < num_rows / offset - 1; y += 2) { for (int y = 1; y < num_rows / offset - 1; y += 2) {
row.clear(); row.clear();
for (int x = 0; x < num_cols / offset - 1; x += 2) { for (int x = 0; x < num_cols / offset - 1; x += 2) {
row.push_back(tiles[y * (num_cols / offset - 1) + x]); row.push_back(tiles[y * (num_cols / offset - 1) + x]);
} }
tiles_vertical.push_back(row); tiles_vertical.push_back(row);
} }
std::vector<std::vector<cv::Mat>> tiles_2d; std::vector<std::vector<cv::Mat>> tiles_2d;
// std::vector<cv::Mat> row; // std::vector<cv::Mat> row;
for (int y = 1; y < num_rows / offset - 1; y += 2) { for (int y = 1; y < num_rows / offset - 1; y += 2) {
row.clear(); row.clear();
for (int x = 1; x < num_cols / offset - 1; x += 2) { for (int x = 1; x < num_cols / offset - 1; x += 2) {
row.push_back(tiles[y * (num_cols / offset - 1) + x]); row.push_back(tiles[y * (num_cols / offset - 1) + x]);
} }
tiles_2d.push_back(row); tiles_2d.push_back(row);
} }
// 2. Concatenate the four subsets // 2. Concatenate the four subsets
cv::Mat img_original = cat2Dtiles(tiles_original); cv::Mat img_original = cat2Dtiles(tiles_original);
cv::Mat img_horizontal = cat2Dtiles(tiles_horizontal); cv::Mat img_horizontal = cat2Dtiles(tiles_horizontal);
cv::Mat img_vertical = cat2Dtiles(tiles_vertical); cv::Mat img_vertical = cat2Dtiles(tiles_vertical);
cv::Mat img_2d = cat2Dtiles(tiles_2d); cv::Mat img_2d = cat2Dtiles(tiles_2d);
// 3. Add the four subsets together // 3. Add the four subsets together
img_original(cv::Rect(offset, 0, num_cols - TILE_SIZE, num_rows)) += img_horizontal; img_original(cv::Rect(offset, 0, num_cols - TILE_SIZE, num_rows)) += img_horizontal;
img_original(cv::Rect(0, offset, num_cols, num_rows - TILE_SIZE)) += img_vertical; img_original(cv::Rect(0, offset, num_cols, num_rows - TILE_SIZE)) += img_vertical;
img_original(cv::Rect(offset, offset, num_cols - TILE_SIZE, num_rows - TILE_SIZE)) += img_2d; img_original(cv::Rect(offset, offset, num_cols - TILE_SIZE, num_rows - TILE_SIZE)) += img_2d;
return img_original; return img_original;
} }
cv::Mat merge::processChannel(hdrplus::burst& burst_images, \ cv::Mat merge::processChannel(hdrplus::burst& burst_images, \
std::vector<std::vector<std::vector<std::pair<int, int>>>>& alignments, \ std::vector<std::vector<std::vector<std::pair<int, int>>>>& alignments, \
cv::Mat channel_image, \ cv::Mat channel_image, \
std::vector<cv::Mat> alternate_channel_i_list,\ std::vector<cv::Mat> alternate_channel_i_list, \
float lambda_shot, \ float lambda_shot, \
float lambda_read) { float lambda_read) {
// Get tiles of the reference image // Get tiles of the reference image
std::vector<cv::Mat> reference_tiles; std::vector<cv::Mat> reference_tiles;
getReferenceTiles(channel_image, reference_tiles); getReferenceTiles(channel_image, reference_tiles);
// Get noise variance (sigma**2 = lambda_shot * tileRMS + lambda_read) // Get noise variance (sigma**2 = lambda_shot * tileRMS + lambda_read)
std::vector<float> noise_variance = getNoiseVariance(reference_tiles, lambda_shot, lambda_read); std::vector<float> noise_variance = getNoiseVariance(reference_tiles, lambda_shot, lambda_read);
// Apply FFT on reference tiles (spatial to frequency) // Apply FFT on reference tiles (spatial to frequency)
std::vector<cv::Mat> reference_tiles_DFT; std::vector<cv::Mat> reference_tiles_DFT;
for (auto ref_tile : reference_tiles) { for (auto ref_tile : reference_tiles) {
cv::Mat ref_tile_DFT; cv::Mat ref_tile_DFT;
ref_tile.convertTo(ref_tile_DFT, CV_32F); ref_tile.convertTo(ref_tile_DFT, CV_32F);
cv::dft(ref_tile_DFT, ref_tile_DFT, cv::DFT_COMPLEX_OUTPUT); cv::dft(ref_tile_DFT, ref_tile_DFT, cv::DFT_COMPLEX_OUTPUT);
reference_tiles_DFT.push_back(ref_tile_DFT); reference_tiles_DFT.push_back(ref_tile_DFT);
} }
// Acquire alternate tiles and apply FFT on them as well // Acquire alternate tiles and apply FFT on them as well
std::vector<std::vector<cv::Mat>> alt_tiles_list(reference_tiles.size()); std::vector<std::vector<cv::Mat>> alt_tiles_list(reference_tiles.size());
int num_tiles_row = alternate_channel_i_list[0].rows / offset - 1; int num_tiles_row = alternate_channel_i_list[0].rows / offset - 1;
int num_tiles_col = alternate_channel_i_list[0].cols / offset - 1; int num_tiles_col = alternate_channel_i_list[0].cols / offset - 1;
std::vector<cv::Mat> alt_tiles; std::vector<cv::Mat> alt_tiles;
for (int y = 0; y < num_tiles_row; ++y) { for (int y = 0; y < num_tiles_row; ++y) {
for (int x = 0; x < num_tiles_col; ++x) { for (int x = 0; x < num_tiles_col; ++x) {
alt_tiles.clear(); alt_tiles.clear();
// Get reference tile location // Get reference tile location
int top_left_y = y * offset; int top_left_y = y * offset;
int top_left_x = x * offset; int top_left_x = x * offset;
for (int i = 0; i < alternate_channel_i_list.size(); ++i) { for (int i = 0; i < alternate_channel_i_list.size(); ++i) {
// Get alignment displacement // Get alignment displacement
int displacement_y, displacement_x; int displacement_y, displacement_x;
std::tie(displacement_y, displacement_x) = alignments[i + 1][y][x]; std::tie(displacement_y, displacement_x) = alignments[i + 1][y][x];
// Get tile // Get tile
cv::Mat alt_tile = alternate_channel_i_list[i](cv::Rect(top_left_x + displacement_x, top_left_y + displacement_y, TILE_SIZE, TILE_SIZE)); cv::Mat alt_tile = alternate_channel_i_list[i](cv::Rect(top_left_x + displacement_x, top_left_y + displacement_y, TILE_SIZE, TILE_SIZE));
// Apply FFT // Apply FFT
cv::Mat alt_tile_DFT; cv::Mat alt_tile_DFT;
alt_tile.convertTo(alt_tile_DFT, CV_32F); alt_tile.convertTo(alt_tile_DFT, CV_32F);
cv::dft(alt_tile_DFT, alt_tile_DFT, cv::DFT_COMPLEX_OUTPUT); cv::dft(alt_tile_DFT, alt_tile_DFT, cv::DFT_COMPLEX_OUTPUT);
alt_tiles.push_back(alt_tile_DFT); alt_tiles.push_back(alt_tile_DFT);
} }
alt_tiles_list[y * num_tiles_col + x] = alt_tiles; alt_tiles_list[y * num_tiles_col + x] = alt_tiles;
} }
} }
// 4.2 Temporal Denoising // 4.2 Temporal Denoising
std::vector<cv::Mat> reference_tiles_DFTNew; std::vector<cv::Mat> reference_tiles_DFTNew;
temporal_denoise(reference_tiles_DFT, alt_tiles_list, noise_variance, TEMPORAL_FACTOR, reference_tiles_DFTNew); temporal_denoise(reference_tiles_DFT, alt_tiles_list, noise_variance, TEMPORAL_FACTOR, reference_tiles_DFTNew);
reference_tiles_DFT.swap(reference_tiles_DFTNew); reference_tiles_DFT.swap(reference_tiles_DFTNew);
// 4.3 Spatial Denoising // 4.3 Spatial Denoising
reference_tiles_DFTNew.clear(); reference_tiles_DFTNew.clear();
spatial_denoise(reference_tiles_DFT, alternate_channel_i_list.size(), noise_variance, SPATIAL_FACTOR, reference_tiles_DFTNew); spatial_denoise(reference_tiles_DFT, alternate_channel_i_list.size(), noise_variance, SPATIAL_FACTOR, reference_tiles_DFTNew);
reference_tiles_DFT.swap(reference_tiles_DFTNew); reference_tiles_DFT.swap(reference_tiles_DFTNew);
{ {
std::vector<cv::Mat> empty; std::vector<cv::Mat> empty;
reference_tiles_DFTNew.swap(empty); reference_tiles_DFTNew.swap(empty);
} }
//now reference tiles are temporally and spatially denoised //now reference tiles are temporally and spatially denoised
// Apply IFFT on reference tiles (frequency to spatial) // Apply IFFT on reference tiles (frequency to spatial)
std::vector<cv::Mat> denoised_tiles; std::vector<cv::Mat> denoised_tiles;
for (auto dft_tile : reference_tiles_DFT) { for (auto dft_tile : reference_tiles_DFT) {
cv::Mat denoised_tile; cv::Mat denoised_tile;
cv::divide(dft_tile, TILE_SIZE * TILE_SIZE, dft_tile); cv::divide(dft_tile, TILE_SIZE * TILE_SIZE, dft_tile);
cv::dft(dft_tile, denoised_tile, cv::DFT_INVERSE | cv::DFT_REAL_OUTPUT); cv::dft(dft_tile, denoised_tile, cv::DFT_INVERSE | cv::DFT_REAL_OUTPUT);
denoised_tiles.push_back(denoised_tile); denoised_tiles.push_back(denoised_tile);
} }
{ {
reference_tiles.swap(denoised_tiles); reference_tiles.swap(denoised_tiles);
std::vector<cv::Mat> empty; std::vector<cv::Mat> empty;
denoised_tiles.swap(empty); denoised_tiles.swap(empty);
} }
// 4.4 Cosine Window Merging // 4.4 Cosine Window Merging
// Process tiles through 2D cosine window // Process tiles through 2D cosine window
std::vector<cv::Mat> windowed_tiles; std::vector<cv::Mat> windowed_tiles;
for (auto tile : reference_tiles) { for (auto tile : reference_tiles) {
windowed_tiles.push_back(cosineWindow2D(tile)); windowed_tiles.push_back(cosineWindow2D(tile));
} }
// Merge tiles // Merge tiles
return mergeTiles(windowed_tiles, channel_image.rows, channel_image.cols); return mergeTiles(windowed_tiles, channel_image.rows, channel_image.cols);
} }
void merge::temporal_denoise(std::vector<cv::Mat> tiles, std::vector<std::vector<cv::Mat>> alt_tiles, std::vector<float> noise_variance, float temporal_factor, std::vector<cv::Mat>& denoised) void merge::temporal_denoise(std::vector<cv::Mat> tiles, std::vector<std::vector<cv::Mat>> alt_tiles, std::vector<float> noise_variance, float temporal_factor, std::vector<cv::Mat>& denoised)
{ {
// goal: temporially denoise using the weiner filter // goal: temporially denoise using the weiner filter
// input: // input:
// 1. array of 2D dft tiles of the reference image // 1. array of 2D dft tiles of the reference image
// 2. array of 2D dft tiles of the aligned alternate image // 2. array of 2D dft tiles of the aligned alternate image
// 3. estimated noise variance // 3. estimated noise variance
// 4. temporal factor // 4. temporal factor
// return: merged image patches dft // return: merged image patches dft
// calculate noise scaling // calculate noise scaling
double temporal_noise_scaling = (TILE_SIZE * TILE_SIZE * (2.0 / 16)) * TEMPORAL_FACTOR; double temporal_noise_scaling = (TILE_SIZE * TILE_SIZE * (2.0 / 16)) * TEMPORAL_FACTOR;
// loop across tiles // loop across tiles
for (int i = 0; i < tiles.size(); ++i) { for (int i = 0; i < tiles.size(); ++i) {
// sum of pairwise denoising // sum of pairwise denoising
cv::Mat tile_sum = tiles[i].clone(); cv::Mat tile_sum = tiles[i].clone();
double coeff = temporal_noise_scaling * noise_variance[i]; double coeff = temporal_noise_scaling * noise_variance[i];
// Ref tile // Ref tile
cv::Mat tile = tiles[i]; cv::Mat tile = tiles[i];
// Alt tiles // Alt tiles
std::vector<cv::Mat> alt_tiles_i = alt_tiles[i]; std::vector<cv::Mat> alt_tiles_i = alt_tiles[i];
for (int j = 0; j < alt_tiles_i.size(); ++j) { for (int j = 0; j < alt_tiles_i.size(); ++j) {
// Alt tile // Alt tile
cv::Mat alt_tile = alt_tiles_i[j]; cv::Mat alt_tile = alt_tiles_i[j];
// Tile difference // Tile difference
cv::Mat diff = tile - alt_tile; cv::Mat diff = tile - alt_tile;
// Calculate absolute difference // Calculate absolute difference
cv::Mat complexMats[2]; cv::Mat complexMats[2];
cv::split(diff, complexMats); // planes[0] = Re(DFT(I)), planes[1] = Im(DFT(I)) cv::split(diff, complexMats); // planes[0] = Re(DFT(I)), planes[1] = Im(DFT(I))
cv::magnitude(complexMats[0], complexMats[1], complexMats[0]); // planes[0] = magnitude cv::magnitude(complexMats[0], complexMats[1], complexMats[0]); // planes[0] = magnitude
cv::Mat absolute_diff = complexMats[0].mul(complexMats[0]); cv::Mat absolute_diff = complexMats[0].mul(complexMats[0]);
// find shrinkage operator A // find shrinkage operator A
cv::Mat shrinkage; cv::Mat shrinkage;
cv::divide(absolute_diff, absolute_diff + coeff, shrinkage); cv::divide(absolute_diff, absolute_diff + coeff, shrinkage);
cv::merge(std::vector<cv::Mat>{shrinkage, shrinkage}, shrinkage); cv::merge(std::vector<cv::Mat>{shrinkage, shrinkage}, shrinkage);
// Interpolation // Interpolation
tile_sum += alt_tile + diff.mul(shrinkage); tile_sum += alt_tile + diff.mul(shrinkage);
} }
// Average by num of frames // Average by num of frames
cv::divide(tile_sum, alt_tiles_i.size() + 1, tile_sum); cv::divide(tile_sum, alt_tiles_i.size() + 1, tile_sum);
denoised.push_back(tile_sum); denoised.push_back(tile_sum);
} }
} }
void merge::spatial_denoise(std::vector<cv::Mat> tiles, int num_alts, std::vector<float> noise_variance, float spatial_factor, std::vector<cv::Mat>& denoised) { void merge::spatial_denoise(std::vector<cv::Mat> tiles, int num_alts, std::vector<float> noise_variance, float spatial_factor, std::vector<cv::Mat>& denoised) {
double spatial_noise_scaling = (TILE_SIZE * TILE_SIZE * (1.0 / 16)) * spatial_factor; double spatial_noise_scaling = (TILE_SIZE * TILE_SIZE * (1.0 / 16)) * spatial_factor;
// Calculate |w| using ifftshift // Calculate |w| using ifftshift
cv::Mat row_distances = cv::Mat::zeros(1, TILE_SIZE, CV_32F); cv::Mat row_distances = cv::Mat::zeros(1, TILE_SIZE, CV_32F);
for(int i = 0; i < TILE_SIZE; ++i) { for (int i = 0; i < TILE_SIZE; ++i) {
row_distances.at<float>(i) = i - offset; row_distances.at<float>(i) = i - offset;
} }
row_distances = cv::repeat(row_distances.t(), 1, TILE_SIZE); row_distances = cv::repeat(row_distances.t(), 1, TILE_SIZE);
cv::Mat col_distances = row_distances.t(); cv::Mat col_distances = row_distances.t();
cv::Mat distances; cv::Mat distances;
cv::sqrt(row_distances.mul(row_distances) + col_distances.mul(col_distances), distances); cv::sqrt(row_distances.mul(row_distances) + col_distances.mul(col_distances), distances);
ifftshift(distances); ifftshift(distances);
// Loop through all tiles // Loop through all tiles
for (int i = 0; i < tiles.size(); ++i) { for (int i = 0; i < tiles.size(); ++i) {
cv::Mat tile = tiles[i]; cv::Mat tile = tiles[i];
float coeff = noise_variance[i] / (num_alts + 1) * spatial_noise_scaling; float coeff = noise_variance[i] / (num_alts + 1) * spatial_noise_scaling;
// Calculate absolute difference // Calculate absolute difference
cv::Mat complexMats[2]; cv::Mat complexMats[2];
cv::split(tile, complexMats); // planes[0] = Re(DFT(I)), planes[1] = Im(DFT(I)) cv::split(tile, complexMats); // planes[0] = Re(DFT(I)), planes[1] = Im(DFT(I))
cv::magnitude(complexMats[0], complexMats[1], complexMats[0]); // planes[0] = magnitude cv::magnitude(complexMats[0], complexMats[1], complexMats[0]); // planes[0] = magnitude
cv::Mat absolute_diff = complexMats[0].mul(complexMats[0]); cv::Mat absolute_diff = complexMats[0].mul(complexMats[0]);
// Division // Division
cv::Mat scale; cv::Mat scale;
cv::divide(absolute_diff, absolute_diff + distances * coeff, scale); cv::divide(absolute_diff, absolute_diff + distances * coeff, scale);
cv::merge(std::vector<cv::Mat>{scale, scale}, scale); cv::merge(std::vector<cv::Mat>{scale, scale}, scale);
denoised.push_back(tile.mul(scale)); denoised.push_back(tile.mul(scale));
} }
} }
} // namespace hdrplus } // namespace hdrplus
Loading…
Cancel
Save