diff --git a/include/hdrplus/bayer_image.h b/include/hdrplus/bayer_image.h index 81b30ef..090d8da 100644 --- a/include/hdrplus/bayer_image.h +++ b/include/hdrplus/bayer_image.h @@ -26,6 +26,10 @@ class bayer_image int white_level; std::vector black_level_per_channel; float iso; + + private: + float baseline_lambda_shot = 3.24 * pow( 10, -4 ); + float baseline_lambda_read = 4.3 * pow( 10, -6 ); }; } // namespace hdrplus diff --git a/include/hdrplus/merge.h b/include/hdrplus/merge.h index d782cf6..f980153 100644 --- a/include/hdrplus/merge.h +++ b/include/hdrplus/merge.h @@ -22,10 +22,7 @@ class merge * Inner most two vector is for horizontal & vertical tiles */ void process( const hdrplus::burst& burst_images, \ - std::vector>>>& alignments, \ - int ISO, \ - int white_level, \ - double black_level ); + std::vector>>>& alignments); }; } // namespace hdrplus diff --git a/src/bayer_image.cpp b/src/bayer_image.cpp index 998fa08..2a1647d 100644 --- a/src/bayer_image.cpp +++ b/src/bayer_image.cpp @@ -5,6 +5,7 @@ #include // std::runtime_error #include // all opencv header #include +#include // exiv2 #include "hdrplus/bayer_image.h" #include "hdrplus/utility.h" // box_filter_2x2 namespace hdrplus @@ -31,13 +32,33 @@ bayer_image::bayer_image( const std::string& bayer_image_path ) // Get image basic info width = int( libraw_processor->imgdata.rawdata.sizes.raw_width ); height = int( libraw_processor->imgdata.rawdata.sizes.raw_height ); - white_level = int( libraw_processor->imgdata.rawdata.color.maximum ); + + // 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 ) = int( libraw_processor->imgdata.rawdata.color.cblack[ 0 ] + libraw_processor->imgdata.rawdata.color.black ); - black_level_per_channel.at( 1 ) = int( libraw_processor->imgdata.rawdata.color.cblack[ 1 ] + libraw_processor->imgdata.rawdata.color.black ); - black_level_per_channel.at( 2 ) = int( libraw_processor->imgdata.rawdata.color.cblack[ 2 ] + libraw_processor->imgdata.rawdata.color.black ); - black_level_per_channel.at( 3 ) = int( libraw_processor->imgdata.rawdata.color.cblack[ 3 ] + libraw_processor->imgdata.rawdata.color.black ); - iso = float( libraw_processor->imgdata.other.iso_speed ); + 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(); + + // white_level = int( libraw_processor->imgdata.rawdata.color.maximum ); + // black_level_per_channel.resize( 4 ); + // black_level_per_channel.at( 0 ) = int( libraw_processor->imgdata.rawdata.color.cblack[ 0 ] + libraw_processor->imgdata.rawdata.color.black ); + // black_level_per_channel.at( 1 ) = int( libraw_processor->imgdata.rawdata.color.cblack[ 1 ] + libraw_processor->imgdata.rawdata.color.black ); + // black_level_per_channel.at( 2 ) = int( libraw_processor->imgdata.rawdata.color.cblack[ 2 ] + libraw_processor->imgdata.rawdata.color.black ); + // black_level_per_channel.at( 3 ) = int( libraw_processor->imgdata.rawdata.color.cblack[ 3 ] + libraw_processor->imgdata.rawdata.color.black ); + // iso = float( libraw_processor->imgdata.other.iso_speed ); // Create CV mat // https://answers.opencv.org/question/105972/de-bayering-a-cr2-image/ @@ -57,13 +78,24 @@ bayer_image::bayer_image( const std::string& bayer_image_path ) std::pair bayer_image::get_noise_params() const { - double iso100_lambdas = 3.24 * 0.0001; - double iso100_lambdar = 4.3 * 0.000001; + // 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; + + 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 lambdas = iso / 100 * iso100_lambdas; - double lambdar = ( iso / 100 ) * ( iso / 100 ) * iso100_lambdar; + // 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 std::make_pair(lambdas, lambdar); + // return pair + return std::make_pair(lambda_shot, lambda_read); } } diff --git a/src/hdrplus_pipeline.cpp b/src/hdrplus_pipeline.cpp index 7c929c4..961ab00 100644 --- a/src/hdrplus_pipeline.cpp +++ b/src/hdrplus_pipeline.cpp @@ -3,7 +3,6 @@ #include #include // std::pair #include // all opencv header -#include // exiv2 #include "hdrplus/hdrplus_pipeline.h" #include "hdrplus/burst.h" #include "hdrplus/align.h" @@ -20,26 +19,12 @@ void hdrplus_pipeline::run_pipeline( \ // Create burst of images burst burst_images( burst_path, reference_image_path ); std::vector>>> alignments; - - // Read exif tags - Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(reference_image_path); - assert(image.get() != 0); - image->readMetadata(); - Exiv2::ExifData &exifData = image->exifData(); - if (exifData.empty()) { - std::string error(reference_image_path); - error += ": No Exif data found in the file"; - std::cout << error << std::endl; - } - int ISO = exifData["Exif.Image.ISOSpeedRatings"].toLong(); - int white_level = exifData["Exif.Image.WhiteLevel"].toLong(); - double black_level = exifData["Exif.Image.BlackLevel"].toFloat(); // Run align align_module.process( burst_images, alignments ); // Run merging - merge_module.process( burst_images, alignments, ISO, white_level, black_level ); + merge_module.process( burst_images, alignments ); // Run finishing } diff --git a/src/merge.cpp b/src/merge.cpp index 7df0a5d..bb7b30b 100644 --- a/src/merge.cpp +++ b/src/merge.cpp @@ -7,10 +7,7 @@ namespace hdrplus { void merge::process( const hdrplus::burst& burst_images, \ - std::vector>>>& alignments, \ - int ISO, \ - int white_level, \ - double black_level ) + std::vector>>>& alignments) { }