Skip to content
Browse files

image: Fix output types for imag, real, abs ImageView operations

They were not preserving PixelMath types. Meaning, previously the code
would convert abs(ImageView<PixelGray<float> >) to
ImageView<float>. This should not be the case anymore since for
CompoundTypes it will refer to the PixelMath variants of imag, real,
abs.
  • Loading branch information...
1 parent 7fd42b8 commit 455b5c60848b68ae7536de2e3f34745d3055d1ab Zack Moratto committed Jul 17, 2012
Showing with 91 additions and 4 deletions.
  1. +37 −3 src/vw/Image/ImageMath.h
  2. +13 −1 src/vw/Image/tests/TestImageMath.cxx
  3. +41 −0 src/vw/Image/tests/TestMaskedPixelMath2.cxx
View
40 src/vw/Image/ImageMath.h
@@ -77,6 +77,40 @@ namespace vw {
return UnaryPerPixelView<ImageT,ftor>( image.impl() ); \
}
+ // Used to get the pixel math operation result .. not necessarily
+ // the math functor solution. This is useful for examples like
+ // taking the abs() of a PixelGray and still getting back a
+ // PixelGray .. instead of having PixelGray cast to a float and then
+ // absoluted by the math functor.
+#define VW_IMAGE_MATH_UNARY_PIXELMATH_FUNCTION(func, ftor) \
+ namespace detail { \
+ struct Functorized##func { \
+ template <class Args> struct result; \
+ template <class FuncT, class ValT> \
+ struct result<FuncT(ValT)> { \
+ typedef typename CompoundResult<FuncT, ValT>::type type; \
+ }; \
+ template <class ValT> \
+ struct result<Functorized##func(ValT)> { \
+ typedef typename boost::mpl::if_c<IsCompound<ValT>::value, typename CompoundResult<ftor,ValT>::type, typename boost::result_of<ftor(ValT)>::type >::type type; \
+ }; \
+ template <class ValT> \
+ typename boost::enable_if< IsCompound< ValT >, typename result<Functorized##func(ValT)>::type>::type \
+ inline operator()( ValT val ) const { \
+ return vw::func( val ); \
+ } \
+ template <class ValT> \
+ typename boost::disable_if< IsCompound< ValT >, typename result<Functorized##func(ValT)>::type>::type \
+ inline operator()( ValT val ) const { \
+ return ftor()( val ); \
+ } \
+ }; \
+ } \
+ template <class ImageT> \
+ inline UnaryPerPixelView<ImageT, detail::Functorized##func> func( ImageViewBase<ImageT> const& image ) { \
+ return UnaryPerPixelView<ImageT, detail::Functorized##func>( image.impl() ); \
+ }
+
#define VW_IMAGE_MATH_BINARY_II_FUNCTION(func,ftor) \
template <class Image1T, class Image2T> \
BinaryPerPixelView<Image1T,Image2T,ftor> \
@@ -397,18 +431,18 @@ namespace vw {
/// image is complex then the resulting image has the corresponding
/// real pixel type. If the source image is real then this function
/// effectively performs no operation.
- VW_IMAGE_MATH_UNARY_FUNCTION(real, vw::math::ArgRealFunctor)
+ VW_IMAGE_MATH_UNARY_PIXELMATH_FUNCTION(real, vw::math::ArgRealFunctor)
/// Takes the complex part of each pixel in an image. If the source
/// image is complex then the resulting image has the corresponding
/// real pixel type. If the source image is real then this function
/// effectively returns an image of zeros.
- VW_IMAGE_MATH_UNARY_FUNCTION(imag, vw::math::ArgImagFunctor)
+ VW_IMAGE_MATH_UNARY_PIXELMATH_FUNCTION(imag, vw::math::ArgImagFunctor)
/// Computes the absolute value of each pixel in an image.
/// If the source image is complex then the resulting image has the
/// corresponding real pixel type.
- VW_IMAGE_MATH_UNARY_FUNCTION(abs, vw::math::ArgAbsFunctor)
+ VW_IMAGE_MATH_UNARY_PIXELMATH_FUNCTION(abs, vw::math::ArgAbsFunctor)
/// Computes the complex conjugate of each pixel in an image.
/// If the source image is real then this function effectively performs
View
14 src/vw/Image/tests/TestImageMath.cxx
@@ -197,7 +197,13 @@ TEST_F( BinaryMaskedDoubleMath, Quotient ) {
ASSERT_TRUE( has_pixel_type<float>( op(ImageView<std::complex<float> >()) ) ); \
ASSERT_TRUE( has_pixel_type<double>( op(ImageView<std::complex<double> >()) ) ); \
ASSERT_TRUE( has_pixel_type<long double>( op(ImageView<std::complex<long double> >()) ) ); \
- ASSERT_TRUE( has_pixel_type<int>( op(ImageView<std::complex<int> >()) ) );
+ ASSERT_TRUE( has_pixel_type<int>( op(ImageView<std::complex<int> >()) ) ); \
+ ASSERT_TRUE( has_pixel_type<PixelGray<float> >( op(ImageView<PixelGray<float> >()) ) ); \
+ ASSERT_TRUE( has_pixel_type<PixelGray<int> >( op(ImageView<PixelGray<int> >()) ) ); \
+ ASSERT_TRUE( has_pixel_type<PixelGray<float> >( op(ImageView<PixelGray<std::complex<float> > >()) ) ); \
+ ASSERT_TRUE( has_pixel_type<PixelRGB<float> >( op(ImageView<PixelRGB<float> >()) ) ); \
+ ASSERT_TRUE( has_pixel_type<PixelRGB<int> >( op(ImageView<PixelRGB<int> >()) ) ); \
+ ASSERT_TRUE( has_pixel_type<PixelRGB<float> >( op(ImageView<PixelRGB<std::complex<float> > >()) ) ); \
TEST( ImageMath, Real ) {
ImageView<std::complex<double> > im(1,1); im(0,0)=std::complex<double>(1.0,2.0);
@@ -234,6 +240,8 @@ TEST( ImageMath, Conj ) {
EXPECT_EQ( conj(im).planes(), im.planes() );
EXPECT_EQ( conj(im)(0,0).real(), 1.0 );
EXPECT_EQ( conj(im)(0,0).imag(), -2.0 );
+
+
ASSERT_TRUE( has_pixel_type<float>( conj(ImageView<float>()) ) );
ASSERT_TRUE( has_pixel_type<double>( conj(ImageView<double>()) ) );
ASSERT_TRUE( has_pixel_type<long double>( conj(ImageView<long double>()) ) );
@@ -255,6 +263,10 @@ TEST( ImageMath, Square ) {
ASSERT_TRUE( has_pixel_type<float>( square(ImageView<float>()) ) );
ASSERT_TRUE( has_pixel_type<double>( square(ImageView<double>()) ) );
ASSERT_TRUE( has_pixel_type<int32>( square(ImageView<int32>()) ) );
+ ASSERT_TRUE( has_pixel_type<PixelGray<float> >( square(ImageView<PixelGray<float> >()) ) );
+ ASSERT_TRUE( has_pixel_type<PixelRGB<float> >( square(ImageView<PixelRGB<float> >()) ) );
+ ASSERT_TRUE( has_pixel_type<PixelGray<int32> >( square(ImageView<PixelGray<int32> >()) ) );
+ ASSERT_TRUE( has_pixel_type<PixelRGB<int32> >( square(ImageView<PixelRGB<int32> >()) ) );
}
TEST( ImageMath, MaskMath ) {
View
41 src/vw/Image/tests/TestMaskedPixelMath2.cxx
@@ -316,6 +316,47 @@ TYPED_TEST( MaskedPixelMath, Quotient ) {
EXPECT_VW_EQ( construct<Px>(50), F.child() );
}
+TYPED_TEST( MaskedPixelMath, Abs ) {
+ assignment( this->Ai, 2 );
+ assignment( this->Av, 2 );
+ assignment( this->Bi, 100 );
+ assignment( this->Bv, 100 );
+ this->Av.validate();
+ this->Bv.validate();
+
+ EXPECT_TRUE( is_valid( this->Av ) );
+ EXPECT_FALSE( is_valid( this->Ai ) );
+ EXPECT_TRUE( is_valid( this->Bv ) );
+ EXPECT_FALSE( is_valid( this->Bi ) );
+
+ // Test traits
+ typedef typename TestFixture::MPx MPx;
+ typedef typename TestFixture::Px Px;
+ typedef typename TestFixture::ChT ChT;
+ ASSERT_TRUE( bool_trait<IsMasked>( this->Av ) );
+ ASSERT_TRUE( bool_trait<IsMasked>( this->Ai ) );
+ ASSERT_FALSE( bool_trait<IsMasked>( Px() ) );
+ ASSERT_FALSE( bool_trait<IsMasked>( ChT() ) );
+ ASSERT_TRUE( bool_trait<IsMasked>( MPx() ) );
+
+ MPx F = abs(this->Av);
+ EXPECT_TRUE( bool_trait<IsMasked>( abs(this->Av) ) );
+ EXPECT_TRUE( is_valid(F) );
+ EXPECT_VW_EQ( construct<Px>(2), F.child() );
+ F = abs(this->Ai);
+ EXPECT_TRUE( bool_trait<IsMasked>( abs(this->Ai) ) );
+ EXPECT_FALSE( is_valid(F) );
+ EXPECT_VW_EQ( construct<Px>(2), F.child() );
+ F = abs(this->Bv);
+ EXPECT_TRUE( bool_trait<IsMasked>( abs(this->Bv) ) );
+ EXPECT_TRUE( is_valid(F) );
+ EXPECT_VW_EQ( construct<Px>(100), F.child() );
+ F = abs(this->Bi);
+ EXPECT_TRUE( bool_trait<IsMasked>( abs(this->Bi) ) );
+ EXPECT_FALSE( is_valid(F) );
+ EXPECT_VW_EQ( construct<Px>(100), F.child() );
+}
+
TEST( MaskedPixelMath, PixelMaskInterpolation ) {
typedef PixelMask<PixelGray<float> > px_type;
ImageView<px_type > test(2,2);

0 comments on commit 455b5c6

Please sign in to comment.
Something went wrong with that request. Please try again.