Field3D
Resample.h
Go to the documentation of this file.
1//----------------------------------------------------------------------------//
2
3/*
4 * Copyright (c) 2009 Sony Pictures Imageworks Inc
5 *
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the
17 * distribution. Neither the name of Sony Pictures Imageworks nor the
18 * names of its contributors may be used to endorse or promote
19 * products derived from this software without specific prior written
20 * permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
33 * OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35
36//----------------------------------------------------------------------------//
37
42//----------------------------------------------------------------------------//
43
44#ifndef _INCLUDED_Field3D_Resample_H_
45#define _INCLUDED_Field3D_Resample_H_
46
47#include "DenseField.h"
48#include "SparseField.h"
49
50//----------------------------------------------------------------------------//
51
52/* TODO LIST
53
54 * x Implement dumb, dense resampling
55 * x For SparseField, only write non-zero results
56 * x Implement more filters
57 * For SparseField, be smart about which blocks are computed
58 * x Multi-threading using boost
59 * Multi-threading using TBB
60
61 */
62
63//----------------------------------------------------------------------------//
64
65#include "ns.h"
66
68
69//----------------------------------------------------------------------------//
70// Resizing functions
71//----------------------------------------------------------------------------//
72
79template <typename Field_T, typename FilterOp_T>
80bool resample(const Field_T &src, Field_T &tgt, const V3i &newRes,
81 const FilterOp_T &filter);
82
83//----------------------------------------------------------------------------//
84// Filter
85//----------------------------------------------------------------------------//
86
87struct Filter
88{
89 // Typedefs ---
90
91 typedef boost::shared_ptr<Filter> Ptr;
92 typedef boost::shared_ptr<const Filter> CPtr;
93
94 // To be overridden by subclasses ---
95
97 virtual float eval(const float t) const = 0;
99 virtual float support() const = 0;
100
101 // May be overridden by subclasses ---
102
104 virtual float initialValue() const
105 { return 0.0f; }
106
107};
108
109//----------------------------------------------------------------------------//
110// BoxFilter
111//----------------------------------------------------------------------------//
112
113struct BoxFilter : public Filter
114{
115 // Typedefs
116 typedef boost::shared_ptr<BoxFilter> Ptr;
117 typedef boost::shared_ptr<const BoxFilter> CPtr;
118
119 static const bool isAnalytic = false;
120
121 // Ctors
123 : m_width(1.0)
124 { }
125 BoxFilter(const float width)
126 : m_width(width)
127 { }
128 // From Filter base class
129 virtual float eval(const float x) const
130 {
131 const float t = x / m_width;
132 if (t <= 0.5f) {
133 return 1.0f;
134 } else {
135 return 0.0f;
136 }
137 }
138 virtual float support() const
139 {
140 return 0.5f * m_width;
141 }
142 template <typename Value_T>
143 static void op(Value_T &accumValue, const Value_T value)
144 { /* no-op */ }
145private:
146 const float m_width;
147};
148
149//----------------------------------------------------------------------------//
150// MinFilter
151//----------------------------------------------------------------------------//
152
153struct MinFilter : public Filter
154{
155 // Typedefs
156 typedef boost::shared_ptr<MinFilter> Ptr;
157 typedef boost::shared_ptr<const MinFilter> CPtr;
158
159 static const bool isAnalytic = true;
160
161 // Ctors
163 : m_width(1.0)
164 { }
165 MinFilter(const float width)
166 : m_width(width)
167 { }
168 // From Filter base class
169 virtual float eval(const float x) const
170 {
171 const float t = x / m_width;
172 if (t <= 0.5f) {
173 return 1.0f;
174 } else {
175 return 0.0f;
176 }
177 }
178 virtual float support() const
179 {
180 return 0.5f * m_width;
181 }
182 virtual float initialValue() const
183 {
184 return std::numeric_limits<float>::max();
185 }
186
187 template <typename T>
188 static void op(Imath::Vec3<T> &accumValue, const Imath::Vec3<T> value)
189 {
190 accumValue.x = std::min(accumValue.x, value.x);
191 accumValue.y = std::min(accumValue.y, value.y);
192 accumValue.z = std::min(accumValue.z, value.z);
193 }
194
195 template <typename Value_T>
196 static void op(Value_T &accumValue, const Value_T value)
197 {
198 accumValue = std::min(accumValue, value);
199 }
200
201private:
202 const float m_width;
203};
204
205//----------------------------------------------------------------------------//
206// MaxFilter
207//----------------------------------------------------------------------------//
208
209struct MaxFilter : public Filter
210{
211 // Typedefs
212 typedef boost::shared_ptr<MaxFilter> Ptr;
213 typedef boost::shared_ptr<const MaxFilter> CPtr;
214
215 static const bool isAnalytic = true;
216
217 // Ctors
219 : m_width(1.0)
220 { }
221 MaxFilter(const float width)
222 : m_width(width)
223 { }
224 // From Filter base class
225 virtual float eval(const float x) const
226 {
227 const float t = x / m_width;
228 if (t <= 0.5f) {
229 return 1.0f;
230 } else {
231 return 0.0f;
232 }
233 }
234 virtual float support() const
235 {
236 return 0.5f * m_width;
237 }
238 virtual float initialValue() const
239 {
240 return -std::numeric_limits<float>::max();
241 }
242
243
244 template <typename T>
245 static void op(Imath::Vec3<T> &accumValue, const Imath::Vec3<T> value)
246 {
247 accumValue.x = std::max(accumValue.x, value.x);
248 accumValue.y = std::max(accumValue.y, value.y);
249 accumValue.z = std::max(accumValue.z, value.z);
250 }
251
252 template <typename Value_T>
253 static void op(Value_T &accumValue, const Value_T value)
254 {
255 accumValue = std::max(accumValue, value);
256 }
257
258private:
259 const float m_width;
260};
261
262//----------------------------------------------------------------------------//
263// TriangleFilter
264//----------------------------------------------------------------------------//
265
266struct TriangleFilter : public Filter
267{
268 // Typedefs
269 typedef boost::shared_ptr<TriangleFilter> Ptr;
270 typedef boost::shared_ptr<const TriangleFilter> CPtr;
271
272 static const bool isAnalytic = false;
273
274 // Ctors
276 : m_width(1.0)
277 { }
279 : m_width(width)
280 { }
281 // From Filter base class
282 virtual float eval(const float x) const
283 {
284 const float t = x / m_width;
285 if (t > 1.0) {
286 return 0.0f;
287 }
288 return 1.0f - t;
289 }
290 virtual float support() const
291 {
292 return 1.0f * m_width;
293 }
294 template <typename Value_T>
295 static void op(Value_T &/*accumValue*/, const Value_T /*value*/)
296 { /* No-op */ }
297private:
298 const float m_width;
299};
300
301//----------------------------------------------------------------------------//
302// GaussianFilter
303//----------------------------------------------------------------------------//
304
305struct GaussianFilter : public Filter
306{
307 // Typedefs
308 typedef boost::shared_ptr<GaussianFilter> Ptr;
309 typedef boost::shared_ptr<const GaussianFilter> CPtr;
310
311 static const bool isAnalytic = false;
312
313 // Ctor
314 GaussianFilter(const float alpha = 2.0, const float width = 2.0)
315 : m_alpha(alpha),
316 m_exp(std::exp(-alpha * width * width)),
318 { /* Empty */ }
319 // From Filter base class
320 virtual float eval(const float t) const
321 {
322 const float x = t / m_width;
323 return std::max(0.0f, std::exp(-m_alpha * x * x) - m_exp);
324 }
325 virtual float support() const
326 {
327 return 2.0f * m_width;
328 }
329 template <typename Value_T>
330 static void op(Value_T &accumValue, const Value_T value)
331 { /* No-op */ }
332private:
333 const float m_alpha, m_exp, m_width;
334};
335
336//----------------------------------------------------------------------------//
337// MitchellFilter
338//----------------------------------------------------------------------------//
339
340struct MitchellFilter : public Filter
341{
342 // Typedefs
343 typedef boost::shared_ptr<MitchellFilter> Ptr;
344 typedef boost::shared_ptr<const MitchellFilter> CPtr;
345
346 static const bool isAnalytic = false;
347
348 // Ctor
349 MitchellFilter(const float width = 1.0,
350 const float B = 1.0 / 3.0, const float C = 1.0 / 3.0)
351 : m_B(B), m_C(C), m_width(width)
352 { /* Empty */ }
353 // From Filter base class
354 virtual float eval(const float x) const
355 {
356 const float ax = std::abs(x / m_width);
357 if (ax < 1) {
358 return ((12 - 9 * m_B - 6 * m_C) * ax * ax * ax +
359 (-18 + 12 * m_B + 6 * m_C) * ax * ax + (6 - 2 * m_B)) / 6;
360 } else if ((ax >= 1) && (ax < 2)) {
361 return ((-m_B - 6 * m_C) * ax * ax * ax +
362 (6 * m_B + 30 * m_C) * ax * ax + (-12 * m_B - 48 * m_C) *
363 ax + (8 * m_B + 24 * m_C)) / 6;
364 } else {
365 return 0;
366 }
367 }
368 virtual float support() const
369 {
370 return 2.0f * m_width;
371 }
372 template <typename Value_T>
373 static void op(Value_T &accumValue, const Value_T value)
374 { /* No-op */ }
375private:
376 const float m_B, m_C;
377 const float m_width;
378};
379
380//----------------------------------------------------------------------------//
381// Implementation details
382//----------------------------------------------------------------------------//
383
384namespace detail {
385
386 //--------------------------------------------------------------------------//
387
388 Box3i srcSupportBBox(const V3f &tgtP, const float support, const V3i &doUpres,
389 const V3f &srcSize, const V3f &tgtSize);
390
391 //--------------------------------------------------------------------------//
392
393 std::pair<int, int>
394 srcSupportBBox(const float &tgtP, const float support, const bool doUpres,
395 const float &srcSize, const float &tgtSize);
396
397 //--------------------------------------------------------------------------//
398
399 V3f getDist(const V3i &doUpres, const V3f &srcP, const V3f &tgtP,
400 const V3f &srcSize, const V3f &tgtSize);
401
402 //--------------------------------------------------------------------------//
403
404 float getDist(const bool doUpres, const float &srcP, const float &tgtP,
405 const float &srcSize, const float &tgtSize);
406
407 //--------------------------------------------------------------------------//
408
409 template <typename Field_T, typename FilterOp_T, bool IsAnalytic_T>
410 void separable(const Field_T &src, Field_T &tgt, const V3i &newRes,
411 const FilterOp_T &filterOp, const size_t dim)
412 {
413 typedef typename Field_T::value_type T;
414
415 const V3i srcRes = src.dataWindow().size() + V3i(1);
416 const float srcDomain = V3f(srcRes)[dim];
417 const float tgtDomain = V3f(newRes)[dim];
418 const float srcSize = 1.0 / srcDomain;
419 const float tgtSize = 1.0 / tgtDomain;
420
421 // Filter info
422 const float support = filterOp.support();
423
424 // Check if we're up-res'ing
425 const bool doUpres = newRes[dim] > srcRes[dim] ? 1 : 0;
426
427 // Resize the target
428 tgt.setSize(newRes);
429
430 // For each output voxel
431 for (int k = 0; k < newRes.z; ++k) {
432 for (int j = 0; j < newRes.y; ++j) {
433 for (int i = 0; i < newRes.x; ++i) {
434 T accumValue(filterOp.initialValue());
435 if (IsAnalytic_T) {
436 // Current position in target coordinates
437 const float tgtP = discToCont(V3i(i, j ,k)[dim]);
438 // Transform support to source coordinates
439 std::pair<int, int> srcInterval =
441 // Clip against new data window
442 srcInterval.first =
443 std::max(srcInterval.first, src.dataWindow().min[dim]);
444 srcInterval.second =
445 std::min(srcInterval.second, src.dataWindow().max[dim]);
446 // For each input voxel
447 for (int s = srcInterval.first; s <= srcInterval.second; ++s) {
448 // Index
449 const int xIdx = dim == 0 ? s : i;
450 const int yIdx = dim == 1 ? s : j;
451 const int zIdx = dim == 2 ? s : k;
452 // Value
453 const T value = src.fastValue(xIdx, yIdx, zIdx);
454 // Weights
455 const float srcP = discToCont(V3i(xIdx, yIdx, zIdx)[dim]);
456 const float dist = getDist(doUpres, srcP, tgtP, srcSize, tgtSize);
457 const float weight = filterOp.eval(dist);
458 // Update
459 if (weight > 0.0f) {
460 FilterOp_T::op(accumValue, value);
461 }
462 }
463 // Update final value
464 if (accumValue != static_cast<T>(filterOp.initialValue())) {
465 tgt.fastLValue(i, j, k) = accumValue;
466 }
467 } else {
468 float accumWeight = 0.0f;
469 // Current position in target coordinates
470 const float tgtP = discToCont(V3i(i, j ,k)[dim]);
471 // Transform support to source coordinates
472 std::pair<int, int> srcInterval =
474 // Clip against new data window
475 srcInterval.first =
476 std::max(srcInterval.first, src.dataWindow().min[dim]);
477 srcInterval.second =
478 std::min(srcInterval.second, src.dataWindow().max[dim]);
479 // For each input voxel
480 for (int s = srcInterval.first; s <= srcInterval.second; ++s) {
481 // Index
482 const int xIdx = dim == 0 ? s : i;
483 const int yIdx = dim == 1 ? s : j;
484 const int zIdx = dim == 2 ? s : k;
485 // Value
486 const T value = src.fastValue(xIdx, yIdx, zIdx);
487 // Weights
488 const float srcP = discToCont(V3i(xIdx, yIdx, zIdx)[dim]);
489 const float dist = getDist(doUpres, srcP, tgtP, srcSize, tgtSize);
490 const float weight = filterOp.eval(dist);
491 // Update
493 accumValue += value * weight;
494 }
495 // Update final value
496 if (accumWeight > 0.0f && accumValue != static_cast<T>(0.0)) {
497 tgt.fastLValue(i, j, k) = accumValue / accumWeight;
498 }
499 }
500 }
501 }
502 }
503 }
504
505 //--------------------------------------------------------------------------//
506
510 template <typename Field_T, typename FilterOp_T>
511 bool separableResample(const Field_T &src, Field_T &tgt, const V3i &newRes,
512 const FilterOp_T &filterOp)
513 {
514 using namespace detail;
515
516 typedef typename Field_T::value_type T;
517
518 if (!src.dataWindow().hasVolume()) {
519 return false;
520 }
521
522 if (src.dataWindow().min != V3i(0)) {
523 return false;
524 }
525
526 // Temporary field for y component
527 Field_T tmp;
528
529 // Cache the old resolution
530 V3i oldRes = src.dataWindow().size() + V3i(1);
531 V3i xRes(newRes.x, oldRes.y, oldRes.z);
532 V3i yRes(newRes.x, newRes.y, oldRes.z);
533 V3i zRes(newRes.x, newRes.y, newRes.z);
534
535 // X axis (src into tgt)
537 // Y axis (tgt into temp)
539 // Z axis (temp into tgt)
541
542 // Update final target with mapping and metadata
543 tgt.name = src.name;
544 tgt.attribute = src.attribute;
545 tgt.setMapping(src.mapping());
546 tgt.copyMetadata(src);
547
548 return true;
549 }
550
551 //--------------------------------------------------------------------------//
552
553} // namespace detail
554
555//----------------------------------------------------------------------------//
556// Resizing function implementations
557//----------------------------------------------------------------------------//
558
559template <typename Field_T, typename FilterOp_T>
560bool resample(const Field_T &src, Field_T &tgt, const V3i &newRes,
561 const FilterOp_T &filterOp)
562{
564}
565
566//----------------------------------------------------------------------------//
567
569
570//----------------------------------------------------------------------------//
571
572#endif // Include guard
573
Contains the DenseField class.
double discToCont(int discCoord)
Goes from discrete coordinates to continuous coordinates See Graphics Gems - What is a pixel.
Definition Field.h:1070
static int filter(std::string &name, const char *suffix)
FIELD3D_NAMESPACE_OPEN bool resample(const Field_T &src, Field_T &tgt, const V3i &newRes, const FilterOp_T &filter)
Resamples the source field into the target field, such that the new data window is @dataWindow.
Definition Resample.h:560
Contains the SparseField class.
Imath::V3i V3i
Definition SpiMathLib.h:71
Imath::Box3i Box3i
Definition SpiMathLib.h:77
Imath::V3f V3f
Definition SpiMathLib.h:73
#define FIELD3D_MTX_T
Definition StdMathLib.h:99
Box3i srcSupportBBox(const V3f &tgtP, const float support, const V3i &doUpres, const V3f &srcSize, const V3f &tgtSize)
Definition Resample.cpp:56
V3f getDist(const V3i &doUpres, const V3f &srcP, const V3f &tgtP, const V3f &srcSize, const V3f &tgtSize)
Definition Resample.cpp:103
void separable(const Field_T &src, Field_T &tgt, const V3i &newRes, const FilterOp_T &filterOp, const size_t dim)
Definition Resample.h:410
bool separableResample(const Field_T &src, Field_T &tgt, const V3i &newRes, const FilterOp_T &filterOp)
Resamples the source field into the target field, using separable execution, which is faster than res...
Definition Resample.h:511
#define FIELD3D_NAMESPACE_HEADER_CLOSE
Definition ns.h:58
static const bool isAnalytic
Definition Resample.h:119
virtual float support() const
Radial width of the filter (half of diameter)
Definition Resample.h:138
boost::shared_ptr< const BoxFilter > CPtr
Definition Resample.h:117
const float m_width
Definition Resample.h:146
virtual float eval(const float x) const
Evaluates the filter at coordinate 't'.
Definition Resample.h:129
static void op(Value_T &accumValue, const Value_T value)
Definition Resample.h:143
boost::shared_ptr< BoxFilter > Ptr
Definition Resample.h:116
BoxFilter(const float width)
Definition Resample.h:125
boost::shared_ptr< const Filter > CPtr
Definition Resample.h:92
virtual float eval(const float t) const =0
Evaluates the filter at coordinate 't'.
boost::shared_ptr< Filter > Ptr
Definition Resample.h:91
virtual float support() const =0
Radial width of the filter (half of diameter)
virtual float initialValue() const
Initial value (zero by default, but need to be different for min/max)
Definition Resample.h:104
static const bool isAnalytic
Definition Resample.h:311
const float m_exp
Definition Resample.h:333
boost::shared_ptr< const GaussianFilter > CPtr
Definition Resample.h:309
boost::shared_ptr< GaussianFilter > Ptr
Definition Resample.h:308
virtual float eval(const float t) const
Evaluates the filter at coordinate 't'.
Definition Resample.h:320
GaussianFilter(const float alpha=2.0, const float width=2.0)
Definition Resample.h:314
const float m_alpha
Definition Resample.h:333
virtual float support() const
Radial width of the filter (half of diameter)
Definition Resample.h:325
const float m_width
Definition Resample.h:333
static void op(Value_T &accumValue, const Value_T value)
Definition Resample.h:330
const float m_width
Definition Resample.h:259
static void op(Value_T &accumValue, const Value_T value)
Definition Resample.h:253
static const bool isAnalytic
Definition Resample.h:215
boost::shared_ptr< MaxFilter > Ptr
Definition Resample.h:212
static void op(Imath::Vec3< T > &accumValue, const Imath::Vec3< T > value)
Definition Resample.h:245
boost::shared_ptr< const MaxFilter > CPtr
Definition Resample.h:213
virtual float support() const
Radial width of the filter (half of diameter)
Definition Resample.h:234
MaxFilter(const float width)
Definition Resample.h:221
virtual float initialValue() const
Initial value (zero by default, but need to be different for min/max)
Definition Resample.h:238
virtual float eval(const float x) const
Evaluates the filter at coordinate 't'.
Definition Resample.h:225
virtual float support() const
Radial width of the filter (half of diameter)
Definition Resample.h:178
const float m_width
Definition Resample.h:202
MinFilter(const float width)
Definition Resample.h:165
static void op(Value_T &accumValue, const Value_T value)
Definition Resample.h:196
virtual float initialValue() const
Initial value (zero by default, but need to be different for min/max)
Definition Resample.h:182
static const bool isAnalytic
Definition Resample.h:159
virtual float eval(const float x) const
Evaluates the filter at coordinate 't'.
Definition Resample.h:169
static void op(Imath::Vec3< T > &accumValue, const Imath::Vec3< T > value)
Definition Resample.h:188
boost::shared_ptr< MinFilter > Ptr
Definition Resample.h:156
boost::shared_ptr< const MinFilter > CPtr
Definition Resample.h:157
virtual float support() const
Radial width of the filter (half of diameter)
Definition Resample.h:368
boost::shared_ptr< MitchellFilter > Ptr
Definition Resample.h:343
const float m_width
Definition Resample.h:377
MitchellFilter(const float width=1.0, const float B=1.0/3.0, const float C=1.0/3.0)
Definition Resample.h:349
static void op(Value_T &accumValue, const Value_T value)
Definition Resample.h:373
const float m_B
Definition Resample.h:376
boost::shared_ptr< const MitchellFilter > CPtr
Definition Resample.h:344
const float m_C
Definition Resample.h:376
virtual float eval(const float x) const
Evaluates the filter at coordinate 't'.
Definition Resample.h:354
static const bool isAnalytic
Definition Resample.h:346
boost::shared_ptr< TriangleFilter > Ptr
Definition Resample.h:269
virtual float eval(const float x) const
Evaluates the filter at coordinate 't'.
Definition Resample.h:282
static const bool isAnalytic
Definition Resample.h:272
TriangleFilter(const float width)
Definition Resample.h:278
static void op(Value_T &, const Value_T)
Definition Resample.h:295
const float m_width
Definition Resample.h:298
boost::shared_ptr< const TriangleFilter > CPtr
Definition Resample.h:270
virtual float support() const
Radial width of the filter (half of diameter)
Definition Resample.h:290