HuggingKatze commited on
Commit
1fa8091
·
1 Parent(s): ead1826

add gif via LFS and update README/app

Browse files
Files changed (5) hide show
  1. .gitattributes +1 -0
  2. README.md +26 -26
  3. app.py +1 -1
  4. screenshots/demo_overview.gif +3 -0
  5. utils.py +1 -1
.gitattributes CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ screenshots/*.gif filter=lfs diff=lfs merge=lfs -text
README.md CHANGED
@@ -10,17 +10,23 @@ pinned: false
10
 
11
  # Image Quantization and CT Windowing Explorer
12
 
13
- An interactive Streamlit app for teaching how quantization and CT-style windowing affect grayscale medical image visualization.
 
 
 
 
 
 
 
14
 
15
  ## Project Summary
16
 
17
- This app demonstrates two related but different operations:
18
 
19
- 1. Quantization reduces the number of representable gray levels, which can introduce information loss, banding, and larger reconstruction error.
20
- 2. Windowing is a display operation that maps a selected intensity range to visible grayscale values and clips values outside that range.
21
 
22
- Users can explore bit depth and window bounds, then observe four synchronized visualization states, histogram behavior, error maps, and summary metrics.
23
- In the histogram view, the overlaid window bounds act as visual reference markers, while the plotted distributions are intended to highlight quantization effects on stored intensities.
24
 
25
  ## Local Run
26
 
@@ -57,30 +63,28 @@ sample_images/builtin_samples/
57
  docs/
58
  requirements.txt
59
  Makefile
 
60
  ```
61
 
62
  ## Features
63
 
64
- - Built-in sample images bundled inside the repository
65
- - Built-in samples derived from CT-RATE, LDCT-and-Projection-data, and RSNA PE sources
66
- - Upload support for `PNG`, `JPG`, `JPEG`, and `DICOM`
67
- - Upload support for `NIfTI` volumes (`.nii`, `.nii.gz`)
68
- - Automatic handling of single-channel grayscale and 3-channel grayscale copies
69
- - Uniform quantization with adjustable bit depth
70
- - Adjustable window lower and upper bounds, with CT window presets
71
- - Slice selection for volumetric inputs and rotation controls for uploaded DICOM/NIfTI files
72
- - Four-panel visualization: original, windowed, quantized, and quantized + windowed
73
- - Clickable double-arrow comparison graph that stays synchronized with the metrics selector
74
- - Intensity histogram with window overlay; the overlay marks the chosen window, while the distribution view focuses on quantization effects
75
- - Squared-error map for the currently selected comparison
76
- - Metrics: MSE, PSNR, gray levels used, and entropy
77
- - In-app explanatory notes for every interactive control
78
 
79
  ## Known Limitations
80
 
81
  - The app is educational and not intended for clinical interpretation.
82
  - Uploaded PNG/JPG images may already be restricted to 8-bit precision.
83
  - The current version works on one 2D slice at a time.
 
84
  - The CT-RATE built-in sample is rotated 90 degrees clockwise in the app to match the expected viewing orientation.
85
  - Public deployment should still respect the original dataset licenses and redistribution terms for bundled sample content.
86
 
@@ -88,8 +92,8 @@ Makefile
88
 
89
  - **Input source** switches between prepared built-in examples and your own uploaded data.
90
  - **Built-in sample** lets you compare different CT-oriented datasets quickly.
91
- - **Slice index** appears for volumetric inputs and chooses the active axial slice.
92
- - **Rotate uploaded image** appears for uploaded DICOM/NIfTI data when the slice orientation needs correction.
93
  - **Quantization bit depth** controls how many gray levels remain after uniform quantization.
94
  - The app initializes the quantization display at 4 bits by default, unless the loaded image has a lower maximum bit depth.
95
  - **CT window preset** applies common lower/upper bound pairs such as lung or mediastinal ranges.
@@ -98,10 +102,6 @@ Makefile
98
  - **Visualization arrows** can be clicked to choose which pair of panels should be compared.
99
  - **Metrics → Compare** is synchronized with the arrow graph and updates all downstream plots.
100
 
101
- ## Screenshots / GIF
102
-
103
- Add screenshots here after the UI is finalized.
104
-
105
  ## Design Notes
106
 
107
  See [docs/design_choices.md](docs/design_choices.md).
 
10
 
11
  # Image Quantization and CT Windowing Explorer
12
 
13
+ An interactive Streamlit app for exploring how quantization and CT-style windowing change grayscale medical image display.
14
+
15
+ ## Screenshots / GIF
16
+
17
+ ### Main app overview
18
+
19
+ ![Main app overview](screenshots/demo_overview.gif)
20
+
21
 
22
  ## Project Summary
23
 
24
+ This app compares two related but different operations on grayscale medical images:
25
 
26
+ 1. Quantization reduces the number of stored gray levels and can introduce banding or reconstruction error.
27
+ 2. Windowing changes only how a chosen intensity range is displayed and clips values outside that range.
28
 
29
+ The interface lets users adjust bit depth and window bounds, then compare four image states, a histogram, an error map, and summary metrics side by side.
 
30
 
31
  ## Local Run
32
 
 
63
  docs/
64
  requirements.txt
65
  Makefile
66
+ Dockerfile
67
  ```
68
 
69
  ## Features
70
 
71
+ - Built-in CT-oriented examples from CT-RATE, LDCT-and-Projection-data, and RSNA PE
72
+ - Upload support for `PNG`, `JPG`, `JPEG`, and single-slice `DICOM`
73
+ - Automatic handling of grayscale images, including 3-channel grayscale copies
74
+ - Adjustable quantization bit depth and CT-style window bounds
75
+ - Slice selection for volumetric built-in samples
76
+ - Rotation control for uploaded DICOM slices
77
+ - Four synchronized views: original, windowed, quantized, and quantized + windowed
78
+ - Histogram, squared-error map, and summary metrics (`MSE`, `PSNR`, gray levels, entropy)
79
+ - Clickable comparison arrows synchronized with the metrics selector
80
+ - In-app explanatory notes for each main control
 
 
 
 
81
 
82
  ## Known Limitations
83
 
84
  - The app is educational and not intended for clinical interpretation.
85
  - Uploaded PNG/JPG images may already be restricted to 8-bit precision.
86
  - The current version works on one 2D slice at a time.
87
+ - Uploaded files are limited to PNG/JPG and single-slice DICOM in the current app; NIfTI upload is not enabled in the active UI.
88
  - The CT-RATE built-in sample is rotated 90 degrees clockwise in the app to match the expected viewing orientation.
89
  - Public deployment should still respect the original dataset licenses and redistribution terms for bundled sample content.
90
 
 
92
 
93
  - **Input source** switches between prepared built-in examples and your own uploaded data.
94
  - **Built-in sample** lets you compare different CT-oriented datasets quickly.
95
+ - **Slice index** appears for volumetric built-in inputs and chooses the active axial slice.
96
+ - **Rotate uploaded image** appears for uploaded DICOM data when the slice orientation needs correction.
97
  - **Quantization bit depth** controls how many gray levels remain after uniform quantization.
98
  - The app initializes the quantization display at 4 bits by default, unless the loaded image has a lower maximum bit depth.
99
  - **CT window preset** applies common lower/upper bound pairs such as lung or mediastinal ranges.
 
102
  - **Visualization arrows** can be clicked to choose which pair of panels should be compared.
103
  - **Metrics → Compare** is synchronized with the arrow graph and updates all downstream plots.
104
 
 
 
 
 
105
  ## Design Notes
106
 
107
  See [docs/design_choices.md](docs/design_choices.md).
app.py CHANGED
@@ -143,7 +143,7 @@ def maybe_reset_controls(loaded_key: str, default_low: float, default_high: floa
143
  return
144
 
145
  max_bits = int(st.session_state.get("bit_depth_max", 12))
146
- bit_depth = min(4, max_bits)
147
  st.session_state["loaded_key"] = loaded_key
148
  st.session_state["bit_depth"] = bit_depth
149
  st.session_state["bit_depth_slider"] = bit_depth
 
143
  return
144
 
145
  max_bits = int(st.session_state.get("bit_depth_max", 12))
146
+ bit_depth = min(6, max_bits)
147
  st.session_state["loaded_key"] = loaded_key
148
  st.session_state["bit_depth"] = bit_depth
149
  st.session_state["bit_depth_slider"] = bit_depth
screenshots/demo_overview.gif ADDED

Git LFS Details

  • SHA256: 93f37612ef13e0094c2145008c06b0a14690578d51a34b369591f615a3ba7e0a
  • Pointer size: 132 Bytes
  • Size of remote file: 1.72 MB
utils.py CHANGED
@@ -432,7 +432,7 @@ def create_histogram_figure(
432
  ax.set_ylabel("Count")
433
  ax.set_title(label, fontsize=10, loc="left")
434
  ax.legend(loc="upper right", fontsize=8)
435
- axes[-1].set_xlabel("Intensity")
436
  fig.suptitle("Intensity Histogram Comparison", fontsize=12)
437
  fig.tight_layout()
438
  return fig
 
432
  ax.set_ylabel("Count")
433
  ax.set_title(label, fontsize=10, loc="left")
434
  ax.legend(loc="upper right", fontsize=8)
435
+ axes[-1].set_xlabel("Intensity/HU Value")
436
  fig.suptitle("Intensity Histogram Comparison", fontsize=12)
437
  fig.tight_layout()
438
  return fig