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