diff --git a/.gitignore b/.gitignore index f1d1082..8fb7119 100644 --- a/.gitignore +++ b/.gitignore @@ -47,4 +47,5 @@ external/ dataset/ # Unit test -tests/test_bayer_image \ No newline at end of file +tests/test_bayer_image +tests/test_utility \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 2981185..bca5105 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -61,3 +61,9 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/tests ) add_executable( test_bayer_image tests/test_bayer_image.cpp ) target_link_libraries( test_bayer_image ${PROJECT_NAME} ) + +add_executable( test_utility + tests/test_utility.cpp ) +target_link_libraries( test_utility + ${OpenCV_LIBS} + ${PROJECT_NAME} ) diff --git a/include/hdrplus/bayer_image.h b/include/hdrplus/bayer_image.h index adfff93..c3342ed 100644 --- a/include/hdrplus/bayer_image.h +++ b/include/hdrplus/bayer_image.h @@ -14,9 +14,11 @@ class bayer_image ~bayer_image(); LibRaw libraw_processor; - cv::Mat image; + cv::Mat raw_image; + cv::Mat grayscale_image; size_t width; size_t height; + size_t white_level; }; } // namespace hdrplus diff --git a/include/hdrplus/utility.h b/include/hdrplus/utility.h new file mode 100644 index 0000000..1e5244f --- /dev/null +++ b/include/hdrplus/utility.h @@ -0,0 +1,49 @@ +#pragma once + +#include +#include // std::runtime_error +#include // all opencv header +// TODO: add openmp support + +namespace hdrplus +{ + +template +cv::Mat box_filter_2x2( cv::Mat src_image ) +{ + // https://stackoverflow.com/questions/34042112/opencv-mat-data-member-access + 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 % 2 != 0 || src_width % 2 != 0 ) + { + throw std::runtime_error( std::string( __FILE__ ) + "::" + __func__ + " source image need to have size multiplier of 2\n" ); + } + + cv::Mat dst_image( src_height / 2, src_width / 2, 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 += 2 ) + { + for ( int col_i = 0; col_i < src_width; col_i += 2 ) + { + T box_sum = src_image_ptr[ ( row_i + 0 ) * src_step + col_i + 0 ] + \ + src_image_ptr[ ( row_i + 0 ) * src_step + col_i + 1 ] + \ + src_image_ptr[ ( row_i + 1 ) * src_step + col_i + 0 ] + \ + src_image_ptr[ ( row_i + 1 ) * src_step + col_i + 1 ]; + T box_avg = ( box_sum + T(3) ) / 4; // take ceiling + dst_image_ptr[ ( row_i / 2 ) * dst_step + ( col_i / 2 ) ] = box_avg; + } + } + + // cv::Mat internally use reference count. Will not copy by value here + return dst_image; +} + +} // namespace hdrplus diff --git a/src/bayer_image.cpp b/src/bayer_image.cpp index 5bae59a..42af44d 100644 --- a/src/bayer_image.cpp +++ b/src/bayer_image.cpp @@ -1,8 +1,10 @@ #include +#include +#include // std::runtime_error #include // all opencv header #include #include "hdrplus/bayer_image.h" - +#include "hdrplus/utility.h" // box_filter_2x2 namespace hdrplus { @@ -25,10 +27,20 @@ bayer_image::bayer_image( const std::string& bayer_image_path ) // Get image basic info width = size_t( libraw_processor.imgdata.rawdata.sizes.raw_width ); height = size_t( libraw_processor.imgdata.rawdata.sizes.raw_height ); + white_level = size_t( libraw_processor.imgdata.rawdata.color.maximum ); + + #ifndef NDEBUG + printf("%s::%s read bayer image %d with width %zu height %zu", \ + __FILE__, __func__, bayer_image_path.c_str(), width, height ); + #endif // Create CV mat // https://answers.opencv.org/question/105972/de-bayering-a-cr2-image/ - image = cv::Mat( width, height, CV_16U, libraw_processor.imgdata.rawdata.raw_image ); + // https://www.libraw.org/node/2141 + raw_image = cv::Mat( width, height, CV_16U, libraw_processor.imgdata.rawdata.raw_image ); + + // 2x2 box filter + grayscale_image = box_filter_2x2( raw_image ); } bayer_image::~bayer_image() diff --git a/tests/test_utility.cpp b/tests/test_utility.cpp new file mode 100644 index 0000000..64182c8 --- /dev/null +++ b/tests/test_utility.cpp @@ -0,0 +1,49 @@ +#include +#include +#include +#include "hdrplus/utility.h" + +template< typename T > +void print_cvmat( cv::Mat image ) +{ + int height = image.size().height; + int width = image.size().width; + + for ( int row_i = 0; row_i < height; ++row_i ) + { + for ( int col_i = 0; col_i < width; ++col_i ) + { + printf("%2.d ", int( image.at( row_i, col_i ) ) ); + } + printf("\n"); + } +} + +void test_box_filter_2x2() +{ + // Intialize input data + int src_width = 10; + int src_height = 6; + std::vector src_data( src_width, src_height ); + + for ( int i = 0; i < src_width * src_height; ++i ) + { + src_data[ i ] = i+1; + } + + // Create input cv::mat + cv::Mat src_image( src_height, src_width, CV_16U, src_data.data() ); + + printf("src cv::Mat is \n"); + print_cvmat( src_image ); + + cv::Mat dst_image = hdrplus::box_filter_2x2( src_image ); + + printf("dst cv::Mat is \n"); + print_cvmat( dst_image ); +} + +int main() +{ + test_box_filter_2x2(); +} \ No newline at end of file