示例#1
0
def test_mosaic_image_two(data_dir, fname, expects):
    with open(data_dir / fname, 'rb') as fp:
        czi = CziFile(czi_filename=fp)
        sze = czi.read_mosaic_size()
        rgion = (sze[0], sze[1], int(sze[2] / 2), int(sze[3] / 2))
        img = czi.read_mosaic(region=rgion, C=0, M=0)
    assert img.shape == expects
示例#2
0
def test_mosaic_image(data_dir, fname, expects):
    with open(data_dir / fname, 'rb') as fp:
        czi = CziFile(czi_filename=fp)
        sze = czi.read_mosaic_size()
        assert sze[2] == 1756
        assert sze[3] == 624
        img = czi.read_mosaic(scale_factor=0.1, C=0)
    assert img.shape[0] == 1
示例#3
0
def load_tile(coords, slide_path, data_mask,
              region_mask, width, downsample, fast):
    """Load a tile from the czi-file (parallizeable)."""
    # Load reader.
    reader = CziFile(slide_path)
    # Unpack coords.
    i, (x, y) = coords
    # Define final out_shape.
    out_shape = (int(width/downsample), int(width/downsample))
    # Get data and region percentages.
    tile_mask = Polygon(
        [[x, y], [x+width, y], [x+width, y+width], [x, y+width], [x, y]])
    intersection = tile_mask.intersection(data_mask)
    data_perc = intersection.area/tile_mask.area
    region_perc = tile_mask.intersection(region_mask).area/tile_mask.area
    if data_perc < 0.05 or region_perc < 1:
        # Return empty image.
        tile = np.ones(out_shape + (3,)) * 255
    else:
        # Load tile.
        bbox = (x, y, width, width)
        if fast:
            tile = reader.read_mosaic(bbox, C=0, scale_factor=1/downsample)
        else:
            tile = reader.read_mosaic(bbox, C=0)
        if tile.shape[0] == 1:
            # Something is wrong with the tile...
            tile = np.ones(out_shape + (3,)) * 255
        else:
            tile = np.moveaxis(tile, 0, 2)
            tile = cv2.resize(tile, out_shape, cv2.INTER_LANCZOS4)
            if data_perc < 1:
                mask = polygon_to_mask(intersection, x, y, width, downsample)
                mask = cv2.resize(mask, out_shape, cv2.INTER_LANCZOS4)
                tile[mask == 0] = 255
    tile = tile.astype(np.uint8)
    return i, tile
示例#4
0

filename = r"C:\Temp\input\DTScan_ID4.czi"

md, addmd = imf.get_metadata(filename)

czi = CziFile(filename)

# Get the shape of the data, the coordinate pairs are (start index, size)
dimensions = czi.dims_shape()
print(dimensions)
print(czi.dims)
print(czi.size)
print(czi.is_mosaic())  # True
# Mosaic files ignore the S dimension and use an internal mIndex to reconstruct, the scale factor allows one to generate a manageable image
mosaic_data = czi.read_mosaic(C=0, scale_factor=1)
print('CZI Mosaic Data Shape : ', mosaic_data.shape)

md = {}
md['SizeS'] = 1
md['SizeT'] = 3
md['SizeZ'] = 5
md['SizeC'] = 2
md['SizeY'] = 100
md['SizeX'] = 200

dimorder = 'STCYX'

dims_dict, dimindex_list, numvalid_dims = get_dimorder(dimorder)

new = {k: v for k, v in dims_dict.items() if v != -1}
示例#5
0
if minholesize > minsize:
    minsize = minholesize

# read the czi mosaic image
czi = CziFile(filename)
# Get the shape of the data
print('Dimensions   : ', czi.dims)
print('Size         : ', czi.size)
print('Shape        : ', czi.dims_shape())
print('IsMoasic     : ', czi.is_mosaic())

if czi.is_mosaic():
    print('Mosaic Size  : ', czi.read_mosaic_size())

# read the mosaic pixel data
mosaic = czi.read_mosaic(C=0, scale_factor=1.0)
print('Mosaic Shape :', mosaic.shape)

image2d = np.squeeze(mosaic, axis=0)
md['SizeX_readmosaic'] = image2d.shape[1]
md['SizeY_readmosaic'] = image2d.shape[0]

image_counter = 0
results = pd.DataFrame()

# create the savename for the OME-TIFF
savename = filename.split('.')[0] + '.ome.tiff'
#savename = filename.split('.')[0] + '.tiff'

# open the TiffWriter in order to save as Multi-Series OME-TIFF
with tifffile.TiffWriter(savename, append=False) as tif:
示例#6
0
def execute(filepath,
            separator=';',
            filter_method='none',
            filter_size=3,
            threshold_method='triangle',
            min_objectsize=1000,
            max_holesize=100,
            saveformat='ome.tiff'):
    """Main function that executed the workflow.

    :param filepath: file path of the CZI image
    :type filepath: tsr
    :param separator: sepeartor for the CSV table, defaults to ';'
    :type separator: str, optional
    :param filter_method: smoothing filer, defaults to 'none'
    :type filter_method: str, optional
    :param filter_size: kernel size or radius of filter element, defaults to 3
    :type filter_size: int, optional
    :param threshold_method: threshold method, defaults to 'triangle'
    :type threshold_method: str, optional
    :param min_objectsize: minimum object size, defaults to 1000
    :type min_objectsize: int, optional
    :param max_holesize: maximum object size, defaults to 100
    :type max_holesize: int, optional
    :param saveformat: format to save the segmented image, defaults to 'ome.tiff'
    :type saveformat: str, optional
    :return: outputs
    :rtype: dict
    """

    print('--------------------------------------------------')
    print('FilePath : ', filepath)
    print(os.getcwd())
    print('File exists : ', os.path.exists(filepath))
    print('--------------------------------------------------')

    # define name for figure to be saved
    filename = os.path.basename(filepath)

    # get the metadata from the czi file
    md, additional_mdczi = imf.get_metadata(filepath)

    # to make it more readable extravt values from metadata dictionary
    stageX = md['SceneStageCenterX']
    stageY = md['SceneStageCenterY']

    # define columns names for dataframe
    cols = ['S', 'T', 'Z', 'C', 'Number']
    objects = pd.DataFrame(columns=cols)

    # optional dipslay of "some" results - empty list = no display
    show_image = [0]

    # scalefactor to read CZI
    sf = 1.0

    # index for channel - currently only single channel images are supported !
    chindex = 0

    # define maximum object sizes
    max_objectsize = 1000000000

    # define save format for mask
    adapt_dtype_mask = True
    dtype_mask = np.int8

    # check if it makes sense
    if max_holesize > min_objectsize:
        min_objectsize = max_holesize

    # read the czi mosaic image
    czi = CziFile(filepath)

    # get the shape of the data using aicspylibczi
    print('Dimensions   : ', czi.dims)
    print('Size         : ', czi.size)
    print('Shape        : ', czi.dims_shape())
    print('IsMosaic     : ', czi.is_mosaic())

    # read the mosaic pixel data
    mosaic = czi.read_mosaic(C=0, scale_factor=sf)
    print('Mosaic Shape :', mosaic.shape)

    # get the mosaic as NumPy.Array - must fit im memory !!!
    image2d = np.squeeze(mosaic, axis=0)
    md['SizeX_readmosaic'] = image2d.shape[1]
    md['SizeY_readmosaic'] = image2d.shape[0]

    # create the savename for the OME-TIFF
    if saveformat == 'ome.tiff':
        savename_seg = filename.split('.')[0] + '.ome.tiff'
    if saveformat == 'tiff':
        savename_seg = filename.split('.')[0] + '.tiff'

    # initialize empty dataframe
    results = pd.DataFrame()

    # main loop over all T - Z - C slices
    for s in progressbar.progressbar(range(md['SizeS']), redirect_stdout=True):
        for t in range(md['SizeT']):
            for z in range(md['SizeZ']):

                values = {'S': s, 'T': t, 'Z': z, 'C': chindex, 'Number': 0}

        # preprocessing - filter the image
        if filter_method == 'none' or filter_method == 'None':
            image2d_filtered = image2d
        if filter_method == 'median':
            image2d_filtered = median(image2d, selem=disk(filter_size))
        if filter_method == 'gauss':
            image2d_filtered = gaussian(image2d,
                                        sigma=filter_size,
                                        mode='reflect')

        # threshold image
        binary = sgt.autoThresholding(image2d_filtered,
                                      method=threshold_method)

        # Remove contiguous holes smaller than the specified size
        mask = morphology.remove_small_holes(binary,
                                             area_threshold=max_holesize,
                                             connectivity=1,
                                             in_place=True)

        # remove small objects
        mask = morphology.remove_small_objects(mask,
                                               min_size=min_objectsize,
                                               in_place=True)

        # clear the border
        mask = segmentation.clear_border(mask, bgval=0, in_place=True)

        # label the objects
        mask = measure.label(binary)

        # adapt pixel type of mask
        if adapt_dtype_mask:
            mask = mask.astype(dtype_mask, copy=False)

        # measure region properties
        to_measure = ('label', 'area', 'centroid', 'bbox')

        # measure the specified parameters store in dataframe
        props = pd.DataFrame(
            measure.regionprops_table(
                mask, intensity_image=image2d,
                properties=to_measure)).set_index('label')

        # filter objects by size
        props = props[(props['area'] >= min_objectsize)
                      & (props['area'] <= max_objectsize)]

        # add well information for CZI metadata
        try:
            props['WellId'] = md['Well_ArrayNames'][s]
            props['Well_ColId'] = md['Well_ColId'][s]
            props['Well_RowId'] = md['Well_RowId'][s]
        except (IndexError, KeyError) as error:
            # Output expected ImportErrors.
            print('Key not found:', error)
            print('Well Information not found. Using S-Index.')
            props['WellId'] = s
            props['Well_ColId'] = s
            props['Well_RowId'] = s

        # add plane indices
        props['S'] = s
        props['T'] = t
        props['Z'] = z
        props['C'] = chindex

        # count the number of objects
        values['Number'] = props.shape[0]

        # update dataframe containing the number of objects
        objects = objects.append(pd.DataFrame(values, index=[0]),
                                 ignore_index=True)
        results = results.append(props, ignore_index=True)

    # make sure the array as 5D of order (T, Z, C, X, Y) to write an correct OME-TIFF
    mask = imf.expand_dims5d(mask, md)

    # write the OME-TIFF suing apeer-ometiff-library
    io.write_ometiff(savename_seg, mask, omexml_string=None)

    # rename columns in pandas datatable
    results.rename(columns={
        'bbox-0': 'ystart',
        'bbox-1': 'xstart',
        'bbox-2': 'yend',
        'bbox-3': 'xend'
    },
                   inplace=True)

    # calculate the bbox width in height in [pixel] and [micron]
    results['bbox_width'] = results['xend'] - results['xstart']
    results['bbox_height'] = results['yend'] - results['ystart']
    results['bbox_width_scaled'] = results['bbox_width'] * md['XScale']
    results['bbox_height_scaled'] = results['bbox_height'] * md['XScale']

    # calculate the bbox center StageXY
    results['bbox_center_stageX'], results[
        'bbox_center_stageY'] = bbox2stageXY(
            image_stageX=stageX,
            image_stageY=stageY,
            sizeX=md['SizeX'],
            sizeY=md['SizeY'],
            scale=md['XScale'],
            xstart=results['xstart'],
            ystart=results['ystart'],
            bbox_width=results['bbox_width'],
            bbox_height=results['bbox_height'])

    # show results
    print(results)
    print('Done.')

    # write the CSV data table
    print('Write to CSV File : ', filename)
    csvfile = os.path.splitext(filename)[0] + '_planetable.csv'
    results.to_csv(csvfile, sep=separator, index=False)

    # set the outputs
    outputs = {}
    outputs['segmented_image'] = savename_seg
    outputs['objects_table'] = csvfile

    return outputs
示例#7
0
def read_mosaic(filename: str, scale: float=1.0) -> Tuple[Union[np.ndarray, None], czimd.CziMetadata]:
    """Read the pixel data of an CZI image file with an option scale factor
    to read the image with lower resolution and array size

    :param filename: filename of the CZI mosaic file to be read
    :param scale: scaling factor when reading the mosaic.
    :return: CZI pixel data and the updated CziMetadata class
    """

    # do not allow scale > 1.0
    if scale > 1.0:
        print("Scale factor > 1.0 is not recommended. Using scale = 1.0.")
        scale = 1.0

    # get the CZI metadata
    md = czimd.CziMetadata(filename)

    # read CZI using aicspylibczi
    aicsczi = CziFile(filename)

    if not aicsczi.is_mosaic():
        # check if this CZI is really a non-mosaic file
        print("CZI is not a mosaic file. Please use the read_nonmosaic method instead")
        return None, md

    # get data for 1st scene and create the required shape for all scenes
    scene = czimd.CziScene(aicsczi, sceneindex=0)
    shape_all = scene.shape_single_scene

    if scene.hasS:
        shape_all[scene.posS] = md.dims.SizeS
    if not scene.hasS:
        num_scenes = 1

    print("Shape all Scenes (scale=1.0): ", shape_all)
    print("DimString all Scenes : ", scene.single_scene_dimstr)

    # create empty array to hold all scenes
    all_scenes = np.empty(shape_all, dtype=md.npdtype)

    resize_done = False

    # loop over scenes if CZI is not Mosaic
    for s in range(num_scenes):
        scene = czimd.CziScene(aicsczi, sceneindex=s)

        # create a slice object for all_scenes array
        if not scene.isRGB:
            #idl_all = [slice(None, None, None)] * (len(all_scenes.shape) - 2)
            idl_all = [slice(None, None, None)] * (len(shape_all) - 2)
        if scene.isRGB:
            #idl_all = [slice(None, None, None)] * (len(all_scenes.shape) - 3)
            idl_all = [slice(None, None, None)] * (len(shape_all) - 3)

        # update the entry with the current S index
        if not scene.hasS:
            idl_all[s] = s
        if scene.hasS:
            idl_all[scene.posS] = s

        # in case T-Z-H dimension are found
        if scene.hasT is True and scene.hasZ is True and scene.hasH is True:

            # read array for the scene
            for h, t, z, c in product(range(scene.sizeH),
                                      range(scene.sizeT),
                                      range(scene.sizeZ),
                                      range(scene.sizeC)):
                # read the array for the 1st scene using the ROI
                scene_array_htzc = aicsczi.read_mosaic(region=(scene.xstart,
                                                               scene.ystart,
                                                               scene.width,
                                                               scene.height),
                                                       scale_factor=scale,
                                                       H=h,
                                                       T=t,
                                                       Z=z,
                                                       C=c)

                print("Shape Single Scene (Scalefactor: ", scale, ": ", scene_array_htzc.shape)

                # check if all_scenes array must be resized due to scaling
                if scale < 1.0 and not resize_done:

                    shape_all[-1] = scene_array_htzc.shape[-1]
                    shape_all[-2] = scene_array_htzc.shape[-2]
                    all_scenes = np.resize(all_scenes, shape_all)

                    # add new entries to metadata
                    md = adaptmd_scale(md, scene_array_htzc.shape[-1], scene_array_htzc.shape[-2], scale=scale)
                    resize_done = True

                # create slide object for the current mosaic scene
                # idl_scene = [slice(None, None, None)] * (len(scene.shape_single_scene) - 2)
                idl_all[scene.posS] = s
                idl_all[scene.posH] = h
                idl_all[scene.posT] = t
                idl_all[scene.posZ] = z
                idl_all[scene.posC] = c

                # cast the current scene into the stack for all scenes
                all_scenes[tuple(idl_all)] = scene_array_htzc

        # in case T-Z-H dimension are found
        if scene.hasT is True and scene.hasZ is True and scene.hasH is False:

            # read array for the scene
            for t, z, c in product(range(scene.sizeT),
                                   range(scene.sizeZ),
                                   range(scene.sizeC)):
                # read the array for the 1st scene using the ROI
                scene_array_tzc = aicsczi.read_mosaic(region=(scene.xstart,
                                                              scene.ystart,
                                                              scene.width,
                                                              scene.height),
                                                       scale_factor=scale,
                                                       T=t,
                                                       Z=z,
                                                       C=c)

                print("Shape Single Scene (Scalefactor: ", scale, ": ", scene_array_tzc.shape)

                # check if all_scenes array must be resized due to scaling
                if scale < 1.0 and not resize_done:
                    shape_all[-1] = scene_array_tzc.shape[-1]
                    shape_all[-2] = scene_array_tzc.shape[-2]
                    all_scenes = np.resize(all_scenes, shape_all)

                    # add new entries to metadata
                    md = adaptmd_scale(md, scene_array_tzc.shape[-1], scene_array_tzc.shape[-2], scale=scale)
                    resize_done = True

                # create slide object for the current mosaic scene
                # idl_scene = [slice(None, None, None)] * (len(scene.shape_single_scene) - 2)
                idl_all[scene.posS] = s
                idl_all[scene.posT] = t
                idl_all[scene.posZ] = z
                idl_all[scene.posC] = c

                # cast the current scene into the stack for all scenes
                all_scenes[tuple(idl_all)] = scene_array_tzc



        if scene.hasT is False and scene.hasZ is False:

            # create an array for the scene
            for c in range(scene.sizeC):
                scene_array_c = aicsczi.read_mosaic(region=(scene.xstart,
                                                            scene.ystart,
                                                            scene.width,
                                                            scene.height),
                                                    scale_factor=scale,
                                                    C=c)

                print("Shape Single Scene (Scalefactor: ", scale, ": ", scene_array_c.shape)

                # check if all_scenes array must be resized due to scaling
                if scale < 1.0 and not resize_done:
                    #new_shape = shape_all
                    shape_all[-1] = scene_array_c.shape[-1]
                    shape_all[-2] = scene_array_c.shape[-2]
                    all_scenes = np.resize(all_scenes, shape_all)

                    # add new entries to metadata
                    md = adaptmd_scale(md, scene_array_c.shape[-1], scene_array_c.shape[-2], scale=scale)
                    resize_done = True

                idl_all[scene.posS] = s
                idl_all[scene.posC] = c

                # cast the current scene into the stack for all scenes
                all_scenes[tuple(idl_all)] = scene_array_c

    return all_scenes, md