44 #ifndef _INCLUDED_Field3D_MIPUtil_H_ 45 #define _INCLUDED_Field3D_MIPUtil_H_ 51 #include <boost/thread/thread.hpp> 52 #include <boost/thread/mutex.hpp> 75 template <
typename MIPField_T,
typename Filter_T>
76 typename MIPField_T::Ptr
77 makeMIP(
const typename MIPField_T::NestedType &base,
const int minSize,
78 const V3i &offset,
const size_t numThreads);
81 template <
typename MIPField_T,
typename Filter_T>
82 typename MIPField_T::Ptr
83 makeMIP(
const typename MIPField_T::NestedType &base,
const int minSize,
84 const size_t numThreads);
120 template <
typename Data_T>
127 template <
typename Data_T>
135 template <
typename Data_T>
138 const Box3i &tgtBox,
const float support,
141 const int intSupport = static_cast<int>(
std::ceil(support * 0.5));
142 const int pad =
std::max(0, intSupport);
143 Box3i tgtBoxPad = tgtBox;
144 tgtBoxPad.min[dim] -= pad;
145 tgtBoxPad.max[dim] += pad;
146 Box3i srcBoxPad = tgtBoxPad;
147 srcBoxPad.min[dim] *= 2;
148 srcBoxPad.max[dim] *= 2;
154 static boost::mutex mutex;
155 boost::mutex::scoped_lock lock(mutex);
158 for (
int k = dbsBounds.min.z; k <= dbsBounds.max.z; ++k) {
159 for (
int j = dbsBounds.min.y; j <= dbsBounds.max.y; ++j) {
160 for (
int i = dbsBounds.min.x; i <= dbsBounds.max.x; ++i) {
176 template <
typename Field_T>
178 const Box3i &,
const float ,
186 template <
typename Field_T,
typename FilterOp_T,
bool IsAnalytic_T>
189 typedef typename Field_T::value_type
T;
192 const size_t level,
const V3i &add,
193 const FilterOp_T &filterOp,
195 const std::vector<Box3i> &blocks,
196 size_t &nextIdx, boost::mutex &mutex)
216 typedef typename Field_T::value_type Data_T;
223 const float tgtToSrcMult = 2.0;
224 const float filterCoordMult = 1.0f / (tgtToSrcMult);
232 boost::mutex::scoped_lock lock(
m_mutex);
243 for (
int k = box.min.z; k <= box.max.z; ++k) {
244 for (
int j = box.min.y; j <= box.max.y; ++j) {
245 for (
int i = box.min.x; i <= box.max.x; ++i) {
246 Value_T accumValue(
m_filterOp.initialValue());
249 const int curTgt =
V3i(i, j, k)[
m_dim];
253 static_cast<int>(
std::floor(curSrc - support * tgtToSrcMult));
255 static_cast<int>(
std::ceil(curSrc + support *
261 for (
int s = startSrc; s <= endSrc; ++s) {
263 const int xIdx =
m_dim == 0 ? s : i;
264 const int yIdx =
m_dim == 1 ? s : j;
265 const int zIdx =
m_dim == 2 ? s : k;
269 const float weight =
m_filterOp.eval(std::abs(srcP - curSrc) *
272 const Value_T value =
m_src.fastValue(xIdx, yIdx, zIdx);
275 FilterOp_T::op(accumValue, value);
280 static_cast<Value_T>(
m_filterOp.initialValue())) {
281 m_tgt.fastLValue(i, j, k) = accumValue;
284 float accumWeight = 0.0f;
286 const int curTgt =
V3i(i, j, k)[
m_dim];
290 static_cast<int>(
std::floor(curSrc - support * tgtToSrcMult));
292 static_cast<int>(
std::ceil(curSrc + support *
298 for (
int s = startSrc; s <= endSrc; ++s) {
300 const int xIdx =
m_dim == 0 ? s : i;
301 const int yIdx =
m_dim == 1 ? s : j;
302 const int zIdx =
m_dim == 2 ? s : k;
306 const float weight =
m_filterOp.eval(std::abs(srcP - curSrc) *
309 const Value_T value =
m_src.fastValue(xIdx, yIdx, zIdx);
311 accumWeight += weight;
312 accumValue += value * weight;
315 if (accumWeight > 0.0f &&
316 accumValue != static_cast<Value_T>(0.0)) {
317 m_tgt.fastLValue(i, j, k) = accumValue / accumWeight;
326 boost::mutex::scoped_lock lock(
m_mutex);
353 template <
typename Field_T,
typename FilterOp_T>
355 const V3i &oldRes,
const V3i &newRes,
const size_t level,
356 const V3i &add,
const FilterOp_T &filterOp,
357 const size_t dim,
const size_t numThreads)
362 Box3i srcDw = src.dataWindow();
368 }
else if (dim == 1) {
369 res =
V3i(newRes.x, newRes.y, oldRes.z);
371 res =
V3i(newRes.x, oldRes.y, oldRes.z);
381 std::vector<Box3i> blocks;
382 for (
int k = 0; k < res.z; k += blockSize) {
383 for (
int j = 0; j < res.y; j += blockSize) {
384 for (
int i = 0; i < res.x; i += blockSize) {
387 box.min =
V3i(i, j, k);
388 box.max = box.min +
V3i(blockSize - 1);
390 box.max.x =
std::min(box.max.x, res.x - 1);
391 box.max.y =
std::min(box.max.y, res.y - 1);
392 box.max.z =
std::min(box.max.z, res.z - 1);
394 blocks.push_back(box);
405 boost::thread_group threads;
407 for (
size_t i = 0; i < numThreads; ++i) {
408 threads.create_thread(
410 (src, tgt, level, add, filterOp,
411 dim, blocks, nextIdx, mutex));
420 template <
typename Field_T,
typename FilterOp_T>
421 void mipResample(
const Field_T &base,
const Field_T &src, Field_T &tgt,
422 const size_t level,
const V3i &offset,
423 const FilterOp_T &filterOp,
424 const size_t numThreads)
429 const V3i add((offset.x % 2 == 0) ? 0 : 1,
430 (offset.y % 2 == 0) ? 0 : 1,
431 (offset.z % 2 == 0) ? 0 : 1);
434 const Box3i baseDw = base.dataWindow();
435 const V3i baseRes = baseDw.size() +
V3i(1);
439 const Box3i srcDw = src.dataWindow();
440 const V3i srcRes = srcDw.size() +
V3i(1);
446 mipSeparable(src, tgt, srcRes, newRes, level, add, filterOp, 0, numThreads);
448 mipSeparable(tgt, tmp, srcRes, newRes, level, add, filterOp, 1, numThreads);
450 mipSeparable(tmp, tgt, srcRes, newRes, level, add, filterOp, 2, numThreads);
453 tgt.name = base.name;
454 tgt.attribute = base.attribute;
455 tgt.setMapping(base.mapping());
456 tgt.copyMetadata(base);
464 const Box3i &extents,
475 template <
typename MIPField_T,
typename Filter_T>
476 typename MIPField_T::Ptr
477 makeMIP(
const typename MIPField_T::NestedType &base,
const int minSize,
478 const size_t numThreads)
483 return makeMIP<MIPField_T, Filter_T>(base, minSize, zero, numThreads);
488 template <
typename MIPField_T,
typename Filter_T>
489 typename MIPField_T::Ptr
490 makeMIP(
const typename MIPField_T::NestedType &base,
const int minSize,
491 const V3i &baseOffset,
const size_t numThreads)
493 using namespace Field3D::detail;
495 typedef typename MIPField_T::value_type Data_T;
496 typedef typename MIPField_T::NestedType Src_T;
497 typedef typename Src_T::Ptr SrcPtr;
498 typedef typename MIPField_T::Ptr MIPPtr;
499 typedef std::vector<typename Src_T::Ptr> SrcVec;
501 if (base.extents() != base.dataWindow()) {
507 result.push_back(field_dynamic_cast<Src_T>(base.clone()));
510 V3i res = base.extents().size() +
V3i(1);
511 V3i offset = baseOffset;
515 while ((res.x > minSize || res.y > minSize || res.z > minSize) &&
516 (res.x > 2 && res.y > 2 && res.z > 2)) {
518 SrcPtr nextField(
new Src_T);
519 mipResample(base, *result.back(), *nextField, level, offset,
520 Filter_T(), numThreads);
522 result.push_back(nextField);
524 res = nextField->dataWindow().size() +
V3i(1);
526 for (
int i = 0; i < 3; ++i) {
528 offset[i] = (offset[i] - 1) / 2;
536 MIPPtr mipField(
new MIPField_T);
537 mipField->name = base.name;
538 mipField->attribute = base.attribute;
539 mipField->copyMetadata(base);
540 mipField->setMIPOffset(baseOffset);
541 mipField->setup(result);
552 #endif // Include guard bool checkInputEmpty(const SparseField< Data_T > &src, const SparseField< Data_T > &, const Box3i &tgtBox, const float support, const size_t dim)
This subclass of Field stores data in a contiguous std::vector.
#define FIELD3D_NAMESPACE_HEADER_CLOSE
MIPSeparableThreadOp(const Field_T &src, Field_T &tgt, const size_t level, const V3i &add, const FilterOp_T &filterOp, const size_t dim, const std::vector< Box3i > &blocks, size_t &nextIdx, boost::mutex &mutex)
FIELD3D_API V3i mipResolution(const V3i &baseRes, const size_t level, const V3i &add)
Box3i clipBounds(const Box3i &bbox, const Box3i &bounds)
Box3i blockCoords(const Box3i &dvsBounds, const SparseField< Data_T > *f)
void mipSeparable(const Field_T &src, Field_T &tgt, const V3i &oldRes, const V3i &newRes, const size_t level, const V3i &add, const FilterOp_T &filterOp, const size_t dim, const size_t numThreads)
Threaded implementation of separable MIP filtering.
Contains typedefs for the commonly used types in Field3D.
MIPField_T::Ptr makeMIP(const typename MIPField_T::NestedType &base, const int minSize, const V3i &offset, const size_t numThreads)
Constructs a MIP representation of the given field, with optional offset vector. The offset vector in...
Contains functions for resampling fields.
bool blockIsAllocated(int bi, int bj, int bk) const
Checks if a block is allocated.
void mipResample(const Field_T &base, const Field_T &src, Field_T &tgt, const size_t level, const V3i &offset, const FilterOp_T &filterOp, const size_t numThreads)
const Data_T getBlockEmptyValue(int bi, int bj, int bk) const
Returns the constant value of an block, whether it's allocated already or not..
FIELD3D_NAMESPACE_OPEN V3i computeOffset(const FieldRes &f)
Computes the origin/offset of a field.
Used to delegate the choice of bit depth to process at.
FIELD3D_NAMESPACE_OPEN typedef ::half half
boost::intrusive_ptr< FieldMapping > Ptr
const Box3i & dataWindow() const
Returns the data window. Any coordinate inside this window is safe to pass to value() in the Field su...
T max(const T a, const T2 b)
Max operation on mixed types.
FIELD3D_API FieldMapping::Ptr adjustedMIPFieldMapping(const FieldRes *base, const V3i &baseRes, const Box3i &extents, const size_t level)
size_t threadingBlockSize(const DenseField< Data_T > &)
Constant size for all dense fields.
FIELD3D_VEC3_T< T > floor(const FIELD3D_VEC3_T< T > &v)
Floor function for Vec3.
Contains the SparseField class.
const std::string k_mipOffsetStr
const FilterOp_T & m_filterOp
This Field subclass stores voxel data in block-allocated arrays.
FIELD3D_VEC3_T< T > ceil(const FIELD3D_VEC3_T< T > &v)
Ceil function for Vec3.
int blockSize() const
Returns the block size.
T min(const T a, const T2 b)
Min operation on mixed types.
const std::vector< Box3i > & m_blocks
double discToCont(int discCoord)
Goes from discrete coordinates to continuous coordinates See Graphics Gems - What is a pixel.