Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added max to bitmap and checkerboard textures, added tests for both m… #719

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)