diff --git a/.gitignore b/.gitignore index dd4eb87..2b7172e 100644 --- a/.gitignore +++ b/.gitignore @@ -50,6 +50,7 @@ dataset/ tests/test_bayer_image tests/test_utility tests/test_burst +tests/test_align # VS/VSCode folder .vs/ diff --git a/include/hdrplus/params.h b/include/hdrplus/params.h index 3648c52..c2f6476 100644 --- a/include/hdrplus/params.h +++ b/include/hdrplus/params.h @@ -5,7 +5,6 @@ #include // all opencv header #include - namespace hdrplus { class RawpyArgs{ diff --git a/include/hdrplus/utility.h b/include/hdrplus/utility.h index cb93af5..367d319 100644 --- a/include/hdrplus/utility.h +++ b/include/hdrplus/utility.h @@ -53,7 +53,7 @@ cv::Mat box_filter_2x2( const cv::Mat& src_image ) } template -cv::Mat box_filter_kxk( cv::Mat src_image ) +cv::Mat box_filter_kxk( const cv::Mat& src_image ) { const T* src_image_ptr = (T*)src_image.data; int src_height = src_image.size().height; @@ -97,33 +97,31 @@ cv::Mat box_filter_kxk( cv::Mat src_image ) template -cv::Mat downsample_nearest_neighbour( cv::Mat src_image ) +cv::Mat downsample_nearest_neighbour( const cv::Mat& src_image ) { const T* src_image_ptr = (T*)src_image.data; int src_height = src_image.size().height; int src_width = src_image.size().width; int src_step = src_image.step1(); - if ( src_height % kernel != 0 || src_width % kernel != 0 ) - { - throw std::runtime_error( std::string( __FILE__ ) + "::" + __func__ + " source image need to have size multiplier of kernel size\n" ); - } - + // int(src_height / kernel) = floor(src_height / kernel) cv::Mat dst_image( src_height / kernel, src_width / kernel, src_image.type() ); T* dst_image_ptr = (T*)dst_image.data; + int dst_height = dst_image.size().height; + int dst_width = dst_image.size().width; int dst_step = dst_image.step1(); // -03 should be enough to optimize below code - for ( int row_i = 0; row_i < src_height; row_i += kernel ) + for ( int row_i = 0; row_i < dst_height; row_i += kernel ) { - for ( int col_i = 0; col_i < src_width; col_i += kernel ) + for ( int col_i = 0; col_i < dst_width; col_i += kernel ) { - dst_image_ptr[ ( row_i / kernel ) * dst_step + ( col_i / kernel ) ] = \ - src_image_ptr[ row_i * src_step + col_i ]; + dst_image_ptr[ row_i * dst_step + col_i ] = \ + src_image_ptr[ (row_i * kernel) * src_step + (col_i * kernel) ]; } } - // cv::Mat internally use reference count. Will not copy by value here + // cv::Mat internally use reference count. Will not copy by value (deepcopy) here return dst_image; } diff --git a/src/align.cpp b/src/align.cpp index 7a99ebe..1f87f63 100644 --- a/src/align.cpp +++ b/src/align.cpp @@ -17,12 +17,23 @@ static void build_per_grayimg_pyramid( \ const cv::Mat& src_image, \ const std::vector& inv_scale_factors ) { + #ifndef NDEBUG + printf("%s::%s build_per_grayimg_pyramid start with scale factor : ", __FILE__, __func__ ); + for ( int i = 0; i < inv_scale_factors.size(); ++i ) + { + printf("%d ", inv_scale_factors.at( i )); + } + printf("\n"); + #endif + images_pyramid.resize( inv_scale_factors.size() ); - + + cv::Mat blur_image; + cv::Mat downsample_image; + for ( int i = 0; i < inv_scale_factors.size(); ++i ) { - cv::Mat blur_image; - cv::Mat downsample_image; + printf("inv scale factor %d\n", inv_scale_factors.at( i ) ); switch ( inv_scale_factors[ i ] ) { @@ -32,9 +43,13 @@ static void build_per_grayimg_pyramid( \ downsample_image = src_image; break; case 2: + printf("gaussian blur 2 start\n"); fflush(stdout); + // Gaussian blur - cv::GaussianBlur( downsample_image, blur_image, cv::Size(0, 0), 1.0 ); + cv::GaussianBlur( downsample_image, blur_image, cv::Size(0, 0), inv_scale_factors[ i ] / 2 ); + printf("gaussian blur 2 done\n"); fflush(stdout); + // Downsample downsample_image = downsample_nearest_neighbour( blur_image ); @@ -43,13 +58,19 @@ static void build_per_grayimg_pyramid( \ break; case 4: - cv::GaussianBlur( downsample_image, blur_image, cv::Size(0, 0), 2.0 ); + printf("gaussian blur 4 start\n"); fflush(stdout); + cv::GaussianBlur( downsample_image, blur_image, cv::Size(0, 0), inv_scale_factors[ i ] / 2 ); + printf("gaussian blur 4 done\n"); fflush(stdout); + downsample_image = downsample_nearest_neighbour( blur_image ); images_pyramid[ images_pyramid.size() - i - 1 ] = downsample_image; break; default: throw std::runtime_error("inv scale factor " + std::to_string( inv_scale_factors[ i ]) + "invalid" ); } + + printf("downsample size h=%d w=%d\n", \ + downsample_image.size().height, downsample_image.size().width ); fflush(stdout); } } @@ -90,6 +111,7 @@ static void upsample_alignment_stride( \ } } + template void print_tile( const cv::Mat& img, int tile_size, int start_idx_x, int start_idx_y ) { @@ -110,6 +132,7 @@ void print_tile( const cv::Mat& img, int tile_size, int start_idx_x, int start_i printf("\n"); } + void align_image_level( \ const cv::Mat& ref_img, \ const cv::Mat& alt_img, \ @@ -230,6 +253,10 @@ static void build_per_pyramid_reftiles_start( \ void align::process( const hdrplus::burst& burst_images, \ std::vector>>>& images_alignment ) { + #ifndef NDEBUG + printf("%s::%s align::process start\n", __FILE__, __func__ ); + #endif + // image pyramid per image, per pyramid level std::vector> per_grayimg_pyramid; @@ -238,9 +265,9 @@ void align::process( const hdrplus::burst& burst_images, \ { // per_grayimg_pyramid[ img_idx ][ 0 ] is the original image // per_grayimg_pyramid[ img_idx ][ 3 ] is the coarsest image - build_per_grayimg_pyramid( per_grayimg_pyramid[ img_idx ], \ - burst_images.grayscale_images_pad[ img_idx ], \ - inv_scale_factors ); + build_per_grayimg_pyramid( per_grayimg_pyramid.at( img_idx ), \ + burst_images.grayscale_images_pad.at( img_idx ), \ + this->inv_scale_factors ); } #ifndef NDEBUG diff --git a/src/burst.cpp b/src/burst.cpp index 4fe43d3..0fa6da0 100644 --- a/src/burst.cpp +++ b/src/burst.cpp @@ -11,7 +11,18 @@ burst::burst( const std::string& burst_path, const std::string& reference_image_ { std::vector bayer_image_paths; // Search through the input path directory to get all input image path - cv::glob( burst_path + "/*.dng", bayer_image_paths, false ); + if ( burst_path.at( burst_path.size() - 1) == '/') + cv::glob( burst_path + "*.dng", bayer_image_paths, false ); + else + cv::glob( burst_path + "/*.dng", bayer_image_paths, false ); + + #ifndef NDEBUG + for ( const auto& bayer_img_path_i : bayer_image_paths ) + { + printf("img i path %s\n", bayer_img_path_i.c_str()); fflush(stdout); + } + printf("ref img path %s\n", reference_image_path.c_str()); fflush(stdout); + #endif // Number of images num_images = bayer_image_paths.size(); @@ -54,11 +65,11 @@ burst::burst( const std::string& burst_path, const std::string& reference_image_ 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 ? \ + ( (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 ? \ + ( (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 }; @@ -83,6 +94,9 @@ burst::burst( const std::string& burst_path, const std::string& reference_image_ 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 } diff --git a/tests/test_align.cpp b/tests/test_align.cpp index fc89353..d281e77 100644 --- a/tests/test_align.cpp +++ b/tests/test_align.cpp @@ -9,6 +9,10 @@ void test_align_one_level(int argc, char** argv) { printf("Usage ./test_align BUTST_PATH REF_PATH"); } + + printf("Burst img dir %s\n", argv[1]); + printf("Ref img path %s\n", argv[2]); + hdrplus::burst burst_images( argv[1], argv[2] ); std::vector>>> alignments;