Skip to content

fix: add vmin vmax to mo.image and do not norm uint8 values#8889

Open
dmadisetti wants to merge 5 commits intomainfrom
dm/mo-5395
Open

fix: add vmin vmax to mo.image and do not norm uint8 values#8889
dmadisetti wants to merge 5 commits intomainfrom
dm/mo-5395

Conversation

@dmadisetti
Copy link
Copy Markdown
Collaborator

📝 Summary

Closes #8569

This PR introduces vmin and vmax to allow un/saturated images. Additionally, it changes the behavior of uint8 to always be normalized between 0-255.

@vercel
Copy link
Copy Markdown

vercel bot commented Mar 26, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
marimo-docs Ready Ready Preview, Comment Mar 26, 2026 11:57pm

Request Review

@dmadisetti dmadisetti added bug Something isn't working api-change labels Mar 26, 2026
@dmadisetti dmadisetti marked this pull request as ready for review March 26, 2026 23:13
Copilot AI review requested due to automatic review settings March 26, 2026 23:13
@dmadisetti dmadisetti requested a review from akshayka March 26, 2026 23:15
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds explicit intensity scaling controls to mo.image so users can preserve relative brightness across images (addressing #8569) while avoiding unintended normalization for uint8 inputs.

Changes:

  • Add vmin/vmax parameters to mo.image and pass them through to the internal normalization routine.
  • Skip min-max normalization for uint8 arrays by default; optionally clip/scale when bounds are provided.
  • Add tests covering uint8 behavior, uniform arrays, and vmin/vmax scaling/clamping.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

File Description
marimo/_plugins/stateless/image.py Adds vmin/vmax support and updates normalization to preserve uint8 values by default.
tests/_plugins/stateless/test_image.py Adds regression tests for uint8 non-normalization and new vmin/vmax behavior.

img = PILImage.open(_io.BytesIO(base64.b64decode(b64)))
pixels = np.array(img).flatten()
# 0 clipped to 100 → 0; 128 → (128-100)/100*255 ≈ 71; 255 clipped to 200 → 255
assert pixels[0] == 0
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test describes the expected middle pixel scaling (~71) but doesn’t assert it, so a regression in the actual normalization math could still pass. Add an assertion for pixels[1] with an appropriate tolerance for rounding.

Suggested change
assert pixels[0] == 0
assert pixels[0] == 0
assert abs(int(pixels[1]) - 71) <= 1

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor

@akshayka akshayka left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm okay with the API change, but see my comment below and inline.

Additionally, it changes the behavior of uint8 to always be normalized between 0-255.

Is this a breaking change? If so, please mention that explicitly in the PR description and add the breaking label to this PR.

Comment on lines +176 to +181
vmin: minimum value for normalization when `src` is an array. Values
below `vmin` are clipped. If `None`, defaults to the array
minimum. Only used when `src` is array-like.
vmax: maximum value for normalization when `src` is an array. Values
above `vmax` are clipped. If `None`, defaults to the array
maximum. Only used when `src` is array-like.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please provide a usage example that demonstrates when vmin/vmax should be supplied (and how to supply them).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

api-change bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

mo.image always normalize image intensity from min-max to 0-255, making inter-image comparison impossibile

3 participants