20 #if !defined(__MITSUBA_CORE_RFILTER_H_)
21 #define __MITSUBA_CORE_RFILTER_H_
28 #define MTS_FILTER_RESOLUTION 31
124 int sourceRes,
int targetRes) : m_bc(bc), m_sourceRes(sourceRes), m_targetRes(targetRes),
125 m_start(NULL), m_weights(NULL) {
126 SAssert(sourceRes > 0 && targetRes > 0);
130 if (targetRes < sourceRes) {
131 scale = (
Float) sourceRes / (
Float) targetRes;
132 invScale = 1 / scale;
133 filterRadius *= scale;
137 if (sourceRes == targetRes && (m_taps % 2) != 1)
139 m_halfTaps = m_taps / 2;
141 if (sourceRes != targetRes) {
142 m_start =
new int[targetRes];
143 m_weights =
new Scalar[m_taps * targetRes];
145 m_fastEnd = m_targetRes;
147 for (
int i=0; i<targetRes; i++) {
149 Float center = (i + (
Float) 0.5f) / targetRes * sourceRes;
156 m_fastStart = std::max(m_fastStart, i + 1);
157 else if (m_start[i] + m_taps - 1 >= m_sourceRes)
158 m_fastEnd = std::min(m_fastEnd, i - 1);
161 for (
int j=0; j<m_taps; j++) {
163 Float pos = m_start[i] + j + (
Float) 0.5f - center;
166 Float weight = rfilter->
eval(pos * invScale);
167 m_weights[i * m_taps + j] = (Scalar) weight;
172 Float normalization = 1.0f / sum;
173 for (
int j=0; j<m_taps; j++) {
174 Scalar &value = m_weights[i * m_taps + j];
175 value = (Scalar) ((
Float) value * normalization);
179 m_weights =
new Scalar[m_taps];
181 for (
int i=0; i<m_taps; i++) {
182 Scalar weight = (Scalar) rfilter->
eval((
Float) (i-m_halfTaps));
183 m_weights[i] = weight;
184 sum += (
Float) weight;
186 Float normalization = 1.0f / sum;
187 for (
int i=0; i<m_taps; i++) {
188 Scalar &value = m_weights[i];
189 value = (Scalar) ((
Float) value * normalization);
191 m_fastStart = std::min(m_halfTaps, m_targetRes-1);
192 m_fastEnd = std::max(m_targetRes-m_halfTaps-1, 0);
197 m_fastStart = std::min(m_fastStart, m_fastEnd);
233 Scalar *target,
size_t targetStride,
int channels,
234 Scalar min = (Scalar) 0, Scalar max = (Scalar) 1) {
235 const int taps = m_taps, halfTaps = m_halfTaps;
236 targetStride = channels * (targetStride - 1);
237 sourceStride *= channels;
241 for (
int i=0; i<m_fastStart; ++i) {
242 int start = m_start[i];
244 for (
int ch=0; ch<channels; ++ch) {
246 for (
int j=0; j<taps; ++j)
247 result += lookup(source, start + j, sourceStride, ch) * m_weights[i * taps + j];
248 *target++ = std::min(max, std::max(min, result));
251 target += targetStride;
255 for (
int i=m_fastStart; i<m_fastEnd; ++i) {
256 int start = m_start[i];
258 for (
int ch=0; ch<channels; ++ch) {
260 for (
int j=0; j<taps; ++j)
261 result += source[sourceStride * (start + j) + ch] * m_weights[i * taps + j];
262 *target++ = std::min(max, std::max(min, result));
265 target += targetStride;
269 for (
int i=m_fastEnd; i<m_targetRes; ++i) {
270 int start = m_start[i];
272 for (
int ch=0; ch<channels; ++ch) {
274 for (
int j=0; j<taps; ++j)
275 result += lookup(source, start + j, sourceStride, ch) * m_weights[i * taps + j];
276 *target++ = std::min(max, std::max(min, result));
279 target += targetStride;
283 for (
int i=0; i<m_fastStart; ++i) {
284 int start = i - halfTaps;
286 for (
int ch=0; ch<channels; ++ch) {
288 for (
int j=0; j<taps; ++j)
289 result += lookup(source, start + j, sourceStride, ch) * m_weights[j];
290 *target++ = std::min(max, std::max(min, result));
293 target += targetStride;
297 for (
int i=m_fastStart; i<m_fastEnd; ++i) {
298 int start = i - halfTaps;
300 for (
int ch=0; ch<channels; ++ch) {
302 for (
int j=0; j<taps; ++j)
303 result += source[sourceStride * (start + j) + ch] * m_weights[j];
304 *target++ = std::min(max, std::max(min, result));
307 target += targetStride;
311 for (
int i=m_fastEnd; i<m_targetRes; ++i) {
312 int start = i - halfTaps;
314 for (
int ch=0; ch<channels; ++ch) {
316 for (
int j=0; j<taps; ++j)
317 result += lookup(source, start + j, sourceStride, ch) * m_weights[j];
318 *target++ = std::min(max, std::max(min, result));
321 target += targetStride;
342 void resample(
const Scalar *source,
size_t sourceStride,
343 Scalar *target,
size_t targetStride,
int channels) {
344 const int taps = m_taps, halfTaps = m_halfTaps;
346 targetStride = channels * (targetStride - 1);
347 sourceStride *= channels;
351 for (
int i=0; i<m_fastStart; ++i) {
352 int start = m_start[i];
354 for (
int ch=0; ch<channels; ++ch) {
356 for (
int j=0; j<taps; ++j)
357 result += lookup(source, start + j, sourceStride, ch) * m_weights[i * taps + j];
361 target += targetStride;
365 for (
int i=m_fastStart; i<m_fastEnd; ++i) {
366 int start = m_start[i];
368 for (
int ch=0; ch<channels; ++ch) {
370 for (
int j=0; j<taps; ++j)
371 result += source[sourceStride * (start + j) + ch] * m_weights[i * taps + j];
375 target += targetStride;
379 for (
int i=m_fastEnd; i<m_targetRes; ++i) {
380 int start = m_start[i];
382 for (
int ch=0; ch<channels; ++ch) {
384 for (
int j=0; j<taps; ++j)
385 result += lookup(source, start + j, sourceStride, ch) * m_weights[i * taps + j];
389 target += targetStride;
393 for (
int i=0; i<m_fastStart; ++i) {
394 int start = i - halfTaps;
396 for (
int ch=0; ch<channels; ++ch) {
398 for (
int j=0; j<taps; ++j)
399 result += lookup(source, start + j, sourceStride, ch) * m_weights[j];
403 target += targetStride;
407 for (
int i=m_fastStart; i<m_fastEnd; ++i) {
408 int start = i - halfTaps;
410 for (
int ch=0; ch<channels; ++ch) {
412 for (
int j=0; j<taps; ++j)
413 result += source[sourceStride * (start + j) + ch] * m_weights[j];
417 target += targetStride;
421 for (
int i=m_fastEnd; i<m_targetRes; ++i) {
422 int start = i - halfTaps;
424 for (
int ch=0; ch<channels; ++ch) {
426 for (
int j=0; j<taps; ++j)
427 result += lookup(source, start + j, sourceStride, ch) * m_weights[j];
431 target += targetStride;
437 FINLINE Scalar lookup(
const Scalar *source,
int pos,
size_t stride,
int offset)
const {
438 if (EXPECT_NOT_TAKEN(pos < 0 || pos >= m_sourceRes)) {
440 case ReconstructionFilter::EClamp:
443 case ReconstructionFilter::ERepeat:
446 case ReconstructionFilter::EMirror:
448 if (pos >= m_sourceRes)
449 pos = 2*m_sourceRes - pos - 1;
451 case ReconstructionFilter::EZero:
453 case ReconstructionFilter::EOne:
457 return source[stride * pos + offset];
461 ReconstructionFilter::EBoundaryCondition m_bc;
466 int m_fastStart, m_fastEnd;
467 int m_taps, m_halfTaps;
470 extern MTS_EXPORT_CORE std::ostream &
operator<<(std::ostream &os,
const ReconstructionFilter::EBoundaryCondition &value);
EBoundaryCondition
When resampling data to a different resolution using Resampler::resample(), this enumeration specifie...
Definition: rfilter.h:53
#define MTS_FILTER_RESOLUTION
Reconstruction filters will be tabulated at this resolution.
Definition: rfilter.h:28
Assume that the input repeats in a periodic fashion.
Definition: rfilter.h:57
Generic serializable object, which supports construction from a Properties instance.
Definition: cobject.h:40
Resampler(const ReconstructionFilter *rfilter, ReconstructionFilter::EBoundaryCondition bc, int sourceRes, int targetRes)
Create a new Resampler object that transforms between the specified resolutions.
Definition: rfilter.h:123
int floorToInt(Scalar value)
Integer floor function (single precision)
Definition: math.h:100
std::ostream & operator<<(std::ostream &os, const ReconstructionFilter::EBoundaryCondition &value)
#define MTS_EXPORT_CORE
Definition: getopt.h:29
Generic interface to separable image reconstruction filters.
Definition: rfilter.h:44
virtual void serialize(Stream *stream, InstanceManager *manager) const
Serialize this object to a binary data stream.
int32_t modulo(int32_t a, int32_t b)
Always-positive modulo function (assumes b > 0)
Definition: math.h:67
Float evalDiscretized(Float x) const
Perform a lookup into the discretized version.
Definition: rfilter.h:76
virtual Float eval(Float x) const =0
Evaluate the filter function.
#define SAssert(cond)
``Static'' assertion (to be used outside of classes that derive from Object)
Definition: logger.h:79
Abstract seekable stream class.
Definition: stream.h:58
#define MTS_DECLARE_CLASS()
This macro must be used in the initial definition in classes that derive from Object.
Definition: class.h:158
virtual void configure()
Configure the object (called once after construction and addition of all child ConfigurableObject ins...
void resampleAndClamp(const Scalar *source, size_t sourceStride, Scalar *target, size_t targetStride, int channels, Scalar min=(Scalar) 0, Scalar max=(Scalar) 1)
Resample a multi-channel array and clamp the results to a specified valid range.
Definition: rfilter.h:232
int ceilToInt(Scalar value)
Integer ceil function (single precision)
Definition: math.h:103
Associative parameter map for constructing subclasses of ConfigurableObject.
Definition: properties.h:46
Coordinates the serialization and unserialization of object graphs.
Definition: serialization.h:65
~Resampler()
Release all memory.
Definition: rfilter.h:201
void resample(const Scalar *source, size_t sourceStride, Scalar *target, size_t targetStride, int channels)
Resample a multi-channel array.
Definition: rfilter.h:342
Assume that the input is mirrored along the boundary.
Definition: rfilter.h:59
Utility class for efficiently resampling discrete datasets to different resolutions.
Definition: rfilter.h:107
Float getRadius() const
Return the filter's width.
Definition: rfilter.h:67
Assume that the input function is zero outside of the defined domain.
Definition: rfilter.h:61
int getBorderSize() const
Return the block border size required when rendering with this filter.
Definition: rfilter.h:70
Scalar clamp(Scalar value, Scalar min, Scalar max)
Generic clamping function.
Definition: math.h:51