Skip to content

Commit

Permalink
image: Fix output types for imag, real, abs ImageView operations
Browse files Browse the repository at this point in the history
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
Zack Moratto committed Jul 22, 2012
1 parent 7fd42b8 commit 455b5c6
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 4 deletions.
40 changes: 37 additions & 3 deletions src/vw/Image/ImageMath.h
Expand Up @@ -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> \
Expand Down Expand Up @@ -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
Expand Down
14 changes: 13 additions & 1 deletion src/vw/Image/tests/TestImageMath.cxx
Expand Up @@ -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);
Expand Down Expand Up @@ -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>()) ) );
Expand All @@ -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 ) {
Expand Down
41 changes: 41 additions & 0 deletions src/vw/Image/tests/TestMaskedPixelMath2.cxx
Expand Up @@ -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);
Expand Down

0 comments on commit 455b5c6

Please sign in to comment.