diff --git a/app/src/main/cpp/PhoneDevice.cpp b/app/src/main/cpp/PhoneDevice.cpp index feba82a3..27de01f1 100644 --- a/app/src/main/cpp/PhoneDevice.cpp +++ b/app/src/main/cpp/PhoneDevice.cpp @@ -1694,7 +1694,6 @@ bool CPhoneDevice::onBurstCapture(std::shared_ptr characteristi delete[] nv21; } - if (photoInfo.outputDbgInfo != 0) { @@ -1755,28 +1754,9 @@ bool CPhoneDevice::onBurstCapture(std::shared_ptr characteristi if (photoInfo.usingRawFormat != 0) { - std::vector rawFilePaths; - for (auto it = rawFiles.cbegin(); it != rawFiles.cend(); ++it) - { - std::string dngFilePath = tmpPath + std::string("-") + std::to_string(std::distance(rawFiles.cbegin(), it)) + std::string(".dng"); -#ifdef _DEBUG - char log[256] = { 0 }; - strcpy(log, dngFilePath.c_str()); -#endif - FILE *file = fopen(dngFilePath.c_str(), "wb"); - if (file) { - if (!(*it).empty()) - { - fwrite((const void*)(&((*it)[0])), 1, (*it).size(), file); - } - fclose(file); - rawFilePaths.push_back(dngFilePath); - } - } - XYLOG(XYLOG_SEVERITY_ERROR, "Start HDR CH=%u IMGID=%u", (uint32_t)mPhotoInfo.channel, (uint32_t)mPhotoInfo.photoId); hdrplus::hdrplus_pipeline pipeline; - pipeline.run_pipeline(rawFilePaths, 0, rgb); + pipeline.run_pipeline(rawFiles, 0, rgb); XYLOG(XYLOG_SEVERITY_ERROR, "Finish HDR CH=%u IMGID=%u", (uint32_t)mPhotoInfo.channel, (uint32_t)mPhotoInfo.photoId); #ifdef NDEBUG diff --git a/app/src/main/cpp/hdrplus/include/hdrplus/bayer_image.h b/app/src/main/cpp/hdrplus/include/hdrplus/bayer_image.h index 090d8da5..93230cf2 100644 --- a/app/src/main/cpp/hdrplus/include/hdrplus/bayer_image.h +++ b/app/src/main/cpp/hdrplus/include/hdrplus/bayer_image.h @@ -14,6 +14,7 @@ class bayer_image { public: explicit bayer_image( const std::string& bayer_image_path ); + explicit bayer_image( const std::vector& bayer_image_content ); ~bayer_image() = default; std::pair get_noise_params() const; diff --git a/app/src/main/cpp/hdrplus/include/hdrplus/burst.h b/app/src/main/cpp/hdrplus/include/hdrplus/burst.h index b65c4389..bde3c04f 100644 --- a/app/src/main/cpp/hdrplus/include/hdrplus/burst.h +++ b/app/src/main/cpp/hdrplus/include/hdrplus/burst.h @@ -13,6 +13,7 @@ class burst public: explicit burst( const std::string& burst_path, const std::string& reference_image_path ); explicit burst(const std::vector& burst_paths, int reference_image_index); + explicit burst( const std::vector >& bayer_image_contents, int reference_image_index ); ~burst() = default; diff --git a/app/src/main/cpp/hdrplus/include/hdrplus/hdrplus_pipeline.h b/app/src/main/cpp/hdrplus/include/hdrplus/hdrplus_pipeline.h index 95f9cd74..3d6f478c 100644 --- a/app/src/main/cpp/hdrplus/include/hdrplus/hdrplus_pipeline.h +++ b/app/src/main/cpp/hdrplus/include/hdrplus/hdrplus_pipeline.h @@ -20,6 +20,8 @@ class hdrplus_pipeline public: void run_pipeline( const std::string& burst_path, const std::string& reference_image_path ); bool run_pipeline( const std::vector& burst_paths, int reference_image_index, cv::Mat& finalImg ); + bool run_pipeline( const std::vector >& burst_contents, int reference_image_index, cv::Mat& finalImg ); + hdrplus_pipeline() = default; ~hdrplus_pipeline() = default; }; diff --git a/app/src/main/cpp/hdrplus/src/bayer_image.cpp b/app/src/main/cpp/hdrplus/src/bayer_image.cpp index a0f53471..0d84199a 100644 --- a/app/src/main/cpp/hdrplus/src/bayer_image.cpp +++ b/app/src/main/cpp/hdrplus/src/bayer_image.cpp @@ -77,6 +77,70 @@ bayer_image::bayer_image( const std::string& bayer_image_path ) #endif } +bayer_image::bayer_image( const std::vector& bayer_image_content ) +{ + libraw_processor = std::make_shared(); + + // 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__ + return; +#else + 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 ) + { +#ifdef __ANDROID__ + return; +#else + 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_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( 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 ); +#endif +} + std::pair bayer_image::get_noise_params() const { // Set ISO to 100 if not positive diff --git a/app/src/main/cpp/hdrplus/src/burst.cpp b/app/src/main/cpp/hdrplus/src/burst.cpp index 12c0e2a6..08ab324c 100644 --- a/app/src/main/cpp/hdrplus/src/burst.cpp +++ b/app/src/main/cpp/hdrplus/src/burst.cpp @@ -178,4 +178,74 @@ burst::burst( const std::vector& bayer_image_paths, int reference_i #endif } +burst::burst( const std::vector >& bayer_image_contents, int reference_image_index ) +{ + // Number of images + num_images = bayer_image_contents.size(); + + // Find reference image path in input directory + // reference image path need to be absolute path + reference_image_idx = -1; + if ( reference_image_index >= 0 && reference_image_index < bayer_image_contents.size() ) + { + reference_image_idx = reference_image_index; + } + + if ( reference_image_idx == -1 ) + { + return; + // throw std::runtime_error("Error reference image index is out of range " ); + } + +#ifndef NDEBUG + printf("%s::%s reference image idx %d\n", \ + __FILE__, __func__, reference_image_idx ); +#endif + + // Get source bayer image + // Downsample original bayer image by 2x2 box filter + for ( const auto& bayer_image_content : bayer_image_contents ) + { + bayer_images.emplace_back( bayer_image_content ); + } + + // Pad information + int tile_size_bayer = 32; + int padding_top = tile_size_bayer / 2; + int padding_bottom = tile_size_bayer / 2 + \ + ( (bayer_images[ 0 ].height % tile_size_bayer) == 0 ? \ + 0 : tile_size_bayer - bayer_images[ 0 ].height % tile_size_bayer ); + int padding_left = tile_size_bayer / 2; + int padding_right = tile_size_bayer / 2 + \ + ( (bayer_images[ 0 ].width % tile_size_bayer) == 0 ? \ + 0 : tile_size_bayer - bayer_images[ 0 ].width % tile_size_bayer ); + padding_info_bayer = std::vector{ padding_top, padding_bottom, padding_left, padding_right }; + + // Pad bayer image + for ( const auto& bayer_image_i : bayer_images ) + { + cv::Mat bayer_image_pad_i; + cv::copyMakeBorder( bayer_image_i.raw_image, \ + bayer_image_pad_i, \ + padding_top, padding_bottom, padding_left, padding_right, \ + cv::BORDER_REFLECT ); + + // cv::Mat use internal reference count + bayer_images_pad.emplace_back( bayer_image_pad_i ); + grayscale_images_pad.emplace_back( box_filter_kxk( bayer_image_pad_i ) ); + } + +#ifndef NDEBUG + printf("%s::%s Pad bayer image from (%d, %d) -> (%d, %d)\n", \ + __FILE__, __func__, \ + bayer_images[ 0 ].height, \ + bayer_images[ 0 ].width, \ + bayer_images_pad[ 0 ].size().height, \ + bayer_images_pad[ 0 ].size().width ); + printf("%s::%s pad top %d, buttom %d, left %d, right %d\n", \ + __FILE__, __func__, \ + padding_top, padding_bottom, padding_left, padding_right ); +#endif +} + } // namespace hdrplus diff --git a/app/src/main/cpp/hdrplus/src/hdrplus_pipeline.cpp b/app/src/main/cpp/hdrplus/src/hdrplus_pipeline.cpp index 2ba525c7..90307a8b 100644 --- a/app/src/main/cpp/hdrplus/src/hdrplus_pipeline.cpp +++ b/app/src/main/cpp/hdrplus/src/hdrplus_pipeline.cpp @@ -70,4 +70,36 @@ bool hdrplus_pipeline::run_pipeline( \ return true; } +bool hdrplus_pipeline::run_pipeline( \ + const std::vector >& burst_contents, \ + int reference_image_index, cv::Mat& finalImg ) +{ + // Create burst of images + burst burst_images( burst_contents, reference_image_index ); + std::vector>>> alignments; +#ifdef __ANDROID__ + ALOGI("Finish loading images"); +#endif + + // Run align + align_module.process( burst_images, alignments ); +#ifdef __ANDROID__ + ALOGI("Finish align"); +#endif + + // Run merging + merge_module.process( burst_images, alignments ); +#ifdef __ANDROID__ + ALOGI("Finish merging"); +#endif + + // Run finishing + finish_module.process( burst_images, finalImg); +#ifdef __ANDROID__ + ALOGI("Finish process"); +#endif + + return true; +} + } // namespace hdrplus