def get_omexml(self, pixel_array, channels, name, pixel_type): omexml = omexmlClass.OMEXML() image = omexml.image() image.Name = name image.AcquisitionDate = datetime.datetime.now().isoformat() pixels = image.Pixels pixels.SizeX = pixel_array.shape[4] pixels.SizeY = pixel_array.shape[3] pixels.SizeC = pixel_array.shape[2] pixels.SizeZ = pixel_array.shape[1] pixels.SizeT = pixel_array.shape[0] pixels.PixelType = pixel_type channel_count = len(channels) pixels.channel_count = channel_count for i in range(channel_count): pixels.Channel(i).ID = "Channel:0:{}".format(i) pixels.Channel(i).Name = channels[i] root = et.XML(str(omexml)) ome = "{http://www.openmicroscopy.org/Schemas/OME/2016-06}" pixels_elem = root.find("{}Image/{}Pixels".format(ome, ome)) # Repeat for-loop because XML parsing must have channel adjustments for i in range(channel_count): et.SubElement(pixels_elem, '{}TiffData'.format(ome), FirstC=str(i), FirstT="0", FirstZ="0", IFD="0", PlaneCount="1") return omexmlClass.OMEXML(et.tostring(root))
def readOmeTiff(input_path): with tifffile.TiffFile(input_path) as tif: array = tif.asarray() omexmlString = tif[0].image_description.decode("utf-8") # Turn Ome XML String to an Bioformats object for parsing metadata = omexmlClass.OMEXML(omexmlString) # Parse pixel sizes pixels = metadata.image(0).Pixels SizeC = pixels.SizeC SizeT = pixels.SizeT SizeZ = pixels.SizeZ SizeX = pixels.SizeX SizeY = pixels.SizeY pixels.DimensionOrder # Expand image array to 5D of order (T, Z, C, X, Y) if SizeC == 1: array = np.expand_dims(array, axis=-3) if SizeZ == 1: array = np.expand_dims(array, axis=-4) if SizeT == 1: array = np.expand_dims(array, axis=-5) return (array, omexmlString)
def read_ometiff(input_path): with tifffile.TiffFile(input_path) as tif: array = tif.asarray() omexml_string = tif[0].image_description.decode("utf-8") # Turn Ome XML String to an Bioformats object for parsing metadata = omexmlClass.OMEXML(omexml_string) # Parse pixel sizes pixels = metadata.image(0).Pixels size_c = pixels.SizeC size_t = pixels.SizeT size_z = pixels.SizeZ size_x = pixels.SizeX size_y = pixels.SizeY # Expand image array to 5D of order (T, Z, C, X, Y) if size_c == 1: array = np.expand_dims(array, axis=-3) if size_z == 1: array = np.expand_dims(array, axis=-4) if size_t == 1: array = np.expand_dims(array, axis=-5) return array, omexml_string
def execute(image_path): image_name = os.path.basename(image_path) print(image_name) with tifffile.TiffFile(image_path) as tif: array6D = [] # Turn Ome XML String to a Bioformats object for parsing omexml = tif[0].image_description.decode("utf-8") metadata = omexmlClass.OMEXML(omexml) # Parse pixel sizes size_c = metadata.image(0).Pixels.SizeC size_z = metadata.image(0).Pixels.SizeZ size_t = metadata.image(0).Pixels.SizeT # Read each series, get the 5d array -> process it -> append to array6D for i in range(len(tif.series)): # Returned value is a 5D array of order (T, Z, C, X, Y) array5D = read_serie(tif.series[i], size_c, size_z, size_t) # Apply inversion operation result5d = apply_2d_transfo_to_serie(_invert, array5D, False) array6D.append(result5d) # Save the inverted image write_ometiff(image_name, array6D, omexml) print("INVERTION DONE") return {'output_image': image_name}
def update_ome_xml_for_fake_channels(ome_string): md = omexmlClass.OMEXML(ome_string) pixels = md.image().Pixels last_cycle_ind = None n_ch_added = 0 origin_n_ch = pixels.get_channel_count() for i in range(origin_n_ch): # pixels.remove_channel(i) current_name = pixels.Channel(i).get_Name() current_cycle_ind = re.search("c0(\d).*", current_name).group(1) if not last_cycle_ind: last_cycle_ind = current_cycle_ind if last_cycle_ind != current_cycle_ind: pixels.append_channel(i + n_ch_added, "c0%s" % last_cycle_ind + " anchor") n_ch_added += 1 pixels.Channel(i).set_ID("Channel:0:" + str(i + n_ch_added)) # for k in pixels.Channel(i).node.attrib: # print(k, pixels.Channel(i).node.get(k)) # print(i, pixels.Channel(i).node.attrib) last_cycle_ind = current_cycle_ind pixels.append_channel(origin_n_ch + n_ch_added, "c0%s" % last_cycle_ind + " anchor") pixels.populate_TiffData() return md
def main(args): ignore_dapi = True with tf.TiffFile(args.ome_tif, "r", is_ome=True) as fh: print(fh) ome_string = fh.ome_metadata shape = fh.pages[0].shape updated_md = update_ome_xml_for_fake_channels(ome_string) clean_xml = xml_cleanup(updated_md.to_xml()) meta = ET.tostring(clean_xml, encoding="ascii") ch_map = map_old_new_chs(ome_string, omexmlClass.OMEXML(meta)) # print(ch_map) tmp_anchor = np.zeros(shape, dtype=np.uint16) new_name = Path(args.ome_tif).stem + "_with_anchors.ome.tif" if args.known_anchor: known_anchor_cyc = args.known_anchor.split(" ")[0] writer = tf.TiffWriter(new_name, bigtiff=True) with tf.TiffFile(args.ome_tif, "r", is_ome=True) as fh: for i in sorted(ch_map.keys()): print(i, ch_map[i]) old_ind = ch_map[i][1] cur_ch_name = ch_map[i][0] if old_ind is not None: tmp_array = normalize(fh.pages[old_ind].asarray().squeeze(), 98) writer.save(tmp_array, photometric="minisblack", description=meta) if ( cur_ch_name.startswith(known_anchor_cyc) and cur_ch_name != args.known_anchor ): continue # print(fh.pages[old_ind]) if ignore_dapi and "DAPI" in cur_ch_name: continue print(cur_ch_name + " max projected") tmp_anchor = np.max(np.array([tmp_array, tmp_anchor]), axis=0) # print(tmp_anchor.shape) else: print("save anchor, and re-intialize anchor image") # print(tmp_anchor.shape) writer.save(tmp_anchor, photometric="minisblack", description=meta) tmp_anchor = np.zeros(shape, dtype=np.uint16) writer.close()
def update_xml(omexml, Image_ID=None, Image_Name=None, Image_AcquisitionDate=None, DimensionOrder=None, dType=None, SizeT=None, SizeZ=None, SizeC=None, SizeX=None, SizeY=None, Channel_ID=None, Channel_Name=None, Channel_SamplesPerPixel=None): metadata = omexmlClass.OMEXML(omexml) if Image_ID: metadata.image().set_ID(Image_ID) if Image_Name: metadata.image().set_Name(Image_Name) if Image_AcquisitionDate: metadata.image().Image.AcquisitionDate = Image_AcquisitionDate if DimensionOrder: metadata.image().Pixels.DimensionOrder = DimensionOrder if dType: metadata.image().Pixels.PixelType = dType if SizeT: metadata.image().Pixels.set_SizeT(SizeT) if SizeZ: metadata.image().Pixels.set_SizeZ(SizeZ) if SizeC: metadata.image().Pixels.set_SizeC(SizeC) if SizeX: metadata.image().Pixels.set_SizeX(SizeX) if SizeY: metadata.image().Pixels.set_SizeY(SizeY) if Channel_ID: metadata.image().Channel.ID = Channel_ID if Channel_Name: metadata.image().Channel.Name = Channel_Name if Channel_SamplesPerPixel: metadata.image().Channel.SamplesPerPixel = Channel_SamplesPerPixel metadata = metadata.to_xml().encode() return metadata
def update_xml(omexml, Image_ID=None, Image_Name=None, Image_AcquisitionDate=None, DimensionOrder=None, dType=None, SizeT=None, SizeZ=None, SizeC=None, SizeX=None, SizeY=None, Channel_ID=None, Channel_Name=None, Channel_SamplesPerPixel=None): metadata = omexmlClass.OMEXML(omexml) if not Image_ID == None: metadata.image(0).Image.ID = Image_ID if not Image_Name == None: metadata.image(0).Name = Image_Name if not Image_AcquisitionDate == None: metadata.image(0).Image.AcquisitionDate = Image_AcquisitionDate if not DimensionOrder == None: metadata.image(0).Pixels.DimensionOrder = DimensionOrder if not dType == None: metadata.image(0).Pixels.PixelType = dType if not SizeT == None: metadata.image(0).Pixels.SizeT = SizeT if not SizeZ == None: metadata.image(0).Pixels.SizeZ = SizeZ if not SizeC == None: metadata.image(0).Pixels.SizeC = SizeC if not SizeX == None: metadata.image(0).Pixels.SizeX = SizeX if not SizeY == None: metadata.image(0).Pixels.SizeY = SizeY if not Channel_ID == None: metadata.image(0).Channel.ID = Channel_ID if not Channel_Name == None: metadata.image(0).Channel.Name = Channel_Name if not Channel_SamplesPerPixel == None: metadata.image(0).Channel.SamplesPerPixel = Channel_SamplesPerPixel metadata = metadata.to_xml(encoding='utf-8') return metadata.replace("<ome:", "<").replace("</ome:", "</")
def create_omexml(image_array, channel_names): metadata = omexmlClass.OMEXML() image = metadata.image() image.AcquisitionDate = datetime.datetime.now().isoformat() pixels = image.Pixels pixels.SizeX = image_array.shape[2] pixels.SizeY = image_array.shape[1] pixels.SizeC = image_array.shape[0] pixels.PixelType = str(image_array.dtype) pixels.channel_count = len(channel_names) for i, name in enumerate(channel_names): pixels.Channel(i).Name = name return f'<?xml version="1.0" encoding="UTF-8"?>\n{metadata}'
def read_ometiff(input_path): with tifffile.TiffFile(input_path) as tif: array = tif.asarray() omexml_string = tif.ome_metadata # Turn Ome XML String to an Bioformats object for parsing metadata = omexmlClass.OMEXML(omexml_string) # Parse pixel sizes pixels = metadata.image(0).Pixels size_c = pixels.SizeC size_t = pixels.SizeT size_z = pixels.SizeZ size_x = pixels.SizeX size_y = pixels.SizeY # Expand image array to 5D of order (T, Z, C, X, Y) if size_c == 1: array = np.expand_dims(array, axis=-3) if size_z == 1: array = np.expand_dims(array, axis=-4) if size_t == 1: array = np.expand_dims(array, axis=-5) # Makes sure to return the array in (T, Z, C, X, Y) order dim_format = pixels.DimensionOrder if dim_format == "XYCZT": pass elif dim_format == "XYZCT": array = np.moveaxis(array, 1, 2) elif dim_format == "XYCTZ": array = np.moveaxis(array, 0, 1) elif dim_format == "XYZTC": array = np.moveaxis(array, 0, 2) elif dim_format == "XYTZC": array = np.moveaxis(array, 0, 2) array = np.moveaxis(array, 0, 1) elif dim_format == "XYTCZ": array = np.moveaxis(array, 1, 2) array = np.moveaxis(array, 0, 1) else: print(array.shape) raise Exception("Unknow dimension format") return array, omexml_string
def map_old_new_chs(ome_string, new_md): ori_ch_names = omexmlClass.OMEXML(ome_string).image().Pixels.get_channel_names() ori_ch_names_i = {ch: i for i, ch in enumerate(ori_ch_names)} pixels = new_md.image().Pixels new_i_ch_name = { int(pixels.Channel(i).node.get("ID").split(":")[-1]): pixels.Channel(i).Name for i in range(pixels.get_channel_count()) } maps = {} for i in sorted(new_i_ch_name.keys()): ch_name = new_i_ch_name[i] if "anchor" not in ch_name: maps[i] = (ch_name, ori_ch_names_i[new_i_ch_name[i]]) else: maps[i] = (ch_name, None) return maps
def gen_xml(array): #Dimension order is assumed to be TZCYX dim_order = "TZCYX" metadata = omexmlClass.OMEXML() shape = array.shape assert (len(shape) == 5), "Expected array of 5 dimensions" metadata.image().set_Name("IMAGE") metadata.image().set_ID("0") pixels = metadata.image().Pixels pixels.ome_uuid = metadata.uuidStr pixels.set_ID("0") pixels.channel_count = shape[2] pixels.set_SizeT(shape[0]) pixels.set_SizeZ(shape[1]) pixels.set_SizeC(shape[2]) pixels.set_SizeY(shape[3]) pixels.set_SizeX(shape[4]) pixels.set_DimensionOrder(dim_order[::-1]) pixels.set_PixelType(omexmlClass.get_pixel_type(array.dtype)) for i in range(pixels.SizeC): pixels.Channel(i).set_ID("Channel:0:" + str(i)) pixels.Channel(i).set_Name("C:" + str(i)) for i in range(pixels.SizeC): pixels.Channel(i).set_SamplesPerPixel(1) pixels.populate_TiffData() return metadata.to_xml().encode()
def __getitem__(self, idx): img_path = self.img_paths_list[idx] image = skimage.io.imread(img_path) if self.metadata_path is not None: tree = ET.parse(self.metadata_path) root = tree.getroot() omexml = ET.tostring(root, encoding=None, method="xml") omemd = omexmlClass.OMEXML(omexml) md = get_metadata_ometiff(img_path, omemd) elif self.metadata_path is None: # get metadata from image if no metadata file found md, additional_mdczi = get_metadata(img_path) # FUTURE IMPLEMENTATION if not .ome.tiff or .czi, check if metadata file in folder # if md == None: # # parent_folder = os.path.dirname(img_path) # for fname in os.listdir(parent_folder): # if fname.endswith('.xml'): # xml_path = os.path.join(parent_folder,fname) # tree = ET.parse(xml_path) # root = tree.getroot() # omexml = ET.tostring(root, encoding=None, method='xml') # omemd = omexmlClass.OMEXML(omexml) # md = get_metadata_ometiff(img_path, omemd) # break if md is not None: return img_path, image, md elif md is None: raise ValueError("No metadata found.")
def get_metadata_ometiff(filename, series=0): """Returns a dictionary with OME-TIFF metadata. :param filename: filename of the OME-TIFF image :type filename: str :param series: Image Series, defaults to 0 :type series: int, optional :return: dictionary with the relevant OME-TIFF metainformation :rtype: dict """ with tifffile.TiffFile(filename) as tif: try: # get OME-XML metadata as string the old way omexml_string = tif[0].image_description.decode('utf-8') except TypeError as e: print(e) omexml_string = tif.ome_metadata # get the OME-XML using the apeer-ometiff-library omemd = omexmlClass.OMEXML(omexml_string) # create dictionary for metadata and get OME-XML data metadata = create_metadata_dict() # get directory and filename etc. metadata['Directory'] = os.path.dirname(filename) metadata['Filename'] = os.path.basename(filename) metadata['Extension'] = 'ome.tiff' metadata['ImageType'] = 'ometiff' metadata['AcqDate'] = omemd.image(series).AcquisitionDate metadata['Name'] = omemd.image(series).Name # get image dimensions TZCXY metadata['SizeT'] = omemd.image(series).Pixels.SizeT metadata['SizeZ'] = omemd.image(series).Pixels.SizeZ metadata['SizeC'] = omemd.image(series).Pixels.SizeC metadata['SizeX'] = omemd.image(series).Pixels.SizeX metadata['SizeY'] = omemd.image(series).Pixels.SizeY # get number of image series metadata['TotalSeries'] = omemd.get_image_count() metadata['Sizes BF'] = [metadata['TotalSeries'], metadata['SizeT'], metadata['SizeZ'], metadata['SizeC'], metadata['SizeY'], metadata['SizeX']] # get dimension order metadata['DimOrder BF'] = omemd.image(series).Pixels.DimensionOrder # reverse the order to reflect later the array shape metadata['DimOrder BF Array'] = metadata['DimOrder BF'][::-1] # get the scaling metadata['XScale'] = omemd.image(series).Pixels.PhysicalSizeX metadata['XScale'] = np.round(metadata['XScale'], 3) # metadata['XScaleUnit'] = omemd.image(series).Pixels.PhysicalSizeXUnit metadata['YScale'] = omemd.image(series).Pixels.PhysicalSizeY metadata['YScale'] = np.round(metadata['YScale'], 3) # metadata['YScaleUnit'] = omemd.image(series).Pixels.PhysicalSizeYUnit metadata['ZScale'] = omemd.image(series).Pixels.PhysicalSizeZ metadata['ZScale'] = np.round(metadata['ZScale'], 3) # metadata['ZScaleUnit'] = omemd.image(series).Pixels.PhysicalSizeZUnit # additional check for faulty z-scaling if metadata['ZScale'] == 0.0: metadata['ZScale'] = 1.0 # get all image IDs for i in range(omemd.get_image_count()): metadata['ImageIDs'].append(i) # get information about the instrument and objective try: metadata['InstrumentID'] = omemd.instrument(series).get_ID() except (KeyError, AttributeError) as e: print('Key not found:', e) metadata['InstrumentID'] = None try: metadata['DetectorModel'] = omemd.instrument(series).Detector.get_Model() metadata['DetectorID'] = omemd.instrument(series).Detector.get_ID() metadata['DetectorModel'] = omemd.instrument(series).Detector.get_Type() except (KeyError, AttributeError) as e: print('Key not found:', e) metadata['DetectorModel'] = None metadata['DetectorID'] = None metadata['DetectorModel'] = None try: metadata['ObjNA'] = omemd.instrument(series).Objective.get_LensNA() metadata['ObjID'] = omemd.instrument(series).Objective.get_ID() metadata['ObjMag'] = omemd.instrument(series).Objective.get_NominalMagnification() except (KeyError, AttributeError) as e: print('Key not found:', e) metadata['ObjNA'] = None metadata['ObjID'] = None metadata['ObjMag'] = None # get channel names for c in range(metadata['SizeC']): metadata['Channels'].append(omemd.image(series).Pixels.Channel(c).Name) # add axes and shape information using aicsimageio package ometiff_aics = AICSImage(filename) metadata['Axes_aics'] = ometiff_aics.dims metadata['Shape_aics'] = ometiff_aics.shape metadata['SizeX_aics'] = ometiff_aics.size_x metadata['SizeY_aics'] = ometiff_aics.size_y metadata['SizeC_aics'] = ometiff_aics.size_c metadata['SizeZ_aics'] = ometiff_aics.size_t metadata['SizeT_aics'] = ometiff_aics.size_t metadata['SizeS_aics'] = ometiff_aics.size_s # close AICSImage object ometiff_aics.close() # check for None inside Scaling to avoid issues later one ... metadata = checkmdscale_none(metadata, tocheck=['XScale', 'YScale', 'ZScale'], replace=[1.0, 1.0, 1.0]) return metadata