2698 lines
93 KiB
C++
2698 lines
93 KiB
C++
//============================================================================
|
|
// Copyright (c) Kitware, Inc.
|
|
// All rights reserved.
|
|
// See LICENSE.txt for details.
|
|
//
|
|
// This software is distributed WITHOUT ANY WARRANTY; without even
|
|
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
// PURPOSE. See the above copyright notice for more information.
|
|
//============================================================================
|
|
|
|
#ifndef vtk_m_worklet_wavelets_waveletdwt_h
|
|
#define vtk_m_worklet_wavelets_waveletdwt_h
|
|
|
|
#include <vtkm/worklet/wavelets/WaveletBase.h>
|
|
|
|
#include <vtkm/worklet/wavelets/WaveletTransforms.h>
|
|
|
|
#include <vtkm/cont/ArrayHandleConcatenate.h>
|
|
#include <vtkm/cont/ArrayHandleCounting.h>
|
|
#include <vtkm/cont/ArrayHandlePermutation.h>
|
|
|
|
#include <vtkm/Math.h>
|
|
#include <vtkm/cont/Timer.h>
|
|
|
|
namespace vtkm
|
|
{
|
|
namespace worklet
|
|
{
|
|
namespace wavelets
|
|
{
|
|
|
|
class WaveletDWT : public WaveletBase
|
|
{
|
|
public:
|
|
// Constructor
|
|
WaveletDWT(WaveletName name)
|
|
: WaveletBase(name)
|
|
{
|
|
}
|
|
|
|
// Function: extend a cube in X direction
|
|
template <typename SigInArrayType, typename ExtensionArrayType>
|
|
vtkm::Id Extend3DLeftRight(const SigInArrayType& sigIn, // input
|
|
vtkm::Id sigDimX,
|
|
vtkm::Id sigDimY,
|
|
vtkm::Id sigDimZ,
|
|
vtkm::Id sigStartX,
|
|
vtkm::Id sigStartY,
|
|
vtkm::Id sigStartZ,
|
|
vtkm::Id sigPretendDimX,
|
|
vtkm::Id sigPretendDimY,
|
|
vtkm::Id sigPretendDimZ,
|
|
ExtensionArrayType& ext1, // output
|
|
ExtensionArrayType& ext2, // output
|
|
vtkm::Id addLen,
|
|
vtkm::worklet::wavelets::DWTMode ext1Method,
|
|
vtkm::worklet::wavelets::DWTMode ext2Method,
|
|
bool pretendSigPaddedZero,
|
|
bool padZeroAtExt2)
|
|
{
|
|
// pretendSigPaddedZero and padZeroAtExt2 cannot happen at the same time
|
|
VTKM_ASSERT(!pretendSigPaddedZero || !padZeroAtExt2);
|
|
|
|
if (addLen == 0) // Haar kernel
|
|
{
|
|
ext1.Allocate(0); // No extension on the left side
|
|
if (pretendSigPaddedZero || padZeroAtExt2) // plane of size 1*dimY*dimZ
|
|
{
|
|
ext2.Allocate(sigPretendDimY * sigPretendDimZ);
|
|
WaveletBase::DeviceAssignZero3DPlaneX(ext2, 1, sigPretendDimY, sigPretendDimZ, 0);
|
|
}
|
|
else
|
|
{
|
|
ext2.Allocate(0); // No extension on the right side
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
using ValueType = typename SigInArrayType::ValueType;
|
|
using ExtendArrayType = vtkm::cont::ArrayHandle<ValueType>;
|
|
using ExtensionWorklet = vtkm::worklet::wavelets::ExtensionWorklet3D;
|
|
using DispatcherType = typename vtkm::worklet::DispatcherMapField<ExtensionWorklet>;
|
|
vtkm::Id extDimX, extDimY, extDimZ;
|
|
vtkm::worklet::wavelets::ExtensionDirection dir;
|
|
|
|
{ // First work on left extension
|
|
dir = LEFT;
|
|
extDimX = addLen;
|
|
extDimY = sigPretendDimY;
|
|
extDimZ = sigPretendDimZ;
|
|
|
|
ext1.Allocate(extDimX * extDimY * extDimZ);
|
|
ExtensionWorklet worklet(extDimX,
|
|
extDimY,
|
|
extDimZ,
|
|
sigDimX,
|
|
sigDimY,
|
|
sigDimZ,
|
|
sigStartX,
|
|
sigStartY,
|
|
sigStartZ,
|
|
sigPretendDimX,
|
|
sigPretendDimY,
|
|
sigPretendDimZ,
|
|
ext1Method,
|
|
dir,
|
|
false); // not treating input signal as having zeros
|
|
DispatcherType dispatcher(worklet);
|
|
dispatcher.Invoke(ext1, sigIn);
|
|
}
|
|
|
|
// Then work on right extension
|
|
dir = RIGHT;
|
|
extDimY = sigPretendDimY;
|
|
extDimZ = sigPretendDimZ;
|
|
if (!pretendSigPaddedZero && !padZeroAtExt2)
|
|
{
|
|
extDimX = addLen;
|
|
ext2.Allocate(extDimX * extDimY * extDimZ);
|
|
ExtensionWorklet worklet(extDimX,
|
|
extDimY,
|
|
extDimZ,
|
|
sigDimX,
|
|
sigDimY,
|
|
sigDimZ,
|
|
sigStartX,
|
|
sigStartY,
|
|
sigStartZ,
|
|
sigPretendDimX,
|
|
sigPretendDimY,
|
|
sigPretendDimZ,
|
|
ext2Method,
|
|
dir,
|
|
false);
|
|
DispatcherType dispatcher(worklet);
|
|
dispatcher.Invoke(ext2, sigIn);
|
|
}
|
|
else if (!pretendSigPaddedZero && padZeroAtExt2)
|
|
{ // This case is not exactly padding a zero at the end of Ext2.
|
|
// Rather, it is to increase extension length by one and fill it
|
|
// to be whatever mirrored.
|
|
extDimX = addLen + 1;
|
|
ext2.Allocate(extDimX * extDimY * extDimZ);
|
|
ExtensionWorklet worklet(extDimX,
|
|
extDimY,
|
|
extDimZ,
|
|
sigDimX,
|
|
sigDimY,
|
|
sigDimZ,
|
|
sigStartX,
|
|
sigStartY,
|
|
sigStartZ,
|
|
sigPretendDimX,
|
|
sigPretendDimY,
|
|
sigPretendDimZ,
|
|
ext2Method,
|
|
dir,
|
|
false);
|
|
DispatcherType dispatcher(worklet);
|
|
dispatcher.Invoke(ext2, sigIn);
|
|
}
|
|
else // pretendSigPaddedZero
|
|
{
|
|
ExtendArrayType ext2Temp;
|
|
extDimX = addLen;
|
|
ext2Temp.Allocate(extDimX * extDimY * extDimZ);
|
|
ExtensionWorklet worklet(extDimX,
|
|
extDimY,
|
|
extDimZ,
|
|
sigDimX,
|
|
sigDimY,
|
|
sigDimZ,
|
|
sigStartX,
|
|
sigStartY,
|
|
sigStartZ,
|
|
sigPretendDimX,
|
|
sigPretendDimY,
|
|
sigPretendDimZ,
|
|
ext2Method,
|
|
dir,
|
|
true); // pretend sig is padded a zero
|
|
DispatcherType dispatcher(worklet);
|
|
dispatcher.Invoke(ext2Temp, sigIn);
|
|
|
|
// Give ext2 one layer thicker to hold the pretend zeros from signal.
|
|
ext2.Allocate((extDimX + 1) * extDimY * extDimZ);
|
|
WaveletBase::DeviceCubeCopyTo(
|
|
ext2Temp, extDimX, extDimY, extDimZ, ext2, extDimX + 1, extDimY, extDimZ, 1, 0, 0);
|
|
WaveletBase::DeviceAssignZero3DPlaneX(ext2, extDimX + 1, extDimY, extDimZ, 0);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// Function: extend a cube in Y direction
|
|
template <typename SigInArrayType, typename ExtensionArrayType>
|
|
vtkm::Id Extend3DTopDown(const SigInArrayType& sigIn, // input
|
|
vtkm::Id sigDimX,
|
|
vtkm::Id sigDimY,
|
|
vtkm::Id sigDimZ,
|
|
vtkm::Id sigStartX,
|
|
vtkm::Id sigStartY,
|
|
vtkm::Id sigStartZ,
|
|
vtkm::Id sigPretendDimX,
|
|
vtkm::Id sigPretendDimY,
|
|
vtkm::Id sigPretendDimZ,
|
|
ExtensionArrayType& ext1, // output
|
|
ExtensionArrayType& ext2, // output
|
|
vtkm::Id addLen,
|
|
vtkm::worklet::wavelets::DWTMode ext1Method,
|
|
vtkm::worklet::wavelets::DWTMode ext2Method,
|
|
bool pretendSigPaddedZero,
|
|
bool padZeroAtExt2)
|
|
{
|
|
// pretendSigPaddedZero and padZeroAtExt2 cannot happen at the same time
|
|
VTKM_ASSERT(!pretendSigPaddedZero || !padZeroAtExt2);
|
|
|
|
if (addLen == 0) // Haar kernel
|
|
{
|
|
ext1.Allocate(0); // No extension on the top side
|
|
if (pretendSigPaddedZero || padZeroAtExt2) // plane of size dimX*dimZ
|
|
{
|
|
ext2.Allocate(sigPretendDimX * 1 * sigPretendDimZ);
|
|
WaveletBase::DeviceAssignZero3DPlaneY(ext2, sigPretendDimX, 1, sigPretendDimZ, 0);
|
|
}
|
|
else
|
|
{
|
|
ext2.Allocate(0); // No extension on the right side
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
using ValueType = typename SigInArrayType::ValueType;
|
|
using ExtendArrayType = vtkm::cont::ArrayHandle<ValueType>;
|
|
using ExtensionWorklet = vtkm::worklet::wavelets::ExtensionWorklet3D;
|
|
using DispatcherType = typename vtkm::worklet::DispatcherMapField<ExtensionWorklet>;
|
|
vtkm::Id extDimX, extDimY, extDimZ;
|
|
vtkm::worklet::wavelets::ExtensionDirection dir;
|
|
|
|
{ // First work on top extension
|
|
dir = TOP;
|
|
extDimX = sigPretendDimX;
|
|
extDimY = addLen;
|
|
extDimZ = sigPretendDimZ;
|
|
|
|
ext1.Allocate(extDimX * extDimY * extDimZ);
|
|
ExtensionWorklet worklet(extDimX,
|
|
extDimY,
|
|
extDimZ,
|
|
sigDimX,
|
|
sigDimY,
|
|
sigDimZ,
|
|
sigStartX,
|
|
sigStartY,
|
|
sigStartZ,
|
|
sigPretendDimX,
|
|
sigPretendDimY,
|
|
sigPretendDimZ,
|
|
ext1Method,
|
|
dir,
|
|
false); // not treating input signal as having zeros
|
|
DispatcherType dispatcher(worklet);
|
|
dispatcher.Invoke(ext1, sigIn);
|
|
}
|
|
|
|
// Then work on bottom extension
|
|
dir = BOTTOM;
|
|
extDimX = sigPretendDimX;
|
|
extDimZ = sigPretendDimZ;
|
|
if (!pretendSigPaddedZero && !padZeroAtExt2)
|
|
{
|
|
extDimY = addLen;
|
|
ext2.Allocate(extDimX * extDimY * extDimZ);
|
|
ExtensionWorklet worklet(extDimX,
|
|
extDimY,
|
|
extDimZ,
|
|
sigDimX,
|
|
sigDimY,
|
|
sigDimZ,
|
|
sigStartX,
|
|
sigStartY,
|
|
sigStartZ,
|
|
sigPretendDimX,
|
|
sigPretendDimY,
|
|
sigPretendDimZ,
|
|
ext2Method,
|
|
dir,
|
|
false);
|
|
DispatcherType dispatcher(worklet);
|
|
dispatcher.Invoke(ext2, sigIn);
|
|
}
|
|
else if (!pretendSigPaddedZero && padZeroAtExt2)
|
|
{ // This case is not exactly padding a zero at the end of Ext2.
|
|
// Rather, it is to increase extension length by one and fill it
|
|
// to be whatever mirrored.
|
|
extDimY = addLen + 1;
|
|
ext2.Allocate(extDimX * extDimY * extDimZ);
|
|
ExtensionWorklet worklet(extDimX,
|
|
extDimY,
|
|
extDimZ,
|
|
sigDimX,
|
|
sigDimY,
|
|
sigDimZ,
|
|
sigStartX,
|
|
sigStartY,
|
|
sigStartZ,
|
|
sigPretendDimX,
|
|
sigPretendDimY,
|
|
sigPretendDimZ,
|
|
ext2Method,
|
|
dir,
|
|
false);
|
|
DispatcherType dispatcher(worklet);
|
|
dispatcher.Invoke(ext2, sigIn);
|
|
}
|
|
else // pretendSigPaddedZero
|
|
{
|
|
ExtendArrayType ext2Temp;
|
|
extDimY = addLen;
|
|
ext2Temp.Allocate(extDimX * extDimY * extDimZ);
|
|
ExtensionWorklet worklet(extDimX,
|
|
extDimY,
|
|
extDimZ,
|
|
sigDimX,
|
|
sigDimY,
|
|
sigDimZ,
|
|
sigStartX,
|
|
sigStartY,
|
|
sigStartZ,
|
|
sigPretendDimX,
|
|
sigPretendDimY,
|
|
sigPretendDimZ,
|
|
ext2Method,
|
|
dir,
|
|
true); // pretend sig is padded a zero
|
|
DispatcherType dispatcher(worklet);
|
|
dispatcher.Invoke(ext2Temp, sigIn);
|
|
|
|
// Give ext2 one layer thicker to hold the pretend zeros from signal.
|
|
ext2.Allocate(extDimX * (extDimY + 1) * extDimZ);
|
|
WaveletBase::DeviceCubeCopyTo(
|
|
ext2Temp, extDimX, extDimY, extDimZ, ext2, extDimX, extDimY + 1, extDimZ, 0, 1, 0);
|
|
WaveletBase::DeviceAssignZero3DPlaneY(ext2, extDimX, extDimY + 1, extDimZ, 0);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// Function: extend a cube in Z direction
|
|
template <typename SigInArrayType, typename ExtensionArrayType>
|
|
vtkm::Id Extend3DFrontBack(const SigInArrayType& sigIn, // input
|
|
vtkm::Id sigDimX,
|
|
vtkm::Id sigDimY,
|
|
vtkm::Id sigDimZ,
|
|
vtkm::Id sigStartX,
|
|
vtkm::Id sigStartY,
|
|
vtkm::Id sigStartZ,
|
|
vtkm::Id sigPretendDimX,
|
|
vtkm::Id sigPretendDimY,
|
|
vtkm::Id sigPretendDimZ,
|
|
ExtensionArrayType& ext1, // output
|
|
ExtensionArrayType& ext2, // output
|
|
vtkm::Id addLen,
|
|
vtkm::worklet::wavelets::DWTMode ext1Method,
|
|
vtkm::worklet::wavelets::DWTMode ext2Method,
|
|
bool pretendSigPaddedZero,
|
|
bool padZeroAtExt2)
|
|
{
|
|
// pretendSigPaddedZero and padZeroAtExt2 cannot happen at the same time
|
|
VTKM_ASSERT(!pretendSigPaddedZero || !padZeroAtExt2);
|
|
|
|
if (addLen == 0) // Haar kernel
|
|
{
|
|
ext1.Allocate(0); // No extension on the front side
|
|
if (pretendSigPaddedZero || padZeroAtExt2) // plane of size dimX * dimY
|
|
{
|
|
ext2.Allocate(sigPretendDimX * sigPretendDimY * 1);
|
|
WaveletBase::DeviceAssignZero3DPlaneZ(ext2, sigPretendDimX, sigPretendDimY, 1, 0);
|
|
}
|
|
else
|
|
{
|
|
ext2.Allocate(0); // No extension on the right side
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
using ValueType = typename SigInArrayType::ValueType;
|
|
using ExtendArrayType = vtkm::cont::ArrayHandle<ValueType>;
|
|
using ExtensionWorklet = vtkm::worklet::wavelets::ExtensionWorklet3D;
|
|
using DispatcherType = typename vtkm::worklet::DispatcherMapField<ExtensionWorklet>;
|
|
vtkm::Id extDimX, extDimY, extDimZ;
|
|
vtkm::worklet::wavelets::ExtensionDirection dir;
|
|
|
|
{ // First work on front extension
|
|
dir = FRONT;
|
|
extDimX = sigPretendDimX;
|
|
extDimY = sigPretendDimY;
|
|
extDimZ = addLen;
|
|
|
|
ext1.Allocate(extDimX * extDimY * extDimZ);
|
|
ExtensionWorklet worklet(extDimX,
|
|
extDimY,
|
|
extDimZ,
|
|
sigDimX,
|
|
sigDimY,
|
|
sigDimZ,
|
|
sigStartX,
|
|
sigStartY,
|
|
sigStartZ,
|
|
sigPretendDimX,
|
|
sigPretendDimY,
|
|
sigPretendDimZ,
|
|
ext1Method,
|
|
dir,
|
|
false); // not treating input signal as having zeros
|
|
DispatcherType dispatcher(worklet);
|
|
dispatcher.Invoke(ext1, sigIn);
|
|
}
|
|
|
|
// Then work on back extension
|
|
dir = BACK;
|
|
extDimX = sigPretendDimX;
|
|
extDimY = sigPretendDimY;
|
|
if (!pretendSigPaddedZero && !padZeroAtExt2)
|
|
{
|
|
extDimZ = addLen;
|
|
ext2.Allocate(extDimX * extDimY * extDimZ);
|
|
ExtensionWorklet worklet(extDimX,
|
|
extDimY,
|
|
extDimZ,
|
|
sigDimX,
|
|
sigDimY,
|
|
sigDimZ,
|
|
sigStartX,
|
|
sigStartY,
|
|
sigStartZ,
|
|
sigPretendDimX,
|
|
sigPretendDimY,
|
|
sigPretendDimZ,
|
|
ext2Method,
|
|
dir,
|
|
false);
|
|
DispatcherType dispatcher(worklet);
|
|
dispatcher.Invoke(ext2, sigIn);
|
|
}
|
|
else if (!pretendSigPaddedZero && padZeroAtExt2)
|
|
{ // This case is not exactly padding a zero at the end of Ext2.
|
|
// Rather, it is to increase extension length by one and fill it
|
|
// to be whatever mirrored.
|
|
extDimZ = addLen + 1;
|
|
ext2.Allocate(extDimX * extDimY * extDimZ);
|
|
ExtensionWorklet worklet(extDimX,
|
|
extDimY,
|
|
extDimZ,
|
|
sigDimX,
|
|
sigDimY,
|
|
sigDimZ,
|
|
sigStartX,
|
|
sigStartY,
|
|
sigStartZ,
|
|
sigPretendDimX,
|
|
sigPretendDimY,
|
|
sigPretendDimZ,
|
|
ext2Method,
|
|
dir,
|
|
false);
|
|
DispatcherType dispatcher(worklet);
|
|
dispatcher.Invoke(ext2, sigIn);
|
|
}
|
|
else // pretendSigPaddedZero
|
|
{
|
|
ExtendArrayType ext2Temp;
|
|
extDimZ = addLen;
|
|
ext2Temp.Allocate(extDimX * extDimY * extDimZ);
|
|
ExtensionWorklet worklet(extDimX,
|
|
extDimY,
|
|
extDimZ,
|
|
sigDimX,
|
|
sigDimY,
|
|
sigDimZ,
|
|
sigStartX,
|
|
sigStartY,
|
|
sigStartZ,
|
|
sigPretendDimX,
|
|
sigPretendDimY,
|
|
sigPretendDimZ,
|
|
ext2Method,
|
|
dir,
|
|
true); // pretend sig is padded a zero
|
|
DispatcherType dispatcher(worklet);
|
|
dispatcher.Invoke(ext2Temp, sigIn);
|
|
|
|
// Give ext2 one layer thicker to hold the pretend zeros from signal.
|
|
ext2.Allocate(extDimX * extDimY * (extDimZ + 1));
|
|
WaveletBase::DeviceCubeCopyTo(
|
|
ext2Temp, extDimX, extDimY, extDimZ, ext2, extDimX, extDimY, extDimZ + 1, 0, 0, 1);
|
|
WaveletBase::DeviceAssignZero3DPlaneZ(ext2, extDimX, extDimY, extDimZ + 1, 0);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// L[3] L[15]
|
|
// -----------------------
|
|
// / / /|
|
|
// L[5] / / / |
|
|
// / LLH / HLH / |
|
|
// / / / | L[16]
|
|
// ----------------------- |
|
|
// / / /| |
|
|
// L[2] / / / | /|
|
|
// / / / | / |
|
|
// /___L[0]___/___L[12]__/ | / | L[22]
|
|
// | | | |/ |
|
|
// L[1] | | | /HHH /
|
|
// | LLL | HLL | /| /
|
|
// | | | / | / L[23]
|
|
// |---------------------|/ | /
|
|
// | | | |/
|
|
// | | | /
|
|
// L[7] | LHL | HHL | /
|
|
// | | | / L[20]
|
|
// |__________|__________|/
|
|
// L[6] L[18]
|
|
//
|
|
// Performs one level of 3D discrete wavelet transform on a small cube of input array
|
|
// The output has the same size as the small cube
|
|
template <typename ArrayInType, typename ArrayOutType>
|
|
vtkm::Float64 DWT3D(ArrayInType& sigIn,
|
|
vtkm::Id sigDimX,
|
|
vtkm::Id sigDimY,
|
|
vtkm::Id sigDimZ,
|
|
vtkm::Id sigStartX,
|
|
vtkm::Id sigStartY,
|
|
vtkm::Id sigStartZ,
|
|
vtkm::Id sigPretendDimX,
|
|
vtkm::Id sigPretendDimY,
|
|
vtkm::Id sigPretendDimZ,
|
|
ArrayOutType& coeffOut,
|
|
bool discardSigIn) // discard sigIn on devices
|
|
{
|
|
std::vector<vtkm::Id> L(27, 0);
|
|
|
|
// LLL
|
|
L[0] = WaveletBase::GetApproxLength(sigPretendDimX);
|
|
L[1] = WaveletBase::GetApproxLength(sigPretendDimY);
|
|
L[2] = WaveletBase::GetApproxLength(sigPretendDimZ);
|
|
// LLH
|
|
L[3] = L[0];
|
|
L[4] = L[1];
|
|
L[5] = WaveletBase::GetDetailLength(sigPretendDimZ);
|
|
// LHL
|
|
L[6] = L[0];
|
|
L[7] = WaveletBase::GetDetailLength(sigPretendDimY);
|
|
L[8] = L[2];
|
|
// LHH
|
|
L[9] = L[0];
|
|
L[10] = L[7];
|
|
L[11] = L[5];
|
|
// HLL
|
|
L[12] = WaveletBase::GetDetailLength(sigPretendDimX);
|
|
L[13] = L[1];
|
|
L[14] = L[2];
|
|
// HLH
|
|
L[15] = L[12];
|
|
L[16] = L[1];
|
|
L[17] = L[5];
|
|
// HHL
|
|
L[18] = L[12];
|
|
L[19] = L[7];
|
|
L[20] = L[2];
|
|
// HHH
|
|
L[21] = L[12];
|
|
L[22] = L[7];
|
|
L[23] = L[5];
|
|
|
|
L[24] = sigPretendDimX;
|
|
L[25] = sigPretendDimY;
|
|
L[26] = sigPretendDimZ;
|
|
|
|
vtkm::Id filterLen = WaveletBase::filter.GetFilterLength();
|
|
bool oddLow = true;
|
|
if (filterLen % 2 != 0)
|
|
{
|
|
oddLow = false;
|
|
}
|
|
vtkm::Id addLen = filterLen / 2;
|
|
|
|
using ValueType = typename ArrayInType::ValueType;
|
|
using ArrayType = vtkm::cont::ArrayHandle<ValueType>;
|
|
using LeftRightXFormType = vtkm::worklet::wavelets::ForwardTransform3DLeftRight;
|
|
using TopDownXFormType = vtkm::worklet::wavelets::ForwardTransform3DTopDown;
|
|
using FrontBackXFormType = vtkm::worklet::wavelets::ForwardTransform3DFrontBack;
|
|
using LeftRightDispatcherType = vtkm::worklet::DispatcherMapField<LeftRightXFormType>;
|
|
using TopDownDispatcherType = vtkm::worklet::DispatcherMapField<TopDownXFormType>;
|
|
using FrontBackDispatcherType = vtkm::worklet::DispatcherMapField<FrontBackXFormType>;
|
|
|
|
vtkm::cont::Timer timer;
|
|
vtkm::Float64 computationTime = 0.0;
|
|
|
|
// First transform in X direction
|
|
ArrayType afterX;
|
|
afterX.Allocate(sigPretendDimX * sigPretendDimY * sigPretendDimZ);
|
|
{
|
|
ArrayType leftExt, rightExt;
|
|
this->Extend3DLeftRight(sigIn,
|
|
sigDimX,
|
|
sigDimY,
|
|
sigDimZ,
|
|
sigStartX,
|
|
sigStartY,
|
|
sigStartZ,
|
|
sigPretendDimX,
|
|
sigPretendDimY,
|
|
sigPretendDimZ,
|
|
leftExt,
|
|
rightExt,
|
|
addLen,
|
|
WaveletBase::wmode,
|
|
WaveletBase::wmode,
|
|
false,
|
|
false);
|
|
LeftRightXFormType worklet(filterLen,
|
|
L[0],
|
|
oddLow,
|
|
addLen,
|
|
sigPretendDimY,
|
|
sigPretendDimZ,
|
|
sigDimX,
|
|
sigDimY,
|
|
sigDimZ,
|
|
sigStartX,
|
|
sigStartY,
|
|
sigStartZ,
|
|
sigPretendDimX,
|
|
sigPretendDimY,
|
|
sigPretendDimZ,
|
|
addLen,
|
|
sigPretendDimY,
|
|
sigPretendDimZ);
|
|
LeftRightDispatcherType dispatcher(worklet);
|
|
timer.Start();
|
|
dispatcher.Invoke(leftExt,
|
|
sigIn,
|
|
rightExt,
|
|
WaveletBase::filter.GetLowDecomposeFilter(),
|
|
WaveletBase::filter.GetHighDecomposeFilter(),
|
|
afterX);
|
|
computationTime += timer.GetElapsedTime();
|
|
}
|
|
|
|
if (discardSigIn)
|
|
{
|
|
sigIn.ReleaseResourcesExecution();
|
|
}
|
|
|
|
// Then do transform in Y direction
|
|
ArrayType afterY;
|
|
afterY.Allocate(sigPretendDimX * sigPretendDimY * sigPretendDimZ);
|
|
{
|
|
ArrayType topExt, bottomExt;
|
|
this->Extend3DTopDown(afterX,
|
|
sigPretendDimX,
|
|
sigPretendDimY,
|
|
sigPretendDimZ,
|
|
0,
|
|
0,
|
|
0,
|
|
sigPretendDimX,
|
|
sigPretendDimY,
|
|
sigPretendDimZ,
|
|
topExt,
|
|
bottomExt,
|
|
addLen,
|
|
WaveletBase::wmode,
|
|
WaveletBase::wmode,
|
|
false,
|
|
false);
|
|
TopDownXFormType worklet(filterLen,
|
|
L[1],
|
|
oddLow,
|
|
sigPretendDimX,
|
|
addLen,
|
|
sigPretendDimZ,
|
|
sigPretendDimX,
|
|
sigPretendDimY,
|
|
sigPretendDimZ,
|
|
0,
|
|
0,
|
|
0,
|
|
sigPretendDimX,
|
|
sigPretendDimY,
|
|
sigPretendDimZ,
|
|
sigPretendDimX,
|
|
addLen,
|
|
sigPretendDimZ);
|
|
TopDownDispatcherType dispatcher(worklet);
|
|
timer.Start();
|
|
dispatcher.Invoke(topExt,
|
|
afterX,
|
|
bottomExt,
|
|
WaveletBase::filter.GetLowDecomposeFilter(),
|
|
WaveletBase::filter.GetHighDecomposeFilter(),
|
|
afterY);
|
|
computationTime += timer.GetElapsedTime();
|
|
}
|
|
|
|
// Then do transform in Z direction
|
|
afterX.ReleaseResources(); // release afterX
|
|
{
|
|
ArrayType frontExt, backExt;
|
|
coeffOut.Allocate(sigPretendDimX * sigPretendDimY * sigPretendDimZ);
|
|
this->Extend3DFrontBack(afterY,
|
|
sigPretendDimX,
|
|
sigPretendDimY,
|
|
sigPretendDimZ,
|
|
0,
|
|
0,
|
|
0,
|
|
sigPretendDimX,
|
|
sigPretendDimY,
|
|
sigPretendDimZ,
|
|
frontExt,
|
|
backExt,
|
|
addLen,
|
|
WaveletBase::wmode,
|
|
WaveletBase::wmode,
|
|
false,
|
|
false);
|
|
FrontBackXFormType worklet(filterLen,
|
|
L[1],
|
|
oddLow,
|
|
sigPretendDimX,
|
|
sigPretendDimY,
|
|
addLen,
|
|
sigPretendDimX,
|
|
sigPretendDimY,
|
|
sigPretendDimZ,
|
|
0,
|
|
0,
|
|
0,
|
|
sigPretendDimX,
|
|
sigPretendDimY,
|
|
sigPretendDimZ,
|
|
sigPretendDimX,
|
|
sigPretendDimY,
|
|
addLen);
|
|
FrontBackDispatcherType dispatcher(worklet);
|
|
timer.Start();
|
|
dispatcher.Invoke(frontExt,
|
|
afterY,
|
|
backExt,
|
|
WaveletBase::filter.GetLowDecomposeFilter(),
|
|
WaveletBase::filter.GetHighDecomposeFilter(),
|
|
coeffOut);
|
|
computationTime += timer.GetElapsedTime();
|
|
}
|
|
|
|
return computationTime;
|
|
}
|
|
|
|
// Performs one level of IDWT on a small cube of a big cube
|
|
// The output array has the same dimensions as the small cube.
|
|
template <typename ArrayInType, typename ArrayOutType>
|
|
vtkm::Float64 IDWT3D(ArrayInType& coeffIn,
|
|
vtkm::Id inDimX,
|
|
vtkm::Id inDimY,
|
|
vtkm::Id inDimZ,
|
|
vtkm::Id inStartX,
|
|
vtkm::Id inStartY,
|
|
vtkm::Id inStartZ,
|
|
const std::vector<vtkm::Id>& L,
|
|
ArrayOutType& sigOut,
|
|
bool discardCoeffIn) // can we discard coeffIn?
|
|
{
|
|
//VTKM_ASSERT( L.size() == 27 );
|
|
//VTKM_ASSERT( inDimX * inDimY * inDimZ == coeffIn.GetNumberOfValues() );
|
|
vtkm::Id inPretendDimX = L[0] + L[12];
|
|
vtkm::Id inPretendDimY = L[1] + L[7];
|
|
vtkm::Id inPretendDimZ = L[2] + L[5];
|
|
|
|
vtkm::Id filterLen = WaveletBase::filter.GetFilterLength();
|
|
using BasicArrayType = vtkm::cont::ArrayHandle<typename ArrayInType::ValueType>;
|
|
using LeftRightXFormType = vtkm::worklet::wavelets::InverseTransform3DLeftRight;
|
|
using TopDownXFormType = vtkm::worklet::wavelets::InverseTransform3DTopDown;
|
|
using FrontBackXFormType = vtkm::worklet::wavelets::InverseTransform3DFrontBack;
|
|
using LeftRightDispatcherType = vtkm::worklet::DispatcherMapField<LeftRightXFormType>;
|
|
using TopDownDispatcherType = vtkm::worklet::DispatcherMapField<TopDownXFormType>;
|
|
using FrontBackDispatcherType = vtkm::worklet::DispatcherMapField<FrontBackXFormType>;
|
|
|
|
vtkm::cont::Timer timer;
|
|
vtkm::Float64 computationTime = 0.0;
|
|
|
|
// First, inverse transform in Z direction
|
|
BasicArrayType afterZ;
|
|
afterZ.Allocate(inPretendDimX * inPretendDimY * inPretendDimZ);
|
|
{
|
|
BasicArrayType ext1, ext2, ext3, ext4;
|
|
vtkm::Id extDimX = inPretendDimX;
|
|
vtkm::Id extDimY = inPretendDimY;
|
|
vtkm::Id ext1DimZ = 0, ext2DimZ = 0, ext3DimZ = 0, ext4DimZ = 0;
|
|
this->IDWTHelper3DFrontBack(coeffIn,
|
|
inDimX,
|
|
inDimY,
|
|
inDimZ,
|
|
inStartX,
|
|
inStartY,
|
|
inStartZ,
|
|
inPretendDimX,
|
|
inPretendDimY,
|
|
inPretendDimZ,
|
|
L[2],
|
|
L[5],
|
|
ext1,
|
|
ext2,
|
|
ext3,
|
|
ext4,
|
|
ext1DimZ,
|
|
ext2DimZ,
|
|
ext3DimZ,
|
|
ext4DimZ,
|
|
filterLen,
|
|
wmode);
|
|
FrontBackXFormType worklet(filterLen,
|
|
extDimX,
|
|
extDimY,
|
|
ext1DimZ, // ext1
|
|
extDimX,
|
|
extDimY,
|
|
ext2DimZ, // ext2
|
|
extDimX,
|
|
extDimY,
|
|
ext3DimZ, // ext3
|
|
extDimX,
|
|
extDimY,
|
|
ext4DimZ, // ext4
|
|
inPretendDimX,
|
|
inPretendDimY,
|
|
L[2], // cA
|
|
inPretendDimX,
|
|
inPretendDimY,
|
|
L[5], // cD
|
|
inDimX,
|
|
inDimY,
|
|
inDimZ, // coeffIn
|
|
inStartX,
|
|
inStartY,
|
|
inStartZ); // coeffIn
|
|
FrontBackDispatcherType dispatcher(worklet);
|
|
timer.Start();
|
|
dispatcher.Invoke(ext1,
|
|
ext2,
|
|
ext3,
|
|
ext4,
|
|
coeffIn,
|
|
WaveletBase::filter.GetLowReconstructFilter(),
|
|
WaveletBase::filter.GetHighReconstructFilter(),
|
|
afterZ);
|
|
computationTime += timer.GetElapsedTime();
|
|
}
|
|
|
|
if (discardCoeffIn)
|
|
{
|
|
coeffIn.ReleaseResourcesExecution();
|
|
}
|
|
|
|
// Second, inverse transform in Y direction
|
|
BasicArrayType afterY;
|
|
afterY.Allocate(inPretendDimX * inPretendDimY * inPretendDimZ);
|
|
{
|
|
BasicArrayType ext1, ext2, ext3, ext4;
|
|
vtkm::Id extDimX = inPretendDimX;
|
|
vtkm::Id extDimZ = inPretendDimZ;
|
|
vtkm::Id ext1DimY = 0, ext2DimY = 0, ext3DimY = 0, ext4DimY = 0;
|
|
this->IDWTHelper3DTopDown(afterZ,
|
|
inPretendDimX,
|
|
inPretendDimY,
|
|
inPretendDimZ,
|
|
0,
|
|
0,
|
|
0,
|
|
inPretendDimX,
|
|
inPretendDimY,
|
|
inPretendDimZ,
|
|
L[1],
|
|
L[7],
|
|
ext1,
|
|
ext2,
|
|
ext3,
|
|
ext4,
|
|
ext1DimY,
|
|
ext2DimY,
|
|
ext3DimY,
|
|
ext4DimY,
|
|
filterLen,
|
|
wmode);
|
|
TopDownXFormType worklet(filterLen,
|
|
extDimX,
|
|
ext1DimY,
|
|
extDimZ, // ext1
|
|
extDimX,
|
|
ext2DimY,
|
|
extDimZ, // ext2
|
|
extDimX,
|
|
ext3DimY,
|
|
extDimZ, // ext3
|
|
extDimX,
|
|
ext4DimY,
|
|
extDimZ, // ext4
|
|
inPretendDimX,
|
|
L[1],
|
|
inPretendDimZ, // cA
|
|
inPretendDimX,
|
|
L[7],
|
|
inPretendDimZ, // cD
|
|
inPretendDimX,
|
|
inPretendDimY,
|
|
inPretendDimZ, // actual signal
|
|
0,
|
|
0,
|
|
0);
|
|
TopDownDispatcherType dispatcher(worklet);
|
|
timer.Start();
|
|
dispatcher.Invoke(ext1,
|
|
ext2,
|
|
ext3,
|
|
ext4,
|
|
afterZ,
|
|
WaveletBase::filter.GetLowReconstructFilter(),
|
|
WaveletBase::filter.GetHighReconstructFilter(),
|
|
afterY);
|
|
computationTime += timer.GetElapsedTime();
|
|
}
|
|
|
|
// Lastly, inverse transform in X direction
|
|
afterZ.ReleaseResources();
|
|
{
|
|
BasicArrayType ext1, ext2, ext3, ext4;
|
|
vtkm::Id extDimY = inPretendDimY;
|
|
vtkm::Id extDimZ = inPretendDimZ;
|
|
vtkm::Id ext1DimX = 0, ext2DimX = 0, ext3DimX = 0, ext4DimX = 0;
|
|
this->IDWTHelper3DLeftRight(afterY,
|
|
inPretendDimX,
|
|
inPretendDimY,
|
|
inPretendDimZ,
|
|
0,
|
|
0,
|
|
0,
|
|
inPretendDimX,
|
|
inPretendDimY,
|
|
inPretendDimZ,
|
|
L[0],
|
|
L[12],
|
|
ext1,
|
|
ext2,
|
|
ext3,
|
|
ext4,
|
|
ext1DimX,
|
|
ext2DimX,
|
|
ext3DimX,
|
|
ext4DimX,
|
|
filterLen,
|
|
wmode);
|
|
sigOut.Allocate(inPretendDimX * inPretendDimY * inPretendDimZ);
|
|
LeftRightXFormType worklet(filterLen,
|
|
ext1DimX,
|
|
extDimY,
|
|
extDimZ, // ext1
|
|
ext2DimX,
|
|
extDimY,
|
|
extDimZ, // ext2
|
|
ext3DimX,
|
|
extDimY,
|
|
extDimZ, // ext3
|
|
ext4DimX,
|
|
extDimY,
|
|
extDimZ, // ext4
|
|
L[0],
|
|
inPretendDimY,
|
|
inPretendDimZ, // cA
|
|
L[12],
|
|
inPretendDimY,
|
|
inPretendDimZ, // cD
|
|
inPretendDimX,
|
|
inPretendDimY,
|
|
inPretendDimZ, // actual signal
|
|
0,
|
|
0,
|
|
0);
|
|
LeftRightDispatcherType dispatcher(worklet);
|
|
timer.Start();
|
|
dispatcher.Invoke(ext1,
|
|
ext2,
|
|
ext3,
|
|
ext4,
|
|
afterY,
|
|
WaveletBase::filter.GetLowReconstructFilter(),
|
|
WaveletBase::filter.GetHighReconstructFilter(),
|
|
sigOut);
|
|
computationTime += timer.GetElapsedTime();
|
|
}
|
|
|
|
return computationTime;
|
|
}
|
|
|
|
//=============================================================================
|
|
|
|
template <typename SigInArrayType, typename ExtensionArrayType>
|
|
vtkm::Id Extend2D(const SigInArrayType& sigIn, // Input
|
|
vtkm::Id sigDimX,
|
|
vtkm::Id sigDimY,
|
|
vtkm::Id sigStartX,
|
|
vtkm::Id sigStartY,
|
|
vtkm::Id sigPretendDimX,
|
|
vtkm::Id sigPretendDimY,
|
|
ExtensionArrayType& ext1, // left/top extension
|
|
ExtensionArrayType& ext2, // right/bottom extension
|
|
vtkm::Id addLen,
|
|
vtkm::worklet::wavelets::DWTMode ext1Method,
|
|
vtkm::worklet::wavelets::DWTMode ext2Method,
|
|
bool pretendSigPaddedZero,
|
|
bool padZeroAtExt2,
|
|
bool modeLR) // true = left-right, false = top-down
|
|
{
|
|
// pretendSigPaddedZero and padZeroAtExt2 cannot happen at the same time
|
|
VTKM_ASSERT(!pretendSigPaddedZero || !padZeroAtExt2);
|
|
|
|
if (addLen == 0) // Haar kernel
|
|
{
|
|
ext1.Allocate(0); // no need to extend on left/top
|
|
if (pretendSigPaddedZero || padZeroAtExt2)
|
|
{
|
|
if (modeLR) // right extension
|
|
{
|
|
ext2.Allocate(sigPretendDimY);
|
|
WaveletBase::DeviceAssignZero2DColumn(ext2, 1, sigPretendDimY, 0);
|
|
}
|
|
else // bottom extension
|
|
{
|
|
ext2.Allocate(sigPretendDimX);
|
|
WaveletBase::DeviceAssignZero2DRow(ext2, sigPretendDimX, 1, 0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ext2.Allocate(0);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
using ValueType = typename SigInArrayType::ValueType;
|
|
using ExtendArrayType = vtkm::cont::ArrayHandle<ValueType>;
|
|
using ExtensionWorklet = vtkm::worklet::wavelets::ExtensionWorklet2D;
|
|
using DispatcherType = typename vtkm::worklet::DispatcherMapField<ExtensionWorklet>;
|
|
vtkm::Id extDimX, extDimY;
|
|
vtkm::worklet::wavelets::ExtensionDirection dir;
|
|
|
|
{ // Work on left/top extension
|
|
if (modeLR)
|
|
{
|
|
dir = LEFT;
|
|
extDimX = addLen;
|
|
extDimY = sigPretendDimY;
|
|
}
|
|
else
|
|
{
|
|
dir = TOP;
|
|
extDimX = sigPretendDimX;
|
|
extDimY = addLen;
|
|
}
|
|
ext1.Allocate(extDimX * extDimY);
|
|
ExtensionWorklet worklet(extDimX,
|
|
extDimY,
|
|
sigDimX,
|
|
sigDimY,
|
|
sigStartX,
|
|
sigStartY,
|
|
sigPretendDimX,
|
|
sigPretendDimY, // use this area
|
|
ext1Method,
|
|
dir,
|
|
false); // not treating sigIn as having zeros
|
|
DispatcherType dispatcher(worklet);
|
|
dispatcher.Invoke(ext1, sigIn);
|
|
}
|
|
|
|
// Work on right/bottom extension
|
|
if (!pretendSigPaddedZero && !padZeroAtExt2)
|
|
{
|
|
if (modeLR)
|
|
{
|
|
dir = RIGHT;
|
|
extDimX = addLen;
|
|
extDimY = sigPretendDimY;
|
|
}
|
|
else
|
|
{
|
|
dir = BOTTOM;
|
|
extDimX = sigPretendDimX;
|
|
extDimY = addLen;
|
|
}
|
|
ext2.Allocate(extDimX * extDimY);
|
|
ExtensionWorklet worklet(extDimX,
|
|
extDimY,
|
|
sigDimX,
|
|
sigDimY,
|
|
sigStartX,
|
|
sigStartY,
|
|
sigPretendDimX,
|
|
sigPretendDimY, // use this area
|
|
ext2Method,
|
|
dir,
|
|
false);
|
|
DispatcherType dispatcher(worklet);
|
|
dispatcher.Invoke(ext2, sigIn);
|
|
}
|
|
else if (!pretendSigPaddedZero && padZeroAtExt2)
|
|
{
|
|
if (modeLR)
|
|
{
|
|
dir = RIGHT;
|
|
extDimX = addLen + 1;
|
|
extDimY = sigPretendDimY;
|
|
}
|
|
else
|
|
{
|
|
dir = BOTTOM;
|
|
extDimX = sigPretendDimX;
|
|
extDimY = addLen + 1;
|
|
}
|
|
ext2.Allocate(extDimX * extDimY);
|
|
ExtensionWorklet worklet(extDimX,
|
|
extDimY,
|
|
sigDimX,
|
|
sigDimY,
|
|
sigStartX,
|
|
sigStartY,
|
|
sigPretendDimX,
|
|
sigPretendDimY,
|
|
ext2Method,
|
|
dir,
|
|
false);
|
|
DispatcherType dispatcher(worklet);
|
|
dispatcher.Invoke(ext2, sigIn);
|
|
/* Pad a zero at the end of cDTemp, when cDTemp is forced to have the same
|
|
length as cATemp. For example, with odd length signal, cA is 1 element
|
|
longer than cD.
|
|
*/
|
|
/* Update 10/24/2016: the extra element of cD shouldn't be zero, just be
|
|
* whatever it extends to be.
|
|
* if( modeLR )
|
|
* WaveletBase::DeviceAssignZero2DColumn( ext2, extDimX, extDimY,
|
|
* extDimX-1 );
|
|
* else
|
|
* WaveletBase::DeviceAssignZero2DRow( ext2, extDimX, extDimY,
|
|
* extDimY-1 );
|
|
*/
|
|
}
|
|
else // pretendSigPaddedZero
|
|
{
|
|
ExtendArrayType ext2Temp;
|
|
if (modeLR)
|
|
{
|
|
dir = RIGHT;
|
|
extDimX = addLen;
|
|
extDimY = sigPretendDimY;
|
|
}
|
|
else
|
|
{
|
|
dir = BOTTOM;
|
|
extDimX = sigPretendDimX;
|
|
extDimY = addLen;
|
|
}
|
|
ext2Temp.Allocate(extDimX * extDimY);
|
|
ExtensionWorklet worklet(extDimX,
|
|
extDimY,
|
|
sigDimX,
|
|
sigDimY,
|
|
sigStartX,
|
|
sigStartY,
|
|
sigPretendDimX,
|
|
sigPretendDimY,
|
|
ext2Method,
|
|
dir,
|
|
true); // pretend sig is padded a zero
|
|
DispatcherType dispatcher(worklet);
|
|
dispatcher.Invoke(ext2Temp, sigIn);
|
|
|
|
if (modeLR)
|
|
{
|
|
ext2.Allocate((extDimX + 1) * extDimY);
|
|
WaveletBase::DeviceRectangleCopyTo(
|
|
ext2Temp, extDimX, extDimY, ext2, extDimX + 1, extDimY, 1, 0);
|
|
WaveletBase::DeviceAssignZero2DColumn(ext2, extDimX + 1, extDimY, 0);
|
|
}
|
|
else
|
|
{
|
|
ext2.Allocate(extDimX * (extDimY + 1));
|
|
WaveletBase::DeviceRectangleCopyTo(
|
|
ext2Temp, extDimX, extDimY, ext2, extDimX, extDimY + 1, 0, 1);
|
|
WaveletBase::DeviceAssignZero2DRow(ext2, extDimX, extDimY + 1, 0);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// Extend 1D signal
|
|
template <typename SigInArrayType, typename SigExtendedArrayType>
|
|
vtkm::Id Extend1D(const SigInArrayType& sigIn, // Input
|
|
SigExtendedArrayType& sigOut, // Output
|
|
vtkm::Id addLen,
|
|
vtkm::worklet::wavelets::DWTMode leftExtMethod,
|
|
vtkm::worklet::wavelets::DWTMode rightExtMethod,
|
|
bool attachZeroRightLeft,
|
|
bool attachZeroRightRight)
|
|
{
|
|
// "right extension" can be attached a zero on either end, but not both ends.
|
|
VTKM_ASSERT(!attachZeroRightRight || !attachZeroRightLeft);
|
|
|
|
using ValueType = typename SigInArrayType::ValueType;
|
|
using ExtensionArrayType = vtkm::cont::ArrayHandle<ValueType>;
|
|
using ArrayConcat = vtkm::cont::ArrayHandleConcatenate<ExtensionArrayType, SigInArrayType>;
|
|
|
|
ExtensionArrayType leftExtend, rightExtend;
|
|
|
|
if (addLen == 0) // Haar kernel
|
|
{
|
|
if (attachZeroRightLeft || attachZeroRightRight)
|
|
{
|
|
leftExtend.Allocate(0);
|
|
rightExtend.Allocate(1);
|
|
WaveletBase::DeviceAssignZero(rightExtend, 0);
|
|
}
|
|
else
|
|
{
|
|
leftExtend.Allocate(0);
|
|
rightExtend.Allocate(0);
|
|
}
|
|
ArrayConcat leftOn(leftExtend, sigIn);
|
|
sigOut = vtkm::cont::make_ArrayHandleConcatenate(leftOn, rightExtend);
|
|
return 0;
|
|
}
|
|
|
|
leftExtend.Allocate(addLen);
|
|
vtkm::Id sigInLen = sigIn.GetNumberOfValues();
|
|
|
|
using LeftSYMH = vtkm::worklet::wavelets::LeftSYMHExtentionWorklet;
|
|
using LeftSYMW = vtkm::worklet::wavelets::LeftSYMWExtentionWorklet;
|
|
using RightSYMH = vtkm::worklet::wavelets::RightSYMHExtentionWorklet;
|
|
using RightSYMW = vtkm::worklet::wavelets::RightSYMWExtentionWorklet;
|
|
using LeftASYMH = vtkm::worklet::wavelets::LeftASYMHExtentionWorklet;
|
|
using LeftASYMW = vtkm::worklet::wavelets::LeftASYMWExtentionWorklet;
|
|
using RightASYMH = vtkm::worklet::wavelets::RightASYMHExtentionWorklet;
|
|
using RightASYMW = vtkm::worklet::wavelets::RightASYMWExtentionWorklet;
|
|
|
|
switch (leftExtMethod)
|
|
{
|
|
case SYMH:
|
|
{
|
|
LeftSYMH worklet(addLen);
|
|
vtkm::worklet::DispatcherMapField<LeftSYMH> dispatcher(worklet);
|
|
dispatcher.Invoke(leftExtend, sigIn);
|
|
break;
|
|
}
|
|
case SYMW:
|
|
{
|
|
LeftSYMW worklet(addLen);
|
|
vtkm::worklet::DispatcherMapField<LeftSYMW> dispatcher(worklet);
|
|
dispatcher.Invoke(leftExtend, sigIn);
|
|
break;
|
|
}
|
|
case ASYMH:
|
|
{
|
|
LeftASYMH worklet(addLen);
|
|
vtkm::worklet::DispatcherMapField<LeftASYMH> dispatcher(worklet);
|
|
dispatcher.Invoke(leftExtend, sigIn);
|
|
break;
|
|
}
|
|
case ASYMW:
|
|
{
|
|
LeftASYMW worklet(addLen);
|
|
vtkm::worklet::DispatcherMapField<LeftASYMW> dispatcher(worklet);
|
|
dispatcher.Invoke(leftExtend, sigIn);
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
vtkm::cont::ErrorInternal("Left extension mode not supported!");
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
if (!attachZeroRightLeft) // no attach zero, or only attach on RightRight
|
|
{
|
|
// Allocate memory
|
|
if (attachZeroRightRight)
|
|
{
|
|
rightExtend.Allocate(addLen + 1);
|
|
}
|
|
else
|
|
{
|
|
rightExtend.Allocate(addLen);
|
|
}
|
|
|
|
switch (rightExtMethod)
|
|
{
|
|
case SYMH:
|
|
{
|
|
RightSYMH worklet(sigInLen);
|
|
vtkm::worklet::DispatcherMapField<RightSYMH> dispatcher(worklet);
|
|
dispatcher.Invoke(rightExtend, sigIn);
|
|
break;
|
|
}
|
|
case SYMW:
|
|
{
|
|
RightSYMW worklet(sigInLen);
|
|
vtkm::worklet::DispatcherMapField<RightSYMW> dispatcher(worklet);
|
|
dispatcher.Invoke(rightExtend, sigIn);
|
|
break;
|
|
}
|
|
case ASYMH:
|
|
{
|
|
RightASYMH worklet(sigInLen);
|
|
vtkm::worklet::DispatcherMapField<RightASYMH> dispatcher(worklet);
|
|
dispatcher.Invoke(rightExtend, sigIn);
|
|
break;
|
|
}
|
|
case ASYMW:
|
|
{
|
|
RightASYMW worklet(sigInLen);
|
|
vtkm::worklet::DispatcherMapField<RightASYMW> dispatcher(worklet);
|
|
dispatcher.Invoke(rightExtend, sigIn);
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
vtkm::cont::ErrorInternal("Right extension mode not supported!");
|
|
return 1;
|
|
}
|
|
}
|
|
if (attachZeroRightRight)
|
|
{
|
|
WaveletBase::DeviceAssignZero(rightExtend, addLen);
|
|
}
|
|
}
|
|
else // attachZeroRightLeft mode
|
|
{
|
|
using ConcatArray = vtkm::cont::ArrayHandleConcatenate<SigInArrayType, ExtensionArrayType>;
|
|
// attach a zero at the end of sigIn
|
|
ExtensionArrayType singleValArray;
|
|
singleValArray.Allocate(1);
|
|
WaveletBase::DeviceAssignZero(singleValArray, 0);
|
|
ConcatArray sigInPlusOne(sigIn, singleValArray);
|
|
|
|
// allocate memory for extension
|
|
rightExtend.Allocate(addLen);
|
|
|
|
switch (rightExtMethod)
|
|
{
|
|
case SYMH:
|
|
{
|
|
RightSYMH worklet(sigInLen + 1);
|
|
vtkm::worklet::DispatcherMapField<RightSYMH> dispatcher(worklet);
|
|
dispatcher.Invoke(rightExtend, sigInPlusOne);
|
|
break;
|
|
}
|
|
case SYMW:
|
|
{
|
|
RightSYMW worklet(sigInLen + 1);
|
|
vtkm::worklet::DispatcherMapField<RightSYMW> dispatcher(worklet);
|
|
dispatcher.Invoke(rightExtend, sigInPlusOne);
|
|
break;
|
|
}
|
|
case ASYMH:
|
|
{
|
|
RightASYMH worklet(sigInLen + 1);
|
|
vtkm::worklet::DispatcherMapField<RightASYMH> dispatcher(worklet);
|
|
dispatcher.Invoke(rightExtend, sigInPlusOne);
|
|
break;
|
|
}
|
|
case ASYMW:
|
|
{
|
|
RightASYMW worklet(sigInLen + 1);
|
|
vtkm::worklet::DispatcherMapField<RightASYMW> dispatcher(worklet);
|
|
dispatcher.Invoke(rightExtend, sigInPlusOne);
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
vtkm::cont::ErrorInternal("Right extension mode not supported!");
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
// make a copy of rightExtend with a zero attached to the left
|
|
ExtensionArrayType rightExtendPlusOne;
|
|
rightExtendPlusOne.Allocate(addLen + 1);
|
|
WaveletBase::DeviceCopyStartX(rightExtend, rightExtendPlusOne, 1);
|
|
WaveletBase::DeviceAssignZero(rightExtendPlusOne, 0);
|
|
rightExtend = rightExtendPlusOne;
|
|
}
|
|
|
|
ArrayConcat leftOn(leftExtend, sigIn);
|
|
sigOut = vtkm::cont::make_ArrayHandleConcatenate(leftOn, rightExtend);
|
|
|
|
return 0;
|
|
}
|
|
|
|
// Performs one level of 1D discrete wavelet transform
|
|
// It takes care of boundary conditions, etc.
|
|
template <typename SignalArrayType, typename CoeffArrayType>
|
|
vtkm::Float64 DWT1D(const SignalArrayType& sigIn, // Input
|
|
CoeffArrayType& coeffOut, // Output: cA followed by cD
|
|
std::vector<vtkm::Id>& L) // Output: how many cA and cD.
|
|
{
|
|
vtkm::Id sigInLen = sigIn.GetNumberOfValues();
|
|
if (GetWaveletMaxLevel(sigInLen) < 1)
|
|
{
|
|
vtkm::cont::ErrorInternal("Signal is too short to perform DWT!");
|
|
return -1;
|
|
}
|
|
|
|
//VTKM_ASSERT( L.size() == 3 );
|
|
L[0] = WaveletBase::GetApproxLength(sigInLen);
|
|
L[1] = WaveletBase::GetDetailLength(sigInLen);
|
|
L[2] = sigInLen;
|
|
|
|
//VTKM_ASSERT( L[0] + L[1] == L[2] );
|
|
|
|
vtkm::Id filterLen = WaveletBase::filter.GetFilterLength();
|
|
|
|
bool doSymConv = false;
|
|
if (WaveletBase::filter.isSymmetric())
|
|
{
|
|
if ((WaveletBase::wmode == SYMW && (filterLen % 2 != 0)) ||
|
|
(WaveletBase::wmode == SYMH && (filterLen % 2 == 0)))
|
|
{
|
|
doSymConv = true;
|
|
}
|
|
}
|
|
|
|
vtkm::Id sigConvolvedLen = L[0] + L[1]; // approx + detail coeffs
|
|
vtkm::Id addLen; // for extension
|
|
bool oddLow = true;
|
|
bool oddHigh = true;
|
|
if (filterLen % 2 != 0)
|
|
{
|
|
oddLow = false;
|
|
}
|
|
if (doSymConv)
|
|
{
|
|
addLen = filterLen / 2;
|
|
if (sigInLen % 2 != 0)
|
|
{
|
|
sigConvolvedLen += 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
addLen = filterLen - 1;
|
|
}
|
|
|
|
vtkm::Id sigExtendedLen = sigInLen + 2 * addLen;
|
|
|
|
using SigInValueType = typename SignalArrayType::ValueType;
|
|
using SigInBasic = vtkm::cont::ArrayHandle<SigInValueType>;
|
|
|
|
using ConcatType1 = vtkm::cont::ArrayHandleConcatenate<SigInBasic, SignalArrayType>;
|
|
using ConcatType2 = vtkm::cont::ArrayHandleConcatenate<ConcatType1, SigInBasic>;
|
|
|
|
ConcatType2 sigInExtended;
|
|
|
|
this->Extend1D(
|
|
sigIn, sigInExtended, addLen, WaveletBase::wmode, WaveletBase::wmode, false, false);
|
|
//VTKM_ASSERT( sigInExtended.GetNumberOfValues() == sigExtendedLen );
|
|
|
|
// initialize a worklet for forward transform
|
|
vtkm::worklet::wavelets::ForwardTransform forwardTransform(
|
|
filterLen, L[0], L[1], oddLow, oddHigh);
|
|
|
|
coeffOut.Allocate(sigExtendedLen);
|
|
vtkm::worklet::DispatcherMapField<vtkm::worklet::wavelets::ForwardTransform> dispatcher(
|
|
forwardTransform);
|
|
// put a timer
|
|
vtkm::cont::Timer timer;
|
|
timer.Start();
|
|
dispatcher.Invoke(sigInExtended,
|
|
WaveletBase::filter.GetLowDecomposeFilter(),
|
|
WaveletBase::filter.GetHighDecomposeFilter(),
|
|
coeffOut);
|
|
vtkm::Float64 elapsedTime = timer.GetElapsedTime();
|
|
|
|
//VTKM_ASSERT( L[0] + L[1] <= coeffOut.GetNumberOfValues() );
|
|
coeffOut.Shrink(L[0] + L[1]);
|
|
|
|
return elapsedTime;
|
|
}
|
|
|
|
// Performs one level of inverse wavelet transform
|
|
// It takes care of boundary conditions, etc.
|
|
template <typename CoeffArrayType, typename SignalArrayType>
|
|
vtkm::Float64 IDWT1D(const CoeffArrayType& coeffIn, // Input, cA followed by cD
|
|
std::vector<vtkm::Id>& L, // Input, how many cA and cD
|
|
SignalArrayType& sigOut) // Output
|
|
{
|
|
vtkm::Id filterLen = WaveletBase::filter.GetFilterLength();
|
|
bool doSymConv = false;
|
|
vtkm::worklet::wavelets::DWTMode cALeftMode = WaveletBase::wmode;
|
|
vtkm::worklet::wavelets::DWTMode cARightMode = WaveletBase::wmode;
|
|
vtkm::worklet::wavelets::DWTMode cDLeftMode = WaveletBase::wmode;
|
|
vtkm::worklet::wavelets::DWTMode cDRightMode = WaveletBase::wmode;
|
|
|
|
if (WaveletBase::filter.isSymmetric()) // this is always true with the 1st 4 filters.
|
|
{
|
|
if ((WaveletBase::wmode == SYMW && (filterLen % 2 != 0)) ||
|
|
(WaveletBase::wmode == SYMH && (filterLen % 2 == 0)))
|
|
{
|
|
doSymConv = true; // doSymConv is always true with the 1st 4 filters.
|
|
|
|
if (WaveletBase::wmode == SYMH)
|
|
{
|
|
cDLeftMode = ASYMH;
|
|
if (L[2] % 2 != 0)
|
|
{
|
|
cARightMode = SYMW;
|
|
cDRightMode = ASYMW;
|
|
}
|
|
else
|
|
{
|
|
cDRightMode = ASYMH;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
cDLeftMode = SYMH;
|
|
if (L[2] % 2 != 0)
|
|
{
|
|
cARightMode = SYMW;
|
|
cDRightMode = SYMH;
|
|
}
|
|
else
|
|
{
|
|
cARightMode = SYMH;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
vtkm::Id cATempLen, cDTempLen; //, reconTempLen;
|
|
vtkm::Id addLen = 0;
|
|
vtkm::Id cDPadLen = 0;
|
|
if (doSymConv) // extend cA and cD
|
|
{
|
|
addLen = filterLen / 4; // addLen == 0 for Haar kernel
|
|
if ((L[0] > L[1]) && (WaveletBase::wmode == SYMH))
|
|
{
|
|
cDPadLen = L[0];
|
|
}
|
|
cATempLen = L[0] + 2 * addLen;
|
|
cDTempLen = cATempLen; // same length
|
|
}
|
|
else // not extend cA and cD
|
|
{ // (biorthogonal kernels won't come into this case)
|
|
cATempLen = L[0];
|
|
cDTempLen = L[1];
|
|
}
|
|
|
|
using IdArrayType = vtkm::cont::ArrayHandleCounting<vtkm::Id>;
|
|
using PermutArrayType = vtkm::cont::ArrayHandlePermutation<IdArrayType, CoeffArrayType>;
|
|
|
|
// Separate cA and cD
|
|
IdArrayType approxIndices(0, 1, L[0]);
|
|
IdArrayType detailIndices(L[0], 1, L[1]);
|
|
PermutArrayType cA(approxIndices, coeffIn);
|
|
PermutArrayType cD(detailIndices, coeffIn);
|
|
|
|
using CoeffValueType = typename CoeffArrayType::ValueType;
|
|
using ExtensionArrayType = vtkm::cont::ArrayHandle<CoeffValueType>;
|
|
using Concat1 = vtkm::cont::ArrayHandleConcatenate<ExtensionArrayType, PermutArrayType>;
|
|
using Concat2 = vtkm::cont::ArrayHandleConcatenate<Concat1, ExtensionArrayType>;
|
|
|
|
Concat2 cATemp, cDTemp;
|
|
|
|
if (doSymConv) // Actually extend cA and cD
|
|
{
|
|
// first extend cA to be cATemp
|
|
this->Extend1D(cA, cATemp, addLen, cALeftMode, cARightMode, false, false);
|
|
|
|
// Then extend cD based on extension needs
|
|
if (cDPadLen > 0)
|
|
{
|
|
// Add back the missing final cD, 0.0, before doing extension
|
|
this->Extend1D(cD, cDTemp, addLen, cDLeftMode, cDRightMode, true, false);
|
|
}
|
|
else
|
|
{
|
|
vtkm::Id cDTempLenWouldBe = L[1] + 2 * addLen;
|
|
if (cDTempLenWouldBe == cDTempLen)
|
|
{
|
|
this->Extend1D(cD, cDTemp, addLen, cDLeftMode, cDRightMode, false, false);
|
|
}
|
|
else if (cDTempLenWouldBe == cDTempLen - 1)
|
|
{
|
|
this->Extend1D(cD, cDTemp, addLen, cDLeftMode, cDRightMode, false, true);
|
|
}
|
|
else
|
|
{
|
|
vtkm::cont::ErrorInternal("cDTemp Length not match!");
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// make cATemp
|
|
ExtensionArrayType dummyArray;
|
|
dummyArray.Allocate(0);
|
|
Concat1 cALeftOn(dummyArray, cA);
|
|
cATemp =
|
|
vtkm::cont::make_ArrayHandleConcatenate<Concat1, ExtensionArrayType>(cALeftOn, dummyArray);
|
|
|
|
// make cDTemp
|
|
Concat1 cDLeftOn(dummyArray, cD);
|
|
cDTemp =
|
|
vtkm::cont::make_ArrayHandleConcatenate<Concat1, ExtensionArrayType>(cDLeftOn, dummyArray);
|
|
}
|
|
|
|
vtkm::cont::ArrayHandleConcatenate<Concat2, Concat2> coeffInExtended(cATemp, cDTemp);
|
|
|
|
// Allocate memory for sigOut
|
|
sigOut.Allocate(cATempLen + cDTempLen);
|
|
|
|
vtkm::Float64 elapsedTime = 0;
|
|
if (filterLen % 2 != 0)
|
|
{
|
|
vtkm::worklet::wavelets::InverseTransformOdd inverseXformOdd(filterLen, L[0], cATempLen);
|
|
vtkm::worklet::DispatcherMapField<vtkm::worklet::wavelets::InverseTransformOdd> dispatcher(
|
|
inverseXformOdd);
|
|
// use a timer
|
|
vtkm::cont::Timer timer;
|
|
timer.Start();
|
|
dispatcher.Invoke(coeffInExtended,
|
|
WaveletBase::filter.GetLowReconstructFilter(),
|
|
WaveletBase::filter.GetHighReconstructFilter(),
|
|
sigOut);
|
|
elapsedTime = timer.GetElapsedTime();
|
|
}
|
|
else
|
|
{
|
|
vtkm::worklet::wavelets::InverseTransformEven inverseXformEven(
|
|
filterLen, L[0], cATempLen, !doSymConv);
|
|
vtkm::worklet::DispatcherMapField<vtkm::worklet::wavelets::InverseTransformEven> dispatcher(
|
|
inverseXformEven);
|
|
// use a timer
|
|
vtkm::cont::Timer timer;
|
|
timer.Start();
|
|
dispatcher.Invoke(coeffInExtended,
|
|
WaveletBase::filter.GetLowReconstructFilter(),
|
|
WaveletBase::filter.GetHighReconstructFilter(),
|
|
sigOut);
|
|
elapsedTime = timer.GetElapsedTime();
|
|
}
|
|
|
|
sigOut.Shrink(L[2]);
|
|
|
|
return elapsedTime;
|
|
}
|
|
|
|
// Performs one level of 2D discrete wavelet transform
|
|
// It takes care of boundary conditions, etc.
|
|
// N.B.
|
|
// L[0] == L[2]
|
|
// L[1] == L[5]
|
|
// L[3] == L[7]
|
|
// L[4] == L[6]
|
|
//
|
|
// ____L[0]_______L[4]____
|
|
// | | |
|
|
// L[1] | cA | cDv | L[5]
|
|
// | (LL) | (HL) |
|
|
// | | |
|
|
// |---------------------|
|
|
// | | |
|
|
// | cDh | cDd | L[7]
|
|
// L[3] | (LH) | (HH) |
|
|
// | | |
|
|
// |__________|__________|
|
|
// L[2] L[6]
|
|
//
|
|
// Performs one level of 2D discrete wavelet transform on a small rectangle of input array
|
|
// The output has the same size as the small rectangle
|
|
template <typename ArrayInType, typename ArrayOutType>
|
|
vtkm::Float64 DWT2D(const ArrayInType& sigIn,
|
|
vtkm::Id sigDimX,
|
|
vtkm::Id sigDimY,
|
|
vtkm::Id sigStartX,
|
|
vtkm::Id sigStartY,
|
|
vtkm::Id sigPretendDimX,
|
|
vtkm::Id sigPretendDimY,
|
|
ArrayOutType& coeffOut,
|
|
std::vector<vtkm::Id>& L)
|
|
{
|
|
L[0] = WaveletBase::GetApproxLength(sigPretendDimX);
|
|
L[2] = L[0];
|
|
L[1] = WaveletBase::GetApproxLength(sigPretendDimY);
|
|
L[5] = L[1];
|
|
L[3] = WaveletBase::GetDetailLength(sigPretendDimY);
|
|
L[7] = L[3];
|
|
L[4] = WaveletBase::GetDetailLength(sigPretendDimX);
|
|
L[6] = L[4];
|
|
L[8] = sigPretendDimX;
|
|
L[9] = sigPretendDimY;
|
|
|
|
vtkm::Id filterLen = WaveletBase::filter.GetFilterLength();
|
|
bool oddLow = true;
|
|
if (filterLen % 2 != 0)
|
|
{
|
|
oddLow = false;
|
|
}
|
|
vtkm::Id addLen = filterLen / 2;
|
|
|
|
using ValueType = typename ArrayInType::ValueType;
|
|
using ArrayType = vtkm::cont::ArrayHandle<ValueType>;
|
|
using ForwardXForm = vtkm::worklet::wavelets::ForwardTransform2D;
|
|
using DispatcherType = typename vtkm::worklet::DispatcherMapField<ForwardXForm>;
|
|
|
|
vtkm::cont::Timer timer;
|
|
vtkm::Float64 computationTime = 0.0;
|
|
|
|
ArrayType afterX;
|
|
afterX.Allocate(sigPretendDimX * sigPretendDimY);
|
|
|
|
// First transform on rows
|
|
{
|
|
ArrayType leftExt, rightExt;
|
|
this->Extend2D(sigIn,
|
|
sigDimX,
|
|
sigDimY,
|
|
sigStartX,
|
|
sigStartY,
|
|
sigPretendDimX,
|
|
sigPretendDimY,
|
|
leftExt,
|
|
rightExt,
|
|
addLen,
|
|
WaveletBase::wmode,
|
|
WaveletBase::wmode,
|
|
false,
|
|
false,
|
|
true); // Extend in left-right direction
|
|
ForwardXForm worklet(filterLen,
|
|
L[0],
|
|
oddLow,
|
|
true, // left-right
|
|
addLen,
|
|
sigPretendDimY,
|
|
sigDimX,
|
|
sigDimY,
|
|
sigStartX,
|
|
sigStartY,
|
|
sigPretendDimX,
|
|
sigPretendDimY,
|
|
addLen,
|
|
sigPretendDimY);
|
|
DispatcherType dispatcher(worklet);
|
|
timer.Start();
|
|
dispatcher.Invoke(leftExt,
|
|
sigIn,
|
|
rightExt,
|
|
WaveletBase::filter.GetLowDecomposeFilter(),
|
|
WaveletBase::filter.GetHighDecomposeFilter(),
|
|
afterX);
|
|
computationTime += timer.GetElapsedTime();
|
|
}
|
|
|
|
// Then do transform in Y direction
|
|
{
|
|
ArrayType topExt, bottomExt;
|
|
coeffOut.Allocate(sigPretendDimX * sigPretendDimY);
|
|
this->Extend2D(afterX,
|
|
sigPretendDimX,
|
|
sigPretendDimY,
|
|
0,
|
|
0,
|
|
sigPretendDimX,
|
|
sigPretendDimY,
|
|
topExt,
|
|
bottomExt,
|
|
addLen,
|
|
WaveletBase::wmode,
|
|
WaveletBase::wmode,
|
|
false,
|
|
false,
|
|
false); // Extend in top-down direction
|
|
ForwardXForm worklet(filterLen,
|
|
L[1],
|
|
oddLow,
|
|
false, // top-down
|
|
sigPretendDimX,
|
|
addLen,
|
|
sigPretendDimX,
|
|
sigPretendDimY,
|
|
0,
|
|
0,
|
|
sigPretendDimX,
|
|
sigPretendDimY,
|
|
sigPretendDimX,
|
|
addLen);
|
|
DispatcherType dispatcher(worklet);
|
|
timer.Start();
|
|
dispatcher.Invoke(topExt,
|
|
afterX,
|
|
bottomExt,
|
|
WaveletBase::filter.GetLowDecomposeFilter(),
|
|
WaveletBase::filter.GetHighDecomposeFilter(),
|
|
coeffOut);
|
|
computationTime += timer.GetElapsedTime();
|
|
}
|
|
|
|
return computationTime;
|
|
}
|
|
|
|
// Performs one level of IDWT.
|
|
// The output array has the same dimensions as the small rectangle.
|
|
template <typename ArrayInType, typename ArrayOutType>
|
|
vtkm::Float64 IDWT2D(const ArrayInType& coeffIn,
|
|
vtkm::Id inDimX,
|
|
vtkm::Id inDimY,
|
|
vtkm::Id inStartX,
|
|
vtkm::Id inStartY,
|
|
const std::vector<vtkm::Id>& L,
|
|
ArrayOutType& sigOut)
|
|
{
|
|
vtkm::Id inPretendDimX = L[0] + L[4];
|
|
vtkm::Id inPretendDimY = L[1] + L[3];
|
|
|
|
vtkm::Id filterLen = WaveletBase::filter.GetFilterLength();
|
|
using BasicArrayType = vtkm::cont::ArrayHandle<typename ArrayInType::ValueType>;
|
|
using IDWT2DWorklet = vtkm::worklet::wavelets::InverseTransform2D;
|
|
using Dispatcher = vtkm::worklet::DispatcherMapField<IDWT2DWorklet>;
|
|
vtkm::cont::Timer timer;
|
|
vtkm::Float64 computationTime = 0.0;
|
|
|
|
// First inverse transform on columns
|
|
BasicArrayType afterY;
|
|
{
|
|
BasicArrayType ext1, ext2, ext3, ext4;
|
|
vtkm::Id extDimX = inPretendDimX;
|
|
vtkm::Id ext1DimY = 0, ext2DimY = 0, ext3DimY = 0, ext4DimY = 0;
|
|
this->IDWTHelper2DTopDown(coeffIn,
|
|
inDimX,
|
|
inDimY,
|
|
inStartX,
|
|
inStartY,
|
|
inPretendDimX,
|
|
inPretendDimY,
|
|
L[1],
|
|
L[3],
|
|
ext1,
|
|
ext2,
|
|
ext3,
|
|
ext4,
|
|
ext1DimY,
|
|
ext2DimY,
|
|
ext3DimY,
|
|
ext4DimY,
|
|
filterLen,
|
|
wmode);
|
|
|
|
afterY.Allocate(inPretendDimX * inPretendDimY);
|
|
IDWT2DWorklet worklet(filterLen,
|
|
extDimX,
|
|
ext1DimY, // ext1
|
|
inPretendDimX,
|
|
L[1], // cA
|
|
extDimX,
|
|
ext2DimY, // ext2
|
|
extDimX,
|
|
ext3DimY, // ext3
|
|
inPretendDimX,
|
|
L[3], // cD
|
|
extDimX,
|
|
ext4DimY, // ext4
|
|
inDimX,
|
|
inDimY, // coeffIn
|
|
inStartX,
|
|
inStartY, // coeffIn
|
|
false); // top-down
|
|
Dispatcher dispatcher(worklet);
|
|
timer.Start();
|
|
dispatcher.Invoke(ext1,
|
|
ext2,
|
|
ext3,
|
|
ext4,
|
|
coeffIn,
|
|
WaveletBase::filter.GetLowReconstructFilter(),
|
|
WaveletBase::filter.GetHighReconstructFilter(),
|
|
afterY);
|
|
computationTime += timer.GetElapsedTime();
|
|
}
|
|
|
|
// Then inverse transform on rows
|
|
{
|
|
BasicArrayType ext1, ext2, ext3, ext4;
|
|
vtkm::Id extDimY = inPretendDimY;
|
|
vtkm::Id ext1DimX = 0, ext2DimX = 0, ext3DimX = 0, ext4DimX = 0;
|
|
this->IDWTHelper2DLeftRight(afterY,
|
|
inPretendDimX,
|
|
inPretendDimY,
|
|
0,
|
|
0,
|
|
inPretendDimX,
|
|
inPretendDimY,
|
|
L[0],
|
|
L[4],
|
|
ext1,
|
|
ext2,
|
|
ext3,
|
|
ext4,
|
|
ext1DimX,
|
|
ext2DimX,
|
|
ext3DimX,
|
|
ext4DimX,
|
|
filterLen,
|
|
wmode);
|
|
sigOut.Allocate(inPretendDimX * inPretendDimY);
|
|
IDWT2DWorklet worklet(filterLen,
|
|
ext1DimX,
|
|
extDimY, // ext1
|
|
L[0],
|
|
inPretendDimY, // cA
|
|
ext2DimX,
|
|
extDimY, // ext2
|
|
ext3DimX,
|
|
extDimY, // ext3
|
|
L[4],
|
|
inPretendDimY, // cA
|
|
ext4DimX,
|
|
extDimY, // ext4
|
|
inPretendDimX,
|
|
inPretendDimY,
|
|
0,
|
|
0,
|
|
true); // left-right
|
|
Dispatcher dispatcher(worklet);
|
|
timer.Start();
|
|
dispatcher.Invoke(ext1,
|
|
ext2,
|
|
ext3,
|
|
ext4,
|
|
afterY,
|
|
WaveletBase::filter.GetLowReconstructFilter(),
|
|
WaveletBase::filter.GetHighReconstructFilter(),
|
|
sigOut);
|
|
computationTime += timer.GetElapsedTime();
|
|
}
|
|
|
|
return computationTime;
|
|
}
|
|
|
|
// decides the correct extension modes for cA and cD separately,
|
|
// and fill the extensions (2D matrices)
|
|
template <typename ArrayInType, typename ArrayOutType>
|
|
void IDWTHelper2DLeftRight(const ArrayInType& coeffIn,
|
|
vtkm::Id inDimX,
|
|
vtkm::Id inDimY,
|
|
vtkm::Id inStartX,
|
|
vtkm::Id inStartY,
|
|
vtkm::Id inPretendDimX,
|
|
vtkm::Id inPretendDimY,
|
|
vtkm::Id cADimX,
|
|
vtkm::Id cDDimX,
|
|
ArrayOutType& ext1,
|
|
ArrayOutType& ext2, // output
|
|
ArrayOutType& ext3,
|
|
ArrayOutType& ext4, // output
|
|
vtkm::Id& ext1DimX,
|
|
vtkm::Id& ext2DimX, // output
|
|
vtkm::Id& ext3DimX,
|
|
vtkm::Id& ext4DimX, // output
|
|
vtkm::Id filterLen,
|
|
DWTMode mode)
|
|
{
|
|
VTKM_ASSERT(inPretendDimX == (cADimX + cDDimX));
|
|
|
|
// determine extension modes
|
|
DWTMode cALeft, cARight, cDLeft, cDRight;
|
|
cALeft = cARight = cDLeft = cDRight = mode;
|
|
if (mode == SYMH)
|
|
{
|
|
cDLeft = ASYMH;
|
|
if (inPretendDimX % 2 != 0)
|
|
{
|
|
cARight = SYMW;
|
|
cDRight = ASYMW;
|
|
}
|
|
else
|
|
{
|
|
cDRight = ASYMH;
|
|
}
|
|
}
|
|
else // mode == SYMW
|
|
{
|
|
cDLeft = SYMH;
|
|
if (inPretendDimX % 2 != 0)
|
|
{
|
|
cARight = SYMW;
|
|
cDRight = SYMH;
|
|
}
|
|
else
|
|
{
|
|
cARight = SYMH;
|
|
}
|
|
}
|
|
// determine length after extension
|
|
vtkm::Id cAExtendedDimX, cDExtendedDimX;
|
|
vtkm::Id cDPadLen = 0;
|
|
vtkm::Id addLen = filterLen / 4; // addLen == 0 for Haar kernel
|
|
if ((cADimX > cDDimX) && (mode == SYMH))
|
|
{
|
|
cDPadLen = cADimX;
|
|
}
|
|
cAExtendedDimX = cADimX + 2 * addLen;
|
|
cDExtendedDimX = cAExtendedDimX;
|
|
|
|
// extend cA
|
|
vtkm::Id cADimY = inPretendDimY;
|
|
this->Extend2D(coeffIn,
|
|
inDimX,
|
|
inDimY,
|
|
inStartX,
|
|
inStartY,
|
|
cADimX,
|
|
cADimY,
|
|
ext1,
|
|
ext2,
|
|
addLen,
|
|
cALeft,
|
|
cARight,
|
|
false,
|
|
false,
|
|
true);
|
|
|
|
ext1DimX = ext2DimX = addLen;
|
|
|
|
// extend cD
|
|
vtkm::Id cDDimY = inPretendDimY;
|
|
if (cDPadLen > 0)
|
|
{
|
|
this->Extend2D(coeffIn,
|
|
inDimX,
|
|
inDimY,
|
|
inStartX + cADimX,
|
|
inStartY,
|
|
cDDimX,
|
|
cDDimY,
|
|
ext3,
|
|
ext4,
|
|
addLen,
|
|
cDLeft,
|
|
cDRight,
|
|
true,
|
|
false,
|
|
true);
|
|
ext3DimX = addLen;
|
|
ext4DimX = addLen + 1;
|
|
}
|
|
else
|
|
{
|
|
vtkm::Id cDExtendedWouldBe = cDDimX + 2 * addLen;
|
|
if (cDExtendedWouldBe == cDExtendedDimX)
|
|
{
|
|
this->Extend2D(coeffIn,
|
|
inDimX,
|
|
inDimY,
|
|
inStartX + cADimX,
|
|
inStartY,
|
|
cDDimX,
|
|
cDDimY,
|
|
ext3,
|
|
ext4,
|
|
addLen,
|
|
cDLeft,
|
|
cDRight,
|
|
false,
|
|
false,
|
|
true);
|
|
ext3DimX = ext4DimX = addLen;
|
|
}
|
|
else if (cDExtendedWouldBe == cDExtendedDimX - 1)
|
|
{
|
|
this->Extend2D(coeffIn,
|
|
inDimX,
|
|
inDimY,
|
|
inStartX + cADimX,
|
|
inStartY,
|
|
cDDimX,
|
|
cDDimY,
|
|
ext3,
|
|
ext4,
|
|
addLen,
|
|
cDLeft,
|
|
cDRight,
|
|
false,
|
|
true,
|
|
true);
|
|
ext3DimX = addLen;
|
|
ext4DimX = addLen + 1;
|
|
}
|
|
else
|
|
{
|
|
vtkm::cont::ErrorInternal("cDTemp Length not match!");
|
|
}
|
|
}
|
|
}
|
|
|
|
// decides the correct extension modes for cA and cD separately,
|
|
// and fill the extensions (2D matrices)
|
|
template <typename ArrayInType, typename ArrayOutType>
|
|
void IDWTHelper2DTopDown(const ArrayInType& coeffIn,
|
|
vtkm::Id inDimX,
|
|
vtkm::Id inDimY,
|
|
vtkm::Id inStartX,
|
|
vtkm::Id inStartY,
|
|
vtkm::Id inPretendDimX,
|
|
vtkm::Id inPretendDimY,
|
|
vtkm::Id cADimY,
|
|
vtkm::Id cDDimY,
|
|
ArrayOutType& ext1,
|
|
ArrayOutType& ext2, // output
|
|
ArrayOutType& ext3,
|
|
ArrayOutType& ext4, // output
|
|
vtkm::Id& ext1DimY,
|
|
vtkm::Id& ext2DimY, // output
|
|
vtkm::Id& ext3DimY,
|
|
vtkm::Id& ext4DimY, // output
|
|
vtkm::Id filterLen,
|
|
DWTMode mode)
|
|
{
|
|
VTKM_ASSERT(inPretendDimY == (cADimY + cDDimY));
|
|
|
|
// determine extension modes
|
|
DWTMode cATopMode, cADownMode, cDTopMode, cDDownMode;
|
|
cATopMode = cADownMode = cDTopMode = cDDownMode = mode;
|
|
if (mode == SYMH)
|
|
{
|
|
cDTopMode = ASYMH;
|
|
if (inPretendDimY % 2 != 0)
|
|
{
|
|
cADownMode = SYMW;
|
|
cDDownMode = ASYMW;
|
|
}
|
|
else
|
|
{
|
|
cDDownMode = ASYMH;
|
|
}
|
|
}
|
|
else // mode == SYMW
|
|
{
|
|
cDTopMode = SYMH;
|
|
if (inPretendDimY % 2 != 0)
|
|
{
|
|
cADownMode = SYMW;
|
|
cDDownMode = SYMH;
|
|
}
|
|
else
|
|
{
|
|
cADownMode = SYMH;
|
|
}
|
|
}
|
|
// determine length after extension
|
|
vtkm::Id cAExtendedDimY, cDExtendedDimY;
|
|
vtkm::Id cDPadLen = 0;
|
|
vtkm::Id addLen = filterLen / 4; // addLen == 0 for Haar kernel
|
|
if ((cADimY > cDDimY) && (mode == SYMH))
|
|
cDPadLen = cADimY;
|
|
cAExtendedDimY = cADimY + 2 * addLen;
|
|
cDExtendedDimY = cAExtendedDimY;
|
|
|
|
// extend cA
|
|
vtkm::Id cADimX = inPretendDimX;
|
|
this->Extend2D(coeffIn,
|
|
inDimX,
|
|
inDimY,
|
|
inStartX,
|
|
inStartY,
|
|
cADimX,
|
|
cADimY,
|
|
ext1,
|
|
ext2,
|
|
addLen,
|
|
cATopMode,
|
|
cADownMode,
|
|
false,
|
|
false,
|
|
false);
|
|
ext1DimY = ext2DimY = addLen;
|
|
|
|
// extend cD
|
|
vtkm::Id cDDimX = inPretendDimX;
|
|
if (cDPadLen > 0)
|
|
{
|
|
this->Extend2D(coeffIn,
|
|
inDimX,
|
|
inDimY,
|
|
inStartX,
|
|
inStartY + cADimY,
|
|
cDDimX,
|
|
cDDimY,
|
|
ext3,
|
|
ext4,
|
|
addLen,
|
|
cDTopMode,
|
|
cDDownMode,
|
|
true,
|
|
false,
|
|
false);
|
|
ext3DimY = addLen;
|
|
ext4DimY = addLen + 1;
|
|
}
|
|
else
|
|
{
|
|
vtkm::Id cDExtendedWouldBe = cDDimY + 2 * addLen;
|
|
if (cDExtendedWouldBe == cDExtendedDimY)
|
|
{
|
|
this->Extend2D(coeffIn,
|
|
inDimX,
|
|
inDimY,
|
|
inStartX,
|
|
inStartY + cADimY,
|
|
cDDimX,
|
|
cDDimY,
|
|
ext3,
|
|
ext4,
|
|
addLen,
|
|
cDTopMode,
|
|
cDDownMode,
|
|
false,
|
|
false,
|
|
false);
|
|
ext3DimY = ext4DimY = addLen;
|
|
}
|
|
else if (cDExtendedWouldBe == cDExtendedDimY - 1)
|
|
{
|
|
this->Extend2D(coeffIn,
|
|
inDimX,
|
|
inDimY,
|
|
inStartX,
|
|
inStartY + cADimY,
|
|
cDDimX,
|
|
cDDimY,
|
|
ext3,
|
|
ext4,
|
|
addLen,
|
|
cDTopMode,
|
|
cDDownMode,
|
|
false,
|
|
true,
|
|
false);
|
|
ext3DimY = addLen;
|
|
ext4DimY = addLen + 1;
|
|
}
|
|
else
|
|
{
|
|
vtkm::cont::ErrorInternal("cDTemp Length not match!");
|
|
}
|
|
}
|
|
}
|
|
|
|
// decides the correct extension modes for cA and cD separately,
|
|
// and fill the extensions (3D cubes)
|
|
template <typename ArrayInType, typename ArrayOutType>
|
|
void IDWTHelper3DLeftRight(const ArrayInType& coeffIn,
|
|
vtkm::Id inDimX,
|
|
vtkm::Id inDimY,
|
|
vtkm::Id inDimZ,
|
|
vtkm::Id inStartX,
|
|
vtkm::Id inStartY,
|
|
vtkm::Id inStartZ,
|
|
vtkm::Id inPretendDimX,
|
|
vtkm::Id inPretendDimY,
|
|
vtkm::Id inPretendDimZ,
|
|
vtkm::Id cADimX,
|
|
vtkm::Id cDDimX,
|
|
ArrayOutType& ext1,
|
|
ArrayOutType& ext2, // output
|
|
ArrayOutType& ext3,
|
|
ArrayOutType& ext4, // output
|
|
vtkm::Id& ext1DimX,
|
|
vtkm::Id& ext2DimX, // output
|
|
vtkm::Id& ext3DimX,
|
|
vtkm::Id& ext4DimX, // output
|
|
vtkm::Id filterLen,
|
|
DWTMode mode)
|
|
{
|
|
VTKM_ASSERT(inPretendDimX == (cADimX + cDDimX));
|
|
|
|
// determine extension modes
|
|
DWTMode cALeftMode, cARightMode, cDLeftMode, cDRightMode;
|
|
cALeftMode = cARightMode = cDLeftMode = cDRightMode = mode;
|
|
if (mode == SYMH)
|
|
{
|
|
cDLeftMode = ASYMH;
|
|
if (inPretendDimX % 2 != 0)
|
|
{
|
|
cARightMode = SYMW;
|
|
cDRightMode = ASYMW;
|
|
}
|
|
else
|
|
{
|
|
cDRightMode = ASYMH;
|
|
}
|
|
}
|
|
else // mode == SYMW
|
|
{
|
|
cDLeftMode = SYMH;
|
|
if (inPretendDimX % 2 != 0)
|
|
{
|
|
cARightMode = SYMW;
|
|
cDRightMode = SYMH;
|
|
}
|
|
else
|
|
{
|
|
cARightMode = SYMH;
|
|
}
|
|
}
|
|
|
|
// determine length after extension
|
|
vtkm::Id cAExtendedDimX, cDExtendedDimX;
|
|
vtkm::Id cDPadLen = 0;
|
|
vtkm::Id addLen = filterLen / 4; // addLen == 0 for Haar kernel
|
|
if ((cADimX > cDDimX) && (mode == SYMH))
|
|
{
|
|
cDPadLen = cADimX;
|
|
}
|
|
cAExtendedDimX = cADimX + 2 * addLen;
|
|
cDExtendedDimX = cAExtendedDimX;
|
|
|
|
// extend cA
|
|
vtkm::Id cADimY = inPretendDimY;
|
|
vtkm::Id cADimZ = inPretendDimZ;
|
|
this->Extend3DLeftRight(coeffIn,
|
|
inDimX,
|
|
inDimY,
|
|
inDimZ,
|
|
inStartX,
|
|
inStartY,
|
|
inStartZ,
|
|
cADimX,
|
|
cADimY,
|
|
cADimZ,
|
|
ext1,
|
|
ext2,
|
|
addLen,
|
|
cALeftMode,
|
|
cARightMode,
|
|
false,
|
|
false);
|
|
ext1DimX = ext2DimX = addLen;
|
|
|
|
// extend cD
|
|
vtkm::Id cDDimY = inPretendDimY;
|
|
vtkm::Id cDDimZ = inPretendDimZ;
|
|
bool pretendSigPaddedZero, padZeroAtExt2;
|
|
if (cDPadLen > 0)
|
|
{
|
|
ext3DimX = addLen;
|
|
ext4DimX = addLen + 1;
|
|
pretendSigPaddedZero = true;
|
|
padZeroAtExt2 = false;
|
|
}
|
|
else
|
|
{
|
|
vtkm::Id cDExtendedWouldBe = cDDimX + 2 * addLen;
|
|
if (cDExtendedWouldBe == cDExtendedDimX)
|
|
{
|
|
ext3DimX = ext4DimX = addLen;
|
|
pretendSigPaddedZero = false;
|
|
padZeroAtExt2 = false;
|
|
}
|
|
else if (cDExtendedWouldBe == cDExtendedDimX - 1)
|
|
{
|
|
ext3DimX = addLen;
|
|
ext4DimX = addLen + 1;
|
|
pretendSigPaddedZero = false;
|
|
padZeroAtExt2 = true;
|
|
}
|
|
else
|
|
{
|
|
pretendSigPaddedZero = padZeroAtExt2 = false; // so the compiler doesn't complain
|
|
vtkm::cont::ErrorInternal("cDTemp Length not match!");
|
|
}
|
|
}
|
|
this->Extend3DLeftRight(coeffIn,
|
|
inDimX,
|
|
inDimY,
|
|
inDimZ,
|
|
inStartX + cADimX,
|
|
inStartY,
|
|
inStartZ,
|
|
cDDimX,
|
|
cDDimY,
|
|
cDDimZ,
|
|
ext3,
|
|
ext4,
|
|
addLen,
|
|
cDLeftMode,
|
|
cDRightMode,
|
|
pretendSigPaddedZero,
|
|
padZeroAtExt2);
|
|
}
|
|
|
|
template <typename ArrayInType, typename ArrayOutType>
|
|
void IDWTHelper3DTopDown(const ArrayInType& coeffIn,
|
|
vtkm::Id inDimX,
|
|
vtkm::Id inDimY,
|
|
vtkm::Id inDimZ,
|
|
vtkm::Id inStartX,
|
|
vtkm::Id inStartY,
|
|
vtkm::Id inStartZ,
|
|
vtkm::Id inPretendDimX,
|
|
vtkm::Id inPretendDimY,
|
|
vtkm::Id inPretendDimZ,
|
|
vtkm::Id cADimY,
|
|
vtkm::Id cDDimY,
|
|
ArrayOutType& ext1,
|
|
ArrayOutType& ext2, // output
|
|
ArrayOutType& ext3,
|
|
ArrayOutType& ext4, // output
|
|
vtkm::Id& ext1DimY,
|
|
vtkm::Id& ext2DimY, // output
|
|
vtkm::Id& ext3DimY,
|
|
vtkm::Id& ext4DimY, // output
|
|
vtkm::Id filterLen,
|
|
DWTMode mode)
|
|
{
|
|
VTKM_ASSERT(inPretendDimY == (cADimY + cDDimY));
|
|
|
|
// determine extension modes
|
|
DWTMode cATopMode, cADownMode, cDTopMode, cDDownMode;
|
|
cATopMode = cADownMode = cDTopMode = cDDownMode = mode;
|
|
if (mode == SYMH)
|
|
{
|
|
cDTopMode = ASYMH;
|
|
if (inPretendDimY % 2 != 0)
|
|
{
|
|
cADownMode = SYMW;
|
|
cDDownMode = ASYMW;
|
|
}
|
|
else
|
|
{
|
|
cDDownMode = ASYMH;
|
|
}
|
|
}
|
|
else // mode == SYMW
|
|
{
|
|
cDTopMode = SYMH;
|
|
if (inPretendDimY % 2 != 0)
|
|
{
|
|
cADownMode = SYMW;
|
|
cDDownMode = SYMH;
|
|
}
|
|
else
|
|
{
|
|
cADownMode = SYMH;
|
|
}
|
|
}
|
|
|
|
// determine length after extension
|
|
vtkm::Id cAExtendedDimY, cDExtendedDimY;
|
|
vtkm::Id cDPadLen = 0;
|
|
vtkm::Id addLen = filterLen / 4; // addLen == 0 for Haar kernel
|
|
if ((cADimY > cDDimY) && (mode == SYMH))
|
|
{
|
|
cDPadLen = cADimY;
|
|
}
|
|
cAExtendedDimY = cADimY + 2 * addLen;
|
|
cDExtendedDimY = cAExtendedDimY;
|
|
|
|
// extend cA
|
|
vtkm::Id cADimX = inPretendDimX;
|
|
vtkm::Id cADimZ = inPretendDimZ;
|
|
this->Extend3DTopDown(coeffIn,
|
|
inDimX,
|
|
inDimY,
|
|
inDimZ,
|
|
inStartX,
|
|
inStartY,
|
|
inStartZ,
|
|
cADimX,
|
|
cADimY,
|
|
cADimZ,
|
|
ext1,
|
|
ext2,
|
|
addLen,
|
|
cATopMode,
|
|
cADownMode,
|
|
false,
|
|
false);
|
|
ext1DimY = ext2DimY = addLen;
|
|
|
|
// extend cD
|
|
vtkm::Id cDDimX = inPretendDimX;
|
|
vtkm::Id cDDimZ = inPretendDimZ;
|
|
bool pretendSigPaddedZero, padZeroAtExt2;
|
|
if (cDPadLen > 0)
|
|
{
|
|
ext3DimY = addLen;
|
|
ext4DimY = addLen + 1;
|
|
pretendSigPaddedZero = true;
|
|
padZeroAtExt2 = false;
|
|
}
|
|
else
|
|
{
|
|
vtkm::Id cDExtendedWouldBe = cDDimY + 2 * addLen;
|
|
if (cDExtendedWouldBe == cDExtendedDimY)
|
|
{
|
|
ext3DimY = ext4DimY = addLen;
|
|
pretendSigPaddedZero = false;
|
|
padZeroAtExt2 = false;
|
|
}
|
|
else if (cDExtendedWouldBe == cDExtendedDimY - 1)
|
|
{
|
|
ext3DimY = addLen;
|
|
ext4DimY = addLen + 1;
|
|
pretendSigPaddedZero = false;
|
|
padZeroAtExt2 = true;
|
|
}
|
|
else
|
|
{
|
|
pretendSigPaddedZero = padZeroAtExt2 = false; // so the compiler doesn't complain
|
|
vtkm::cont::ErrorInternal("cDTemp Length not match!");
|
|
}
|
|
}
|
|
this->Extend3DTopDown(coeffIn,
|
|
inDimX,
|
|
inDimY,
|
|
inDimZ,
|
|
inStartX,
|
|
inStartY + cADimY,
|
|
inStartZ,
|
|
cDDimX,
|
|
cDDimY,
|
|
cDDimZ,
|
|
ext3,
|
|
ext4,
|
|
addLen,
|
|
cDTopMode,
|
|
cDDownMode,
|
|
pretendSigPaddedZero,
|
|
padZeroAtExt2);
|
|
}
|
|
|
|
template <typename ArrayInType, typename ArrayOutType>
|
|
void IDWTHelper3DFrontBack(const ArrayInType& coeffIn,
|
|
vtkm::Id inDimX,
|
|
vtkm::Id inDimY,
|
|
vtkm::Id inDimZ,
|
|
vtkm::Id inStartX,
|
|
vtkm::Id inStartY,
|
|
vtkm::Id inStartZ,
|
|
vtkm::Id inPretendDimX,
|
|
vtkm::Id inPretendDimY,
|
|
vtkm::Id inPretendDimZ,
|
|
vtkm::Id cADimZ,
|
|
vtkm::Id cDDimZ,
|
|
ArrayOutType& ext1,
|
|
ArrayOutType& ext2, // output
|
|
ArrayOutType& ext3,
|
|
ArrayOutType& ext4, // output
|
|
vtkm::Id& ext1DimZ,
|
|
vtkm::Id& ext2DimZ, // output
|
|
vtkm::Id& ext3DimZ,
|
|
vtkm::Id& ext4DimZ, // output
|
|
vtkm::Id filterLen,
|
|
DWTMode mode)
|
|
{
|
|
VTKM_ASSERT(inPretendDimZ == (cADimZ + cDDimZ));
|
|
|
|
// determine extension modes
|
|
DWTMode cAFrontMode, cABackMode, cDFrontMode, cDBackMode;
|
|
cAFrontMode = cABackMode = cDFrontMode = cDBackMode = mode;
|
|
if (mode == SYMH)
|
|
{
|
|
cDFrontMode = ASYMH;
|
|
if (inPretendDimZ % 2 != 0)
|
|
{
|
|
cABackMode = SYMW;
|
|
cDBackMode = ASYMW;
|
|
}
|
|
else
|
|
{
|
|
cDBackMode = ASYMH;
|
|
}
|
|
}
|
|
else // mode == SYMW
|
|
{
|
|
cDFrontMode = SYMH;
|
|
if (inPretendDimZ % 2 != 0)
|
|
{
|
|
cABackMode = SYMW;
|
|
cDBackMode = SYMH;
|
|
}
|
|
else
|
|
{
|
|
cABackMode = SYMH;
|
|
}
|
|
}
|
|
|
|
// determine length after extension
|
|
vtkm::Id cAExtendedDimZ, cDExtendedDimZ;
|
|
vtkm::Id cDPadLen = 0;
|
|
vtkm::Id addLen = filterLen / 4; // addLen == 0 for Haar kernel
|
|
if ((cADimZ > cDDimZ) && (mode == SYMH))
|
|
{
|
|
cDPadLen = cADimZ;
|
|
}
|
|
cAExtendedDimZ = cADimZ + 2 * addLen;
|
|
cDExtendedDimZ = cAExtendedDimZ;
|
|
|
|
// extend cA
|
|
vtkm::Id cADimX = inPretendDimX;
|
|
vtkm::Id cADimY = inPretendDimY;
|
|
this->Extend3DFrontBack(coeffIn,
|
|
inDimX,
|
|
inDimY,
|
|
inDimZ,
|
|
inStartX,
|
|
inStartY,
|
|
inStartZ,
|
|
cADimX,
|
|
cADimY,
|
|
cADimZ,
|
|
ext1,
|
|
ext2,
|
|
addLen,
|
|
cAFrontMode,
|
|
cABackMode,
|
|
false,
|
|
false);
|
|
ext1DimZ = ext2DimZ = addLen;
|
|
|
|
// extend cD
|
|
vtkm::Id cDDimX = inPretendDimX;
|
|
vtkm::Id cDDimY = inPretendDimY;
|
|
bool pretendSigPaddedZero, padZeroAtExt2;
|
|
if (cDPadLen > 0)
|
|
{
|
|
ext3DimZ = addLen;
|
|
ext4DimZ = addLen + 1;
|
|
pretendSigPaddedZero = true;
|
|
padZeroAtExt2 = false;
|
|
}
|
|
else
|
|
{
|
|
vtkm::Id cDExtendedWouldBe = cDDimZ + 2 * addLen;
|
|
if (cDExtendedWouldBe == cDExtendedDimZ)
|
|
{
|
|
ext3DimZ = ext4DimZ = addLen;
|
|
pretendSigPaddedZero = false;
|
|
padZeroAtExt2 = false;
|
|
}
|
|
else if (cDExtendedWouldBe == cDExtendedDimZ - 1)
|
|
{
|
|
ext3DimZ = addLen;
|
|
ext4DimZ = addLen + 1;
|
|
pretendSigPaddedZero = false;
|
|
padZeroAtExt2 = true;
|
|
}
|
|
else
|
|
{
|
|
pretendSigPaddedZero = padZeroAtExt2 = false; // so the compiler doesn't complain
|
|
vtkm::cont::ErrorInternal("cDTemp Length not match!");
|
|
}
|
|
}
|
|
this->Extend3DFrontBack(coeffIn,
|
|
inDimX,
|
|
inDimY,
|
|
inDimZ,
|
|
inStartX,
|
|
inStartY,
|
|
inStartZ + cADimZ,
|
|
cDDimX,
|
|
cDDimY,
|
|
cDDimZ,
|
|
ext3,
|
|
ext4,
|
|
addLen,
|
|
cDFrontMode,
|
|
cDBackMode,
|
|
pretendSigPaddedZero,
|
|
padZeroAtExt2);
|
|
}
|
|
};
|
|
|
|
} // namespace wavelets
|
|
} // namespace worklet
|
|
} // namespace vtkm
|
|
|
|
#endif
|