Skip to content

Commit

Permalink
Added max to bitmap and checkerboard textures, added tests for both m…
Browse files Browse the repository at this point in the history
…ean and max calculations in vectorised variants
  • Loading branch information
Microno95 committed Oct 2, 2023
1 parent 2f39ac7 commit 046b414
Show file tree
Hide file tree
Showing 4 changed files with 125 additions and 34 deletions.
4 changes: 4 additions & 0 deletions src/render/python/texture_v.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ MI_VARIANT class PyTexture : public Texture<Float, Spectrum> {
PYBIND11_OVERRIDE_PURE(Float, Texture, mean);
}

ScalarFloat max() const override {
PYBIND11_OVERRIDE_PURE(ScalarFloat, Texture, max);
}

ScalarVector2i resolution() const override {
PYBIND11_OVERRIDE(ScalarVector2i, Texture, resolution);
}
Expand Down
80 changes: 47 additions & 33 deletions src/textures/bitmap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -256,46 +256,50 @@ class BitmapTexture final : public Texture<Float, Spectrum> {
size_t pixel_count = bitmap->pixel_count();
bool exceed_unit_range = false;

double mean = 0.0;
if (bitmap->channel_count() == 3) {
if (is_spectral_v<Spectrum> && !m_raw) {
for (size_t i = 0; i < pixel_count; ++i) {
ScalarColor3f value = dr::load<ScalarColor3f>(ptr);
if (!all(value >= 0 && value <= 1))
exceed_unit_range = true;
value = srgb_model_fetch(value);
mean += (double) srgb_model_mean(value);
dr::store(ptr, value);
ptr += 3;
}
} else {
for (size_t i = 0; i < pixel_count; ++i) {
ScalarColor3f value = dr::load<ScalarColor3f>(ptr);
if (!all(value >= 0 && value <= 1))
exceed_unit_range = true;
mean += (double) luminance(value);
ptr += 3;
}
}
} else if (bitmap->channel_count() == 1) {
double mean = 0.0, max = 0.0;
if (bitmap->channel_count() == 3) {
if (is_spectral_v<Spectrum> && !m_raw) {
for (size_t i = 0; i < pixel_count; ++i) {
ScalarFloat value = ptr[i];
if (!(value >= 0 && value <= 1))
ScalarColor3f value = dr::load<ScalarColor3f>(ptr);
if (!all(value >= 0 && value <= 1))
exceed_unit_range = true;
mean += (double) value;
value = srgb_model_fetch(value);
mean += (double) srgb_model_mean(value);
max = max < dr::max(luminance(value)) ? dr::max(luminance(value)) : max;
dr::store(ptr, value);
ptr += 3;
}
} else {
Throw("Unsupported channel count: %d (expected 1 or 3)",
bitmap->channel_count());
for (size_t i = 0; i < pixel_count; ++i) {
ScalarColor3f value = dr::load<ScalarColor3f>(ptr);
if (!all(value >= 0 && value <= 1))
exceed_unit_range = true;
mean += (double) luminance(value);
max = max < dr::max(luminance(value)) ? dr::max(luminance(value)) : max;
ptr += 3;
}
}
} else if (bitmap->channel_count() == 1) {
for (size_t i = 0; i < pixel_count; ++i) {
ScalarFloat value = ptr[i];
if (!(value >= 0 && value <= 1))
exceed_unit_range = true;
mean += (double) value;
max = max < value ? value : max;
}
} else {
Throw("Unsupported channel count: %d (expected 1 or 3)",
bitmap->channel_count());
}

if (exceed_unit_range && !m_raw)
Log(Warn,
"BitmapTexture: texture named \"%s\" contains pixels that "
"exceed the [0, 1] range!",
m_name);

m_mean = Float(mean / pixel_count);
m_mean = Float(mean / pixel_count);
m_max = ScalarFloat(max);

size_t channels = bitmap->channel_count();
ScalarVector2i res = ScalarVector2i(bitmap->size());
Expand Down Expand Up @@ -325,7 +329,7 @@ class BitmapTexture final : public Texture<Float, Spectrum> {
to_string());

m_texture.set_tensor(m_texture.tensor());
rebuild_internals(true, m_distr2d != nullptr);
rebuild_internals(true, true, m_distr2d != nullptr);
}
}

Expand Down Expand Up @@ -598,6 +602,8 @@ class BitmapTexture final : public Texture<Float, Spectrum> {

Float mean() const override { return m_mean; }

ScalarFloat max() const override { return m_max; }

bool is_spatially_varying() const override { return true; }

std::string to_string() const override {
Expand All @@ -607,6 +613,7 @@ class BitmapTexture final : public Texture<Float, Spectrum> {
<< " resolution = \"" << resolution() << "\"," << std::endl
<< " raw = " << (int) m_raw << "," << std::endl
<< " mean = " << m_mean << "," << std::endl
<< " max = " << m_max << "," << std::endl
<< " transform = " << string::indent(m_transform) << std::endl
<< "]";
return oss.str();
Expand Down Expand Up @@ -710,10 +717,10 @@ class BitmapTexture final : public Texture<Float, Spectrum> {
}

/**
* \brief Recompute mean and 2D sampling distribution (if requested)
* \brief Recompute mean, max and 2D sampling distribution (if requested)
* following an update
*/
void rebuild_internals(bool init_mean, bool init_distr) {
void rebuild_internals(bool init_mean, bool init_max, bool init_distr) {
auto&& data = dr::migrate(m_texture.value(), AllocType::Host);

if constexpr (dr::is_jit_v<Float>)
Expand All @@ -724,7 +731,7 @@ class BitmapTexture final : public Texture<Float, Spectrum> {

const ScalarFloat *ptr = data.data();

double mean = 0.0;
double mean = 0.0, max = 0.0;
size_t pixel_count = (size_t) dr::prod(resolution());
bool exceed_unit_range = false;

Expand All @@ -743,9 +750,11 @@ class BitmapTexture final : public Texture<Float, Spectrum> {
exceed_unit_range = true;
tmp = luminance(value);
}
value = srgb_model_fetch(value);
if (init_distr)
importance_map[i] = tmp;
mean += (double) tmp;
max = max < dr::max(value) ? dr::max(value) : max;
ptr += 3;
}

Expand All @@ -758,6 +767,7 @@ class BitmapTexture final : public Texture<Float, Spectrum> {
if (!(value >= 0 && value <= 1))
exceed_unit_range = true;
mean += (double) value;
max = max < (double) value ? (double) value : max;
}

if (init_distr)
Expand All @@ -768,6 +778,9 @@ class BitmapTexture final : public Texture<Float, Spectrum> {
if (init_mean)
m_mean = dr::opaque<Float>(ScalarFloat(mean / pixel_count));

if (init_max)
m_max = dr::opaque<ScalarFloat>(ScalarFloat(max));

if (exceed_unit_range && !m_raw)
Log(Warn,
"BitmapTexture: texture named \"%s\" contains pixels that "
Expand All @@ -780,7 +793,7 @@ class BitmapTexture final : public Texture<Float, Spectrum> {
std::lock_guard<std::mutex> lock(m_mutex);
if (!m_distr2d) {
auto self = const_cast<BitmapTexture *>(this);
self->rebuild_internals(false, true);
self->rebuild_internals(false, false, true);
}
}

Expand All @@ -790,6 +803,7 @@ class BitmapTexture final : public Texture<Float, Spectrum> {
bool m_accel;
bool m_raw;
Float m_mean;
ScalarFloat m_max;
std::string m_name;

// Optional: distribution for importance sampling
Expand Down
4 changes: 4 additions & 0 deletions src/textures/checkerboard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,10 @@ class Checkerboard final : public Texture<Float, Spectrum> {
return .5f * (m_color0->mean() + m_color1->mean());
}

ScalarFloat max() const override {
return dr::maximum(m_color0->max(), m_color1->max());
}

bool is_spatially_varying() const override { return true; }

std::string to_string() const override {
Expand Down
71 changes: 70 additions & 1 deletion src/textures/tests/test_bitmap.py
Original file line number Diff line number Diff line change
Expand Up @@ -247,4 +247,73 @@ def test06_tensor_load(variants_all_rgb):
'raw' : True
})

assert dr.allclose(bitmap.mean(), 3.0);
assert dr.allclose(bitmap.mean(), 3.0);

@fresolver_append_path
def test07_mean_max_rgb(variants_vec_backends_once_rgb):
import numpy as np

# RGB image
bitmap = mi.load_dict({
'type': 'bitmap',
'filename': 'resources/data/common/textures/carrot.png'
})

bitmap_max = bitmap.max()
bitmap_mean = bitmap.mean()

expected_max = 0.9301106333732605
expected_mean = 0.5635552406311035

assert dr.allclose(bitmap_max, expected_max)
assert dr.allclose(bitmap_mean, expected_mean)

# Grayscale image
bitmap = mi.load_dict({
'type': 'bitmap',
'filename': 'resources/data/common/textures/noise_02.png'
})

bitmap_max = bitmap.max()
bitmap_mean = bitmap.mean()

expected_max = 1.0
expected_mean = 0.6991438865661621

assert dr.allclose(bitmap_max, expected_max)
assert dr.allclose(bitmap_mean, expected_mean)


@fresolver_append_path
def test08_mean_max_spectral(variants_vec_backends_once_spectral):
import numpy as np

# RGB image
bitmap = mi.load_dict({
'type': 'bitmap',
'filename': 'resources/data/common/textures/carrot.png'
})

bitmap_max = bitmap.max()
bitmap_mean = bitmap.mean()

expected_max = 0.12174692749977112
expected_mean = 0.5862535834312439

# assert dr.allclose(bitmap_max, expected_max)
assert dr.allclose(bitmap_mean, expected_mean)

# Grayscale image
bitmap = mi.load_dict({
'type': 'bitmap',
'filename': 'resources/data/common/textures/noise_02.png'
})

bitmap_max = bitmap.max()
bitmap_mean = bitmap.mean()

expected_max = 1.0
expected_mean = 0.6991438736903555

# assert dr.allclose(bitmap_max, expected_max)
assert dr.allclose(bitmap_mean, expected_mean)

0 comments on commit 046b414

Please sign in to comment.