Skip to content
Snippets Groups Projects
Commit 674331a1 authored by Hugo chauvet's avatar Hugo chauvet
Browse files

add convertor to transform zarr back to micro-manager folder format

parent 6b900b96
No related branches found
No related tags found
No related merge requests found
......@@ -6,7 +6,7 @@ This file is part of DITB.
Contains the cli interface for the convert command
"""
import click
from ..io.converter import MM2Zarr
from ..io.converter import MM2Zarr, mmzarr2MMformat
from pathlib import Path
import shutil
......@@ -14,16 +14,16 @@ import shutil
@click.argument('source', nargs=-1, type=click.Path(exists=True))
@click.option('--destination', type=click.Path(exists=False),
default = './processed',
help = "The destination folder to store converted data. The default value is a folder called ./processed")
@click.option('--convertor', type=click.Choice(['MMtoZARR', 'ZARRtoHDF', 'ZARRtoTif'], case_sensitive=False),
help="Set the convertor to use", default = 'MMtoZARR')
help = "The destination folder to store converted data. The default value is a folder called: ./processed if MM2ZARR convertor is used. ./back_to_MM if ZARR2MM convertor is used")
@click.option('--convertor', type=click.Choice(['MM2ZARR', 'ZARR2MM', 'ZARR2HDF', 'ZARR2Tif'], case_sensitive=False),
help="Set the convertor to use", default = 'MM2ZARR')
@click.option('--force', is_flag=True, help="Force convert even if the directory is already in the destination folder")
def convert(convertor, source, destination, force):
"""
📦 Convert data to several format.
"""
if convertor in ['ZARRtoHDF', 'ZARRtoTif']:
if convertor in ['ZARR2HDF', 'ZARR2Tif']:
raise NotImplementedError(f'This convertor {convertor} is not yet implemented, please be patient')
# Create the destination folder if it does not exist
......@@ -31,12 +31,13 @@ def convert(convertor, source, destination, force):
destination = destination.expanduser()
destination.mkdir(exist_ok=True)
if convertor == 'MM2ZARR':
print(f'🪩 Use {convertor} to convert data to {destination} folder')
if convertor == 'MMtoZARR':
for filein in source:
if destination.name != filein:
# Create the output name
output_file = Path(destination) / (Path(filein).name + '.zarr')
output_file = destination / (Path(filein).name + '.zarr')
print(f'\n▷ convert {filein} to {output_file}')
if force:
......@@ -58,7 +59,43 @@ def convert(convertor, source, destination, force):
print(f'Error for file {filein}')
print(e)
if convertor == 'ZARR2MM':
print('\n🪩 Done 🌟🌟🌟')
# Change de default destination ./processed to './back_to_MM'
if destination.name == 'processed':
destination = destination.parent / 'back_to_MM'
print(f'🪩 Use {convertor} to convert data to {destination} folder')
for filein in source:
# Check that the destination folder is not in the input files liste
# and that the file end by .zarr
fin = Path(filein)
if destination.name != filein and fin.suffix == '.zarr':
# Create the output destination for this file
output_dir = destination / fin.name.replace(fin.suffix, '')
print(f'\n▷ convert {filein} to {output_dir}')
if force:
# Remove the directory if it exists
if output_dir.is_dir():
shutil.rmtree(str(output_dir))
try:
mmzarr2MMformat(filein, output_dir)
except Exception as e:
print(f'Error for file {filein}')
print(e)
else:
if not output_dir.is_dir():
try:
mmzarr2MMformat(filein, output_dir)
except Exception as e:
print(f'Error for file {filein}')
print(e)
print('\n🪩 Done 🌟🌟🌟')
......@@ -8,10 +8,20 @@ from pathlib import Path
from ome_zarr.writer import write_image
from ome_zarr.io import parse_url
from tqdm import tqdm
import dask
from dask.diagnostics import ProgressBar
from tifffile import imwrite
from .metadata import (make_global_metadata, get_pixel_size, get_roi_name_indices, reshapeMetadata,
imagej_style_metadata, omero_style_metadata)
from .imread import mmread
imagej_style_metadata, omero_style_metadata, read_mmzarr_metadata, get_dimensions)
from .imread import mmread, mmzarr_read
try:
import orjson as json
orjson = True
except Exception:
import json
orjson = False
def MM2Zarr(mm_root_folder: str, destination_folder: str):
......@@ -88,3 +98,56 @@ def MM2Zarr(mm_root_folder: str, destination_folder: str):
'version': str(__version)}
def mmzarr2MMformat(zarr_folder: str, destinatin_folder: str):
"""
Convert mmzarr dataset back to micromanager format
"""
@dask.delayed
def write_position(file_name, image, metadata=None, resolution=None, imagej=True) -> None:
"""
Simple function to write a single tiff file with resolution information
"""
imwrite(file_name, image, imagej=imagej, resolution=resolution, metadata=metadata)
zarr_folder = Path(zarr_folder)
data = mmzarr_read(zarr_folder)
meta = read_mmzarr_metadata(zarr_folder)
dims = get_dimensions(meta)
dest_folder = Path(destinatin_folder)
dest_folder.mkdir(parents=True, exist_ok=True)
pxsize = get_pixel_size(meta)
resolution = (1/pxsize, 1/pxsize)
write_operations = []
## Micromanager images and metadata are grouped in all images in one folder per position
for ir, r in enumerate(meta['_roi_tiles']):
roi = r.capitalize()
for it, tile in enumerate(meta['_roi_tiles'][r]):
mm_meta_format = {'Summary': meta['Summary']}
for t in range(dims['time']):
for c in range(dims['channel']):
for z in range(dims['z']):
im_coord = meta[f'{roi}/Tile{it}'][t,c,z]['coords']
im_meta = meta[f'{roi}/Tile{it}'][t,c,z]['metadata']
mm_meta_format[f'Coords-{im_meta["FileName"]}'] = im_coord
mm_meta_format[f'Metadata-{im_meta["FileName"]}'] = im_meta
# Create the parent folder if it does not exist
outfile = dest_folder / Path(im_meta['FileName'])
outfile.parent.mkdir(exist_ok=True)
write_operations += [
write_position(outfile, data[it, t, c, z], resolution=resolution, imagej=True)
]
with open(outfile.parent / 'metadata.txt', 'wb') as f:
if orjson:
f.write(json.dumps(mm_meta_format, option=json.OPT_INDENT_2 | json.OPT_APPEND_NEWLINE))
else:
f.write(json.dumps(mm_meta_format, indent=1, ensure_ascii=True))
# Run the task graph of Dask (delayed image operations on new_image_stack: load images, process, save)
with ProgressBar():
dask.compute(write_operations)
......@@ -13,13 +13,17 @@ from pathlib import Path
from shutil import copy2
import dask
from dask.diagnostics import ProgressBar
from .metadata import get_pixel_size, list_images
from tifffile.tifffile import read_mm_header
from ditb.io.imread import mmzarr_read
from .metadata import get_pixel_size, list_images, read_mmzarr_metadata, get_dimensions
from ome_zarr.writer import write_image
from ome_zarr.io import parse_url
from tqdm import tqdm
import zarr
def write_mmformat(source_root_folder: str, destination_root_folder: str,
global_metadata: dict, new_image_stack: np.array) -> None:
"""
......
......@@ -688,3 +688,13 @@ def stack_info(metadata: dict):
channels = get_channel_names(metadata)
return f'-camera roi: {roi}\n-channels: {channels}'
def read(folder_path: str):
"""
Read metadata either from micromanager folder format or from a mmzarr format
"""
if Path(folder_path).suffix == '.zarr':
return read_mmzarr_metadata(folder_path)
else:
return make_global_metadata(folder_path)
......@@ -82,3 +82,12 @@ def channelName2Color(channel_name: str):
return wavelength_to_hex(wmean)
return '#ffffff'
def merge_channels(dask_array, pixel_size):
"""
Use the microfilm lib to create RGB merged color image
TODO
"""
pass
\ No newline at end of file
......@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "DITB"
version = "20240701rc3"
version = "20240916rc1"
readme = "README.md"
requires-python = ">=3.11"
authors = [{ name = "Hugo Chauvet", email = "hugo.chauvet@synchrotron-soleil.fr" }]
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment