main
Matthew 6 months ago
parent 2767bab6ea
commit 38e4ef464c

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

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

File diff suppressed because it is too large Load Diff

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

File diff suppressed because it is too large Load Diff

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

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