#!/usr/bin/env python """ Extract and Parse Metadata from IMS/LSM/CZI files. """ from argparse import ArgumentParser import os import subprocess import logging import utility import ome_schema def extract_metadata(input_path, output_path): """ Extract OME metadata from the input file and write it out as a nicely formatted xml using bftools. (http://www.openmicroscopy.org/site/support/bio-formats5.3/users/comlinetools/display.html) """ bf_tools_dir = os.getenv('BFTOOLS_DIR', os.getcwd()) + "/" command = bf_tools_dir +"showinf -omexml-only -nopix " + input_path + " | " + bf_tools_dir + "xmlindent > " + output_path p = subprocess.Popen(command, shell=True) p.wait() def get_metadata_as_class(input_xml_path): """ Return the OME metadata from the input XML file as a Python class. The class is automatically generated using pyxbgen (http://pyxb.sourceforge.net/pyxbgen_cli.html) and the current OME XML Schema (https://www.openmicroscopy.org/Schemas/OME/2016-06/ome.xsd). If you need to use a newer schema you need to regenerate the file ome_schema.py by doing: pip install pyxb pyxbgen -m ome_schema -u https://www.openmicroscopy.org/Schemas/OME/2016-06/ome.xsd where the web address points to the new schema. You can then access the elements of the OME XML as instance attributes etc. """ xml = open(input_xml_path).read() image_metadata = ome_schema.CreateFromDocument(xml) return image_metadata def integer_color_to_rgb(color): """ Convert integer color to (r,g,b) """ return ((color >> 16) & 255, (color >> 8) & 255, color & 255) def print_metadata_overview(image_metadata): """ Print a reader-friendly metadata summary """ print "Number of Images: ", len(image_metadata.Image) print "Image '0' - Name: ", image_metadata.Image[0].Name print "Image '0' - Num Channels: ", image_metadata.Image[0].Pixels.SizeC print "Image '0' - Num Times: ", image_metadata.Image[0].Pixels.SizeT pixel_size_x = image_metadata.Image[0].Pixels.PhysicalSizeX pixel_size_y = image_metadata.Image[0].Pixels.PhysicalSizeY pixel_size_z = image_metadata.Image[0].Pixels.PhysicalSizeZ pixel_unit_x = image_metadata.Image[0].Pixels.PhysicalSizeXUnit pixel_unit_y = image_metadata.Image[0].Pixels.PhysicalSizeYUnit pixel_unit_z = image_metadata.Image[0].Pixels.PhysicalSizeZUnit print "Image '0' - Pixel Physical Size X: ", pixel_size_x, pixel_unit_x print "Image '0' - Pixel Physical Size Y: ", pixel_size_y, pixel_unit_y print "Image '0' - Pixel Physical Size Z: ", pixel_size_z, pixel_unit_z print "Image '0' - Pixel Size X: ", image_metadata.Image[0].Pixels.SizeX print "Image '0' - Pixel Size Y:", image_metadata.Image[0].Pixels.SizeY print "Image '0' - Pixel Size Z:", image_metadata.Image[0].Pixels.SizeZ print "Image '0' - Pixel Dimension Order: ", image_metadata.Image[0].Pixels.DimensionOrder print "Image '0' - Pixel Bits: ", image_metadata.Image[0].Pixels.SignificantBits for idx, eachChannel in enumerate(image_metadata.Image[0].Pixels.Channel): print "Image '0' - Channel " +str(idx) + " Color: ", integer_color_to_rgb(eachChannel.Color) if __name__ == "__main__": # Do setup tool_name = "extract_metadata" utility.do_setup(tool_name) logger1 = logging.getLogger('format_conversion.'+tool_name) # Suppress XML Parse warnings pyxb_logger = logging.getLogger('pyxb') pyxb_logger.setLevel(logging.CRITICAL) parser = ArgumentParser() parser.add_argument("-i", "--input_file", type=str, help='Input file in a ZEISS format.') parser.add_argument("-o", "--output_file", type=str, help='Output metadata file.') parser.add_argument("--verbose", type=bool, help='Output a simple metadata summary.') args = parser.parse_args() logger1.info('Reading Metadata At: ' + args.input_file) extract_metadata(args.input_file, args.output_file) if(args.verbose): image_metadata = get_metadata_as_class(args.output_file) print_metadata_overview(image_metadata) logger1.info('Completed Reading Metadata')