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 
79 template <typename Field_T, typename FilterOp_T>
80 bool resample(const Field_T &src, Field_T &tgt, const V3i &newRes,
81  const FilterOp_T &filter);
82 
83 //----------------------------------------------------------------------------//
84 // Filter
85 //----------------------------------------------------------------------------//
86 
87 struct 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 };
102 
103 //----------------------------------------------------------------------------//
104 // BoxFilter
105 //----------------------------------------------------------------------------//
106 
107 struct BoxFilter : public Filter
108 {
109  // Typedefs
110  typedef boost::shared_ptr<BoxFilter> Ptr;
111  typedef boost::shared_ptr<const BoxFilter> CPtr;
112  // Ctors
114  : m_width(1.0)
115  { }
116  BoxFilter(const float width)
117  : m_width(width)
118  { }
119  // From Filter base class
120  virtual float eval(const float x) const
121  {
122  const float t = x / m_width;
123  if (t <= 0.5f) {
124  return 1.0f;
125  } else {
126  return 0.0f;
127  }
128  }
129  virtual float support() const
130  {
131  return 0.5f * m_width;
132  }
133 private:
134  const float m_width;
135 };
136 
137 //----------------------------------------------------------------------------//
138 // TriangleFilter
139 //----------------------------------------------------------------------------//
140 
141 struct TriangleFilter : public Filter
142 {
143  // Typedefs
144  typedef boost::shared_ptr<TriangleFilter> Ptr;
145  typedef boost::shared_ptr<const TriangleFilter> CPtr;
146  // Ctors
148  : m_width(1.0)
149  { }
150  TriangleFilter(const float width)
151  : m_width(width)
152  { }
153  // From Filter base class
154  virtual float eval(const float x) const
155  {
156  const float t = x / m_width;
157  if (t > 1.0) {
158  return 0.0f;
159  }
160  return 1.0f - t;
161  }
162  virtual float support() const
163  {
164  return 1.0f * m_width;
165  }
166 private:
167  const float m_width;
168 };
169 
170 //----------------------------------------------------------------------------//
171 // GaussianFilter
172 //----------------------------------------------------------------------------//
173 
174 struct GaussianFilter : public Filter
175 {
176  // Typedefs
177  typedef boost::shared_ptr<GaussianFilter> Ptr;
178  typedef boost::shared_ptr<const GaussianFilter> CPtr;
179  // Ctor
180  GaussianFilter(const float alpha = 2.0, const float width = 2.0)
181  : m_alpha(alpha),
182  m_exp(std::exp(-alpha * width * width)),
183  m_width(width)
184  { /* Empty */ }
185  // From Filter base class
186  virtual float eval(const float t) const
187  {
188  const float x = t / m_width;
189  return std::max(0.0f, std::exp(-m_alpha * x * x) - m_exp);
190  }
191  virtual float support() const
192  {
193  return 2.0f * m_width;
194  }
195 private:
196  const float m_alpha, m_exp, m_width;
197 };
198 
199 //----------------------------------------------------------------------------//
200 // MitchellFilter
201 //----------------------------------------------------------------------------//
202 
203 struct MitchellFilter : public Filter
204 {
205  // Typedefs
206  typedef boost::shared_ptr<MitchellFilter> Ptr;
207  typedef boost::shared_ptr<const MitchellFilter> CPtr;
208  // Ctor
209  MitchellFilter(const float width = 1.0,
210  const float B = 1.0 / 3.0, const float C = 1.0 / 3.0)
211  : m_B(B), m_C(C), m_width(width)
212  { /* Empty */ }
213  // From Filter base class
214  virtual float eval(const float x) const
215  {
216  const float ax = std::abs(x / m_width);
217  if (ax < 1) {
218  return ((12 - 9 * m_B - 6 * m_C) * ax * ax * ax +
219  (-18 + 12 * m_B + 6 * m_C) * ax * ax + (6 - 2 * m_B)) / 6;
220  } else if ((ax >= 1) && (ax < 2)) {
221  return ((-m_B - 6 * m_C) * ax * ax * ax +
222  (6 * m_B + 30 * m_C) * ax * ax + (-12 * m_B - 48 * m_C) *
223  ax + (8 * m_B + 24 * m_C)) / 6;
224  } else {
225  return 0;
226  }
227  }
228  virtual float support() const
229  {
230  return 2.0f * m_width;
231  }
232 private:
233  const float m_B, m_C;
234  const float m_width;
235 };
236 
237 //----------------------------------------------------------------------------//
238 // Implementation details
239 //----------------------------------------------------------------------------//
240 
241 namespace detail {
242 
243  //--------------------------------------------------------------------------//
244 
245  Box3i srcSupportBBox(const V3f &tgtP, const float support, const V3i &doUpres,
246  const V3f &srcSize, const V3f &tgtSize);
247 
248  //--------------------------------------------------------------------------//
249 
250  std::pair<int, int>
251  srcSupportBBox(const float &tgtP, const float support, const bool doUpres,
252  const float &srcSize, const float &tgtSize);
253 
254  //--------------------------------------------------------------------------//
255 
256  V3f getDist(const V3i &doUpres, const V3f &srcP, const V3f &tgtP,
257  const V3f &srcSize, const V3f &tgtSize);
258 
259  //--------------------------------------------------------------------------//
260 
261  float getDist(const bool doUpres, const float &srcP, const float &tgtP,
262  const float &srcSize, const float &tgtSize);
263 
264  //--------------------------------------------------------------------------//
265 
266  template <typename Field_T, typename FilterOp_T>
267  void separable(const Field_T &src, Field_T &tgt, const V3i &newRes,
268  const FilterOp_T &filterOp, const size_t dim)
269  {
270  typedef typename Field_T::value_type T;
271 
272  const V3i srcRes = src.dataWindow().size() + V3i(1);
273  const float srcDomain = V3f(srcRes)[dim];
274  const float tgtDomain = V3f(newRes)[dim];
275  const float srcSize = 1.0 / srcDomain;
276  const float tgtSize = 1.0 / tgtDomain;
277 
278  // Filter info
279  const float support = filterOp.support();
280 
281  // Check if we're up-res'ing
282  const bool doUpres = newRes[dim] > srcRes[dim] ? 1 : 0;
283 
284  // Resize the target
285  tgt.setSize(newRes);
286 
287  // For each output voxel
288  for (int k = 0; k < newRes.z; ++k) {
289  for (int j = 0; j < newRes.y; ++j) {
290  for (int i = 0; i < newRes.x; ++i) {
291  T accumValue = static_cast<T>(0.0);
292  float accumWeight = 0.0f;
293  // Current position in target coordinates
294  const float tgtP = discToCont(V3i(i, j ,k)[dim]);
295  // Transform support to source coordinates
296  std::pair<int, int> srcInterval =
297  srcSupportBBox(tgtP, support, doUpres, srcSize, tgtSize);
298  // Clip against new data window
299  srcInterval.first =
300  std::max(srcInterval.first, src.dataWindow().min[dim]);
301  srcInterval.second =
302  std::min(srcInterval.second, src.dataWindow().max[dim]);
303  // For each input voxel
304  for (int s = srcInterval.first; s <= srcInterval.second; ++s) {
305  // Index
306  const int xIdx = dim == 0 ? s : i;
307  const int yIdx = dim == 1 ? s : j;
308  const int zIdx = dim == 2 ? s : k;
309  // Value
310  const T value = src.fastValue(xIdx, yIdx, zIdx);
311  // Weights
312  const float srcP = discToCont(V3i(xIdx, yIdx, zIdx)[dim]);
313  const float dist = getDist(doUpres, srcP, tgtP, srcSize, tgtSize);
314  const float weight = filterOp.eval(dist);
315  // Update
316  accumWeight += weight;
317  accumValue += value * weight;
318  }
319  // Update final value
320  if (accumWeight > 0.0f && accumValue != static_cast<T>(0.0)) {
321  tgt.fastLValue(i, j, k) = accumValue / accumWeight;
322  }
323  }
324  }
325  }
326 
327  }
328 
329  //--------------------------------------------------------------------------//
330 
334  template <typename Field_T, typename FilterOp_T>
335  bool separableResample(const Field_T &src, Field_T &tgt, const V3i &newRes,
336  const FilterOp_T &filterOp)
337  {
338  using namespace detail;
339 
340  typedef typename Field_T::value_type T;
341 
342  if (!src.dataWindow().hasVolume()) {
343  return false;
344  }
345 
346  if (src.dataWindow().min != V3i(0)) {
347  return false;
348  }
349 
350  // Temporary field for y component
351  Field_T tmp;
352 
353  // Cache the old resolution
354  V3i oldRes = src.dataWindow().size() + V3i(1);
355  V3i xRes(newRes.x, oldRes.y, oldRes.z);
356  V3i yRes(newRes.x, newRes.y, oldRes.z);
357  V3i zRes(newRes.x, newRes.y, newRes.z);
358 
359  // X axis (src into tgt)
360  separable(src, tgt, xRes, filterOp, 0);
361  // Y axis (tgt into temp)
362  separable(tgt, tmp, yRes, filterOp, 1);
363  // Z axis (temp into tgt)
364  separable(tmp, tgt, zRes, filterOp, 2);
365 
366  // Update final target with mapping and metadata
367  tgt.name = src.name;
368  tgt.attribute = src.attribute;
369  tgt.setMapping(src.mapping());
370  tgt.copyMetadata(src);
371 
372  return true;
373  }
374 
375  //--------------------------------------------------------------------------//
376 
377 } // namespace detail
378 
379 //----------------------------------------------------------------------------//
380 // Resizing function implementations
381 //----------------------------------------------------------------------------//
382 
383 template <typename Field_T, typename FilterOp_T>
384 bool resample(const Field_T &src, Field_T &tgt, const V3i &newRes,
385  const FilterOp_T &filterOp)
386 {
387  return detail::separableResample(src, tgt, newRes, filterOp);
388 }
389 
390 //----------------------------------------------------------------------------//
391 
393 
394 //----------------------------------------------------------------------------//
395 
396 #endif // Include guard
397 
#define FIELD3D_NAMESPACE_HEADER_CLOSE
Definition: ns.h:58
Imath::Box3i Box3i
Definition: SpiMathLib.h:77
Contains the DenseField class.
virtual float support() const
Radial width of the filter (half of diameter)
Definition: Resample.h:162
boost::shared_ptr< const BoxFilter > CPtr
Definition: Resample.h:111
virtual float support() const
Radial width of the filter (half of diameter)
Definition: Resample.h:228
boost::shared_ptr< GaussianFilter > Ptr
Definition: Resample.h:177
GaussianFilter(const float alpha=2.0, const float width=2.0)
Definition: Resample.h:180
boost::shared_ptr< TriangleFilter > Ptr
Definition: Resample.h:144
boost::shared_ptr< const GaussianFilter > CPtr
Definition: Resample.h:178
boost::shared_ptr< const MitchellFilter > CPtr
Definition: Resample.h:207
void separable(const Field_T &src, Field_T &tgt, const V3i &newRes, const FilterOp_T &filterOp, const size_t dim)
Definition: Resample.h:267
const float m_width
Definition: Resample.h:167
TriangleFilter(const float width)
Definition: Resample.h:150
boost::shared_ptr< Filter > Ptr
Definition: Resample.h:91
Imath::V3i V3i
Definition: SpiMathLib.h:71
BoxFilter()
Definition: Resample.h:113
const float m_width
Definition: Resample.h:134
std::pair< int, int > srcSupportBBox(const float &tgtP, const float support, const bool doUpres, const float &srcSize, const float &tgtSize)
Definition: Resample.cpp:83
float getDist(const bool doUpres, const float &srcP, const float &tgtP, const float &srcSize, const float &tgtSize)
Definition: Resample.cpp:121
virtual float eval(const float t) const =0
Evaluates the filter at coordinate &#39;t&#39;.
virtual float eval(const float x) const
Evaluates the filter at coordinate &#39;t&#39;.
Definition: Resample.h:214
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:335
virtual float eval(const float t) const
Evaluates the filter at coordinate &#39;t&#39;.
Definition: Resample.h:186
MitchellFilter(const float width=1.0, const float B=1.0/3.0, const float C=1.0/3.0)
Definition: Resample.h:209
boost::shared_ptr< const Filter > CPtr
Definition: Resample.h:92
Imath::V3f V3f
Definition: SpiMathLib.h:73
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 ...
Definition: Resample.h:384
virtual float eval(const float x) const
Evaluates the filter at coordinate &#39;t&#39;.
Definition: Resample.h:120
const float m_C
Definition: Resample.h:233
virtual float support() const
Radial width of the filter (half of diameter)
Definition: Resample.h:129
BoxFilter(const float width)
Definition: Resample.h:116
boost::shared_ptr< MitchellFilter > Ptr
Definition: Resample.h:206
const float m_width
Definition: Resample.h:196
const float m_width
Definition: Resample.h:234
Contains the SparseField class.
virtual float eval(const float x) const
Evaluates the filter at coordinate &#39;t&#39;.
Definition: Resample.h:154
virtual float support() const
Radial width of the filter (half of diameter)
Definition: Resample.h:191
boost::shared_ptr< const TriangleFilter > CPtr
Definition: Resample.h:145
boost::shared_ptr< BoxFilter > Ptr
Definition: Resample.h:110
virtual float support() const =0
Radial width of the filter (half of diameter)
double discToCont(int discCoord)
Goes from discrete coordinates to continuous coordinates See Graphics Gems - What is a pixel...
Definition: Field.h:1075