Back to Discrete Haar transform
#ifndef PASTELGFX_HAAR_TRANSFORM_HPP
#define PASTELGFX_HAAR_TRANSFORM_HPP
#include "pastel/gfx/transform/haar_transform.h"
#include "pastel/sys/ensure.h"
#include <vector>
namespace Pastel
{
namespace Haar_
{
template <
bool Orthogonal,
typename Real_ConstRange,
typename Real_Range>
void haar(
const Real_ConstRange& inputRange,
const Real_Range& outputRange)
{
typedef typename boost::range_value<Real_ConstRange>::type
Real;
integer n = inputRange.size();
ENSURE1(isPowerOfTwo(n), n);
std::vector<Real> a(inputRange.begin(), inputRange.end());
std::vector<Real> b(n);
Real InvSqrt2 =
inverse(std::sqrt((Real)2));
integer k = n;
while(k > 1)
{
// This algorithm works from the fine-grained
// wavelets towards the coarse-grained ones.
k >>= 1;
for (integer i = 0;i < k;++i)
{
b[i] = a[i << 1] + a[(i << 1) + 1];
b[k + i] = a[i << 1] - a[(i << 1) + 1];
if (Orthogonal)
{
// These multiplies make the transform
// orthogonal.
b[i] *= InvSqrt2;
b[k + i] *= InvSqrt2;
}
}
std::copy(
b.begin(), b.begin() + (k << 1),
a.begin());
}
std::copy(a.begin(), a.end(), outputRange.begin());
}
template <
bool Orthogonal,
typename Real_ConstRange,
typename Real_Range>
void inverseHaar(
const Real_ConstRange& inputRange,
const Real_Range& outputRange)
{
typedef typename boost::range_value<Real_ConstRange>::type
Real;
integer n = inputRange.size();
std::vector<Real> a(inputRange.begin(), inputRange.end());
std::vector<Real> b(n);
ENSURE1(isPowerOfTwo(n), n);
Real normalization =
Orthogonal ?
inverse(std::sqrt((Real)2)) : inverse((Real)2);
integer k = 1;
while(k < n)
{
for (integer i = 0;i < k;++i)
{
b[i << 1] = (a[i] + a[k + i]) * normalization;
b[(i << 1) + 1] = (a[i] - a[k + i]) * normalization;
}
std::copy(
b.begin(), b.begin() + (k << 1),
a.begin());
k <<= 1;
}
std::copy(a.begin(), a.end(), outputRange.begin());
}
}
template <
typename Real_ConstRange,
typename Real_Range>
void haar(
const Real_ConstRange& input,
const Real_Range& output)
{
Haar_::haar<false>(input, output);
}
template <typename Real_Range>
void haar(
const Real_Range& inputOutput)
{
Pastel::haar(inputOutput, inputOutput);
}
template <
typename Real_ConstRange,
typename Real_Range>
void inverseHaar(
const Real_ConstRange& input,
const Real_Range& output)
{
Haar_::inverseHaar<false>(input, output);
}
template <typename Real_Range>
void inverseHaar(
const Real_Range& inputOutput)
{
Pastel::inverseHaar(inputOutput, inputOutput);
}
template <
typename Real_ConstRange,
typename Real_Range>
void orthogonalHaar(
const Real_ConstRange& input,
const Real_Range& output)
{
Haar_::haar<true>(input, output);
}
template <typename Real_Range>
void orthogonalHaar(
const Real_Range& inputOutput)
{
Pastel::orthogonalHaar(
inputOutput, inputOutput);
}
template <
typename Real_ConstRange,
typename Real_Range>
void inverseOrthogonalHaar(
const Real_ConstRange& input,
const Real_Range& output)
{
Haar_::inverseHaar<true>(input, output);
}
template <typename Real_Range>
void inverseOrthogonalHaar(
const Real_Range& inputOutput)
{
Pastel::inverseOrthogonalHaar(
inputOutput, inputOutput);
}
}
#endif