diff --git a/include/boost/gil/extension/toolbox/color_spaces/ycbcr.hpp b/include/boost/gil/extension/toolbox/color_spaces/ycbcr.hpp index 41b927785..99dd7630a 100644 --- a/include/boost/gil/extension/toolbox/color_spaces/ycbcr.hpp +++ b/include/boost/gil/extension/toolbox/color_spaces/ycbcr.hpp @@ -25,6 +25,8 @@ #include #include +#include + namespace boost{ namespace gil { /// \addtogroup ColorNameModel @@ -41,13 +43,13 @@ struct cr_t {}; /// \} /// \ingroup ColorSpaceModel -typedef boost::mpl::vector3 ycbcr_t; +typedef boost::mpl::vector3 ycbcr_601__t; /// \ingroup LayoutModel -typedef boost::gil::layout ycbcr_layout_t; +typedef boost::gil::layout ycbcr_601__layout_t; //The channel depth is ALWAYS 8bits ofr YCbCr! -GIL_DEFINE_ALL_TYPEDEFS(8, ycbcr) +GIL_DEFINE_ALL_TYPEDEFS(8, ycbcr_601_) /* * Source: http://en.wikipedia.org/wiki/YCbCr#ITU-R_BT.601_conversion @@ -58,12 +60,61 @@ GIL_DEFINE_ALL_TYPEDEFS(8, ycbcr) * @brief Convert YCbCr ITU.BT-601 to RGB. */ template<> -struct default_color_converter_impl +struct default_color_converter_impl { // Note: the RGB_t channels range can be set later on by the users. We dont want to cast to bits8 or anything here. template < typename SRCP, typename DSTP > void operator()( const SRCP& src, DSTP& dst ) const { + typedef channel_type< DSTP >::type dst_channel_t; + convert( src, dst + , boost::is_same< mpl::int_<8>::type, mpl::int_<8>::type >::type() + ); + } + +private: + + // optimization for bit8 channels + template< typename Src_Pixel + , typename Dst_Pixel + > + void convert( const Src_Pixel& src + , Dst_Pixel& dst + , mpl::true_ // is 8 bit channel + ) const + { + using namespace boost::algorithm; + using namespace boost::gil::ycbcr_color_space; + + typedef channel_type< Src_Pixel >::type src_channel_t; + typedef channel_type< Dst_Pixel >::type dst_channel_t; + + src_channel_t y = channel_convert( get_color(src, y_t())); + src_channel_t cb = channel_convert( get_color(src, cb_t())); + src_channel_t cr = channel_convert( get_color(src, cr_t())); + + // The intermediate results of the formulas require at least 16bits of precission. + boost::int_fast16_t c = y - 16; + boost::int_fast16_t d = cb - 128; + boost::int_fast16_t e = cr - 128; + boost::int_fast16_t red = clamp((( 298 * c + 409 * e + 128) >> 8), 0, 255); + boost::int_fast16_t green = clamp((( 298 * c - 100 * d - 208 * e + 128) >> 8), 0, 255); + boost::int_fast16_t blue = clamp((( 298 * c + 516 * d + 128) >> 8), 0, 255); + + get_color( dst, red_t() ) = (dst_channel_t) red; + get_color( dst, green_t() ) = (dst_channel_t) green; + get_color( dst, blue_t() ) = (dst_channel_t) blue; + } + + + template< typename Src_Pixel + , typename Dst_Pixel + > + void convert( const Src_Pixel& s + , Dst_Pixel& d + , mpl::false_ // is 8 bit channel + ) const + { using namespace boost::algorithm; using namespace boost::gil::ycbcr_color_space; @@ -87,7 +138,7 @@ struct default_color_converter_impl , 0.0 , 255.0 ); - } + } }; /* @@ -99,7 +150,7 @@ struct default_color_converter_impl * @brief Convert RGB to YCbCr ITU.BT-601. */ template<> -struct default_color_converter_impl +struct default_color_converter_impl { template < typename SRCP, typename DSTP > void operator()( const SRCP& src, DSTP& dst ) const @@ -120,12 +171,11 @@ struct default_color_converter_impl get_color( dst, y_t() ) = (dst_channel_t) y; get_color( dst, cb_t() ) = (dst_channel_t) cb; - get_color( dst, cr_t() ) = (dst_channel_t) cr; + get_color( dst, cr_t() ) = (dst_channel_t) cr; } }; } // namespace gil - } // namespace boost #endif diff --git a/include/boost/gil/extension/toolbox/image_types/subsampled_image.hpp b/include/boost/gil/extension/toolbox/image_types/subsampled_image.hpp index 79a54c279..29a19a2b7 100644 --- a/include/boost/gil/extension/toolbox/image_types/subsampled_image.hpp +++ b/include/boost/gil/extension/toolbox/image_types/subsampled_image.hpp @@ -69,13 +69,13 @@ struct subsampled_image_deref_fn /// operator() typename result_type operator()( const point_t& p ) const { - auto y = *_y_locator.xy_at( p ); - auto v = *_v_locator.xy_at( p.x / _ux_ssfactor, p.y / _uy_ssfactor ); - auto u = *_u_locator.xy_at( p.x / _vx_ssfactor, p.y / _vy_ssfactor ); + plane_locator_t y = _y_locator.xy_at( p ); + plane_locator_t v = _v_locator.xy_at( p.x / _ux_ssfactor, p.y / _uy_ssfactor ); + plane_locator_t u = _u_locator.xy_at( p.x / _vx_ssfactor, p.y / _vy_ssfactor ); - return value_type( at_c<0>( y ) - , at_c<0>( v ) - , at_c<0>( u ) + return value_type( at_c<0>( *y ) + , at_c<0>( *v ) + , at_c<0>( *u ) ); } @@ -212,7 +212,9 @@ public: typedef typename plane_view_t::locator plane_locator_t; typedef typename view_type_from_pixel< Pixel >::type pixel_view_t; - typedef typename subsampled_image_locator< typename pixel_view_t::locator >::type locator_t; + typedef typename pixel_view_t::locator pixel_locator_t; + + typedef typename subsampled_image_locator< pixel_locator_t >::type locator_t; typedef typename plane_image_t::coord_t x_coord_t; typedef typename plane_image_t::coord_t y_coord_t; @@ -254,7 +256,7 @@ private: , const std::size_t uy_ssfactor ) { - typedef subsampled_image_deref_fn< locator_t > defer_fn_t; + typedef subsampled_image_deref_fn< pixel_locator_t > defer_fn_t; defer_fn_t deref_fn( view( _y_plane ).xy_at( 0, 0 ) , view( _v_plane ).xy_at( 0, 0 ) @@ -328,67 +330,66 @@ void fill_pixels( const subsampled_image_view< Locator >& view /// \ingroup ImageViewConstructors /// \brief Creates a subsampled view from a raw memory ///////////////////////////////////////////////////////////////////////////////////////// -//template< typename Pixel > -//typename subsampled_image< Pixel >::view_t subsampled_view( std::size_t y_width -// , std::size_t y_height -// , unsigned char* y_base -// , std::size_t vx_ssfactor = 2 -// , std::size_t vy_ssfactor = 2 -// , std::size_t ux_ssfactor = 2 -// , std::size_t uy_ssfactor = 2 -// ) -//{ -// std::size_t y_channel_size = 1; -// std::size_t u_channel_size = 1; -// -// unsigned char* u_base = y_base + ( y_width * y_height * y_channel_size ); -// unsigned char* v_base = u_base + ( y_width / ux_ssfactor ) * ( y_height / uy_ssfactor ) * u_channel_size; -// -// typedef subsampled_image< Pixel >::plane_view_t plane_view_t; -// -// plane_view_t y_plane = interleaved_view( y_width -// , y_height -// , (plane_view_t::value_type*) y_base // pixels -// , y_width // rowsize_in_bytes -// ); -// -// plane_view_t v_plane = interleaved_view( y_width / vx_ssfactor -// , y_height / vy_ssfactor -// , (plane_view_t::value_type*) v_base // pixels -// , y_width // rowsize_in_bytes -// ); -// -// plane_view_t u_plane = interleaved_view( y_width / ux_ssfactor -// , y_height / uy_ssfactor -// , (plane_view_t::value_type*) u_base // pixels -// , y_width // rowsize_in_bytes -// ); -// -// typedef subsampled_image_deref_fn< subsampled_image< Pixel >::locator_t > defer_fn_t; -// defer_fn_t deref_fn( y_plane.xy_at( 0, 0 ) -// , v_plane.xy_at( 0, 0 ) -// , u_plane.xy_at( 0, 0 ) -// , vx_ssfactor -// , vy_ssfactor -// , ux_ssfactor -// , uy_ssfactor -// ); -// -// -// typedef subsampled_image< Pixel >::locator_t locator_t; -// locator_t locator( point_t( 0, 0 ) // p -// , point_t( 1, 1 ) // step -// , deref_fn -// ); -// -// typedef subsampled_image< Pixel >::view_t view_t; -// return view_t( point_t( y_width, y_height ) -// , point_t( y_width / vx_ssfactor, y_height / vy_ssfactor ) -// , point_t( y_width / ux_ssfactor, y_height / uy_ssfactor ) -// , locator -// ); -//} +template< typename Pixel > +typename subsampled_image< Pixel >::view_t subsampled_view( std::size_t y_width + , std::size_t y_height + , unsigned char* y_base + , std::size_t vx_ssfactor = 2 + , std::size_t vy_ssfactor = 2 + , std::size_t ux_ssfactor = 2 + , std::size_t uy_ssfactor = 2 + ) +{ + std::size_t y_channel_size = 1; + std::size_t u_channel_size = 1; + unsigned char* u_base = y_base + ( y_width * y_height * y_channel_size ); + unsigned char* v_base = u_base + ( y_width / ux_ssfactor ) * ( y_height / uy_ssfactor ) * u_channel_size; + + typedef subsampled_image< Pixel >::plane_view_t plane_view_t; + + plane_view_t y_plane = interleaved_view( y_width + , y_height + , (plane_view_t::value_type*) y_base // pixels + , y_width // rowsize_in_bytes + ); + + plane_view_t v_plane = interleaved_view( y_width / vx_ssfactor + , y_height / vy_ssfactor + , (plane_view_t::value_type*) v_base // pixels + , y_width // rowsize_in_bytes + ); + + plane_view_t u_plane = interleaved_view( y_width / ux_ssfactor + , y_height / uy_ssfactor + , (plane_view_t::value_type*) u_base // pixels + , y_width // rowsize_in_bytes + ); + + typedef subsampled_image_deref_fn< typename subsampled_image< Pixel >::pixel_locator_t > defer_fn_t; + defer_fn_t deref_fn( y_plane.xy_at( 0, 0 ) + , v_plane.xy_at( 0, 0 ) + , u_plane.xy_at( 0, 0 ) + , vx_ssfactor + , vy_ssfactor + , ux_ssfactor + , uy_ssfactor + ); + + + typedef subsampled_image< Pixel >::locator_t locator_t; + locator_t locator( point_t( 0, 0 ) // p + , point_t( 1, 1 ) // step + , deref_fn + ); + + typedef subsampled_image< Pixel >::view_t view_t; + return view_t( point_t( y_width, y_height ) + , point_t( y_width / vx_ssfactor, y_height / vy_ssfactor ) + , point_t( y_width / ux_ssfactor, y_height / uy_ssfactor ) + , locator + ); +} } // namespace gil } // namespace boost