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
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
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)
def test_grayscale_image(self): GrayscaleImage(name='test_grayscale_image', data=np.ones((2, 2)))
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()
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')
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)
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()
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)