imagej / imagej/ImageJ

Image -> Type -> 8 bit have unexpected behavior

Open
#134 5 comments 0 reactions 0 assignees View on GitHub

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.

![image](https://user-images.githubusercontent.com/49025029/136633094-6bb1b082-4589-4e7f-8e28-57dd14e9bd35.png)

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](https://user-images.githubusercontent.com/49025029/136633131-6096b392-4f55-42fe-a887-f7f05917ec9e.png)

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

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.