Source code for mesmerize.viewer.core.mesfile

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Tue Dec 22 13:58:20 2017

@author: kushal, adapted from Daniel Dondorp

Chatzigeorgiou Group
Sars International Centre for Marine Molecular Biology

GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007
"""

import numpy as np
import traceback
#from common.misc_functions import *
import scipy.io as spio


class MatlabFuncs:
    @staticmethod
    def loadmat(filename: str) -> dict:
        data = spio.loadmat(filename, struct_as_record=False, squeeze_me=True)
        return MatlabFuncs._check_keys(data)

    @staticmethod
    def _check_keys(d: dict) -> dict:
        for key in d:
            if isinstance(d[key], spio.matlab.mio5_params.mat_struct):
                d[key] = MatlabFuncs._todict(d[key])
        return d

    @staticmethod
    def _todict(matobj: spio.matlab.mio5_params.mat_struct) -> dict:
        d = {}
        for strg in matobj._fieldnames:
            elem = matobj.__dict__[strg]
            if isinstance(elem, spio.matlab.mio5_params.mat_struct):
                d[strg] = MatlabFuncs._todict(elem)
            else:
                d[strg] = elem
        return d


[docs]class MES: """ Handles of opening .mes files and organizing the images and meta data. The load_img() method returns a 3D array (dims are [time, cols, rows]) of the image sequence and its associated meta data. Usage: Create a MES instance by passing the path of your mes file, example: mesfile = MES('/path/to/mesfile/experiment_Feb_31.mes') Call the get_image_references() method to get a list of references for images that can be loaded. To load an image that is available in the instance, just pass one of the references from get_image_references() to the load_img method: img_array, meta_dict = mesfile.load_img('IF0001_0001') """
[docs] def __init__(self, filename: str): # Open the weird matlab type objects and organize the images & meta data """ :param filename: full path of a single .mes file """ self.main_dict = MatlabFuncs.loadmat(filename) self.main_dict_keys = [x for x in self.main_dict.keys()] self.main_dict_keys.sort() self._images = [x for x in self.main_dict_keys if "I" in x] self.image_descriptions = {} self.voltages_lists_dict = {} self.errors = [] for image in self._images: try: meta = self.main_dict["D" + image[1:6]].tolist() meta = self._todict(meta[int(image[-1]) - 1]) except Exception: self.errors.append('Error opening an image, There as an error when opening the following image: ' + str( "D" + image[1:6]) + '\n' + traceback.format_exc()) # If auxiliary voltage information (which for example contains information # about stimulus timings & can be mapped to stimulus definitions). for prefix in ['AUXi', 'AUXo', 'Sh', 'Stim']: for n in range(0, 9): channel = prefix + str(n) if channel in meta.keys(): try: if meta[channel]['y'].ndim == 2: if channel in self.voltages_lists_dict.keys(): self.voltages_lists_dict[channel] += list(set(meta[channel]['y'][1])) else: self.voltages_lists_dict[channel] = list(set(meta[channel]['y'][1])) except (KeyError, IndexError) as e: self.errors.append(str(e) + ': ' + meta['IMAGE'] + ' Does not have: ' + channel) for channel in ['PMT_EN', 'Trig', 'PMTenUG', 'PMTenUR', 'PMTenUB']: if channel in meta.keys(): try: if channel in self.voltages_lists_dict.keys(): self.voltages_lists_dict[channel] += list(set(meta[channel]['y'][1])) else: self.voltages_lists_dict[channel] = list(set(meta[channel]['y'][1])) except (KeyError, IndexError) as e: self.errors.append(str(e) + ': ' + meta['IMAGE'] + ' Does not have: ' + channel) try: comment = meta["Comment"] if type(comment) != str: comment = "No description" self.image_descriptions[image] = comment except KeyError as e: self.errors.append(str(e) + ': ' + '"error for: "' + image) for channel in self.voltages_lists_dict.keys(): self.voltages_lists_dict[channel] = list(set(self.voltages_lists_dict[channel]))
def _loadmat(self, filename): data = spio.loadmat(filename, struct_as_record=False, squeeze_me=True) return self._check_keys(data) def _check_keys(self, dict): for key in dict: if isinstance(dict[key], spio.matlab.mio5_params.mat_struct): dict[key] = self._todict(dict[key]) return dict def _todict(self, matobj): dict = {} for strg in matobj._fieldnames: elem = matobj.__dict__[strg] if isinstance(elem, spio.matlab.mio5_params.mat_struct): dict[strg] = self._todict(elem) else: dict[strg] = elem return dict
[docs] def get_image_references(self) -> list: """Get a list of all image references available in the instance""" return self._images
# Returns image as ImgData class object.
[docs] def load_img(self, img_reference: str) -> (np.ndarray, dict): """ :param img_reference: The image reference, usually something like IFxxxx_xxxx or Ifxxxx_xxxx :return: (image sequence array, meta data dict) """ if img_reference not in self._images: raise KeyError('fImage reference: {img_reference} not found.\nCall get_image_references for a ' 'list of all available references to images that can be loaded.') meta = self.main_dict["D" + img_reference[1:6]].tolist() meta = self._todict(meta[0]) # except KeyError: # return False, KeyError if len(meta["FoldedFrameInfo"]) > 0: start = meta["FoldedFrameInfo"]["firstFramePos"] stop = meta["TransversePixNum"] # print("Images starting at: ",start) # print("Frame width = ",stop) im = self.main_dict[img_reference] # Trim the 2D array to start at where img acquisition actually begins im = im[:, start:] # Figure out where the 2D array stops at end of acquisition im = im[:, :(im.shape[1] - (im.shape[1] % stop))] # Divide the single large 2D array into individual arrays which each # represent a single frame image_sequence = np.hsplit(im, im.shape[1] / stop) # Combine all the frames into one 3D array, 2D + time seq = np.dstack(image_sequence) return seq, meta else: raise ValueError("'" + str(img_reference) + "' does not have the required " "'FoldedFrameInfo' meta-data which is " "required for the construction of an image " "sequence from mesfile data")
# For testing #if __name__ == '__main__': # y = imdata.meta['AUXo3']['y']