44 #ifndef _INCLUDED_Field3D_MIPUtil_H_ 45 #define _INCLUDED_Field3D_MIPUtil_H_ 51 #include <boost/thread/thread.hpp> 52 #include <boost/thread/mutex.hpp> 69 template <
typename MIPField_T,
typename Filter_T>
70 typename MIPField_T::Ptr
71 makeMIP(
const typename MIPField_T::NestedType &base,
const int minSize,
72 const size_t numThreads);
103 template <
typename Data_T>
110 template <
typename Data_T>
118 template <
typename Data_T>
121 const Box3i &tgtBox,
const float support,
124 const int intSupport =
static_cast<int>(
std::ceil(support * 0.5));
125 const int pad = std::max(0, intSupport);
126 Box3i tgtBoxPad = tgtBox;
127 tgtBoxPad.min[dim] -= pad;
128 tgtBoxPad.max[dim] += pad;
129 Box3i srcBoxPad = tgtBoxPad;
130 srcBoxPad.min[dim] *= 2;
131 srcBoxPad.max[dim] *= 2;
137 static boost::mutex mutex;
138 boost::mutex::scoped_lock lock(mutex);
141 for (
int k = dbsBounds.min.z; k <= dbsBounds.max.z; ++k) {
142 for (
int j = dbsBounds.min.y; j <= dbsBounds.max.y; ++j) {
143 for (
int i = dbsBounds.min.x; i <= dbsBounds.max.x; ++i) {
159 template <
typename Field_T>
161 const Box3i &,
const float ,
169 template <
typename Field_T,
typename FilterOp_T>
173 const size_t level,
const FilterOp_T &filterOp,
175 const std::vector<Box3i> &blocks,
176 size_t &nextIdx, boost::mutex &mutex)
179 m_filterOp(filterOp),
185 m_numBlocks(blocks.size())
195 typedef typename Field_T::value_type Data_T;
199 Box3i srcDw = m_src.dataWindow();
202 const float tgtToSrcMult = 2.0;
203 const float filterCoordMult = 1.0f / (tgtToSrcMult);
206 const float support = m_filterOp.support();
211 boost::mutex::scoped_lock lock(m_mutex);
216 while (idx < m_numBlocks) {
218 const Box3i box = m_blocks[idx];
222 for (
int k = box.min.z; k <= box.max.z; ++k) {
223 for (
int j = box.min.y; j <= box.max.y; ++j) {
224 for (
int i = box.min.x; i <= box.max.x; ++i) {
225 Value_T accumValue =
static_cast<Value_T
>(0.0);
226 float accumWeight = 0.0f;
228 const int curTgt =
V3i(i, j, k)[m_dim];
229 const float curSrc =
discToCont(curTgt) * tgtToSrcMult;
232 static_cast<int>(
std::floor(curSrc - support * tgtToSrcMult));
234 static_cast<int>(
std::ceil(curSrc + support *
236 startSrc = std::max(startSrc, srcDw.min[m_dim]);
237 endSrc = std::min(endSrc, srcDw.max[m_dim]);
239 for (
int s = startSrc; s <= endSrc; ++s) {
241 const int xIdx = m_dim == 0 ? s : i;
242 const int yIdx = m_dim == 1 ? s : j;
243 const int zIdx = m_dim == 2 ? s : k;
247 const float weight = m_filterOp.eval(std::abs(srcP - curSrc) *
250 const Value_T value = m_src.fastValue(xIdx, yIdx, zIdx);
252 accumWeight += weight;
253 accumValue += value * weight;
256 if (accumWeight > 0.0f &&
257 accumValue != static_cast<Value_T>(0.0)) {
258 m_tgt.fastLValue(i, j, k) = accumValue / accumWeight;
266 boost::mutex::scoped_lock lock(m_mutex);
292 template <
typename Field_T,
typename FilterOp_T>
294 const V3i &oldRes,
const V3i &newRes,
const size_t level,
295 const FilterOp_T &filterOp,
const size_t dim,
296 const size_t numThreads)
304 }
else if (dim == 1) {
305 res =
V3i(newRes.x, newRes.y, oldRes.z);
307 res =
V3i(newRes.x, oldRes.y, oldRes.z);
317 std::vector<Box3i> blocks;
318 for (
int k = 0; k < res.z; k += blockSize) {
319 for (
int j = 0; j < res.y; j += blockSize) {
320 for (
int i = 0; i < res.x; i += blockSize) {
323 box.min =
V3i(i, j, k);
324 box.max = box.min +
V3i(blockSize - 1);
326 box.max.x = std::min(box.max.x, res.x - 1);
327 box.max.y = std::min(box.max.y, res.y - 1);
328 box.max.z = std::min(box.max.z, res.z - 1);
330 blocks.push_back(box);
341 boost::thread_group threads;
343 for (
size_t i = 0; i < numThreads; ++i) {
344 threads.create_thread(
346 dim, blocks, nextIdx, mutex));
355 template <
typename Field_T,
typename FilterOp_T>
356 void mipResample(
const Field_T &base,
const Field_T &src, Field_T &tgt,
357 const size_t level,
const FilterOp_T &filterOp,
358 const size_t numThreads)
363 const Box3i baseDw = base.dataWindow();
364 const V3i baseRes = baseDw.size() +
V3i(1);
368 const Box3i srcDw = src.dataWindow();
369 const V3i srcRes = srcDw.size() +
V3i(1);
375 mipSeparable(src, tgt, srcRes, newRes, level, filterOp, 0, numThreads);
377 mipSeparable(tgt, tmp, srcRes, newRes, level, filterOp, 1, numThreads);
379 mipSeparable(tmp, tgt, srcRes, newRes, level, filterOp, 2, numThreads);
382 tgt.name = base.name;
383 tgt.attribute = base.attribute;
384 tgt.setMapping(base.mapping());
385 tgt.copyMetadata(base);
393 const Box3i &extents,
404 template <
typename MIPField_T,
typename Filter_T>
405 typename MIPField_T::Ptr
406 makeMIP(
const typename MIPField_T::NestedType &base,
const int minSize,
407 const size_t numThreads)
409 using namespace Field3D::detail;
411 typedef typename MIPField_T::value_type Data_T;
412 typedef typename MIPField_T::NestedType Src_T;
413 typedef typename Src_T::Ptr SrcPtr;
414 typedef typename MIPField_T::Ptr MIPPtr;
415 typedef std::vector<typename Src_T::Ptr> SrcVec;
417 if (base.extents() != base.dataWindow()) {
423 result.push_back(field_dynamic_cast<Src_T>(base.clone()));
426 V3i res = base.extents().size() +
V3i(1);
430 while ((res.x > minSize || res.y > minSize || res.z > minSize) &&
431 (res.x > 1 && res.y > 1 && res.z > 1)) {
433 SrcPtr nextField(
new Src_T);
434 mipResample(base, *result.back(), *nextField, level,
435 Filter_T(), numThreads);
437 result.push_back(nextField);
439 res = nextField->dataWindow().size() +
V3i(1);
443 MIPPtr mipField(
new MIPField_T);
444 mipField->setup(result);
445 mipField->name = base.name;
446 mipField->attribute = base.attribute;
447 mipField->copyMetadata(base);
458 #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
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 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.
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..
const std::vector< Box3i > & m_blocks
Contains functions for resampling fields.
FIELD3D_API FieldMapping::Ptr adjustedMIPFieldMapping(const FieldMapping::Ptr baseMapping, const V3i &baseRes, const Box3i &extents, const size_t level)
MIPSeparableThreadOp(const Field_T &src, Field_T &tgt, const size_t level, const FilterOp_T &filterOp, const size_t dim, const std::vector< Box3i > &blocks, size_t &nextIdx, boost::mutex &mutex)
Used to delegate the choice of bit depth to process at.
FIELD3D_NAMESPACE_OPEN typedef::half half
boost::intrusive_ptr< FieldMapping > Ptr
const FilterOp_T & m_filterOp
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.
bool blockIsAllocated(int bi, int bj, int bk) const
Checks if a block is allocated.
FIELD3D_NAMESPACE_OPEN MIPField_T::Ptr makeMIP(const typename MIPField_T::NestedType &base, const int minSize, const size_t numThreads)
Constructs a MIP representation of the given field.
void mipResample(const Field_T &base, const Field_T &src, Field_T &tgt, const size_t level, const FilterOp_T &filterOp, const size_t numThreads)
FIELD3D_API V3i mipResolution(const V3i &baseRes, const size_t level)
Contains the SparseField class.
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.
const Box3i & dataWindow() const
Returns the data window. Any coordinate inside this window is safe to pass to value() in the Field su...
int blockSize() const
Returns the block size.
double discToCont(int discCoord)
Goes from discrete coordinates to continuous coordinates See Graphics Gems - What is a pixel...