Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion transforms/images/apply-flatfield-tool/.bumpversion.cfg
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[bumpversion]
current_version = 2.0.1
current_version = 2.0.1-dev1
commit = False
tag = False
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)(\-(?P<release>[a-z]+)(?P<dev>\d+))?
Expand Down
29 changes: 29 additions & 0 deletions transforms/images/apply-flatfield-tool/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog],
and this project adheres to [Semantic Versioning].


## [2.0.1-dev1] - 2025-01-12

### Added

- "keepOrigDtype" option is added to the tool, so that the end user can choose to keep the original data type after the correction is applied, e.g., uint16 -> uint16. Otherwise, floating point output is kept.

### Changed

### Deprecated

### Removed

### Fixed

### Security


<!-- Links -->
[keep a changelog]: https://keepachangelog.com/en/1.0.0/
[semantic versioning]: https://semver.org/spec/v2.0.0.html

1 change: 1 addition & 0 deletions transforms/images/apply-flatfield-tool/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,4 @@ Command line options:
| `--dfPattern` | Filename pattern used to match darkfield files to image files | Input | string |
| `--outDir` | Output collection | Output | collection |
| `--preview` | Preview the output images' names without actually running computation | Input | boolean |
| `--keepOrigDtype`| Keep the original image data type if true | Input | boolean |
2 changes: 1 addition & 1 deletion transforms/images/apply-flatfield-tool/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2.0.1
2.0.1-dev1
4 changes: 4 additions & 0 deletions transforms/images/apply-flatfield-tool/applyflatfield.cwl
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ inputs:
inputBinding:
prefix: --preview
type: boolean?
keepOrigDtype:
inputBinding:
prefix: --keepOrigDtype
type: boolean?
outputs:
outDir:
outputBinding:
Expand Down
6 changes: 6 additions & 0 deletions transforms/images/apply-flatfield-tool/ict.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ inputs:
name: preview
required: false
type: boolean
- description: Keep original image data type if true, otherwise convert to float
format:
- boolean
name: keepOrigDtype
required: false
type: boolean
name: polusai/ApplyFlatfield
outputs:
- description: Output collection
Expand Down
8 changes: 7 additions & 1 deletion transforms/images/apply-flatfield-tool/plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,13 @@
"type": "boolean",
"description": "Preview the output images' names without actually running computation",
"required": false
}
},
{
"name": "keepOrigDtype",
"type": "boolean",
"description": "Keep original image data type if true, otherwise convert to float",
"required": false
}
],
"outputs": [
{
Expand Down
2 changes: 1 addition & 1 deletion transforms/images/apply-flatfield-tool/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "polus-images-transforms-images-apply-flatfield"
version = "2.0.1"
version = "2.0.1-dev1"
description = ""
authors = [
"Nick Schaub <nicholas.schaub@nih.gov>",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
from . import utils
from .apply_flatfield import apply

__version__ = "2.0.1"
__version__ = "2.0.1-dev1"
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@
import typing

import typer
from polus.images.transforms.images.apply_flatfield import apply
from polus.images.transforms.images.apply_flatfield import utils
from polus.images.transforms.images.apply_flatfield import apply, utils

# Initialize the logger
logging.basicConfig(
Expand Down Expand Up @@ -69,6 +68,11 @@ def main( # noqa: PLR0913
"--preview",
help="Preview the output without saving.",
),
keep_orig_dtype: typing.Optional[bool] = typer.Option(
True,
"--keepOrigDtype",
help="Keep the original dtype of the input images.",
),
) -> None:
"""CLI for the Apply Flatfield plugin.

Expand All @@ -87,6 +91,7 @@ def main( # noqa: PLR0913
logger.info(f"dfPattern = {df_pattern}")
logger.info(f"outDir = {out_dir}")
logger.info(f"preview = {preview}")
logger.info(f"keepOrigDtype = {keep_orig_dtype}")

out_files = apply(
img_dir=img_dir,
Expand All @@ -96,6 +101,7 @@ def main( # noqa: PLR0913
df_pattern=df_pattern,
out_dir=out_dir,
preview=preview,
keep_orig_dtype=keep_orig_dtype,
)

if preview:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import bfio
import numpy
import numpy as np
import preadator
import tqdm
from filepattern import FilePattern
Expand All @@ -26,7 +27,8 @@ def apply( # noqa: PLR0913
df_pattern: typing.Optional[str],
out_dir: pathlib.Path,
preview: bool = False,
) -> list[pathlib.Path]:
keep_orig_dtype: typing.Optional[bool] = True,
) -> typing.List[pathlib.Path]:
"""Run batch-wise flatfield correction on the image collection.

Args:
Expand All @@ -41,6 +43,9 @@ def apply( # noqa: PLR0913
saved.
preview: if True, return the paths to the images that would be saved
without actually performing any other computation.
keep_orig_dtype: if True, the output images will be saved with the same
dtype as the input images. If False, the output images will be saved as
float32.
"""
img_fp = FilePattern(str(img_dir), img_pattern)
img_variables = img_fp.get_variables()
Expand Down Expand Up @@ -82,16 +87,17 @@ def apply( # noqa: PLR0913
if preview:
out_files.extend(img_paths)
else:
_unshade_images(img_paths, out_dir, ff_path, df_path)
_unshade_images(img_paths, out_dir, ff_path, df_path, keep_orig_dtype)

return out_files


def _unshade_images(
img_paths: list[pathlib.Path],
img_paths: typing.List[pathlib.Path],
out_dir: pathlib.Path,
ff_path: pathlib.Path,
df_path: typing.Optional[pathlib.Path],
keep_orig_dtype: typing.Optional[bool] = True,
) -> None:
"""Remove the given flatfield components from all images and save outputs.

Expand All @@ -100,6 +106,9 @@ def _unshade_images(
out_dir: directory to save the corrected images
ff_path: path to the flatfield image
df_path: path to the darkfield image
keep_orig_dtype: if True, the output images will be saved with the same
dtype as the input images. If False, the output images will be saved as
float32.
"""
logger.info(f"Applying flatfield correction to {len(img_paths)} images ...")
logger.info(f"{ff_path.name = } ...")
Expand All @@ -123,18 +132,16 @@ def _unshade_images(
total=len(batch_indices) - 1,
):
_unshade_batch(
img_paths[i_start:i_end],
out_dir,
ff_image,
df_image,
img_paths[i_start:i_end], out_dir, ff_image, df_image, keep_orig_dtype
)


def _unshade_batch(
batch_paths: list[pathlib.Path],
batch_paths: typing.List[pathlib.Path],
out_dir: pathlib.Path,
ff_image: numpy.ndarray,
df_image: typing.Optional[numpy.ndarray] = None,
keep_orig_dtype: typing.Optional[bool] = True,
) -> None:
"""Apply flatfield correction to a batch of images.

Expand All @@ -143,6 +150,9 @@ def _unshade_batch(
out_dir: directory to save the corrected images
ff_image: component to be used for flatfield correction
df_image: component to be used for flatfield correction
keep_orig_dtype: if True, the output images will be saved with the same
dtype as the input images. If False, the output images will be saved as
float32.
"""
# Load images
with preadator.ProcessManager(
Expand All @@ -162,12 +172,44 @@ def _unshade_batch(
images = [img for _, img in sorted(images, key=operator.itemgetter(0))]
img_stack = numpy.stack(images, axis=0).astype(numpy.float32)

# find min and max values of original images (across last 2 axes)
def get_min_max(img_stack):
min_val = img_stack.min(axis=(-1, -2), keepdims=True)
max_val = img_stack.max(axis=(-1, -2), keepdims=True)
return min_val, max_val

min_orig, max_orig = get_min_max(img_stack) # dim: n_images x 1 x 1

# Apply flatfield correction
if df_image is not None:
img_stack -= df_image

img_stack /= ff_image + 1e-8

# calculate min and max values of corrected images
min_new, max_new = get_min_max(img_stack)

# scale corrected images to original range
img_stack = (img_stack - min_new) / (max_new - min_new) * (
max_orig - min_orig
) + min_orig

if keep_orig_dtype:
orig_dtype = images[0].dtype
# if integer type
if np.issubdtype(orig_dtype, np.integer):
# clip out of range values for orig dtype
dtype_info = np.iinfo(orig_dtype)
img_stack = np.clip(img_stack, dtype_info.min, dtype_info.max)

# round and cast to original dtype
img_stack = np.round(img_stack).astype(orig_dtype)

elif np.issubdtype(orig_dtype, np.floating):
# floating point image, clamp to [0,1]
img_stack = np.clip(img_stack, 0.0, 1.0)
img_stack = img_stack.astype(orig_dtype)

# Save outputs
with preadator.ProcessManager(
name="unshade_batch::save",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
"""Utilities for the apply flatfield plugin."""

import logging
import multiprocessing
import os
import pathlib
import typing

import bfio
import numpy
Expand All @@ -13,7 +13,7 @@
MAX_WORKERS = max(1, multiprocessing.cpu_count() // 2)


def load_img(path: pathlib.Path, i: int) -> tuple[int, numpy.ndarray]:
def load_img(path: pathlib.Path, i: int) -> typing.Tuple[int, numpy.ndarray]:
"""Load image from path.

This method is intended to be used in a thread. The index is used to
Expand Down
Loading
Loading