Skip to content

Image -> Type -> 8 bit have unexpected behavior  #134

@Michael-H777

Description

@Michael-H777

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.

image

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

image

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions