-
Notifications
You must be signed in to change notification settings - Fork 1
fullfield stitching #52
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,107 @@ | ||||||
| import numpy as np | ||||||
| from tifffile import imread | ||||||
| from PIL import Image | ||||||
| from PIL.TiffTags import TAGS | ||||||
| import json | ||||||
|
|
||||||
|
|
||||||
| ############################################# | ||||||
| # Full field | ||||||
| ############################################# | ||||||
|
|
||||||
| def read_si_fullfield_metadata(fullfield_fn): | ||||||
| '''Reads metadata from a ScanImage full-field tiff file. | ||||||
|
|
||||||
| Args: | ||||||
| fullfield_fn: str or Path, path to the full-field tiff file | ||||||
|
|
||||||
| Returns: | ||||||
| num_slices: int, number of slices in the z-stack | ||||||
| num_volumes: int, number of volumes in the z-stack | ||||||
| num_columns: int, number of columns in the full-field image | ||||||
| ''' | ||||||
|
|
||||||
| with Image.open(fullfield_fn) as img: | ||||||
| meta_dict = {TAGS[key] : img.tag[key] for key in img.tag_v2} | ||||||
|
|
||||||
| num_slices_ind = np.where(['SI.hStackManager.actualNumSlices = ' in x for x in meta_dict['Software'][0].split('\n')])[0][0] | ||||||
| num_slices_txt = meta_dict['Software'][0].split('\n')[num_slices_ind] | ||||||
| num_slices = int(num_slices_txt.split('= ')[1]) | ||||||
|
|
||||||
| num_volumes_ind = np.where(['SI.hStackManager.actualNumVolumes = ' in x for x in meta_dict['Software'][0].split('\n')])[0][0] | ||||||
| num_volumes_txt = meta_dict['Software'][0].split('\n')[num_volumes_ind] | ||||||
| num_volumes = int(num_volumes_txt.split('= ')[1]) | ||||||
|
|
||||||
| artist_json = json.loads(meta_dict['Artist'][0]) | ||||||
| num_columns = len(artist_json['RoiGroups']['imagingRoiGroup']['rois']) | ||||||
|
|
||||||
| return num_slices, num_volumes, num_columns | ||||||
|
|
||||||
|
|
||||||
| def stitch_fullfield(fullfield_fn, channels=[0]): | ||||||
| '''Stitches a full-field tiff file. | ||||||
|
|
||||||
| Args: | ||||||
| fullfield_fn: str or Path, path to the full-field tiff file | ||||||
| channels: list of int, channels to stitch | ||||||
| Only applicable if the full-field tiff file contains multiple channels | ||||||
|
|
||||||
| Returns: | ||||||
| fullfield_stitched: 2D or 3D array, stitched full-field image | ||||||
| ''' | ||||||
| num_slices, num_volumes, num_columns = read_si_fullfield_metadata(fullfield_fn) | ||||||
| fullfield_all = imread(fullfield_fn) | ||||||
| assert fullfield_all.shape[0] == num_slices * num_volumes | ||||||
| num_rows = int((fullfield_all.shape[1]+1) / num_columns) | ||||||
|
||||||
| num_rows = int((fullfield_all.shape[1]+1) / num_columns) | |
| num_rows = int((fullfield_all.shape[-2]+1) / num_columns) |
Copilot
AI
Jul 3, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This assignment to fullfield_ is immediately overwritten on the next line, making it dead code. Remove or consolidate these lines to avoid confusion.
| fullfield_ = np.concatenate([fullfield_all[ind,:,:],np.zeros((fullfield_all.shape[0],1,fullfield_all.shape[2]))], axis=1) |
Copilot
AI
Jul 3, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] The roll offset multiplier 12 is a magic number with no explanation. Consider defining a named constant or adding a comment describing why 12 was chosen.
| fullfield_stitched = np.concatenate([np.roll(fullfield_[:, i*num_rows : (i+1)*num_rows, :], -i*12, axis=1) for i in range(num_columns)],axis=2) | |
| fullfield_stitched = np.concatenate([np.roll(fullfield_[:, i*num_rows : (i+1)*num_rows, :], -i*ROLL_OFFSET_MULTIPLIER, axis=1) for i in range(num_columns)],axis=2) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using a mutable default argument (
channels=[0]) can lead to unexpected behavior if the list is modified. Consider usingchannels=Noneand initializing inside the function (e.g.if channels is None: channels = [0]).