Exemple #1
0
def add_image(nwbfile, image_data, image_name, module_name, module_description, image_api=None):

    description = '{} image at pixels/cm resolution'.format(image_name)

    if image_api is None:
        image_api = ImageApi

    if isinstance(image_data, sitk.Image):
        data, spacing, unit = ImageApi.deserialize(image_data)
    elif isinstance(image_data, Image):
        data = image_data.data
        spacing = image_data.spacing
        unit = image_data.unit
    else:
        raise ValueError("Not a supported image_data type: {}".format(type(image_data)))

    assert spacing[0] == spacing[1] and len(spacing) == 2 and unit == 'mm'

    if module_name not in nwbfile.modules:
        ophys_mod = ProcessingModule(module_name, module_description)
        nwbfile.add_processing_module(ophys_mod)
    else:
        ophys_mod = nwbfile.modules[module_name]

    image = GrayscaleImage(image_name, data, resolution=spacing[0] / 10, description=description)

    if 'images' not in ophys_mod.containers:
        images = Images(name='images')
        ophys_mod.add_data_interface(images)
    else:
        images = ophys_mod['images']
    images.add_image(image)

    return nwbfile
Exemple #2
0
def add_images_to_subject(subject, subject_image_list):
    images = Images(name='images', description="images of subject's brain")
    for image_path in subject_image_list:
        image_name = os.path.split(image_path)[1]
        image_name = os.path.splitext(image_name)[0]
        image_data = imread(image_path)
        kwargs = {'data': image_data, 'name': image_name}
        if len(image_data.shape) == 2:
            image = GrayscaleImage(**kwargs)
        elif image_data.shape[2] == 3:
            image = RGBImage(**kwargs)
        elif image_data.shape[2] == 4:
            image = RGBAImage(**kwargs)

        images.add_image(image)
    subject.images = images
    return subject
Exemple #3
0
def add_image_to_nwb(nwbfile: NWBFile, image_data: Image, image_name: str):
    """
    Adds image given by image_data with name image_name to nwbfile

    Parameters
    ----------
    nwbfile
        nwbfile to add image to
    image_data
        The image data
    image_name
        Image name

    Returns
    -------
    None
    """
    module_name = 'ophys'
    description = '{} image at pixels/cm resolution'.format(image_name)

    data, spacing, unit = image_data

    assert spacing[0] == spacing[1] and len(spacing) == 2 and unit == 'mm'

    if module_name not in nwbfile.processing:
        ophys_mod = ProcessingModule(module_name, 'Ophys processing module')
        nwbfile.add_processing_module(ophys_mod)
    else:
        ophys_mod = nwbfile.processing[module_name]

    image = GrayscaleImage(image_name,
                           data,
                           resolution=spacing[0] / 10,
                           description=description)

    if 'images' not in ophys_mod.containers:
        images = Images(name='images')
        ophys_mod.add_data_interface(images)
    else:
        images = ophys_mod['images']
    images.add_image(image)
Exemple #4
0
 def test_grayscale_image(self):
     GrayscaleImage(name='test_grayscale_image', data=np.ones((2, 2)))
Exemple #5
0
    def write_segmentation(
        segext_obj: SegmentationExtractor,
        save_path: PathType = None,
        plane_num=0,
        metadata: dict = None,
        overwrite: bool = True,
        buffer_size: int = 10,
        nwbfile=None,
    ):
        assert (
            save_path is None or nwbfile is None
        ), "Either pass a save_path location, or nwbfile object, but not both!"

        # parse metadata correctly:
        if isinstance(segext_obj, MultiSegmentationExtractor):
            segext_objs = segext_obj.segmentations
            if metadata is not None:
                assert isinstance(metadata, list), (
                    "For MultiSegmentationExtractor enter 'metadata' as a list of "
                    "SegmentationExtractor metadata")
                assert len(metadata) == len(segext_objs), (
                    "The 'metadata' argument should be a list with the same "
                    "number of elements as the segmentations in the "
                    "MultiSegmentationExtractor")
        else:
            segext_objs = [segext_obj]
            if metadata is not None and not isinstance(metadata, list):
                metadata = [metadata]
        metadata_base_list = [
            NwbSegmentationExtractor.get_nwb_metadata(sgobj)
            for sgobj in segext_objs
        ]
        print(f"writing nwb for {segext_obj.extractor_name}\n")
        # updating base metadata with new:
        for num, data in enumerate(metadata_base_list):
            metadata_input = metadata[num] if metadata else {}
            metadata_base_list[num] = dict_recursive_update(
                metadata_base_list[num], metadata_input)
        metadata_base_common = metadata_base_list[0]

        # build/retrieve nwbfile:
        if nwbfile is not None:
            assert isinstance(
                nwbfile, NWBFile), "'nwbfile' should be of type pynwb.NWBFile"
            write = False
        else:
            write = True
            save_path = Path(save_path)
            assert save_path.suffix == ".nwb"
            if save_path.is_file() and not overwrite:
                nwbfile_exist = True
                file_mode = "r+"
            else:
                if save_path.is_file():
                    os.remove(save_path)
                if not save_path.parent.is_dir():
                    save_path.parent.mkdir(parents=True)
                nwbfile_exist = False
                file_mode = "w"
            io = NWBHDF5IO(str(save_path), file_mode)
            if nwbfile_exist:
                nwbfile = io.read()
            else:
                nwbfile = NWBFile(**metadata_base_common["NWBFile"])

        # Subject:
        if metadata_base_common.get("Subject") and nwbfile.subject is None:
            nwbfile.subject = Subject(**metadata_base_common["Subject"])

        # Processing Module:
        if "ophys" not in nwbfile.processing:
            ophys = nwbfile.create_processing_module(
                "ophys", "contains optical physiology processed data")
        else:
            ophys = nwbfile.get_processing_module("ophys")

        for plane_no_loop, (segext_obj, metadata) in enumerate(
                zip(segext_objs, metadata_base_list)):
            # Device:
            if metadata["Ophys"]["Device"][0]["name"] not in nwbfile.devices:
                nwbfile.create_device(**metadata["Ophys"]["Device"][0])

            # ImageSegmentation:
            image_segmentation_name = (
                "ImageSegmentation" if plane_no_loop == 0 else
                f"ImageSegmentation_Plane{plane_no_loop}")
            if image_segmentation_name not in ophys.data_interfaces:
                image_segmentation = ImageSegmentation(
                    name=image_segmentation_name)
                ophys.add(image_segmentation)
            else:
                image_segmentation = ophys.data_interfaces.get(
                    image_segmentation_name)

            # OpticalChannel:
            optical_channels = [
                OpticalChannel(**i) for i in metadata["Ophys"]["ImagingPlane"]
                [0]["optical_channel"]
            ]

            # ImagingPlane:
            image_plane_name = ("ImagingPlane" if plane_no_loop == 0 else
                                f"ImagePlane_{plane_no_loop}")
            if image_plane_name not in nwbfile.imaging_planes.keys():
                input_kwargs = dict(
                    name=image_plane_name,
                    device=nwbfile.get_device(
                        metadata_base_common["Ophys"]["Device"][0]["name"]),
                )
                metadata["Ophys"]["ImagingPlane"][0][
                    "optical_channel"] = optical_channels
                input_kwargs.update(**metadata["Ophys"]["ImagingPlane"][0])
                if "imaging_rate" in input_kwargs:
                    input_kwargs["imaging_rate"] = float(
                        input_kwargs["imaging_rate"])
                imaging_plane = nwbfile.create_imaging_plane(**input_kwargs)
            else:
                imaging_plane = nwbfile.imaging_planes[image_plane_name]

            # PlaneSegmentation:
            input_kwargs = dict(
                description="output from segmenting imaging plane",
                imaging_plane=imaging_plane,
            )
            ps_metadata = metadata["Ophys"]["ImageSegmentation"][
                "plane_segmentations"][0]
            if ps_metadata[
                    "name"] not in image_segmentation.plane_segmentations:
                ps_exist = False
            else:
                ps = image_segmentation.get_plane_segmentation(
                    ps_metadata["name"])
                ps_exist = True

            roi_ids = segext_obj.get_roi_ids()
            accepted_list = segext_obj.get_accepted_list()
            accepted_list = [] if accepted_list is None else accepted_list
            rejected_list = segext_obj.get_rejected_list()
            rejected_list = [] if rejected_list is None else rejected_list
            accepted_ids = [1 if k in accepted_list else 0 for k in roi_ids]
            rejected_ids = [1 if k in rejected_list else 0 for k in roi_ids]
            roi_locations = np.array(segext_obj.get_roi_locations()).T

            def image_mask_iterator():
                for id in segext_obj.get_roi_ids():
                    img_msks = segext_obj.get_roi_image_masks(
                        roi_ids=[id]).T.squeeze()
                    yield img_msks

            if not ps_exist:
                input_kwargs.update(
                    **ps_metadata,
                    columns=[
                        VectorData(
                            data=H5DataIO(
                                DataChunkIterator(image_mask_iterator(),
                                                  buffer_size=buffer_size),
                                compression=True,
                                compression_opts=9,
                            ),
                            name="image_mask",
                            description="image masks",
                        ),
                        VectorData(
                            data=roi_locations,
                            name="RoiCentroid",
                            description=
                            "x,y location of centroid of the roi in image_mask",
                        ),
                        VectorData(
                            data=accepted_ids,
                            name="Accepted",
                            description=
                            "1 if ROi was accepted or 0 if rejected as a cell during segmentation operation",
                        ),
                        VectorData(
                            data=rejected_ids,
                            name="Rejected",
                            description=
                            "1 if ROi was rejected or 0 if accepted as a cell during segmentation operation",
                        ),
                    ],
                    id=roi_ids,
                )

                ps = image_segmentation.create_plane_segmentation(
                    **input_kwargs)

            # Fluorescence Traces:
            if "Flourescence" not in ophys.data_interfaces:
                fluorescence = Fluorescence()
                ophys.add(fluorescence)
            else:
                fluorescence = ophys.data_interfaces["Fluorescence"]
            roi_response_dict = segext_obj.get_traces_dict()
            roi_table_region = ps.create_roi_table_region(
                description=f"region for Imaging plane{plane_no_loop}",
                region=list(range(segext_obj.get_num_rois())),
            )
            rate = (np.float("NaN")
                    if segext_obj.get_sampling_frequency() is None else
                    segext_obj.get_sampling_frequency())
            for i, j in roi_response_dict.items():
                data = getattr(segext_obj, f"_roi_response_{i}")
                if data is not None:
                    data = np.asarray(data)
                    trace_name = "RoiResponseSeries" if i == "raw" else i.capitalize(
                    )
                    trace_name = (trace_name if plane_no_loop == 0 else
                                  trace_name + f"_Plane{plane_no_loop}")
                    input_kwargs = dict(
                        name=trace_name,
                        data=data.T,
                        rois=roi_table_region,
                        rate=rate,
                        unit="n.a.",
                    )
                    if trace_name not in fluorescence.roi_response_series:
                        fluorescence.create_roi_response_series(**input_kwargs)

            # create Two Photon Series:
            if "TwoPhotonSeries" not in nwbfile.acquisition:
                warn(
                    "could not find TwoPhotonSeries, using ImagingExtractor to create an nwbfile"
                )

            # adding images:
            images_dict = segext_obj.get_images_dict()
            if any([image is not None for image in images_dict.values()]):
                images_name = ("SegmentationImages" if plane_no_loop == 0 else
                               f"SegmentationImages_Plane{plane_no_loop}")
                if images_name not in ophys.data_interfaces:
                    images = Images(images_name)
                    for img_name, img_no in images_dict.items():
                        if img_no is not None:
                            images.add_image(
                                GrayscaleImage(name=img_name, data=img_no.T))
                    ophys.add(images)

            # saving NWB file:
            if write:
                io.write(nwbfile)
                io.close()
                # test read
                with NWBHDF5IO(str(save_path), "r") as io:
                    io.read()
Exemple #6
0
def save_nwb(ops1):
    if NWB and not ops1[0]['mesoscan']:
        if len(ops1) > 1:
            multiplane = True
        else:
            multiplane = False

        ops = ops1[0]

        ### INITIALIZE NWB FILE
        nwbfile = NWBFile(
            session_description='suite2p_proc',
            identifier=ops['data_path'][0],
            session_start_time=(ops['date_proc'] if 'date_proc' in ops else
                                datetime.datetime.now()))
        print(nwbfile)

        device = nwbfile.create_device(
            name='Microscope',
            description='My two-photon microscope',
            manufacturer='The best microscope manufacturer')
        optical_channel = OpticalChannel(name='OpticalChannel',
                                         description='an optical channel',
                                         emission_lambda=500.)

        imaging_plane = nwbfile.create_imaging_plane(
            name='ImagingPlane',
            optical_channel=optical_channel,
            imaging_rate=ops['fs'],
            description='standard',
            device=device,
            excitation_lambda=600.,
            indicator='GCaMP',
            location='V1',
            grid_spacing=([2, 2, 30] if multiplane else [2, 2]),
            grid_spacing_unit='microns')

        # link to external data
        image_series = TwoPhotonSeries(
            name='TwoPhotonSeries',
            dimension=[ops['Ly'], ops['Lx']],
            external_file=(ops['filelist'] if 'filelist' in ops else ['']),
            imaging_plane=imaging_plane,
            starting_frame=[0],
            format='external',
            starting_time=0.0,
            rate=ops['fs'] * ops['nplanes'])
        nwbfile.add_acquisition(image_series)

        # processing
        img_seg = ImageSegmentation()
        ps = img_seg.create_plane_segmentation(name='PlaneSegmentation',
                                               description='suite2p output',
                                               imaging_plane=imaging_plane,
                                               reference_images=image_series)
        ophys_module = nwbfile.create_processing_module(
            name='ophys', description='optical physiology processed data')
        ophys_module.add(img_seg)

        file_strs = ['F.npy', 'Fneu.npy', 'spks.npy']
        traces = []
        ncells_all = 0
        for iplane, ops in enumerate(ops1):
            if iplane == 0:
                iscell = np.load(os.path.join(ops['save_path'], 'iscell.npy'))
                for fstr in file_strs:
                    traces.append(np.load(os.path.join(ops['save_path'],
                                                       fstr)))
            else:
                iscell = np.append(iscell,
                                   np.load(
                                       os.path.join(ops['save_path'],
                                                    'iscell.npy')),
                                   axis=0)
                for i, fstr in enumerate(file_strs):
                    traces[i] = np.append(
                        traces[i],
                        np.load(os.path.join(ops['save_path'], fstr)),
                        axis=0)

            stat = np.load(os.path.join(ops['save_path'], 'stat.npy'),
                           allow_pickle=True)
            ncells = len(stat)
            for n in range(ncells):
                if multiplane:
                    pixel_mask = np.array([
                        stat[n]['ypix'], stat[n]['xpix'],
                        iplane * np.ones(stat[n]['npix']), stat[n]['lam']
                    ])
                    ps.add_roi(voxel_mask=pixel_mask.T)
                else:
                    pixel_mask = np.array(
                        [stat[n]['ypix'], stat[n]['xpix'], stat[n]['lam']])
                    ps.add_roi(pixel_mask=pixel_mask.T)
            ncells_all += ncells

        ps.add_column('iscell', 'two columns - iscell & probcell', iscell)

        rt_region = ps.create_roi_table_region(region=list(
            np.arange(0, ncells_all)),
                                               description='all ROIs')

        # FLUORESCENCE (all are required)
        file_strs = ['F.npy', 'Fneu.npy', 'spks.npy']
        name_strs = ['Fluorescence', 'Neuropil', 'Deconvolved']

        for i, (fstr, nstr) in enumerate(zip(file_strs, name_strs)):
            roi_resp_series = RoiResponseSeries(name=nstr,
                                                data=traces[i],
                                                rois=rt_region,
                                                unit='lumens',
                                                rate=ops['fs'])
            fl = Fluorescence(roi_response_series=roi_resp_series, name=nstr)
            ophys_module.add(fl)

        # BACKGROUNDS
        # (meanImg, Vcorr and max_proj are REQUIRED)
        bg_strs = ['meanImg', 'Vcorr', 'max_proj', 'meanImg_chan2']
        nplanes = ops['nplanes']
        for iplane in range(nplanes):
            images = Images('Backgrounds_%d' % iplane)
            for bstr in bg_strs:
                if bstr in ops:
                    if bstr == 'Vcorr' or bstr == 'max_proj':
                        img = np.zeros((ops['Ly'], ops['Lx']), np.float32)
                        img[ops['yrange'][0]:ops['yrange'][-1],
                            ops['xrange'][0]:ops['xrange'][-1]] = ops[bstr]
                    else:
                        img = ops[bstr]
                    images.add_image(GrayscaleImage(name=bstr, data=img))

            ophys_module.add(images)

        with NWBHDF5IO(os.path.join(ops['save_path0'], 'suite2p', 'ophys.nwb'),
                       'w') as fio:
            fio.write(nwbfile)
    else:
        print('pip install pynwb OR don"t use mesoscope recording')
Exemple #7
0
import numpy as np

from pynwb.image import RGBAImage, RGBImage, GrayscaleImage
from pynwb.base import Images

img = Image.open('docs/source/logo.png')  # an example image

# you can store an RGBA image
rgba_logo = RGBAImage(name='RGBA_logo', data=np.array(img))

# or RGB
rgb_logo = RGBImage(name='RGB_logo', data=np.array(img.convert('RGB')))

# or Grayscale. Here with the optional description and resolution specified.
gs_logo = GrayscaleImage(name='Grayscale_logo',
                         data=np.array(img.convert('L')),
                         description='Grayscale version of the NWB logo',
                         resolution=35.433071)

# Images is a container that accepts any of these image types
images = Images(name='logo_images', images=[rgb_logo, rgba_logo, gs_logo])

# Finally, do not forget to add the images object to the nwb file.
nwbfile.processing['behavior'].add(images)

####################
# Now we overwrite the file with all of the data

with NWBHDF5IO('example_file_path.nwb', 'w') as io:
    io.write(nwbfile)

####################
def test_show_grayscale_image():

    data = np.random.rand(900).reshape((30, 30))
    grayscale_image = GrayscaleImage(name='test_image', data=data)

    assert isinstance(show_grayscale_image(grayscale_image), plt.Figure)
Exemple #9
0
def add_ophys_processing_from_suite2p(save_folder,
                                      nwbfile,
                                      CaImaging_timestamps,
                                      device=None,
                                      optical_channel=None,
                                      imaging_plane=None,
                                      image_series=None):
    """ 
    adapted from suite2p/suite2p/io/nwb.py "save_nwb" function
    """

    plane_folders = natsorted([
        f.path for f in os.scandir(save_folder)
        if f.is_dir() and f.name[:5] == 'plane'
    ])
    ops1 = [
        np.load(os.path.join(f, 'ops.npy'), allow_pickle=True).item()
        for f in plane_folders
    ]
    if len(ops1) > 1:
        multiplane = True
    else:
        multiplane = False

    ops = ops1[0]

    if device is None:
        device = nwbfile.create_device(
            name='Microscope',
            description='My two-photon microscope',
            manufacturer='The best microscope manufacturer')
    if optical_channel is None:
        optical_channel = OpticalChannel(name='OpticalChannel',
                                         description='an optical channel',
                                         emission_lambda=500.)
    if imaging_plane is None:
        imaging_plane = nwbfile.create_imaging_plane(
            name='ImagingPlane',
            optical_channel=optical_channel,
            imaging_rate=ops['fs'],
            description='standard',
            device=device,
            excitation_lambda=600.,
            indicator='GCaMP',
            location='V1',
            grid_spacing=([2, 2, 30] if multiplane else [2, 2]),
            grid_spacing_unit='microns')

    if image_series is None:
        # link to external data
        image_series = TwoPhotonSeries(
            name='TwoPhotonSeries',
            dimension=[ops['Ly'], ops['Lx']],
            external_file=(ops['filelist'] if 'filelist' in ops else ['']),
            imaging_plane=imaging_plane,
            starting_frame=[0],
            format='external',
            starting_time=0.0,
            rate=ops['fs'] * ops['nplanes'])
        nwbfile.add_acquisition(image_series)  # otherwise, were added

    # processing
    img_seg = ImageSegmentation()
    ps = img_seg.create_plane_segmentation(name='PlaneSegmentation',
                                           description='suite2p output',
                                           imaging_plane=imaging_plane,
                                           reference_images=image_series)
    ophys_module = nwbfile.create_processing_module(
        name='ophys', description='optical physiology processed data')
    ophys_module.add(img_seg)

    file_strs = ['F.npy', 'Fneu.npy', 'spks.npy']
    traces = []
    ncells_all = 0
    for iplane, ops in enumerate(ops1):
        if iplane == 0:
            iscell = np.load(
                os.path.join(save_folder, 'plane%i' % iplane, 'iscell.npy'))
            for fstr in file_strs:
                traces.append(
                    np.load(os.path.join(save_folder, 'plane%i' % iplane,
                                         fstr)))
        else:
            iscell = np.append(iscell,
                               np.load(
                                   os.path.join(save_folder,
                                                'plane%i' % iplane,
                                                'iscell.npy')),
                               axis=0)
            for i, fstr in enumerate(file_strs):
                traces[i] = np.append(
                    traces[i],
                    np.load(os.path.join(save_folder, 'plane%i' % iplane,
                                         fstr)),
                    axis=0)

        stat = np.load(os.path.join(save_folder, 'plane%i' % iplane,
                                    'stat.npy'),
                       allow_pickle=True)
        ncells = len(stat)
        for n in range(ncells):
            if multiplane:
                pixel_mask = np.array([
                    stat[n]['ypix'], stat[n]['xpix'],
                    iplane * np.ones(stat[n]['npix']), stat[n]['lam']
                ])
                ps.add_roi(voxel_mask=pixel_mask.T)
            else:
                pixel_mask = np.array(
                    [stat[n]['ypix'], stat[n]['xpix'], stat[n]['lam']])
                ps.add_roi(pixel_mask=pixel_mask.T)
        ncells_all += ncells

    ps.add_column('iscell', 'two columns - iscell & probcell', iscell)

    rt_region = ps.create_roi_table_region(region=list(np.arange(
        0, ncells_all)),
                                           description='all ROIs')

    # FLUORESCENCE (all are required)
    file_strs = ['F.npy', 'Fneu.npy', 'spks.npy']
    name_strs = ['Fluorescence', 'Neuropil', 'Deconvolved']

    for i, (fstr, nstr) in enumerate(zip(file_strs, name_strs)):
        roi_resp_series = RoiResponseSeries(
            name=nstr,
            data=traces[i],
            rois=rt_region,
            unit='lumens',
            timestamps=CaImaging_timestamps
        )  # CRITICAL TO HAVE IT HERE FOR RE-ALIGNEMENT
        fl = Fluorescence(roi_response_series=roi_resp_series, name=nstr)
        ophys_module.add(fl)

    # BACKGROUNDS
    # (meanImg, Vcorr and max_proj are REQUIRED)
    bg_strs = ['meanImg', 'meanImgE', 'Vcorr', 'max_proj', 'meanImg_chan2']
    nplanes = ops['nplanes']
    for iplane in range(nplanes):
        images = Images('Backgrounds_%d' % iplane)
        for bstr in bg_strs:
            if bstr in ops:
                if bstr == 'Vcorr' or bstr == 'max_proj':
                    img = np.zeros((ops['Ly'], ops['Lx']), np.float32)
                    img[ops['yrange'][0]:ops['yrange'][-1],
                        ops['xrange'][0]:ops['xrange'][-1]] = ops[bstr]
                else:
                    img = ops[bstr]
                images.add_image(GrayscaleImage(name=bstr, data=img))

        ophys_module.add(images)
    def write_segmentation(segext_obj,
                           save_path,
                           plane_num=0,
                           metadata=None,
                           overwrite=True):
        save_path = Path(save_path)
        assert save_path.suffix == '.nwb'
        if save_path.is_file() and not overwrite:
            nwbfile_exist = True
            file_mode = 'r+'
        else:
            if save_path.is_file():
                os.remove(save_path)
            if not save_path.parent.is_dir():
                save_path.parent.mkdir(parents=True)
            nwbfile_exist = False
            file_mode = 'w'

        # parse metadata correctly:
        if isinstance(segext_obj, MultiSegmentationExtractor):
            segext_objs = segext_obj.segmentations
            if metadata is not None:
                assert isinstance(metadata, list), "For MultiSegmentationExtractor enter 'metadata' as a list of " \
                                                   "SegmentationExtractor metadata"
                assert len(metadata) == len(segext_objs), "The 'metadata' argument should be a list with the same " \
                                                          "number of elements as the segmentations in the " \
                                                          "MultiSegmentationExtractor"
        else:
            segext_objs = [segext_obj]
            if metadata is not None and not isinstance(metadata, list):
                metadata = [metadata]
        metadata_base_list = [
            NwbSegmentationExtractor.get_nwb_metadata(sgobj)
            for sgobj in segext_objs
        ]

        print(f'writing nwb for {segext_obj.extractor_name}\n')
        # updating base metadata with new:
        for num, data in enumerate(metadata_base_list):
            metadata_input = metadata[num] if metadata else {}
            metadata_base_list[num] = dict_recursive_update(
                metadata_base_list[num], metadata_input)
        # loop for every plane:
        with NWBHDF5IO(str(save_path), file_mode) as io:
            metadata_base_common = metadata_base_list[0]
            if nwbfile_exist:
                nwbfile = io.read()
            else:
                nwbfile = NWBFile(**metadata_base_common['NWBFile'])
                # Subject:
                if metadata_base_common.get('Subject'):
                    nwbfile.subject = Subject(
                        **metadata_base_common['Subject'])

            # Processing Module:
            if 'ophys' not in nwbfile.processing:
                ophys = nwbfile.create_processing_module(
                    'ophys', 'contains optical physiology processed data')
            else:
                ophys = nwbfile.get_processing_module('ophys')

            for plane_no_loop, (segext_obj, metadata) in enumerate(
                    zip(segext_objs, metadata_base_list)):
                # Device:
                if metadata['Ophys']['Device'][0][
                        'name'] not in nwbfile.devices:
                    nwbfile.create_device(**metadata['Ophys']['Device'][0])

                # ImageSegmentation:
                image_segmentation_name = 'ImageSegmentation' if plane_no_loop == 0 else f'ImageSegmentation_Plane{plane_no_loop}'
                if image_segmentation_name not in ophys.data_interfaces:
                    image_segmentation = ImageSegmentation(
                        name=image_segmentation_name)
                    ophys.add_data_interface(image_segmentation)
                else:
                    image_segmentation = ophys.data_interfaces.get(
                        image_segmentation_name)

                # OpticalChannel:
                optical_channels = [
                    OpticalChannel(**i) for i in metadata['Ophys']
                    ['ImagingPlane'][0]['optical_channel']
                ]

                # ImagingPlane:
                image_plane_name = 'ImagingPlane' if plane_no_loop == 0 else f'ImagePlane_{plane_no_loop}'
                if image_plane_name not in nwbfile.imaging_planes.keys():
                    input_kwargs = dict(
                        name=image_plane_name,
                        device=nwbfile.get_device(metadata_base_common['Ophys']
                                                  ['Device'][0]['name']),
                    )
                    metadata['Ophys']['ImagingPlane'][0][
                        'optical_channel'] = optical_channels
                    input_kwargs.update(**metadata['Ophys']['ImagingPlane'][0])
                    if 'imaging_rate' in input_kwargs:
                        input_kwargs['imaging_rate'] = float(
                            input_kwargs['imaging_rate'])
                    imaging_plane = nwbfile.create_imaging_plane(
                        **input_kwargs)
                else:
                    imaging_plane = nwbfile.imaging_planes[image_plane_name]

                # PlaneSegmentation:
                input_kwargs = dict(
                    description='output from segmenting imaging plane',
                    imaging_plane=imaging_plane)
                ps_metadata = metadata['Ophys']['ImageSegmentation'][
                    'plane_segmentations'][0]
                if ps_metadata[
                        'name'] not in image_segmentation.plane_segmentations:
                    input_kwargs.update(**ps_metadata)
                    ps = image_segmentation.create_plane_segmentation(
                        **input_kwargs)
                    ps_exist = False
                else:
                    ps = image_segmentation.get_plane_segmentation(
                        ps_metadata['name'])
                    ps_exist = True

                # ROI add:
                image_masks = segext_obj.get_roi_image_masks()
                roi_ids = segext_obj.get_roi_ids()
                accepted_list = segext_obj.get_accepted_list()
                accepted_list = [] if accepted_list is None else accepted_list
                rejected_list = segext_obj.get_rejected_list()
                rejected_list = [] if rejected_list is None else rejected_list
                accepted_ids = [
                    1 if k in accepted_list else 0 for k in roi_ids
                ]
                rejected_ids = [
                    1 if k in rejected_list else 0 for k in roi_ids
                ]
                roi_locations = np.array(segext_obj.get_roi_locations()).T
                if not ps_exist:
                    ps.add_column(
                        name='RoiCentroid',
                        description=
                        'x,y location of centroid of the roi in image_mask')
                    ps.add_column(
                        name='Accepted',
                        description=
                        '1 if ROi was accepted or 0 if rejected as a cell during segmentation operation'
                    )
                    ps.add_column(
                        name='Rejected',
                        description=
                        '1 if ROi was rejected or 0 if accepted as a cell during segmentation operation'
                    )
                    for num, row in enumerate(roi_ids):
                        ps.add_roi(id=row,
                                   image_mask=image_masks[:, :, num],
                                   RoiCentroid=roi_locations[num, :],
                                   Accepted=accepted_ids[num],
                                   Rejected=rejected_ids[num])

                # Fluorescence Traces:
                if 'Flourescence' not in ophys.data_interfaces:
                    fluorescence = Fluorescence()
                    ophys.add_data_interface(fluorescence)
                else:
                    fluorescence = ophys.data_interfaces['Fluorescence']
                roi_response_dict = segext_obj.get_traces_dict()
                roi_table_region = ps.create_roi_table_region(
                    description=f'region for Imaging plane{plane_no_loop}',
                    region=list(range(segext_obj.get_num_rois())))
                rate = np.float('NaN') if segext_obj.get_sampling_frequency(
                ) is None else segext_obj.get_sampling_frequency()
                for i, j in roi_response_dict.items():
                    data = getattr(segext_obj, f'_roi_response_{i}')
                    if data is not None:
                        data = np.asarray(data)
                        trace_name = 'RoiResponseSeries' if i == 'raw' else i.capitalize(
                        )
                        trace_name = trace_name if plane_no_loop == 0 else trace_name + f'_Plane{plane_no_loop}'
                        input_kwargs = dict(name=trace_name,
                                            data=data.T,
                                            rois=roi_table_region,
                                            rate=rate,
                                            unit='n.a.')
                        if trace_name not in fluorescence.roi_response_series:
                            fluorescence.create_roi_response_series(
                                **input_kwargs)

                # create Two Photon Series:
                if 'TwoPhotonSeries' not in nwbfile.acquisition:
                    warn(
                        'could not find TwoPhotonSeries, using ImagingExtractor to create an nwbfile'
                    )

                # adding images:
                images_dict = segext_obj.get_images_dict()
                if any([image is not None for image in images_dict.values()]):
                    images_name = 'SegmentationImages' if plane_no_loop == 0 else f'SegmentationImages_Plane{plane_no_loop}'
                    if images_name not in ophys.data_interfaces:
                        images = Images(images_name)
                        for img_name, img_no in images_dict.items():
                            if img_no is not None:
                                images.add_image(
                                    GrayscaleImage(name=img_name, data=img_no))
                        ophys.add(images)

            # saving NWB file:
            io.write(nwbfile)

        # test read
        with NWBHDF5IO(str(save_path), 'r') as io:
            io.read()
Exemple #11
0
def add_ophys_processing_from_suite2p(save_folder, nwbfile, xml, 
                                      device=None,
                                      optical_channel=None,
                                      imaging_plane=None,
                                      image_series=None):
    """ 
    adapted from suite2p/suite2p/io/nwb.py "save_nwb" function
    """

    plane_folders = natsorted([ f.path for f in os.scandir(save_folder) if f.is_dir() and f.name[:5]=='plane'])
    OPS = [np.load(os.path.join(f, 'ops.npy'), allow_pickle=True).item() for f in plane_folders]

    if len(OPS)>1:
        multiplane, nplanes = True, len(plane_folders)
        pData_folder = os.path.join(save_folder, 'combined') # processed data folder -> using the "combined output from suite2p"
    else:
        multiplane, nplanes = False, 1
        pData_folder = os.path.join(save_folder, 'plane0') # processed data folder

    # find time sampling per plane
    functional_chan = ('Ch1' if len(xml['Ch1']['relativeTime'])>1 else 'Ch2') # functional channel is one of the two !!
    CaImaging_timestamps = xml[functional_chan]['relativeTime']+float(xml['settings']['framePeriod'])/2.

    ops = np.load(os.path.join(pData_folder, 'ops.npy'), allow_pickle=True).item() 
    
    if device is None:
        device = nwbfile.create_device(
            name='Microscope', 
            description='My two-photon microscope',
            manufacturer='The best microscope manufacturer')
    if optical_channel is None:
        optical_channel = OpticalChannel(
            name='OpticalChannel', 
            description='an optical channel', 
            emission_lambda=500.)
    if imaging_plane is None:
        imaging_plane = nwbfile.create_imaging_plane(
            name='ImagingPlane',
            optical_channel=optical_channel,
            imaging_rate=ops['fs'],
            description='standard',
            device=device,
            excitation_lambda=600.,
            indicator='GCaMP',
            location='V1',
            grid_spacing=([2,2,30] if multiplane else [2,2]),
            grid_spacing_unit='microns')

    if image_series is None:
        # link to external data
        image_series = TwoPhotonSeries(
            name='TwoPhotonSeries', 
            dimension=[ops['Ly'], ops['Lx']],
            external_file=(ops['filelist'] if 'filelist' in ops else ['']), 
            imaging_plane=imaging_plane,
            starting_frame=[0], 
            format='external', 
            starting_time=0.0, 
            rate=ops['fs'] * ops['nplanes']
        )
        nwbfile.add_acquisition(image_series) # otherwise, were added

    # processing
    img_seg = ImageSegmentation()
    ps = img_seg.create_plane_segmentation(
        name='PlaneSegmentation',
        description='suite2p output',
        imaging_plane=imaging_plane,
        reference_images=image_series
    )
    ophys_module = nwbfile.create_processing_module(
        name='ophys', 
        description='optical physiology processed data\n TSeries-folder=%s' % save_folder)
    ophys_module.add(img_seg)

    file_strs = ['F.npy', 'Fneu.npy', 'spks.npy']
    traces = []

    iscell = np.load(os.path.join(pData_folder, 'iscell.npy')).astype(bool)

    if ops['nchannels']>1:
        if os.path.isfile(os.path.join(pData_folder, 'redcell_manual.npy')):
            redcell = np.load(os.path.join(pData_folder, 'redcell_manual.npy'))[iscell[:,0], :]
        else:
            print('\n'+30*'--')
            print(' /!\ no file found for the manual labelling of red cells (generate it with the red-cell labelling GUI) /!\ ')
            print(' /!\ taking the raw suit2p output with the classifier settings /!\ ')
            print('\n'+30*'--')
            redcell = np.load(os.path.join(pData_folder, 'redcell.npy'))[iscell[:,0], :]
            
    for fstr in file_strs:
        traces.append(np.load(os.path.join(pData_folder, fstr))[iscell[:,0], :])
        
    stat = np.load(os.path.join(pData_folder, 'stat.npy'), allow_pickle=True)

    ncells = np.sum(iscell[:,0])
    plane_ID = np.zeros(ncells)
    for n in np.arange(ncells):
        pixel_mask = np.array([stat[iscell[:,0]][n]['ypix'], stat[iscell[:,0]][n]['xpix'], 
                               stat[iscell[:,0]][n]['lam']])
        ps.add_roi(pixel_mask=pixel_mask.T)
        if 'iplane' in stat[0]:
            plane_ID[n] = stat[iscell[:,0]][n]['iplane']

    if ops['nchannels']>1:
        ps.add_column('redcell', 'two columns - redcell & probcell', redcell)
    ps.add_column('plane', 'one column - plane ID', plane_ID)

    rt_region = ps.create_roi_table_region(
        region=list(np.arange(0, ncells)),
        description='all ROIs')

    # FLUORESCENCE (all are required)
    file_strs = ['F.npy', 'Fneu.npy', 'spks.npy']
    name_strs = ['Fluorescence', 'Neuropil', 'Deconvolved']

    for i, (fstr,nstr) in enumerate(zip(file_strs, name_strs)):
        roi_resp_series = RoiResponseSeries(
            name=nstr,
            data=traces[i],
            rois=rt_region,
            unit='lumens',
            timestamps=CaImaging_timestamps[::nplanes]) # ideally should be shifted for each ROI depending on the plane...
        fl = Fluorescence(roi_response_series=roi_resp_series, name=nstr)
        ophys_module.add(fl)

    # BACKGROUNDS
    # (meanImg, Vcorr and max_proj are REQUIRED)
    bg_strs = ['meanImg', 'meanImgE', 'Vcorr', 'max_proj', 'meanImg_chan2']
    nplanes = ops['nplanes']
    for iplane in range(nplanes):
        images = Images('Backgrounds_%d'%iplane)
        for bstr in bg_strs:
            if bstr in ops:
                if bstr=='Vcorr' or bstr=='max_proj':
                    img = np.zeros((ops['Ly'], ops['Lx']), np.float32)
                    img[ops['yrange'][0]:ops['yrange'][-1], 
                        ops['xrange'][0]:ops['xrange'][-1]] = ops[bstr]
                else:
                    img = ops[bstr]
                images.add_image(GrayscaleImage(name=bstr, data=img))

        ophys_module.add(images)