vtk-m/vtkm/filter/image_processing/worklet/ComputeMoments.h

320 lines
10 KiB
C
Raw Permalink Normal View History

2019-04-23 22:14:56 +00:00
//============================================================================
2019-04-23 14:57:35 +00:00
//
2019-04-23 14:57:35 +00:00
// 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.
2019-04-23 14:57:35 +00:00
//
2019-04-23 22:14:56 +00:00
//=======================================================================
2019-04-23 14:57:35 +00:00
#ifndef vtk_m_worklet_moments_ComputeMoments_h
#define vtk_m_worklet_moments_ComputeMoments_h
2019-06-14 18:46:43 +00:00
#include <vtkm/Math.h>
2019-04-23 14:57:35 +00:00
#include <vtkm/worklet/WorkletPointNeighborhood.h>
#include <vtkm/cont/ArrayHandleRecombineVec.h>
#include <vtkm/cont/ArrayHandleRuntimeVec.h>
#include <vtkm/cont/DataSet.h>
2019-07-24 15:32:03 +00:00
#include <vtkm/cont/Field.h>
#include <vtkm/cont/UncertainArrayHandle.h>
2022-02-07 17:03:08 +00:00
#include <vtkm/cont/UncertainCellSet.h>
2019-07-24 15:32:03 +00:00
#include <vtkm/exec/BoundaryState.h>
#include <cassert>
#include <string>
2019-04-23 14:57:35 +00:00
namespace vtkm
{
namespace worklet
{
namespace moments
{
struct ComputeMoments2D : public vtkm::worklet::WorkletPointNeighborhood
2019-04-23 14:57:35 +00:00
{
public:
2022-02-07 17:51:04 +00:00
ComputeMoments2D(const vtkm::Vec3f& _spacing, vtkm::Float64 _radius, int _p, int _q)
2022-02-07 18:09:59 +00:00
: RadiusDiscrete(vtkm::IdComponent(_radius / (_spacing[0] - 1e-10)),
2019-10-16 13:47:29 +00:00
vtkm::IdComponent(_radius / (_spacing[1] - 1e-10)),
vtkm::IdComponent(_radius / (_spacing[2] - 1e-10)))
, SpacingProduct(_spacing[0] * _spacing[1])
2019-04-23 14:57:35 +00:00
, p(_p)
, q(_q)
{
assert(_spacing[0] > 1e-10);
assert(_spacing[1] > 1e-10);
assert(_spacing[2] > 1e-10);
2019-06-17 18:27:52 +00:00
2019-04-23 14:57:35 +00:00
assert(_p >= 0);
assert(_q >= 0);
}
using ControlSignature = void(CellSetIn, FieldInNeighborhood, FieldOut);
using ExecutionSignature = void(_2, Boundary, _3);
2019-04-23 14:57:35 +00:00
template <typename NeighIn, typename TOut>
VTKM_EXEC void operator()(const NeighIn& image,
const vtkm::exec::BoundaryState& boundary,
TOut& moment) const
2019-04-23 14:57:35 +00:00
{
using ComponentType = typename TOut::ComponentType;
const vtkm::IdComponent numComponents = moment.GetNumberOfComponents();
// For variable sized Vecs, need to iterate over each component.
for (vtkm::IdComponent componentI = 0; componentI < numComponents; ++componentI)
{
moment[componentI] = vtkm::TypeTraits<ComponentType>::ZeroInitialization();
}
// Clamp the radius to the dataset bounds (discard out-of-bounds points).
2019-10-16 13:47:29 +00:00
const auto minRadius = boundary.ClampNeighborIndex(-this->RadiusDiscrete);
const auto maxRadius = boundary.ClampNeighborIndex(this->RadiusDiscrete);
2019-10-16 13:47:29 +00:00
vtkm::Vec2f_64 radius;
for (vtkm::IdComponent j = minRadius[1]; j <= maxRadius[1]; ++j)
{
2019-10-16 13:47:29 +00:00
if (j > -this->RadiusDiscrete[1] && boundary.IJK[1] + j == 0)
{ // Don't double count samples that exist on other nodes:
continue;
}
2019-10-16 13:47:29 +00:00
radius[1] = j * 1. / this->RadiusDiscrete[1];
for (vtkm::IdComponent i = minRadius[0]; i <= maxRadius[0]; ++i)
{
2019-10-16 13:47:29 +00:00
if (i > -this->RadiusDiscrete[0] && boundary.IJK[0] + i == 0)
{ // Don't double count samples that exist on other nodes:
continue;
}
2019-10-16 13:47:29 +00:00
radius[0] = i * 1. / this->RadiusDiscrete[0];
2019-10-16 13:47:29 +00:00
if (vtkm::Dot(radius, radius) <= 1)
{
ComponentType multiplier =
static_cast<ComponentType>(vtkm::Pow(radius[0], p) * vtkm::Pow(radius[1], q));
auto inputField = image.Get(i, j, 0);
// For variable sized Vecs, need to iterate over each component.
for (vtkm::IdComponent componentI = 0; componentI < numComponents; ++componentI)
{
moment[componentI] += multiplier * inputField[componentI];
}
}
}
}
// For variable sized Vecs, need to iterate over each component.
for (vtkm::IdComponent componentI = 0; componentI < numComponents; ++componentI)
{
moment[componentI] *= static_cast<ComponentType>(this->SpacingProduct);
}
}
private:
2019-10-16 13:47:29 +00:00
vtkm::Vec3i_32 RadiusDiscrete;
2022-02-07 17:51:04 +00:00
const vtkm::Float64 SpacingProduct;
const int p;
const int q;
};
struct ComputeMoments3D : public vtkm::worklet::WorkletPointNeighborhood
{
public:
2022-02-07 17:51:04 +00:00
ComputeMoments3D(const vtkm::Vec3f& _spacing, vtkm::Float64 _radius, int _p, int _q, int _r)
2022-02-07 18:09:59 +00:00
: RadiusDiscrete(vtkm::IdComponent(_radius / (_spacing[0] - 1e-10)),
2019-10-16 13:47:29 +00:00
vtkm::IdComponent(_radius / (_spacing[1] - 1e-10)),
vtkm::IdComponent(_radius / (_spacing[2] - 1e-10)))
, SpacingProduct(vtkm::ReduceProduct(_spacing))
, p(_p)
, q(_q)
, r(_r)
{
assert(_spacing[0] > 1e-10);
assert(_spacing[1] > 1e-10);
assert(_spacing[2] > 1e-10);
2019-07-24 15:32:03 +00:00
assert(_p >= 0);
assert(_q >= 0);
assert(_r >= 0);
}
using ControlSignature = void(CellSetIn, FieldInNeighborhood, FieldOut);
using ExecutionSignature = void(_2, Boundary, _3);
template <typename NeighIn, typename TOut>
VTKM_EXEC void operator()(const NeighIn& image,
const vtkm::exec::BoundaryState& boundary,
TOut& moment) const
{
using ComponentType = typename TOut::ComponentType;
const vtkm::IdComponent numComponents = moment.GetNumberOfComponents();
// For variable sized Vecs, need to iterate over each component.
for (vtkm::IdComponent componentI = 0; componentI < numComponents; ++componentI)
{
moment[componentI] = vtkm::TypeTraits<ComponentType>::ZeroInitialization();
}
// Clamp the radius to the dataset bounds (discard out-of-bounds points).
2019-10-16 13:47:29 +00:00
const auto minRadius = boundary.ClampNeighborIndex(-this->RadiusDiscrete);
const auto maxRadius = boundary.ClampNeighborIndex(this->RadiusDiscrete);
2019-10-16 13:47:29 +00:00
vtkm::Vec3f_64 radius;
for (vtkm::IdComponent k = minRadius[2]; k <= maxRadius[2]; ++k)
2019-04-23 14:57:35 +00:00
{
2019-10-16 13:47:29 +00:00
if (k > -this->RadiusDiscrete[2] && boundary.IJK[2] + k == 0)
{ // Don't double count samples that exist on other nodes:
continue;
}
2019-10-16 13:47:29 +00:00
radius[2] = k * 1. / this->RadiusDiscrete[2];
for (vtkm::IdComponent j = minRadius[1]; j <= maxRadius[1]; ++j)
2019-04-23 14:57:35 +00:00
{
2019-10-16 13:47:29 +00:00
if (j > -this->RadiusDiscrete[1] && boundary.IJK[1] + j == 0)
{ // Don't double count samples that exist on other nodes:
continue;
}
2019-10-16 13:47:29 +00:00
radius[1] = j * 1. / this->RadiusDiscrete[1];
for (vtkm::IdComponent i = minRadius[0]; i <= maxRadius[0]; ++i)
2019-04-23 22:34:07 +00:00
{
2019-10-16 13:47:29 +00:00
if (i > -this->RadiusDiscrete[0] && boundary.IJK[0] + i == 0)
{ // Don't double count samples that exist on other nodes:
continue;
}
2019-10-16 13:47:29 +00:00
radius[0] = i * 1. / this->RadiusDiscrete[0];
2019-10-16 13:47:29 +00:00
if (vtkm::Dot(radius, radius) <= 1)
2019-07-24 15:32:03 +00:00
{
ComponentType multiplier = static_cast<ComponentType>(
vtkm::Pow(radius[0], p) * vtkm::Pow(radius[1], q) * vtkm::Pow(radius[2], r));
auto inputField = image.Get(i, j, k);
// For variable sized Vecs, need to iterate over each component.
for (vtkm::IdComponent componentI = 0; componentI < numComponents; ++componentI)
{
moment[componentI] += multiplier * inputField[componentI];
}
2019-07-24 15:32:03 +00:00
}
2019-04-23 22:34:07 +00:00
}
2019-04-23 14:57:35 +00:00
}
}
// For variable sized Vecs, need to iterate over each component.
for (vtkm::IdComponent componentI = 0; componentI < numComponents; ++componentI)
{
moment[componentI] *= static_cast<ComponentType>(this->SpacingProduct);
}
2019-04-23 14:57:35 +00:00
}
private:
2019-10-16 13:47:29 +00:00
vtkm::Vec3i_32 RadiusDiscrete;
2022-02-07 17:51:04 +00:00
const vtkm::Float64 SpacingProduct;
2019-04-23 14:57:35 +00:00
const int p;
const int q;
const int r;
};
class ComputeMoments
{
public:
2022-02-07 17:03:08 +00:00
ComputeMoments(double _radius, const vtkm::Vec3f& _spacing)
: Radius(_radius)
, Spacing(_spacing)
2019-06-17 18:27:52 +00:00
{
}
class ResolveUnknownCellSet
{
public:
template <typename T>
void operator()(const vtkm::cont::CellSetStructured<2>& input,
const vtkm::cont::ArrayHandleRecombineVec<T>& pixels,
2022-02-07 17:51:04 +00:00
vtkm::Vec3f spacing,
vtkm::Float64 radius,
2019-07-24 15:32:03 +00:00
int maxOrder,
vtkm::cont::DataSet& output) const
{
2019-07-24 15:32:03 +00:00
using WorkletType = vtkm::worklet::moments::ComputeMoments2D;
using DispatcherType = vtkm::worklet::DispatcherPointNeighborhood<WorkletType>;
for (int order = 0; order <= maxOrder; ++order)
{
for (int p = 0; p <= order; ++p)
{
const int q = order - p;
vtkm::cont::ArrayHandleRuntimeVec<T> moments{ pixels.GetNumberOfComponents() };
2019-07-24 15:32:03 +00:00
2022-02-07 17:51:04 +00:00
DispatcherType dispatcher(WorkletType{ spacing, radius, p, q });
2019-07-24 15:32:03 +00:00
dispatcher.Invoke(input, pixels, moments);
std::string fieldName = std::string("index") + std::string(p, '0') + std::string(q, '1');
vtkm::cont::Field momentsField(
fieldName, vtkm::cont::Field::Association::Points, moments);
2019-07-24 15:32:03 +00:00
output.AddField(momentsField);
}
}
}
2019-06-17 18:27:52 +00:00
template <typename T>
void operator()(const vtkm::cont::CellSetStructured<3>& input,
const vtkm::cont::ArrayHandleRecombineVec<T>& pixels,
2022-02-07 17:51:04 +00:00
vtkm::Vec3f spacing,
vtkm::Float64 radius,
2019-07-24 15:32:03 +00:00
int maxOrder,
vtkm::cont::DataSet& output) const
{
2019-07-24 15:32:03 +00:00
using WorkletType = vtkm::worklet::moments::ComputeMoments3D;
using DispatcherType = vtkm::worklet::DispatcherPointNeighborhood<WorkletType>;
for (int order = 0; order <= maxOrder; ++order)
{
for (int r = 0; r <= order; ++r)
{
const int qMax = order - r;
for (int q = 0; q <= qMax; ++q)
{
const int p = order - r - q;
vtkm::cont::ArrayHandleRuntimeVec<T> moments{ pixels.GetNumberOfComponents() };
2019-07-24 15:32:03 +00:00
2022-02-07 17:51:04 +00:00
DispatcherType dispatcher(WorkletType{ spacing, radius, p, q, r });
2019-07-24 15:32:03 +00:00
dispatcher.Invoke(input, pixels, moments);
std::string fieldName = std::string("index") + std::string(p, '0') +
std::string(q, '1') + std::string(r, '2');
vtkm::cont::Field momentsField(
fieldName, vtkm::cont::Field::Association::Points, moments);
2019-07-24 15:32:03 +00:00
output.AddField(momentsField);
}
}
}
}
};
template <typename T>
void Run(const vtkm::cont::UnknownCellSet& input,
const vtkm::cont::ArrayHandleRecombineVec<T>& pixels,
2019-07-24 15:32:03 +00:00
int maxOrder,
vtkm::cont::DataSet& output) const
{
input.ResetCellSetList(vtkm::cont::CellSetListStructured())
.CastAndCall(ResolveUnknownCellSet(), pixels, this->Spacing, this->Radius, maxOrder, output);
}
private:
2022-02-07 17:51:04 +00:00
const vtkm::Float64 Radius;
2022-02-07 17:03:08 +00:00
const vtkm::Vec3f Spacing;
2019-04-23 14:57:35 +00:00
};
}
}
}
#endif // vtk_m_worklet_moments_ComputeMoments_h