diff --git a/include/mitsuba/core/bitmap.h b/include/mitsuba/core/bitmap.h
index 3b64bb25..9384ff33 100644
--- a/include/mitsuba/core/bitmap.h
+++ b/include/mitsuba/core/bitmap.h
@@ -1023,9 +1023,9 @@ public:
* horizontal and vertical boundary conditions when looking up data
* outside of the input domain.
*
- * A maximum and maximum image value can be specified to prevent to prevent
- * out-of-range values that are created by the resampling process.
- *
+ * A maximum and maximum image value can be specified to prevent to
+ * prevent out-of-range values that are created by the resampling process.
+ *
* The optional 'temp' parameter can be used to pass an image of
* resolution Vector2i(target->getWidth(), this->getHeight())
* to avoid intermediate memory allocations.
@@ -1036,25 +1036,6 @@ public:
Bitmap *target, Bitmap *temp = NULL,
Float minValue = 0.0f, Float maxValue = 1.0f) const;
- /**
- * \brief Apply a separable filter to the image
- *
- * Applies the provided filter while observing the specified
- * horizontal and vertical boundary conditions when looking up data
- * outside of the input domain.
- *
- * A maximum and maximum image value can be specified to prevent to prevent
- * out-of-range values that are created by the filtering process.
- *
- * The optional 'temp' parameter can be used to pass an image of
- * the same dimensions as the source and target image.
- */
- void filter(const ReconstructionFilter *rfilter,
- ReconstructionFilter::EBoundaryCondition bch,
- ReconstructionFilter::EBoundaryCondition bcv,
- Bitmap *target, Bitmap *temp = NULL,
- Float minValue = 0.0f, Float maxValue = 1.0f) const;
-
/**
* \brief Up- or down-sample this image to a different resolution
*
@@ -1064,6 +1045,8 @@ public:
*
* A maximum and maximum image value can be specified to prevent to prevent
* out-of-range values that are created by the resampling process.
+ *
+ * This function allocates a new output image and returns it.
*/
ref resample(const ReconstructionFilter *rfilter,
ReconstructionFilter::EBoundaryCondition bch,
@@ -1071,6 +1054,48 @@ public:
const Vector2i &size, Float minValue = 0.0f,
Float maxValue = 1.0f) const;
+ /**
+ * \brief Apply a separable convolution filter to the image
+ *
+ * Applies the provided filter while observing the specified
+ * horizontal and vertical boundary conditions when looking up data
+ * outside of the input domain.
+ *
+ * In comparison to \ref convolve(), this function operates
+ * in the primal domain.
+ *
+ * A maximum and maximum image value can be specified to prevent to
+ * prevent out-of-range values that are created by the filtering process.
+ *
+ * The optional 'temp' parameter can be used to pass an image of
+ * the same dimensions as the source and target image.
+ */
+ void filter(const ReconstructionFilter *rfilter,
+ ReconstructionFilter::EBoundaryCondition bch,
+ ReconstructionFilter::EBoundaryCondition bcv,
+ Bitmap *target, Bitmap *temp = NULL,
+ Float minValue = 0.0f, Float maxValue = 1.0f) const;
+
+ /**
+ * \brief Apply a separable convolution filter to the image
+ *
+ * Applies the provided filter while observing the specified
+ * horizontal and vertical boundary conditions when looking up data
+ * outside of the input domain.
+ *
+ * In comparison to \ref convolve(), this function operates
+ * in the primal domain.
+ *
+ * A maximum and maximum image value can be specified to prevent to
+ * prevent out-of-range values that are created by the filtering process.
+ *
+ * This function allocates a new output image and returns it.
+ */
+ ref filter(const ReconstructionFilter *rfilter,
+ ReconstructionFilter::EBoundaryCondition bch,
+ ReconstructionFilter::EBoundaryCondition bcv,
+ Float minValue = 0.0f, Float maxValue = 1.0f) const;
+
//! @}
// ======================================================================
diff --git a/include/mitsuba/core/rfilter.h b/include/mitsuba/core/rfilter.h
index 186d71cd..81e3617d 100644
--- a/include/mitsuba/core/rfilter.h
+++ b/include/mitsuba/core/rfilter.h
@@ -84,8 +84,8 @@ public:
MTS_DECLARE_CLASS()
protected:
- /// Create a new reconstruction filter
- ReconstructionFilter(const Properties &props);
+ /// Create a new reconstruction filter
+ ReconstructionFilter(const Properties &props);
/// Unserialize a filter
ReconstructionFilter(Stream *stream, InstanceManager *manager);
@@ -121,126 +121,88 @@ template struct Resampler {
* outside of the defined input domain.
*/
Resampler(const ReconstructionFilter *rfilter, ReconstructionFilter::EBoundaryCondition bc,
- int sourceRes, int targetRes) : m_bc(bc), m_sourceRes(sourceRes), m_targetRes(targetRes) {
+ int sourceRes, int targetRes) : m_bc(bc), m_sourceRes(sourceRes), m_targetRes(targetRes),
+ m_start(NULL), m_weights(NULL) {
SAssert(sourceRes > 0 && targetRes > 0);
Float filterRadius = rfilter->getRadius(), scale = 1.0f, invScale = 1.0f;
/* Low-pass filter: scale reconstruction filters when downsampling */
if (targetRes < sourceRes) {
scale = (Float) sourceRes / (Float) targetRes;
- invScale = 1 / scale;
+ invScale = 1 / scale;
filterRadius *= scale;
}
- m_taps = floorToInt(filterRadius * 2);
- m_start = new int[targetRes];
- m_weights = new Scalar[m_taps * targetRes];
- m_fastStart = 0;
- m_fastEnd = m_targetRes;
+ m_taps = ceilToInt(filterRadius * 2);
+ if (sourceRes == targetRes && (m_taps % 2) != 1)
+ --m_taps;
+ m_halfTaps = m_taps / 2;
- for (int i=0; i= m_sourceRes)
- m_fastEnd = std::min(m_fastEnd, i - 1);
+ /* Determine the index of the first original sample that might contribute */
+ m_start[i] = floorToInt(center - filterRadius + (Float) 0.5f);
+ /* Determine the size of center region, on which to run fast non condition-aware code */
+ if (m_start[i] < 0)
+ m_fastStart = std::max(m_fastStart, i + 1);
+ else if (m_start[i] + m_taps - 1 >= m_sourceRes)
+ m_fastEnd = std::min(m_fastEnd, i - 1);
+
+ Float sum = 0;
+ for (int j=0; jeval(pos * invScale);
+ m_weights[i * m_taps + j] = (Scalar) weight;
+ sum += weight;
+ }
+
+ /* Normalize the contribution of each sample */
+ Float normalization = 1.0f / sum;
+ for (int j=0; jeval(pos * invScale);
- m_weights[i * m_taps + j] = (Scalar) weight;
+ for (int i=0; ieval((Float) (i-m_halfTaps));
+ m_weights[i] = weight;
sum += weight;
}
-
- /* Normalize the contribution of each sample */
Float normalization = 1.0f / sum;
- for (int j=0; j struct Resampler {
void resampleAndClamp(const Scalar *source, size_t sourceStride,
Scalar *target, size_t targetStride, int channels,
Scalar min = (Scalar) 0, Scalar max = (Scalar) 1) {
- const int taps = m_taps;
+ const int taps = m_taps, halfTaps = m_halfTaps;
targetStride = channels * (targetStride - 1);
sourceStride *= channels;
- /* Resample the left border region, while accounting for the boundary conditions */
- for (int i=0; i
#include
#include
+#include
#if defined(__WINDOWS__)
#undef _CRT_SECURE_NO_WARNINGS
@@ -2216,12 +2217,12 @@ void Bitmap::applyMatrix(Float matrix_[3][3]) {
}
}
-/// Bitmap resampling utility function
+/// Bitmap filtering / resampling utility function
template static void resample(ref rfilter,
ReconstructionFilter::EBoundaryCondition bch,
ReconstructionFilter::EBoundaryCondition bcv,
const Bitmap *source, Bitmap *target, ref temp, Float minValue,
- Float maxValue, bool forceFiltering) {
+ Float maxValue, bool filter) {
if (!rfilter) {
/* Resample using a 2-lobed Lanczos reconstruction filter */
@@ -2235,7 +2236,7 @@ template static void resample(ref
}
if (source->getHeight() == target->getHeight() &&
- source->getWidth() == target->getWidth() && !forceFiltering) {
+ source->getWidth() == target->getWidth() && !filter) {
memcpy(target->getData(), source->getData(), source->getBufferSize());
return;
}
@@ -2245,13 +2246,13 @@ template static void resample(ref
minValue != -std::numeric_limits::infinity() ||
maxValue != std::numeric_limits::infinity();
- if (source->getWidth() != target->getWidth() || forceFiltering) {
+ if (source->getWidth() != target->getWidth() || filter) {
/* Re-sample along the X direction */
Resampler r(rfilter, bch, source->getWidth(), target->getWidth());
/* Create a bitmap for intermediate storage */
if (!temp) {
- if (source->getHeight() == target->getHeight() && !forceFiltering)
+ if (source->getHeight() == target->getHeight() && !filter)
temp = target; // write directly to the output bitmap
else // otherwise: write to a temporary bitmap
temp = new Bitmap(source->getPixelFormat(), source->getComponentFormat(),
@@ -2289,7 +2290,7 @@ template static void resample(ref
source = temp;
}
- if (source->getHeight() != target->getHeight() || forceFiltering) {
+ if (source->getHeight() != target->getHeight() || filter) {
/* Re-sample along the Y direction */
Resampler r(rfilter, bcv, source->getHeight(), target->getHeight());
@@ -2370,7 +2371,6 @@ void Bitmap::filter(const ReconstructionFilter *rfilter,
}
}
-
ref Bitmap::resample(const ReconstructionFilter *rfilter,
ReconstructionFilter::EBoundaryCondition bch,
ReconstructionFilter::EBoundaryCondition bcv,
@@ -2378,10 +2378,23 @@ ref Bitmap::resample(const ReconstructionFilter *rfilter,
ref result = new Bitmap(m_pixelFormat, m_componentFormat, size);
result->m_metadata = m_metadata;
result->m_gamma = m_gamma;
+ result->m_channelNames = m_channelNames;
resample(rfilter, bch, bcv, result, NULL, minValue, maxValue);
return result;
}
+ref Bitmap::filter(const ReconstructionFilter *rfilter,
+ ReconstructionFilter::EBoundaryCondition bch,
+ ReconstructionFilter::EBoundaryCondition bcv,
+ Float minValue, Float maxValue) const {
+ ref result = new Bitmap(m_pixelFormat, m_componentFormat, getSize());
+ result->m_metadata = m_metadata;
+ result->m_gamma = m_gamma;
+ result->m_channelNames = m_channelNames;
+ filter(rfilter, bch, bcv, result, NULL, minValue, maxValue);
+ return result;
+}
+
bool Bitmap::operator==(const Bitmap &bitmap) const {
return m_pixelFormat == bitmap.m_pixelFormat &&
m_componentFormat == bitmap.m_componentFormat &&
diff --git a/src/libpython/base.h b/src/libpython/base.h
index 5e546a4d..71c75ed0 100644
--- a/src/libpython/base.h
+++ b/src/libpython/base.h
@@ -26,6 +26,11 @@
#pragma warning(disable : 4267) // 'return' : conversion from 'size_t' to 'long', possible loss of data
#endif
+#define BP_RETURN_CONSTREF bp::return_value_policy()
+#define BP_RETURN_NONCONSTREF bp::return_value_policy()
+#define BP_RETURN_VALUE bp::return_value_policy()
+#define BP_RETURN_INTREF bp::return_internal_reference<>()
+
#define BP_STRUCT_DECL(Name, Init) \
bp::class_ Name ##_struct(#Name, Init); \
bp::register_ptr_to_python();
@@ -149,11 +154,6 @@
bp::detail::current_scope = value.ptr(); \
} while (0);
-#define BP_RETURN_CONSTREF bp::return_value_policy()
-#define BP_RETURN_NONCONSTREF bp::return_value_policy()
-#define BP_RETURN_VALUE bp::return_value_policy()
-#define BP_RETURN_INTREF bp::return_internal_reference<>()
-
namespace boost {
namespace python {
template T* get_pointer(mitsuba::ref & p) {
diff --git a/src/libpython/core.cpp b/src/libpython/core.cpp
index 233b73af..74e2473f 100644
--- a/src/libpython/core.cpp
+++ b/src/libpython/core.cpp
@@ -604,13 +604,13 @@ static ref pluginmgr_create_helper(PluginManager *manager, b
return object;
}
-static ref pluginmgr_create(PluginManager *manager, bp::dict dict) {
+static bp::object pluginmgr_create(PluginManager *manager, bp::dict dict) {
std::map objs;
ref result = pluginmgr_create_helper(manager, dict, objs);
for (std::map::iterator it = objs.begin();
it != objs.end(); ++it)
it->second->decRef();
- return result;
+ return cast(result);
}
static bp::tuple mkCoordinateSystem(const Vector &n) {
@@ -1099,8 +1099,10 @@ BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(fromLinearRGB_overloads, fromLinearRGB, 3
BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(fromXYZ_overloads, fromXYZ, 3, 4)
BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(fromIPT_overloads, fromIPT, 3, 4)
BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(reset_overloads, reset, 0, 1)
-BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(filter_overloads, filter, 4, 7)
-BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(resample_overloads, resample, 4, 7)
+BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(resample1_overloads, resample, 4, 7)
+BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(resample2_overloads, resample, 6, 4)
+BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(filter1_overloads, filter, 4, 7)
+BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(filter2_overloads, filter, 3, 5)
#define IMPLEMENT_ANIMATION_TRACK(Name) \
BP_CLASS(Name, AbstractAnimationTrack, (bp::init())) \
@@ -1475,13 +1477,17 @@ void export_core() {
ReconstructionFilter::EBoundaryCondition, ReconstructionFilter::EBoundaryCondition,
Bitmap *, Bitmap *, Float, Float) const = &Bitmap::resample;
+ ref (Bitmap::*resample_2)(const ReconstructionFilter *,
+ ReconstructionFilter::EBoundaryCondition, ReconstructionFilter::EBoundaryCondition,
+ const Vector2i &, Float, Float) const = &Bitmap::resample;
+
void (Bitmap::*filter_1)(const ReconstructionFilter *,
ReconstructionFilter::EBoundaryCondition, ReconstructionFilter::EBoundaryCondition,
Bitmap *, Bitmap *, Float, Float) const = &Bitmap::filter;
- ref (Bitmap::*resample_2)(const ReconstructionFilter *,
+ ref (Bitmap::*filter_2)(const ReconstructionFilter *,
ReconstructionFilter::EBoundaryCondition, ReconstructionFilter::EBoundaryCondition,
- const Vector2i &, Float, Float) const = &Bitmap::resample;
+ Float, Float) const = &Bitmap::filter;
const std::vector & (Bitmap::*getChannelNames_1)() const = &Bitmap::getChannelNames;
@@ -1541,9 +1547,10 @@ void export_core() {
.def("copyFrom", copyFrom_3)
.def("convolve", &Bitmap::convolve)
.def("arithmeticOperation", &Bitmap::arithmeticOperation, BP_RETURN_VALUE)
- .def("filter", filter_1, filter_overloads())
- .def("resample", resample_1, resample_overloads())
- .def("resample", resample_2, BP_RETURN_VALUE)
+ .def("resample", resample_1, resample1_overloads())
+ .def("resample", resample_2, resample2_overloads()[BP_RETURN_VALUE])
+ .def("filter", filter_1, filter1_overloads())
+ .def("filter", filter_2, filter2_overloads()[BP_RETURN_VALUE])
.def("setGamma", &Bitmap::setGamma)
.def("getGamma", &Bitmap::getGamma)
.def("setMetadataString", &Bitmap::setMetadataString)
diff --git a/src/rfilters/box.cpp b/src/rfilters/box.cpp
index 7f7e148a..072022ab 100644
--- a/src/rfilters/box.cpp
+++ b/src/rfilters/box.cpp
@@ -48,7 +48,7 @@ public:
}
std::string toString() const {
- return "BoxFilter[]";
+ return formatString("GaussianFilter[radius=%f]", m_radius);
}
MTS_DECLARE_CLASS()