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 &tgtBox,
const float support,
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)
301 Box3i srcDw = src.dataWindow();
307 }
else if (dim == 1) {
308 res =
V3i(newRes.x, newRes.y, oldRes.z);
310 res =
V3i(newRes.x, oldRes.y, oldRes.z);
320 std::vector<Box3i> blocks;
321 for (
int k = 0; k < res.z; k += blockSize) {
322 for (
int j = 0; j < res.y; j += blockSize) {
323 for (
int i = 0; i < res.x; i += blockSize) {
326 box.min =
V3i(i, j, k);
327 box.max = box.min +
V3i(blockSize - 1);
329 box.max.x = std::min(box.max.x, res.x - 1);
330 box.max.y = std::min(box.max.y, res.y - 1);
331 box.max.z = std::min(box.max.z, res.z - 1);
333 blocks.push_back(box);
344 boost::thread_group threads;
346 for (
size_t i = 0; i < numThreads; ++i) {
347 threads.create_thread(
349 dim, blocks, nextIdx, mutex));
358 template <
typename Field_T,
typename FilterOp_T>
359 void mipResample(
const Field_T &base,
const Field_T &src, Field_T &tgt,
360 const size_t level,
const FilterOp_T &filterOp,
361 const size_t numThreads)
366 const Box3i baseDw = base.dataWindow();
367 const V3i baseRes = baseDw.size() +
V3i(1);
371 const Box3i srcDw = src.dataWindow();
372 const V3i srcRes = srcDw.size() +
V3i(1);
378 mipSeparable(src, tgt, srcRes, newRes, level, filterOp, 0, numThreads);
380 mipSeparable(tgt, tmp, srcRes, newRes, level, filterOp, 1, numThreads);
382 mipSeparable(tmp, tgt, srcRes, newRes, level, filterOp, 2, numThreads);
385 tgt.name = base.name;
386 tgt.attribute = base.attribute;
387 tgt.setMapping(base.mapping());
388 tgt.copyMetadata(base);
395 const Box3i &extents,
406 template <
typename MIPField_T,
typename Filter_T>
407 typename MIPField_T::Ptr
408 makeMIP(
const typename MIPField_T::NestedType &base,
const int minSize,
409 const size_t numThreads)
411 using namespace Field3D::detail;
413 typedef typename MIPField_T::value_type Data_T;
414 typedef typename MIPField_T::NestedType Src_T;
415 typedef typename Src_T::Ptr SrcPtr;
416 typedef typename MIPField_T::Ptr MIPPtr;
417 typedef std::vector<typename Src_T::Ptr> SrcVec;
419 if (base.extents() != base.dataWindow()) {
425 result.push_back(field_dynamic_cast<Src_T>(base.clone()));
428 V3i res = base.extents().size() +
V3i(1);
432 while ((res.x > minSize || res.y > minSize || res.z > minSize) &&
433 (res.x > 1 && res.y > 1 && res.z > 1)) {
435 SrcPtr nextField(
new Src_T);
436 mipResample(base, *result.back(), *nextField, level,
437 Filter_T(), numThreads);
439 result.push_back(nextField);
441 res = nextField->dataWindow().size() +
V3i(1);
445 MIPPtr mipField(
new MIPField_T);
446 mipField->setup(result);
447 mipField->name = base.name;
448 mipField->attribute = base.attribute;
449 mipField->copyMetadata(base);
460 #endif // Include guard 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.
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)
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...
bool checkInputEmpty(const SparseField< Data_T > &src, const SparseField< Data_T > &tgt, const Box3i &tgtBox, const float support, const size_t dim)
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...