diff --git a/CMakeLists.txt b/CMakeLists.txt index c3027f8..2a30263 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,8 +6,8 @@ project(hdrplus) # set c++ standard set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED True) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3") -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -Wall") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3 -Wall") # make sure we use Release and warn otherwise if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) @@ -37,6 +37,9 @@ message(STATUS "Found LIBRAW_LIBRARY to be ${LIBRAW_LIBRARY}" ) find_package(exiv2 REQUIRED CONFIG NAMES exiv2) message(STATUS "Found Exiv2 and linked") +# OpenMP +find_package(OpenMP REQUIRED) + # library include_directories( include ) @@ -60,7 +63,8 @@ add_library(${PROJECT_NAME} SHARED ${src_files} ) target_link_libraries(${PROJECT_NAME} PUBLIC ${OpenCV_LIBS} ${LIBRAW_LIBRARY} - exiv2lib ) + exiv2lib + OpenMP::OpenMP_CXX ) # example set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/bin ) diff --git a/INSTALL.md b/INSTALL.md index ab3f45f..16acc57 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -17,6 +17,7 @@ step 3: ```shell cd LibRaw-X.YY + autoreconf -f -i ./configure # with optional args make ``` diff --git a/include/hdrplus/utility.h b/include/hdrplus/utility.h index c192ab9..9569bb5 100644 --- a/include/hdrplus/utility.h +++ b/include/hdrplus/utility.h @@ -3,21 +3,33 @@ #include #include // std::runtime_error #include // all opencv header -// TODO: add openmp support - -#if defined(__clang__) - #define LOOP_UNROLL unroll -#elif defined(__GNUC__) || defined(__GNUG__) - #define LOOP_UNROLL GCC unroll -#elif defined(_MSC_VER) - #define LOOP_UNROLL unroll +#include + +// https://stackoverflow.com/questions/63404539/portable-loop-unrolling-with-template-parameter-in-c-with-gcc-icc +/// Helper macros for stringification +#define TO_STRING_HELPER(X) #X +#define TO_STRING(X) TO_STRING_HELPER(X) + +// Define loop unrolling depending on the compiler +#if defined(__ICC) || defined(__ICL) + #define UNROLL_LOOP(n) _Pragma(TO_STRING(unroll (n))) +#elif defined(__clang__) + #define UNROLL_LOOP(n) _Pragma(TO_STRING(unroll (n))) +#elif defined(__GNUC__) && !defined(__clang__) + #define UNROLL_LOOP(n) _Pragma(TO_STRING(GCC unroll (16))) +#elif defined(_MSC_BUILD) + #pragma message ("Microsoft Visual C++ (MSVC) detected: Loop unrolling not supported!") + #define UNROLL_LOOP(n) +#else + #warning "Unknown compiler: Loop unrolling not supported!" + #define UNROLL_LOOP(n) #endif + namespace hdrplus { - template cv::Mat box_filter_kxk( const cv::Mat& src_image ) { @@ -45,10 +57,11 @@ cv::Mat box_filter_kxk( const cv::Mat& src_image ) { // Take ceiling for rounding T box_sum = T( 0 ); - //#pragma LOOP_UNROLL + + UNROLL_LOOP( kernel ) for ( int kernel_row_i = 0; kernel_row_i < kernel; ++kernel_row_i ) { - //#pragma LOOP_UNROLL + UNROLL_LOOP( kernel ) for ( int kernel_col_i = 0; kernel_col_i < kernel; ++kernel_col_i ) { box_sum += src_image_ptr[ ( row_i * kernel + kernel_row_i ) * src_step + ( col_i * kernel + kernel_col_i ) ]; @@ -84,6 +97,7 @@ cv::Mat downsample_nearest_neighbour( const cv::Mat& src_image ) // -03 should be enough to optimize below code for ( int row_i = 0; row_i < dst_height; row_i++ ) { + UNROLL_LOOP( 32 ) for ( int col_i = 0; col_i < dst_width; col_i++ ) { dst_image_ptr[ row_i * dst_step + col_i ] = \ @@ -126,10 +140,10 @@ void print_cvmat( cv::Mat image ) * @return vector of RGB image. OpenCV internally maintain reference count. * Thus this step won't create deep copy overhead. * - * @example extract_rgb_fmom_bayer( bayer_img, rgb_vector_container ); + * @example extract_rgb_from_bayer( bayer_img, rgb_vector_container ); */ template -void extract_rgb_fmom_bayer( const cv::Mat& bayer_img, \ +void extract_rgb_from_bayer( const cv::Mat& bayer_img, \ cv::Mat& img_ch1, cv::Mat& img_ch2, cv::Mat& img_ch3, cv::Mat& img_ch4 ) { const T* bayer_img_ptr = (const T*)bayer_img.data; @@ -156,6 +170,7 @@ void extract_rgb_fmom_bayer( const cv::Mat& bayer_img, \ T* img_ch3_ptr = (T*)img_ch3.data; T* img_ch4_ptr = (T*)img_ch4.data; + #pragma omp parallel for for ( int rgb_row_i = 0; rgb_row_i < rgb_height; rgb_row_i++ ) { int rgb_row_i_offset = rgb_row_i * rgb_step; @@ -184,8 +199,6 @@ template void print_tile( const cv::Mat& img, int tile_size, int start_idx_row, int start_idx_col ) { const T* img_ptr = (T*)img.data; - int src_height = img.size().height; - int src_width = img.size().width; int src_step = img.step1(); for ( int row = start_idx_row; row < tile_size + start_idx_row; ++row ) diff --git a/src/align.cpp b/src/align.cpp index 0a100b0..6681716 100644 --- a/src/align.cpp +++ b/src/align.cpp @@ -5,6 +5,7 @@ #include // std::make_pair #include // std::runtime_error #include // all opencv header +#include #include "hdrplus/align.h" #include "hdrplus/burst.h" #include "hdrplus/utility.h" @@ -30,7 +31,7 @@ static void build_per_grayimg_pyramid( \ images_pyramid.resize( inv_scale_factors.size() ); - for ( int i = 0; i < inv_scale_factors.size(); ++i ) + for ( size_t i = 0; i < inv_scale_factors.size(); ++i ) { cv::Mat blur_image; cv::Mat downsample_image; @@ -43,7 +44,6 @@ static void build_per_grayimg_pyramid( \ downsample_image = src_image; break; case 2: - //printf("downsample with gaussian sigma %.2f", inv_scale_factors[ i ] * 0.5 ); // // Gaussian blur cv::GaussianBlur( images_pyramid.at( i-1 ), blur_image, cv::Size(0, 0), inv_scale_factors[ i ] * 0.5 ); @@ -56,9 +56,10 @@ static void build_per_grayimg_pyramid( \ break; case 4: - printf("downsample with gaussian sigma %.2f", inv_scale_factors[ i ] * 0.5 ); cv::GaussianBlur( images_pyramid.at( i-1 ), blur_image, cv::Size(0, 0), inv_scale_factors[ i ] * 0.5 ); + downsample_image = downsample_nearest_neighbour( blur_image ); + //downsample_image = downsample_nearest_neighbour( images_pyramid.at( i-1 ) ); images_pyramid.at( i ) = downsample_image.clone(); break; @@ -81,7 +82,7 @@ static void build_upsampled_prev_aligement( \ constexpr int repeat_factor = pyramid_scale_factor_prev_curr / tilesize_scale_factor_prev_curr; // printf("build_upsampled_prev_aligement with scale factor %d, repeat factor %d, tile size factor %d\n", \ - pyramid_scale_factor_prev_curr, repeat_factor, tilesize_scale_factor_prev_curr ); + // pyramid_scale_factor_prev_curr, repeat_factor, tilesize_scale_factor_prev_curr ); int dst_height = src_height * repeat_factor; int dst_width = src_width * repeat_factor; @@ -97,6 +98,7 @@ static void build_upsampled_prev_aligement( \ dst_alignment.resize( num_tiles_h, std::vector>( num_tiles_w, std::pair(0, 0) ) ); // Upsample alignment + #pragma omp parallel for collapse(2) for ( int row_i = 0; row_i < src_height; row_i++ ) { for ( int col_i = 0; col_i < src_width; col_i++ ) @@ -107,11 +109,15 @@ static void build_upsampled_prev_aligement( \ align_i.second *= pyramid_scale_factor_prev_curr; // repeat + UNROLL_LOOP( repeat_factor ) for ( int repeat_row_i = 0; repeat_row_i < repeat_factor; ++repeat_row_i ) { + int repeat_row_i_offset = row_i * repeat_factor + repeat_row_i; + UNROLL_LOOP( repeat_factor ) for ( int repeat_col_i = 0; repeat_col_i < repeat_factor; ++repeat_col_i ) { - dst_alignment[ row_i * repeat_factor + repeat_row_i ][ col_i * repeat_factor + repeat_col_i ] = align_i; + int repeat_col_i_offset = col_i * repeat_factor + repeat_col_i; + dst_alignment[ repeat_row_i_offset ][ repeat_col_i_offset ] = align_i; } } } @@ -142,12 +148,14 @@ static unsigned long long l1_distance( const cv::Mat& img1, const cv::Mat& img2, // Range check for safety if ( img1_tile_row_start_idx < 0 || img1_tile_row_start_idx > img1_height - tile_size ) { - throw std::runtime_error("l1 distance img1_tile_row_start_idx out of valid range\n"); + throw std::runtime_error("l1 distance img1_tile_row_start_idx" + std::to_string( img1_tile_row_start_idx ) + \ + " out of valid range (0, " + std::to_string( img1_height - tile_size ) + ")\n" ); } if ( img1_tile_col_start_idx < 0 || img1_tile_col_start_idx > img1_width - tile_size ) { - throw std::runtime_error("l1 distance img1_tile_col_start_idx out of valid range\n"); + throw std::runtime_error("l1 distance img1_tile_col_start_idx" + std::to_string( img1_tile_col_start_idx ) + \ + " out of valid range (0, " + std::to_string( img1_width - tile_size ) + ")\n" ); } if ( img2_tile_row_start_idx < 0 || img2_tile_row_start_idx > img2_height - tile_size ) @@ -161,12 +169,14 @@ static unsigned long long l1_distance( const cv::Mat& img1, const cv::Mat& img2, } return_type sum(0); - // TODO: add pragma unroll here + + UNROLL_LOOP( tile_size ) for ( int row_i = 0; row_i < tile_size; ++row_i ) { const data_type* img1_ptr_row_i = img1_ptr + (img1_tile_row_start_idx + row_i) * img1_step + img1_tile_col_start_idx; const data_type* img2_ptr_row_i = img2_ptr + (img2_tile_row_start_idx + row_i) * img2_step + img2_tile_col_start_idx; + UNROLL_LOOP( tile_size ) for ( int col_i = 0; col_i < tile_size; ++col_i ) { data_type l1 = CUSTOME_ABS( img1_ptr_row_i[ col_i ] - img2_ptr_row_i[ col_i ] ); @@ -202,22 +212,24 @@ static return_type l2_distance( const cv::Mat& img1, const cv::Mat& img2, \ // Range check for safety if ( img1_tile_row_start_idx < 0 || img1_tile_row_start_idx > img1_height - tile_size ) { - throw std::runtime_error("l1 distance img1_tile_row_start_idx out of valid range\n"); + throw std::runtime_error("l2 distance img1_tile_row_start_idx" + std::to_string( img1_tile_row_start_idx ) + \ + " out of valid range (0, " + std::to_string( img1_height - tile_size ) + ")\n" ); } if ( img1_tile_col_start_idx < 0 || img1_tile_col_start_idx > img1_width - tile_size ) { - throw std::runtime_error("l1 distance img1_tile_col_start_idx out of valid range\n"); + throw std::runtime_error("l2 distance img1_tile_col_start_idx" + std::to_string( img1_tile_col_start_idx ) + \ + " out of valid range (0, " + std::to_string( img1_width - tile_size ) + ")\n" ); } if ( img2_tile_row_start_idx < 0 || img2_tile_row_start_idx > img2_height - tile_size ) { - throw std::runtime_error("l1 distance img2_tile_row_start_idx out of valid range\n"); + throw std::runtime_error("l2 distance img2_tile_row_start_idx out of valid range\n"); } if ( img2_tile_col_start_idx < 0 || img2_tile_col_start_idx > img2_width - tile_size ) { - throw std::runtime_error("l1 distance img2_tile_col_start_idx out of valid range\n"); + throw std::runtime_error("l2 distance img2_tile_col_start_idx out of valid range\n"); } // printf("Search two tile with ref : \n"); @@ -226,12 +238,14 @@ static return_type l2_distance( const cv::Mat& img1, const cv::Mat& img2, \ // print_tile( img2, tile_size, img2_tile_row_start_idx, img2_tile_col_start_idx ); return_type sum(0); - // TODO: add pragma unroll here + + UNROLL_LOOP( tile_size ) for ( int row_i = 0; row_i < tile_size; ++row_i ) { const data_type* img1_ptr_row_i = img1_ptr + (img1_tile_row_start_idx + row_i) * img1_step + img1_tile_col_start_idx; const data_type* img2_ptr_row_i = img2_ptr + (img2_tile_row_start_idx + row_i) * img2_step + img2_tile_col_start_idx; + UNROLL_LOOP( tile_size ) for ( int col_i = 0; col_i < tile_size; ++col_i ) { data_type l1 = CUSTOME_ABS( img1_ptr_row_i[ col_i ] - img2_ptr_row_i[ col_i ] ); @@ -245,6 +259,47 @@ static return_type l2_distance( const cv::Mat& img1, const cv::Mat& img2, \ } +template +static cv::Mat extract_img_tile( const cv::Mat& img, int img_tile_row_start_idx, int img_tile_col_start_idx ) +{ + const T* img_ptr = (const T*)img.data; + int img_width = img.size().width; + int img_height = img.size().height; + int img_step = img.step1(); + + if ( img_tile_row_start_idx < 0 || img_tile_row_start_idx > img_height - tile_size ) + { + throw std::runtime_error("extract_img_tile img_tile_row_start_idx " + std::to_string( img_tile_row_start_idx ) + \ + " out of valid range (0, " + std::to_string( img_height - tile_size ) + ")\n" ); + } + + if ( img_tile_col_start_idx < 0 || img_tile_col_start_idx > img_width - tile_size ) + { + throw std::runtime_error("extract_img_tile img_tile_col_start_idx " + std::to_string( img_tile_col_start_idx ) + \ + " out of valid range (0, " + std::to_string( img_width - tile_size ) + ")\n" ); + } + + cv::Mat img_tile( tile_size, tile_size, img.type() ); + T* img_tile_ptr = (T*)img_tile.data; + int img_tile_step = img_tile.step1(); + + UNROLL_LOOP( tile_size ) + for ( int row_i = 0; row_i < tile_size; ++row_i ) + { + const T* img_ptr_row_i = img_ptr + img_step * ( img_tile_row_start_idx + row_i ); + T* img_tile_ptr_row_i = img_tile_ptr + img_tile_step * row_i; + + UNROLL_LOOP( tile_size ) + for ( int col_i = 0; col_i < tile_size; ++col_i ) + { + img_tile_ptr_row_i[ col_i ] = img_ptr_row_i[ img_tile_col_start_idx + col_i ]; + } + } + + return img_tile; +} + + void align_image_level( \ const cv::Mat& ref_img, \ const cv::Mat& alt_img, \ @@ -316,6 +371,42 @@ void align_image_level( \ } } + // Function to extract reference image tile for memory cache + cv::Mat (*extract_ref_img_tile)(const cv::Mat&, int, int) = nullptr; + if ( curr_tile_size == 8 ) + { + extract_ref_img_tile = &extract_img_tile; + } + else if ( curr_tile_size == 16 ) + { + extract_ref_img_tile = &extract_img_tile; + } + + // Function to extract search image tile for memory cache + cv::Mat (*extract_alt_img_search)(const cv::Mat&, int, int) = nullptr; + if ( curr_tile_size == 8 ) + { + if ( search_radiou == 1 ) + { + extract_alt_img_search = &extract_img_tile; + } + else if ( search_radiou == 4 ) + { + extract_alt_img_search = &extract_img_tile; + } + } + else if ( curr_tile_size == 16 ) + { + if ( search_radiou == 1 ) + { + extract_alt_img_search = &extract_img_tile; + } + else if ( search_radiou == 4 ) + { + extract_alt_img_search = &extract_img_tile; + } + } + int num_tiles_h = ref_img.size().height / (curr_tile_size / 2) - 1; int num_tiles_w = ref_img.size().width / (curr_tile_size / 2 ) - 1; @@ -372,15 +463,16 @@ void align_image_level( \ // printf("Alter image pad h=%d, w=%d: \n", alt_img_pad.size().height, alt_img_pad.size().width ); // print_img( alt_img_pad ); - //printf("!! enlarged tile size %d\n", curr_tile_size + 2 * search_radiou ); + // printf("!! enlarged tile size %d\n", curr_tile_size + 2 * search_radiou ); int alt_tile_row_idx_max = alt_img_pad.size().height - ( curr_tile_size + 2 * search_radiou ); int alt_tile_col_idx_max = alt_img_pad.size().width - ( curr_tile_size + 2 * search_radiou ); - // TODO delete below distance vector, this is for debug only + // Dlete below distance vector, this is for debug only std::vector> distances( num_tiles_h, std::vector( num_tiles_w, 0 )); /* Iterate through all reference tile & compute distance */ + #pragma omp parallel for collapse(2) for ( int ref_tile_row_i = 0; ref_tile_row_i < num_tiles_h; ref_tile_row_i++ ) { for ( int ref_tile_col_i = 0; ref_tile_col_i < num_tiles_w; ref_tile_col_i++ ) @@ -389,8 +481,8 @@ void align_image_level( \ int ref_tile_row_start_idx_i = ref_tile_row_i * curr_tile_size / 2; int ref_tile_col_start_idx_i = ref_tile_col_i * curr_tile_size / 2; - //printf("\nRef img tile [%d, %d] -> start idx [%d, %d] (row, col)\n", \ - ref_tile_row_i, ref_tile_col_i, ref_tile_row_start_idx_i, ref_tile_col_start_idx_i ); + // printf("\nRef img tile [%d, %d] -> start idx [%d, %d] (row, col)\n", \ + // ref_tile_row_i, ref_tile_col_i, ref_tile_row_start_idx_i, ref_tile_col_start_idx_i ); // printf("\nRef img tile [%d, %d]\n", ref_tile_row_i, ref_tile_col_i ); // print_tile( ref_img, curr_tile_size, ref_tile_row_start_idx_i, ref_tile_col_start_idx_i ); @@ -410,21 +502,25 @@ void align_image_level( \ alt_tile_col_start_idx_i = 0; if ( alt_tile_row_start_idx_i > alt_tile_row_idx_max ) { - int before = alt_tile_row_start_idx_i; + // int before = alt_tile_row_start_idx_i; alt_tile_row_start_idx_i = alt_tile_row_idx_max; // printf("@@ change start x from %d to %d\n", before, alt_tile_row_idx_max); } if ( alt_tile_col_start_idx_i > alt_tile_col_idx_max ) { - int before = alt_tile_col_start_idx_i; + // int before = alt_tile_col_start_idx_i; alt_tile_col_start_idx_i = alt_tile_col_idx_max; // printf("@@ change start y from %d to %d\n", before, alt_tile_col_idx_max ); } + // Explicitly caching reference image tile + cv::Mat ref_img_tile_i = extract_ref_img_tile( ref_img, ref_tile_row_start_idx_i, ref_tile_col_start_idx_i ); + cv::Mat alt_img_search_i = extract_alt_img_search( alt_img_pad, alt_tile_row_start_idx_i, alt_tile_col_start_idx_i ); + // Because alternative image is padded with search radious. // Using same coordinate with reference image will automatically considered search radious * 2 - //printf("Alt image tile [%d, %d]-> start idx [%d, %d]\n", \ - ref_tile_row_i, ref_tile_col_i, alt_tile_row_start_idx_i, alt_tile_col_start_idx_i ); + // printf("Alt image tile [%d, %d]-> start idx [%d, %d]\n", \ + // ref_tile_row_i, ref_tile_col_i, alt_tile_row_start_idx_i, alt_tile_col_start_idx_i ); // printf("\nAlt image tile [%d, %d]\n", ref_tile_row_i, ref_tile_col_i ); // print_tile( alt_img_pad, curr_tile_size + 2 * search_radiou, alt_tile_row_start_idx_i, alt_tile_col_start_idx_i ); @@ -436,16 +532,23 @@ void align_image_level( \ { for ( int search_col_j = 0; search_col_j < ( search_radiou * 2 + 1 ); search_col_j++ ) { - //printf("\n--->tile at [%d, %d] search (%d, %d)\n", \ - ref_tile_row_i, ref_tile_col_i, search_row_j - search_radiou, search_col_j - search_radiou ); + // printf("\n--->tile at [%d, %d] search (%d, %d)\n", \ + // ref_tile_row_i, ref_tile_col_i, search_row_j - search_radiou, search_col_j - search_radiou ); + + // unsigned long long distance_j = distance_func_ptr( ref_img, alt_img_pad, \ + // ref_tile_row_start_idx_i, ref_tile_col_start_idx_i, \ + // alt_tile_row_start_idx_i + search_row_j, alt_tile_col_start_idx_i + search_col_j ); - // TODO: currently distance is incorrect - unsigned long long distance_j = distance_func_ptr( ref_img, alt_img_pad, \ - ref_tile_row_start_idx_i, ref_tile_col_start_idx_i, \ - alt_tile_row_start_idx_i + search_row_j, alt_tile_col_start_idx_i + search_col_j ); + // unsigned long long distance_j = distance_func_ptr( ref_img_tile_i, alt_img_pad, \ + // 0, 0, \ + // alt_tile_row_start_idx_i + search_row_j, alt_tile_col_start_idx_i + search_col_j ); - //printf("<---tile at [%d, %d] search (%d, %d), new dis %llu, old dis %llu\n", \ - ref_tile_row_i, ref_tile_col_i, search_row_j - search_radiou, search_col_j - search_radiou, distance_j, min_distance_i ); + unsigned long long distance_j = distance_func_ptr( ref_img_tile_i, alt_img_search_i, \ + 0, 0, \ + search_row_j, search_col_j ); + + // printf("<---tile at [%d, %d] search (%d, %d), new dis %llu, old dis %llu\n", \ + // ref_tile_row_i, ref_tile_col_i, search_row_j - search_radiou, search_col_j - search_radiou, distance_j, min_distance_i ); // If this is smaller distance if ( distance_j < min_distance_i ) @@ -456,30 +559,30 @@ void align_image_level( \ } // If same value, choose the one closer to the original tile location - // if ( distance_j == min_distance_i && min_distance_row_i != -1 && min_distance_col_i != -1 ) - // { - // int prev_distance_row_2_ref = min_distance_row_i - search_radiou; - // int prev_distance_col_2_ref = min_distance_col_i - search_radiou; - // int curr_distance_row_2_ref = search_row_j - search_radiou; - // int curr_distance_col_2_ref = search_col_j - search_radiou; - - // int prev_distance_2_ref_sqr = prev_distance_row_2_ref * prev_distance_row_2_ref + prev_distance_col_2_ref * prev_distance_col_2_ref; - // int curr_distance_2_ref_sqr = curr_distance_row_2_ref * curr_distance_row_2_ref + curr_distance_col_2_ref * curr_distance_col_2_ref; - - // // previous min distance idx is farther away from ref tile start location - // if ( prev_distance_2_ref_sqr > curr_distance_2_ref_sqr ) - // { - // // printf("@@@ Same distance %d, choose closer one (%d, %d) instead of (%d, %d)\n", \ - // distance_j, search_row_j, search_col_j, min_distance_row_i, min_distance_col_i); - // min_distance_col_i = search_col_j; - // min_distance_row_i = search_row_j; - // } - // } + if ( distance_j == min_distance_i && min_distance_row_i != -1 && min_distance_col_i != -1 ) + { + int prev_distance_row_2_ref = min_distance_row_i - search_radiou; + int prev_distance_col_2_ref = min_distance_col_i - search_radiou; + int curr_distance_row_2_ref = search_row_j - search_radiou; + int curr_distance_col_2_ref = search_col_j - search_radiou; + + int prev_distance_2_ref_sqr = prev_distance_row_2_ref * prev_distance_row_2_ref + prev_distance_col_2_ref * prev_distance_col_2_ref; + int curr_distance_2_ref_sqr = curr_distance_row_2_ref * curr_distance_row_2_ref + curr_distance_col_2_ref * curr_distance_col_2_ref; + + // previous min distance idx is farther away from ref tile start location + if ( prev_distance_2_ref_sqr > curr_distance_2_ref_sqr ) + { + // printf("@@@ Same distance %d, choose closer one (%d, %d) instead of (%d, %d)\n", \ + // distance_j, search_row_j, search_col_j, min_distance_row_i, min_distance_col_i); + min_distance_col_i = search_col_j; + min_distance_row_i = search_row_j; + } + } } } - //printf("tile at (%d, %d) alignment (%d, %d)\n", \ - ref_tile_row_i, ref_tile_col_i, min_distance_row_i, min_distance_col_i ); + // printf("tile at (%d, %d) alignment (%d, %d)\n", \ + // ref_tile_row_i, ref_tile_col_i, min_distance_row_i, min_distance_col_i ); int alignment_row_i = prev_alignment_row_i + min_distance_row_i - search_radiou; int alignment_col_i = prev_alignment_col_i + min_distance_col_i - search_radiou; @@ -516,38 +619,6 @@ void align_image_level( \ } -static void build_per_pyramid_reftiles_start( \ - std::vector>>>& per_pyramid_reftiles_start, \ - const std::vector>& per_grayimg_pyramid, \ - const std::vector& grayimg_tile_sizes ) -{ - per_pyramid_reftiles_start.resize( per_grayimg_pyramid.at(0).size() ); - - // Every image pyramid level - for ( int level_i = 0; level_i < per_grayimg_pyramid.at(0).size(); level_i++ ) - { - int level_i_img_h = per_grayimg_pyramid.at(0).at( level_i ).size().height; - int level_i_img_w = per_grayimg_pyramid.at(0).at( level_i ).size().width; - - int level_i_tile_size = grayimg_tile_sizes.at( level_i ); - - int num_tiles_h = level_i_img_h / (level_i_tile_size / 2) - 1; - int num_tiles_w = level_i_img_w / (level_i_tile_size / 2) - 1; - - // Allocate memory - per_pyramid_reftiles_start.at( level_i ).resize( num_tiles_h, std::vector>( num_tiles_w ) ); - - for ( int tile_col_i = 0; tile_col_i < num_tiles_h; tile_col_i++ ) - { - for ( int tile_row_j = 0; tile_row_j < num_tiles_w; tile_row_j++ ) - { - per_pyramid_reftiles_start.at( level_i ).at( tile_col_i ).at( tile_row_j ) \ - = std::make_pair( tile_col_i * level_i_tile_size, tile_row_j * level_i_tile_size ); - } - } - } -} - void align::process( const hdrplus::burst& burst_images, \ std::vector>>>& images_alignment ) @@ -571,6 +642,8 @@ void align::process( const hdrplus::burst& burst_images, \ // exit(1); per_grayimg_pyramid.resize( burst_images.num_images ); + + #pragma omp parallel for for ( int img_idx = 0; img_idx < burst_images.num_images; ++img_idx ) { // per_grayimg_pyramid[ img_idx ][ 0 ] is the original image diff --git a/src/burst.cpp b/src/burst.cpp index c6156fe..5aec7b7 100644 --- a/src/burst.cpp +++ b/src/burst.cpp @@ -1,5 +1,6 @@ #include #include +#include #include // all opencv header #include "hdrplus/burst.h" #include "hdrplus/utility.h" @@ -30,7 +31,7 @@ burst::burst( const std::string& burst_path, const std::string& reference_image_ // Find reference image path in input directory // reference image path need to be absolute path reference_image_idx = -1; - for ( int i = 0; i < bayer_image_paths.size(); ++i ) + for ( size_t i = 0; i < bayer_image_paths.size(); ++i ) { if ( bayer_image_paths[ i ] == reference_image_path ) { @@ -85,7 +86,7 @@ burst::burst( const std::string& burst_path, const std::string& reference_image_ // 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", \ diff --git a/src/merge.cpp b/src/merge.cpp index 0c12723..5e0de3b 100644 --- a/src/merge.cpp +++ b/src/merge.cpp @@ -24,7 +24,7 @@ namespace hdrplus // Get raw channels std::vector channels(4); - hdrplus::extract_rgb_fmom_bayer(reference_image, channels[0], channels[2], channels[1], channels[3]); + hdrplus::extract_rgb_from_bayer(reference_image, channels[0], channels[1], channels[2], channels[3]); std::vector processed_channels(4); // For each channel, perform denoising and merge @@ -44,7 +44,7 @@ namespace hdrplus //get alternate image cv::Mat alt_image = burst_images.bayer_images_pad[j]; std::vector alt_channels(4); - hdrplus::extract_rgb_fmom_bayer(alt_image, alt_channels[0], alt_channels[1], alt_channels[2], alt_channels[3]); + hdrplus::extract_rgb_from_bayer(alt_image, alt_channels[0], alt_channels[1], alt_channels[2], alt_channels[3]); alternate_channel_i_list.push_back(alt_channels[i]); } diff --git a/tests/test_align.cpp b/tests/test_align.cpp index 43521b7..cbe95c9 100644 --- a/tests/test_align.cpp +++ b/tests/test_align.cpp @@ -21,6 +21,8 @@ void test_align_one_level(int argc, char** argv) hdrplus::align align_module; align_module.process( burst_images, alignments ); + exit(1); + // Access alternative image tile in each channel // Below code can be use in merging part for ( int img_idx = 0; img_idx < burst_images.num_images; ++img_idx ) @@ -36,14 +38,14 @@ void test_align_one_level(int argc, char** argv) // Create RGB channel std::vector rggb_imgs( 4 ); - hdrplus::extract_rgb_fmom_bayer( bayer_image_pad, rggb_imgs.at(0), rggb_imgs.at(1), rggb_imgs.at(2), rggb_imgs.at(3) ); + hdrplus::extract_rgb_from_bayer( bayer_image_pad, rggb_imgs.at(0), rggb_imgs.at(1), rggb_imgs.at(2), rggb_imgs.at(3) ); // Get tile of each channel with the alignments int tilesize = 16; // tile size of grayscale image int num_tiles_h = rggb_imgs.at(0).size().height / ( tilesize / 2 ) - 1; int num_tiles_w = rggb_imgs.at(0).size().width / ( tilesize / 2 ) - 1; - for ( int img_channel = 0; img_channel < rggb_imgs.size(); ++img_channel ) + for ( int img_channel = 0; img_channel < int(rggb_imgs.size()); ++img_channel ) { for ( int tile_row_i = 0; tile_row_i < num_tiles_h; ++tile_row_i ) { diff --git a/tests/test_utility.cpp b/tests/test_utility.cpp index 163f320..98889cf 100644 --- a/tests/test_utility.cpp +++ b/tests/test_utility.cpp @@ -4,7 +4,6 @@ #include #include "hdrplus/utility.h" - void test_downsample_nearest_neighbour( ) { printf("\n###Test test_box_filter_kxk()###\n"); @@ -91,7 +90,7 @@ void test_extract_rgb_from_bayer() printf("\nbayer cv::Mat is \n"); hdrplus::print_cvmat( bayer_img ); - hdrplus::extract_rgb_fmom_bayer( bayer_img, red_img, green_img1, green_img2, blue_img ); + hdrplus::extract_rgb_from_bayer( bayer_img, red_img, green_img1, green_img2, blue_img ); printf("\nRed cv::Mat is \n"); hdrplus::print_cvmat( red_img );