Image -> Type -> 8 bit have unexpected behavior
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 786
- Forks
- 267
- PR merge metrics
- No merged PRs in 30d
Description
Hello all,
I am working with imageJ and python. My data is float32, and was converted into int8 in ImageJ. After investigating, I realized that binning into 0 -> 255 range using ImageJ (Image- > type -> int8) have different distribution vs binning into 0 -> 255 range using python. Code to reproduce as follow
import numpy as np
import tifffile
np.random.seed(20) # seed is only for reproducing min/max, described behavior continues to show without using seed
test_data = np.random.normal(size=(5, 500, 500))
test_data = test_data.cumsum(axis=0).astype(np.float32)
# at this stage, test_data[0] have smaller range than test_data itself due to cumsum()
print(test_data.min(), test_data.max()) #prints: -10.676156, 10.48997
print(test_data[0].min(), test_data[0].max()) #prints: -4.385402 4.4191904
tifffile.imwrite('test.tif', test_data)
# manually convert float32 data into int8 using imageJ
# please note that converting test_data into min_max_location then multiply by 255, then round should in theory yield
# equivalent result to converting float32 into int8 using a linear scaling
min_max_location = (test_data - test_data.min()) / (test_data.max() - test_data.min())
python_binning = (min_max_location * 255).round() # this operation bins the test_data into 0->255 range using a lienar scaling
imagej_binned = tifffile.imread('test-1.tif') # read the data binned by imageJ
However, after plotting the data, the distribution changed **dramatically**.
please note the difference in y-axis scale between python-binned data vs imagej-binned data
as well as difference in number of 0 and 255 between python-binned data vs imagej-binned data
Also pay attention to how the shape of the distribution changed, original data and python-binned data both have taller and skinner distribution compared to imageJ binned data.

After further investigation, the binning is done using the display range in **ImageJ -> Image -> Show Info** that only captures the range of first slice of stack

and not the **-10.676156, 10.48997** range of the entire stack printed by python.
Shouldn't the int8 conversion min/max reflect the **entire stack's** distribution? Please let me know.
@rasband
python version: 3.8.11
numpy version: 1.20.3
ImageJ version: ImageJ 1.53k; Java 1.8.0_172 [64-bit]
python platform: Linux version 5.11.0-37-generic (buildd@lcy01-amd64-021) (gcc (Ubuntu 9.3.0-17ubuntu1\~20.04) 9.3.0, GNU ld (GNU Binutils for Ubuntu) 2.34)
ImageJ platform: win10
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Reproduce the behavior with the supplied NumPy and tifffile script, then open the generated stack in ImageJ and compare Image > Type > 8-bit conversion with the reported display ranges. Check whether conversion uses the first slice or the entire stack; done means the behavior is explained and the conversion consistently reflects the intended range.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java, numpy, python
- Domain
- computer-vision
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100