align dev (tmp save)

main
Xiao Song 3 years ago
parent f3423a4d81
commit 0fcb8e6e63

@ -26,7 +26,12 @@ class align
std::vector<std::vector<std::vector<std::pair<int, int>>>>& aligements );
private:
const std::vector<int> inv_scale_factors = { 1, 2, 2, 4 };
// From original image to coarse image
const std::vector<int> inv_scale_factors = { 1, 2, 4, 4 };
const std::vector<int> distances = { 1, 2, 2, 2 }; // L1 / L2 distance
const std::vector<int> search_radious = { 1, 4, 4, 4 };
const std::vector<int> tile_sizes = { 16, 16, 16, 8 };
const int num_levels = 4;
};
} // namespace hdrplus

@ -5,6 +5,14 @@
#include <opencv2/opencv.hpp> // 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
#endif
namespace hdrplus
{
@ -68,10 +76,10 @@ cv::Mat box_filter_kxk( cv::Mat src_image )
{
T box_sum = T(0);
#pragma GCC unroll kernel
#pragma LOOP_UNROLL
for ( int kernel_row_i = 0; kernel_row_i < kernel; ++kernel_row_i )
{
#pragma GCC unroll kernel
#pragma LOOP_UNROLL
for ( int kernel_col_i = 0; kernel_col_i < kernel; ++kernel_col_i )
{
box_sum += src_image_ptr[ ( row_i + kernel_row_i ) * src_step + ( col_i + kernel_col_i ) ];

@ -51,20 +51,174 @@ static void build_image_pyramid( \
}
}
template< int stride >
static void upsample_alignment_stride( \
std::vector<std::vector<std::pair<int, int>>>& src_alignment, \
std::vector<std::vector<std::pair<int, int>>>& dst_alignment,
int scale_factor )
{
int src_height = src_alignment.size();
int src_width = src_alignment[ 0 ].size();
int dst_height = src_height * stride;
int dst_width = src_width * stride;
// Allocate data for dst_alignment
dst_alignment.resize( dst_height, std::vector<std::pair<int, int>>( dst_width ) );
for ( int row_i = 0; row_i < src_height; row_i++ )
{
for ( int col_i = 0; col_i < src_width; col_i++ )
{
// Scale alignment
std::pair<int, int> align_i = src_alignment[ row_i ][ col_i ];
align_i.first *= scale_factor;
align_i.second *= scale_factor;
// repeat
#pragma LOOP_UNROLL
for ( int stride_row_i = 0; stride_row_i < stride; ++stride_row_i )
{
#pragma LOOP_UNROLL
for ( int stride_col_i = 0; stride_col_i < stride; ++stride_col_i )
{
dst_alignment[ row_i + stride_row_i ][ col_i + stride_col_i ] = align_i;
}
}
}
}
}
static void align_image_level( \
const cv::Mat& ref_img, \
const cv::Mat& alt_img, \
const std::pair<int, int>& num_tiles, \
std::vector<std::vector<std::pair<int, int>>>& prev_aligement, \
std::vector<std::vector<std::pair<int, int>>>& alignment, \
int inv_scale_factor, \
int tile_size, \
int prev_tile_size, \
int search_radiou, \
int distance )
{
// Upsample pervious layer alignment
// Coarsest level
// prev_alignment is invalid / empty, construct alignment as (0,0)
if ( prev_tile_size == -1 )
{
alignment.resize( num_tiles.first, std::vector<std::pair<int, int>>( num_tiles.second, std::pair<int, int>(0, 0) ) );
}
// Upsample previous level alignment
else
{
if ( inv_scale_factor == 2 )
{
upsample_alignment_stride<2>( prev_aligement, alignment, inv_scale_factor );
}
else if ( inv_scale_factor == 4 )
{
upsample_alignment_stride<4>( prev_aligement, alignment, inv_scale_factor );
}
else
{
throw std::runtime_error("Invalid scale factor" + std::to_string( inv_scale_factor ) );
}
}
}
void align::process( const hdrplus::burst& burst_images, \
std::vector<std::vector<std::vector<std::pair<int, int>>>>& aligements )
std::vector<std::vector<std::vector<std::pair<int, int>>>>& images_alignment )
{
// Build image pyramid
// image pyramid per image, per pyramid level
std::vector<std::vector<cv::Mat>> grayscale_images_pyramid;
grayscale_images_pyramid.resize( burst_images.grayscale_images_pad.size() );
for ( int img_idx = 0; img_idx < burst_images.grayscale_images_pad.size(); ++img_idx )
grayscale_images_pyramid.resize( burst_images.num_images );
for ( int img_idx = 0; img_idx < burst_images.num_images; ++img_idx )
{
build_image_pyramid( grayscale_images_pyramid[ img_idx ], \
burst_images.grayscale_images_pad[ img_idx ], \
inv_scale_factors );
}
#ifndef NDEBUG
printf("%s::%s build image pyramid of size : ", __FILE__, __func__ );
for ( int level_i = 0; level_i < num_levels; ++level_i )
{
printf("(%d, %d) ", grayscale_images_pyramid[ 0 ][ level_i ].size().height,
grayscale_images_pyramid[ 0 ][ level_i ].size().width );
}
printf("\n");
#endif
// number of tiles per pyramid level
// this is shared across all image at particular level
// `num_tiles_pyramid[0]` represent number of tiles in level 0 (finest level, original image)
std::vector<std::pair<int, int>> num_tiles_pyramid( num_levels );
for ( int level_i = 0; level_i < num_levels; ++level_i )
{
cv::Size image_size_level_i = grayscale_images_pyramid[ 0 ][ level_i ].size();
int half_tile_size_level_i = tile_sizes[ level_i ] / 2;
num_tiles_pyramid[ level_i ] = std::make_pair<int, int>( \
image_size_level_i.height / half_tile_size_level_i - 1, \
image_size_level_i.width / half_tile_size_level_i - 1 );
}
#ifndef NDEBUG
printf("%s::%s each pyramid tile size : ", __FILE__, __func__ );
for ( int level_i = 0; level_i < num_levels; ++level_i )
{
printf("(%d, %d) ", num_tiles_pyramid[ level_i ].first,
num_tiles_pyramid[ level_i ].second );
}
printf("\n");
#endif
// Align every image
const std::vector<cv::Mat>& ref_imgs_pyramid = grayscale_images_pyramid[ burst_images.reference_image_idx ];
for ( int img_idx = 0; img_idx < burst_images.num_images; ++img_idx )
{
// Do not align with reference image
if ( img_idx == burst_images.reference_image_idx )
continue;
const std::vector<cv::Mat>& alt_imgs_pyramid = grayscale_images_pyramid[ img_idx ];
// Align every level from coarse to grain
// level 0 : finest level, the original image
// level 3 : coarsest level
std::vector<std::pair<int, int>> curr_alignment;
std::vector<std::pair<int, int>> prev_alignment;
for ( int level_i = num_levels - 1; level_i >= 0; level_i-- )
{
align_image_level(
ref_imgs_pyramid[ level_i ], // reference image at current level
alt_imgs_pyramid[ level_i ], // alternative image at current level
num_tiles_pyramid[ level_i ], // number of tiles at this level
prev_alignment, // previous layer alignment
curr_alignment, // current layer alignment
inv_scale_factors[ level_i ], // ?
tile_sizes[ level_i ], // current level tile size
( level_i == ( num_levels - 1 ) ? -1 : tile_sizes[ level_i + 1] ), // previous level tile size
search_radious[ level_i ], // search radious
distances[ level_i ] ); // L1/L2 distance
// make curr alignment as previous alignment
prev_alignment.swap( curr_alignment );
curr_alignment.clear();
} // for pyramid level
} // for alternative image
}

Loading…
Cancel
Save