Skip to content

Commit ed4e8d4

Browse files
hongquanliclaude
andcommitted
Address PR review comments #9, #10, #11, #12
- Fix #9: Preserve flatfield data when checkbox is toggled off (just hide UI) - Fix #10: Combine error message string into single line - Fix #11: Add shape validation in apply_flatfield and apply_flatfield_region - Fix #12: Add error handling in load_flatfield for invalid file formats 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 9bd52a7 commit ed4e8d4

2 files changed

Lines changed: 49 additions & 10 deletions

File tree

gui/app.py

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1235,15 +1235,8 @@ def on_blend_toggled(self, checked):
12351235
self.blend_value_widget.setVisible(checked)
12361236

12371237
def on_flatfield_toggled(self, checked):
1238+
# Only show/hide flatfield options; preserve any loaded/calculated data
12381239
self.flatfield_options_widget.setVisible(checked)
1239-
if not checked:
1240-
# Clear flatfield when disabled
1241-
self.flatfield = None
1242-
self.darkfield = None
1243-
self.flatfield_status.setText("No flatfield")
1244-
self.flatfield_status.setStyleSheet("color: #86868b; font-size: 11px;")
1245-
self.view_flatfield_button.setEnabled(False)
1246-
self.clear_flatfield_button.setEnabled(False)
12471240

12481241
def on_flatfield_mode_changed(self, button):
12491242
is_calculate = self.calc_radio.isChecked()

src/tilefusion/flatfield.py

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ def calculate_flatfield(
5454
"""
5555
if not HAS_BASICPY:
5656
raise ImportError(
57-
"basicpy is required for flatfield calculation. " "Install with: pip install basicpy"
57+
"basicpy is required for flatfield calculation. Install with: pip install basicpy"
5858
)
5959

6060
if not tiles:
@@ -121,7 +121,22 @@ def apply_flatfield(
121121
-------
122122
corrected : ndarray
123123
Corrected tile with shape (C, Y, X), same dtype as input.
124+
125+
Raises
126+
------
127+
ValueError
128+
If tile and flatfield shapes are incompatible.
124129
"""
130+
# Validate shapes
131+
if tile.shape != flatfield.shape:
132+
raise ValueError(
133+
f"Tile shape {tile.shape} does not match flatfield shape {flatfield.shape}"
134+
)
135+
if darkfield is not None and tile.shape != darkfield.shape:
136+
raise ValueError(
137+
f"Tile shape {tile.shape} does not match darkfield shape {darkfield.shape}"
138+
)
139+
125140
# Avoid division by zero
126141
flatfield_safe = np.where(flatfield > 1e-6, flatfield, 1.0)
127142

@@ -158,7 +173,18 @@ def apply_flatfield_region(
158173
-------
159174
corrected : ndarray
160175
Corrected region with same shape as input.
176+
177+
Raises
178+
------
179+
ValueError
180+
If region and flatfield shapes are incompatible.
161181
"""
182+
# Validate channel count for 3D regions
183+
if region.ndim == 3 and region.shape[0] != flatfield.shape[0]:
184+
raise ValueError(
185+
f"Region has {region.shape[0]} channels but flatfield has {flatfield.shape[0]} channels"
186+
)
187+
162188
# Extract corresponding flatfield/darkfield regions
163189
if region.ndim == 2:
164190
ff_region = flatfield[0, y_slice, x_slice]
@@ -219,8 +245,28 @@ def load_flatfield(path: Path) -> Tuple[np.ndarray, Optional[np.ndarray]]:
219245
Flatfield array with shape (C, Y, X).
220246
darkfield : ndarray or None
221247
Darkfield array with shape (C, Y, X), or None if not present.
248+
249+
Raises
250+
------
251+
ValueError
252+
If the file format is invalid (not a dictionary with 'flatfield' key).
222253
"""
223-
data = np.load(path, allow_pickle=True).item()
254+
loaded = np.load(path, allow_pickle=True)
255+
try:
256+
data = loaded.item()
257+
except (AttributeError, ValueError) as exc:
258+
raise ValueError(
259+
f"Invalid flatfield file format at '{path}'. "
260+
"Expected a NumPy .npy file containing a dictionary as saved by "
261+
"`save_flatfield` (with keys like 'flatfield' and 'darkfield')."
262+
) from exc
263+
264+
if not isinstance(data, dict) or "flatfield" not in data:
265+
raise ValueError(
266+
f"Invalid flatfield file format at '{path}'. "
267+
"Expected a dictionary with at least a 'flatfield' entry."
268+
)
269+
224270
flatfield = data["flatfield"]
225271
darkfield = data.get("darkfield", None)
226272
return flatfield, darkfield

0 commit comments

Comments
 (0)