Repository 's3segmenter'
hg clone https://toolshed.g2.bx.psu.edu/repos/perssond/s3segmenter

Changeset 2:96d0d969ebc9 (2022-09-16)
Previous changeset 1:41e8efe8df43 (2022-03-11)
Commit message:
planemo upload for repository https://github.com/goeckslab/tools-mti/tree/main/tools/s3segmenter commit 0f4f17235c5961c2fd3d4c30180507f66214c11d
modified:
macros.xml
s3segmenter.xml
added:
test-data/stack_probabilities.tiff
test-data/test.ome.tiff
removed:
S3segmenter.py
rowit.py
save_tifffile_pyramid.py
b
diff -r 41e8efe8df43 -r 96d0d969ebc9 S3segmenter.py
--- a/S3segmenter.py Fri Mar 11 23:37:49 2022 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
[
b"@@ -1,592 +0,0 @@\n-import matplotlib.pyplot as plt\n-import tifffile\n-import os\n-import numpy as np\n-from skimage import io as skio\n-from scipy.ndimage import *\n-import scipy.ndimage as ndi\n-from skimage.morphology import *\n-from skimage.morphology import extrema\n-from skimage import morphology\n-from skimage.measure import regionprops\n-from skimage.transform import resize\n-from skimage.filters import gaussian, threshold_otsu, threshold_local\n-from skimage.feature import peak_local_max\n-from skimage.color import label2rgb\n-from skimage.io import imsave,imread\n-from skimage.segmentation import clear_border, watershed, find_boundaries\n-from scipy.ndimage.filters import uniform_filter\n-from os.path import *\n-from os import listdir, makedirs, remove\n-import pickle\n-import shutil\n-import fnmatch\n-import cv2\n-import sys\n-import argparse\n-import re\n-import copy\n-import datetime\n-from joblib import Parallel, delayed\n-from rowit import WindowView, crop_with_padding_mask\n-from save_tifffile_pyramid import save_pyramid\n-import subprocess\n-import ome_types\n-\n-\n-def imshowpair(A,B):\n-    plt.imshow(A,cmap='Purples')\n-    plt.imshow(B,cmap='Greens',alpha=0.5)\n-    plt.show()\n-\n-    \n-def imshow(A):\n-    plt.imshow(A)\n-    plt.show()\n-    \n-def overlayOutline(outline,img):\n-    img2 = img.copy()\n-    stacked_img = np.stack((img2,)*3, axis=-1)\n-    stacked_img[outline > 0] = [65535, 0, 0]\n-    imshowpair(img2,stacked_img)\n-    \n-def normI(I):\n-    Irs=resize(I,(I.shape[0]//10,I.shape[1]//10) );\n-    p1 = np.percentile(Irs,10);\n-    J = I-p1;\n-    p99 = np.percentile(Irs,99.99);\n-    J = J/(p99-p1);\n-    return J\n-\n-def contour_pm_watershed(\n-    contour_pm, sigma=2, h=0, tissue_mask=None,\n-    padding_mask=None, min_area=None, max_area=None\n-):\n-    if tissue_mask is None:\n-        tissue_mask = np.ones_like(contour_pm)\n-    padded = None\n-    if padding_mask is not None and np.any(padding_mask == 0):\n-        contour_pm, padded = crop_with_padding_mask(\n-            contour_pm, padding_mask, return_mask=True\n-        )\n-        tissue_mask = crop_with_padding_mask(\n-            tissue_mask, padding_mask\n-        )\n-    \n-    maxima = peak_local_max(\n-        extrema.h_maxima(\n-            ndi.gaussian_filter(np.invert(contour_pm), sigma=sigma),\n-            h=h\n-        ),\n-        indices=False,\n-        footprint=np.ones((3, 3))\n-    )\n-    maxima = label(maxima).astype(np.int32)\n-    \n-    # Passing mask into the watershed function will exclude seeds outside\n-    # of the mask, which gives fewer and more accurate segments\n-    maxima = watershed(\n-        contour_pm, maxima, watershed_line=True, mask=tissue_mask\n-    ) > 0\n-    \n-    if min_area is not None and max_area is not None:\n-        maxima = label(maxima, connectivity=1).astype(np.int32)\n-        areas = np.bincount(maxima.ravel())\n-        size_passed = np.arange(areas.size)[\n-            np.logical_and(areas > min_area, areas < max_area)\n-        ]\n-        maxima *= np.isin(maxima, size_passed)\n-        np.greater(maxima, 0, out=maxima)\n-\n-    if padded is None:\n-        return maxima.astype(np.bool)\n-    else:\n-        padded[padded == 1] = maxima.flatten()\n-        return padded.astype(np.bool)\n-\n-def S3AreaSegmenter(nucleiPM, images, TMAmask, threshold,fileprefix,outputPath):\n-    nucleiCenters = nucleiPM[:,:,0]\n-    TMAmask= (nucleiCenters>np.amax(nucleiCenters)*0.8)*TMAmask\n-    area = []\n-    area.append(np.sum(np.sum(TMAmask)))\n-    for iChan in range(len(images)):\n-        image_gauss = gaussian(resize(images[iChan,:,:],(int(0.25*images.shape[1]),int(0.25*images.shape[2]))),1)\n-        if threshold ==-1:\n-            threshold = threshold_otsu(image_gauss)\n-        mask=resize(image_gauss>threshold,(images.shape[1],images.shape[2]),order = 0)*TMAmask\n-        area.append(np.sum(np.sum(mask)))\n-    os.mk    \n-    np.savetxt(outputPath + os.path.sep + fileprefix + '_area.csv',(np.transpose(np.asarray(area))),fmt='%10.5f')  \n-    return TMAmask\n-\n-def getMetadata(path,comm"..b"-                cytoFull= tifffile.imread(imagePath, key=iChan)\n-                cyto[count,:,:] = cytoFull[int(PMrect[0]):int(PMrect[0]+PMrect[2]), int(PMrect[1]):int(PMrect[1]+PMrect[3])]\n-                count+=1                \n-        else:\n-            cyto=np.empty((len(CytoMaskChan),rect[3],rect[2]),dtype=np.int16)\n-            for iChan in CytoMaskChan:\n-                cytoFull= tifffile.imread(imagePath, key=iChan)\n-                cyto[count,:,:] = cytoFull[int(PMrect[0]):int(PMrect[0]+PMrect[2]), int(PMrect[1]):int(PMrect[1]+PMrect[3])]\n-                count+=1\n-        cyto = np.amax(cyto,axis=0)\n-        cytoplasmMask,nucleiMaskTemp,cellMask = S3CytoplasmSegmentation(nucleiMask,cyto,TMAmask,args.cytoMethod,args.cytoDilation)\n-        exportMasks(nucleiMaskTemp,nucleiCrop,outputPath,filePrefix,'nuclei',commit,metadata,args.saveFig,args.saveMask)\n-        exportMasks(cytoplasmMask,cyto,outputPath,filePrefix,'cyto',commit,metadata,args.saveFig,args.saveMask)\n-        exportMasks(cellMask,cyto,outputPath,filePrefix,'cell',commit,metadata,args.saveFig,args.saveMask)\n-  \n-        cytoplasmMask,nucleiMaskTemp,cellMask = S3CytoplasmSegmentation(nucleiMask,cyto,TMAmask,'ring',args.cytoDilation)\n-        exportMasks(nucleiMaskTemp,nucleiCrop,outputPath,filePrefix,'nucleiRing',commit,metadata,args.saveFig,args.saveMask)\n-        exportMasks(cytoplasmMask,cyto,outputPath,filePrefix,'cytoRing',commit,metadata,args.saveFig,args.saveMask)\n-        exportMasks(cellMask,cyto,outputPath,filePrefix,'cellRing',commit,metadata,args.saveFig,args.saveMask)\n-        \n-    elif args.segmentCytoplasm == 'ignoreCytoplasm':\n-        exportMasks(nucleiMask,nucleiCrop,outputPath,filePrefix,'nuclei',commit,metadata)\n-        cellMask = nucleiMask\n-        exportMasks(nucleiMask,nucleiCrop,outputPath,filePrefix,'cell',commit,metadata)\n-        cytoplasmMask = nucleiMask\n-        \n-    detectPuncta = args.detectPuncta\n-    if (np.min(detectPuncta)>0):\n-        detectPuncta[:] = [number - 1 for number in detectPuncta] #convert 1-based indexing to 0-based indexing    \n-        if len(detectPuncta) != len(args.punctaSigma):\n-            args.punctaSigma = args.punctaSigma[0] * np.ones(len(detectPuncta))\n- \n-  \n-        if len(detectPuncta) != len(args.punctaSD):\n-            args.punctaSD = args.punctaSD[0] * np.ones(len(detectPuncta))\n-  \n-        counter=0\n-        for iPunctaChan in detectPuncta:\n-            punctaChan = tifffile.imread(imagePath,key = iPunctaChan)\n-            punctaChan = punctaChan[int(PMrect[0]):int(PMrect[0]+PMrect[2]), int(PMrect[1]):int(PMrect[1]+PMrect[3])]\n-            spots=S3punctaDetection(punctaChan,cellMask,args.punctaSigma[counter],args.punctaSD[counter])\n-            cellspotmask = nucleiMask\n-            P = regionprops(cellspotmask,intensity_image = spots ,cache=False)\n-            numSpots = []\n-            for prop in P:\n-                numSpots.append(np.uint16(np.round(prop.mean_intensity * prop.area)))\n-            np.savetxt(outputPath + os.path.sep + 'numSpots_chan' + str(iPunctaChan+1) +'.csv',(np.transpose(np.asarray(numSpots))),fmt='%10.5f')    \n-            edges = 1-(cellMask>0)\n-            stacked_img=np.stack((np.uint16((spots+edges)>0)*np.amax(punctaChan),punctaChan),axis=0)\n-             \n-            \n-            outputPathPuncta = outputPath + os.path.sep + filePrefix + os.path.sep + 'punctaChan'+str(iPunctaChan+1) + 'Outlines.ome.tif'\n-            \n-            # metadata_args = dict(\n-            #     pixel_sizes=(metadata.physical_size_y, metadata.physical_size_x),\n-            #     pixel_size_units=('\xc2\xb5m', '\xc2\xb5m'),\n-            #     software= 's3segmenter v' + commit\n-            #     )\n-            save_pyramid(\n-                stacked_img,\n-                outputPathPuncta,\n-                channel_names=['puncta outlines', 'image channel'],\n-                is_mask=False,\n-                **metadata\n-                )     \n-            \n-            counter=counter+1    \n-\n"
b
diff -r 41e8efe8df43 -r 96d0d969ebc9 macros.xml
--- a/macros.xml Fri Mar 11 23:37:49 2022 +0000
+++ b/macros.xml Fri Sep 16 20:05:54 2022 +0000
[
@@ -2,25 +2,36 @@
 <macros>
     <xml name="requirements">
         <requirements>
-            <container type="docker">labsyspharm/s3segmenter:@VERSION@</container>
+            <!--
             <requirement type="package" version="3.7">python</requirement>
             <requirement type="package">scikit-learn</requirement>
             <requirement version="0.14.2" type="package">scikit-image</requirement>
             <requirement type="package">matplotlib</requirement>
             <requirement version="2021.6.6" type="package">tifffile</requirement>
             <requirement type="package">opencv</requirement>
-            <!-- <requirement type="package">ome_types</requirement> -->
+            -->  
+            <container type="docker">labsyspharm/s3segmenter:@TOOL_VERSION@</container>
         </requirements>
     </xml>
 
-    <xml name="version_cmd">
-        <version_command>echo @VERSION@</version_command>
-    </xml>
     <xml name="citations">
         <citations>
         </citations>
     </xml>
 
-    <token name="@VERSION@">1.3.12</token>
-    <token name="@CMD_BEGIN@">python3 $__tool_directory__/S3segmenter.py</token>
+    <token name="@TOOL_VERSION@">1.3.12</token>
+    <token name="@VERSION_SUFFIX@">0</token>
+    <token name="@PROFILE@">19.01</token>
+    <token name="@CMD_BEGIN@"><![CDATA[
+        S3SEG_CMD="" &&
+        if [ -f "/app/S3segmenter.py" ]; then
+            export S3SEG_CMD="python /app/S3segmenter.py";
+            export PYTHONPATH="/app";
+        else
+            export S3SEG_CMD="S3segmenter.py";
+        fi &&
+    ]]></token>
+    <xml name="version_cmd">
+        <version_command>@CMD_BEGIN@ $S3SEG_CMD --help</version_command>
+    </xml>
 </macros>
b
diff -r 41e8efe8df43 -r 96d0d969ebc9 rowit.py
--- a/rowit.py Fri Mar 11 23:37:49 2022 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
[
@@ -1,76 +0,0 @@
-import numpy as np
-from skimage.util import view_as_windows, montage
-
-
-class WindowView(object):
-
-    def __init__(
-        self, img_shape, block_size, overlap_size
-    ):
-        self.img_shape = img_shape
-        self.block_size = block_size
-        self.overlap_size = overlap_size
-
-        self.step_size = block_size - overlap_size
-
-    def window_view_list(self, img, pad_mode='constant'):
-        half = int(self.overlap_size / 2)
-        img = np.pad(img, (
-            (half, self.padded_shape[0] - self.img_shape[0] - half), 
-            (half, self.padded_shape[1] - self.img_shape[1] - half),
-        ), mode=pad_mode)
-        
-        return self._window_view_list(img)
-    
-    def padding_mask(self):
-        half = int(self.overlap_size / 2)
-        padding_mask = np.ones(self.img_shape, dtype=np.bool)
-        padding_mask = np.pad(padding_mask, (
-            (half, self.padded_shape[0] - self.img_shape[0] - half), 
-            (half, self.padded_shape[1] - self.img_shape[1] - half),
-        ), mode='constant', constant_values=0)
-        return self._window_view_list(padding_mask)
-
-    def reconstruct(self, img_window_view_list):
-        grid_shape = self.window_view_shape[:2]
-
-        start = int(self.overlap_size / 2)
-        end = int(self.block_size - start)
-
-        img_window_view_list = img_window_view_list[..., start:end, start:end]
-
-        return montage(
-            img_window_view_list, grid_shape=grid_shape
-        )[:self.img_shape[0], :self.img_shape[1]]
-        
-    @property
-    def padded_shape(self):
-        padded_shape = np.array(self.img_shape) + self.overlap_size
-        n = np.ceil((padded_shape - self.block_size) / self.step_size)
-        padded_shape = (self.block_size + (n * self.step_size)).astype(np.int)
-        return tuple(padded_shape)
-
-    @property 
-    def window_view_shape(self):
-        return view_as_windows(
-            np.empty(self.padded_shape), 
-            self.block_size, self.step_size
-        ).shape
-
-    def _window_view_list(self, img):
-        return (
-            view_as_windows(img, self.block_size, self.step_size)
-                .reshape(-1, self.block_size, self.block_size)
-        )
-
-def crop_with_padding_mask(img, padding_mask, return_mask=False):
-    if np.all(padding_mask == 1):
-        return (img, padding_mask) if return_mask else img
-    (r_s, r_e), (c_s, c_e) = [
-        (i.min(), i.max() + 1)
-        for i in np.where(padding_mask == 1)
-    ]
-    padded = np.zeros_like(img)
-    img = img[r_s:r_e, c_s:c_e]
-    padded[r_s:r_e, c_s:c_e] = 1
-    return (img, padded) if return_mask else img
\ No newline at end of file
b
diff -r 41e8efe8df43 -r 96d0d969ebc9 s3segmenter.xml
--- a/s3segmenter.xml Fri Mar 11 23:37:49 2022 +0000
+++ b/s3segmenter.xml Fri Sep 16 20:05:54 2022 +0000
[
@@ -1,49 +1,49 @@
-<tool id="s3segmenter" name="s3segmenter" version="@VERSION@.0" profile="17.09">
-    <description>S3segmenter is a Python-based set of functions that generates single cell (nuclei and cytoplasm) label masks.</description>
+<tool id="s3segmenter" name="s3segmenter" version="@TOOL_VERSION@+galaxy@VERSION_SUFFIX@" profile="@PROFILE@">
+    <description>single cell (nuclei and cytoplasm) label masks.</description>
     <macros>
         <import>macros.xml</import>
     </macros>
  
     <expand macro="requirements"/>
-    @VERSION_CMD@
+    <expand macro="version_cmd"/>
 
     <command detect_errors="exit_code"><![CDATA[
 
-        ln -s '${imagePath}' ./image.tif;
+        ln -s '${imagePath}' './image.tif' &&
 
         #if $contoursClassProbPath
-        ln -s ${contoursClassProbPath} ./ContoursPM.tif;
+        ln -s '${contoursClassProbPath}' './ContoursPM.tif' &&
         #end if
 
         #if $nucleiClassProbPath
-        ln -s ${nucleiClassProbPath} ./NucleiPM.tif;
+        ln -s '${nucleiClassProbPath}' './NucleiPM.tif' &&
         #end if
 
         #if $stackProbPath
-        ln -s ${stackProbPath} ./Probabilities.tif;
+        ln -s '${stackProbPath}' './Probabilities.tif' &&
         #end if
 
 
-        @CMD_BEGIN@ 
-        --imagePath ./image.tif
+        @CMD_BEGIN@ \$S3SEG_CMD 
+        --imagePath './image.tif'
 
         #if $contoursClassProbPath
-        --contoursClassProbPath ./ContoursPM.tif
+        --contoursClassProbPath './ContoursPM.tif'
         #end if
 
         #if $nucleiClassProbPath
-        --nucleiClassProbPath ./NucleiPM.tif
+        --nucleiClassProbPath './NucleiPM.tif'
         #end if
 
         #if $stackProbPath
-        --stackProbPath ./Probabilities.tif
+        --stackProbPath './Probabilities.tif'
         #end if
 
         --probMapChan $probMapChan
         --crop $crop_select.crop
         
         #if $crop_select.crop == "dearray"
-          --maskPath $crop_select.maskPath
+          --maskPath '$crop_select.maskPath'
         #end if
 
         --cytoMethod $cytoMethod
@@ -63,16 +63,9 @@
         --detectPuncta $adv.detectPuncta
         --punctaSigma $adv.punctaSigma
         --punctaSD $adv.punctaSD
-
-        #if not $saveMask
-        --saveMask
-        #end if
-
-        #if not $saveFig
-        --saveFig
-        #end if
-
-        --outputPath .
+        $saveMask
+        $saveFig
+        --outputPath '.'
     ]]></command>
 
 
@@ -94,6 +87,9 @@
             <when value="dearray">
                 <param name="maskPath" type="data" format="tiff" label="TMA Mask File"/>
             </when>
+            <when value="noCrop" />
+            <when value="autoCrop" />
+            <when value="plate" />
         </conditional>
 
         <param name="cytoMethod" type="select" label="Cyto Method">
@@ -121,17 +117,24 @@
                 <option value="pixellevel">pixellevel</option>
             </param>
             <when value="pixellevel">
-                <param name="pixelThreshold" type="float" value="-1.0" Label="Pixel Threshold"/>
-                <param name="pixelMaskChan" type="text" value="2" Label="Pixel Mask Channel"/>
+                <param name="pixelThreshold" type="float" value="-1.0" label="Pixel Threshold"/>
+                <param name="pixelMaskChan" type="text" value="2" label="Pixel Mask Channel"/>
             </when>
+             <when value="watershedContourDist"/>
+             <when value="watershedContourInt"/>
+             <when value="watershedBWDist"/>
+             <when value="dilation"/>
+             <when value="localThreshold"/>
+             <when value="localMax"/>
+             <when value="bypass"/>
         </conditional>
 
         <param name="segmentCytoplasm" type="select" label="Segment Cytoplasm">
             <option value="segmentCytoplasm">segmentCytoplasm</option>
             <option selected="true" value="ignoreCytoplasm">ignoreCytoplasm</option>
         </param>
-        <param name="saveMask" type="boolean" checked="true" label="Save Mask"/>
-        <param name="saveFig" type="boolean" checked="true" label="Save Figure"/>
+        <param argument="saveMask" type="boolean" checked="true" truevalue="--saveMask" falsevalue="" label="Save Mask"/>
+        <param argument="saveFig" type="boolean" checked="true" truevalue="--saveFig" falsevalue="" label="Save Figure"/>
 
         <section name="adv" title="Advanced Options" expanded="false">
             <param name="cytoDilation" type="integer" value="5" label="Cyto Dilation"/>
@@ -161,7 +164,29 @@
             <filter>saveFig is True</filter>
         </data>
     </outputs>
+    <tests>
+        <test>
+            <param name="imagePath" value="test.ome.tiff" />
+            <param name="stackProbPath" value="stack_probabilities.tiff" />
+            <param name="punctaSD" value="4" />
+            <output name="cell_mask" ftype="tiff">
+                <assert_contents>
+                    <has_size value="6600000" delta="1000000" />
+                </assert_contents>
+            </output>
+            <output name="nuclei_mask" ftype="tiff">
+                <assert_contents>
+                    <has_size value="6600000" delta="1000000" />
+                </assert_contents>
+            </output>
+        </test>
+    </tests>
     <help><![CDATA[
+-------------------        
+S3segmenter
+-------------------        
+**S3segmenter** is a Python-based set of functions that generates single cell (nuclei and cytoplasm) label masks.
+
 Inputs are:
 
 1. an .ome.tif (preferably flat field corrected)
@@ -172,7 +197,6 @@
 To segment cytoplasm, the nuclei are in turn used for a marker-controlled watershed segmentation constrained by a cytoplasmic marker such as B-catenin. The channel number of this marker must be specified. A 3-pixel annulus around each nucleus will also be used to segment cytoplasm.
 
 The source repository can be found here: https://github.com/HMS-IDAC/S3segmenter
-OHSU Wrapper Repo: https://github.com/ohsu-comp-bio/S3segmenter
     ]]></help>
     <expand macro="citations" />
 </tool>
b
diff -r 41e8efe8df43 -r 96d0d969ebc9 save_tifffile_pyramid.py
--- a/save_tifffile_pyramid.py Fri Mar 11 23:37:49 2022 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
[
@@ -1,114 +0,0 @@
-import numpy as np
-import tifffile
-import skimage.transform
-
-PHYSICAL_SIZE_UNIT = ['Ym', 'Zm', 'Em', 'Pm', 'Tm', 'Gm', 'Mm', 'km', 'hm', 'dam', 'm', 'dm', 'cm', 'mm', 'µm', 'nm', 'pm', 'fm', 'am', 'zm', 'ym', 'Å', 'thou', 'li', 'in', 'ft', 'yd', 'mi', 'ua', 'ly', 'pc', 'pt', 'pixel', 'reference frame']
-
-def normalize_image_shape(img):
-    assert img.ndim in (2, 3), (
-        'image must be 2D (Y, X) or 3D (C, Y, X)'
-    )
-    if img.ndim == 2:
-        img = img.reshape(1, *img.shape)
-    assert np.argmin(img.shape) == 0, (
-        '3D image must be in (C, Y, X) order'
-    )
-    return img
-
-def save_pyramid(
-    out_img, output_path,
-    pixel_sizes=(1, 1),
-    pixel_size_units=('µm', 'µm'),
-    channel_names=None,
-    software=None,
-    is_mask=False
-):
-    assert '.ome.tif' in str(output_path)
-    assert len(pixel_sizes) == len(pixel_size_units) == 2
-    assert out_img.ndim in (2, 3), (
-        'image must be either 2D (Y, X) or 3D (C, Y, X)'
-    )
-    
-    img_shape_ori = out_img.shape
-    out_img = normalize_image_shape(out_img)
-    img_shape = out_img.shape
-
-    size_x, size_y = np.array(pixel_sizes, dtype=float)
-    unit_x, unit_y = pixel_size_units
-
-    assert (unit_x in PHYSICAL_SIZE_UNIT) & (unit_y in PHYSICAL_SIZE_UNIT), (
-        f'pixel_size_units must be a tuple of the followings: '
-        f'{", ".join(PHYSICAL_SIZE_UNIT)}'
-    )
-
-    n_channels = img_shape[0]
-    if channel_names == None:
-        channel_names = [f'Channel {i}' for i in range(n_channels)]
-    else:
-        if type(channel_names) == str:
-            channel_names = [channel_names]
-        n_channel_names = len(channel_names)
-        assert n_channel_names == n_channels, (
-            f'number of channel_names ({n_channel_names}) must match '
-            f'number of channels ({n_channels})'
-        )
-    
-    if software == None:
-        software = ''
-        
-    metadata = {
-        'Creator': software,
-        'Pixels': {
-            'PhysicalSizeX': size_x,
-            'PhysicalSizeXUnit': unit_x,
-            'PhysicalSizeY': size_y,
-            'PhysicalSizeYUnit': unit_y,
-        },
-        'Channel': {'Name': channel_names},
-        
-    }
-
-    max_size = np.max(img_shape)
-    subifds = np.ceil(np.log2(max_size / 1024)).astype(int)
-    
-    # use optimal tile size for disk space
-    tile_size = 16*np.ceil(
-        np.array(img_shape[1:]) / (2**subifds) / 16
-    ).astype(int)
-    options = {
-        'tile': tuple(tile_size)
-    }
-
-    with tifffile.TiffWriter(output_path, bigtiff=True) as tiff_out:
-        tiff_out.write(
-            data=out_img,
-            metadata=metadata,
-            software=software,
-            subifds=subifds,
-            **options
-        )
-        for i in range(subifds):
-            if i == 0:
-                down_2x_img = downsize_img_channels(out_img, is_mask=is_mask)
-            else:
-                down_2x_img = downsize_img_channels(down_2x_img, is_mask=is_mask)
-            tiff_out.write(
-                data=down_2x_img,
-                subfiletype=1,
-                **options
-            )
-
-    out_img = out_img.reshape(img_shape_ori)
-    return
-
-def downsize_channel(img, is_mask):
-    if is_mask:
-        return img[::2, ::2]
-    else:
-        return skimage.transform.downscale_local_mean(img, (2, 2)).astype(img.dtype)
-
-def downsize_img_channels(img, is_mask):
-    return np.array([
-        downsize_channel(c, is_mask=is_mask)
-        for c in img
-    ])
b
diff -r 41e8efe8df43 -r 96d0d969ebc9 test-data/stack_probabilities.tiff
b
Binary file test-data/stack_probabilities.tiff has changed
b
diff -r 41e8efe8df43 -r 96d0d969ebc9 test-data/test.ome.tiff
b
Binary file test-data/test.ome.tiff has changed