template<typename Scalar,bool ConjLhs,bool ConjRhs> void test_conj_helper(Scalar* data1, Scalar* data2, Scalar* ref, Scalar* pval)
{
  typedef typename internal::packet_traits<Scalar>::type Packet;
  const int PacketSize = internal::packet_traits<Scalar>::size;
  
  internal::conj_if<ConjLhs> cj0;
  internal::conj_if<ConjRhs> cj1;
  internal::conj_helper<Scalar,Scalar,ConjLhs,ConjRhs> cj;
  internal::conj_helper<Packet,Packet,ConjLhs,ConjRhs> pcj;
  
  for(int i=0;i<PacketSize;++i)
  {
    ref[i] = cj0(data1[i]) * cj1(data2[i]);
    VERIFY(internal::isApprox(ref[i], cj.pmul(data1[i],data2[i])) && "conj_helper pmul");
  }
  internal::pstore(pval,pcj.pmul(internal::pload<Packet>(data1),internal::pload<Packet>(data2)));
  VERIFY(areApprox(ref, pval, PacketSize) && "conj_helper pmul");
  
  for(int i=0;i<PacketSize;++i)
  {
    Scalar tmp = ref[i];
    ref[i] += cj0(data1[i]) * cj1(data2[i]);
    VERIFY(internal::isApprox(ref[i], cj.pmadd(data1[i],data2[i],tmp)) && "conj_helper pmadd");
  }
  internal::pstore(pval,pcj.pmadd(internal::pload<Packet>(data1),internal::pload<Packet>(data2),internal::pload<Packet>(pval)));
  VERIFY(areApprox(ref, pval, PacketSize) && "conj_helper pmadd");
}
   template <class P> static
   void Apply( const GenericImage<P>& image, MultiscaleMedianTransform& T )
   {
      InitializeStructures();

      bool statusInitialized = false;
      StatusMonitor& status = (StatusMonitor&)image.Status();
      try
      {
         if ( status.IsInitializationEnabled() )
         {
            status.Initialize( String( T.m_medianWaveletTransform ? "Median-wavelet" : "Multiscale median" ) + " transform",
                               image.NumberOfSelectedSamples()*T.m_numberOfLayers*(T.m_medianWaveletTransform ? 2 : 1) );
            status.DisableInitialization();
            statusInitialized = true;
         }

         GenericImage<P> cj0( image );
         cj0.Status().Clear();

         for ( int j = 1, j0 = 0; ; ++j, ++j0 )
         {
            GenericImage<P> cj( cj0 );
            cj.Status() = status;

            MedianFilterLayer( cj, T.FilterSize( j0 ), T.m_parallel, T.m_maxProcessors );

            if ( T.m_medianWaveletTransform )
            {
               GenericImage<P> w0( cj0 );
               GenericImage<P> d0( cj0 );
               d0 -= cj;
               for ( int c = 0; c < d0.NumberOfChannels(); ++c )
               {
                  w0.SelectChannel( c );
                  d0.SelectChannel( c );
                  cj.SelectChannel( c );
                  double t = T.m_medianWaveletThreshold*d0.MAD( d0.Median() )/0.6745;
                  for ( typename GenericImage<P>::sample_iterator iw( w0 ), id( d0 ), ic( cj ); iw; ++iw, ++id, ++ic )
                     if ( Abs( *id ) > t )
                        *iw = *ic;
               }
               w0.ResetSelections();
               cj.ResetSelections();
               w0.Status() = cj.Status();
               LinearFilterLayer( w0, T.FilterSize( j0 ), T.m_parallel, T.m_maxProcessors );
               cj = w0;
            }

            status = cj.Status();
            cj.Status().Clear();

            if ( T.m_layerEnabled[j0] )
            {
               cj0 -= cj;
               T.m_transform[j0] = Image( cj0 );
            }

            if ( j == T.m_numberOfLayers )
            {
               if ( T.m_layerEnabled[j] )
                  T.m_transform[j] = Image( cj );
               break;
            }

            cj0 = cj;
         }

         if ( statusInitialized )
            status.EnableInitialization();
      }
      catch ( ... )
      {
         T.DestroyLayers();
         if ( statusInitialized )
            status.EnableInitialization();
         throw;
      }
   }