Movie reconstruction from mouse visual cortex activity.
The 12 matches
- [1] § Methods › State-of-the-art dynamic neural encoding model ↔ src/models/dwiseneuro.py, lines 343–405 · score 0.70 · SiLU, DwiseNeuro, Softplus, readout, kernel, cortex
- [2] § Results › Video reconstruction using state-of-the-art dynamic neural encoding models › Not all spatial and temporal frequencies are reconstructed equally ↔ scripts/analyse_reconstructions_gaussian_noise.ipynb, lines 11–81 · score 0.61 · phase inverted, Reconstructed Gaussian, Gaussian noise, temporal length constants, stimulus, mask
- [3] § Methods › Additional visual stimuli ↔ scripts/analyse_reconstructions_gaussian_noise.ipynb, lines 11–81 · score 0.60 · phase inverted, Gaussian noise, temporal length constant, stimuli
- [4] § Methods › Additional visual stimuli ↔ scripts/reconstruct_videos_gaussian_noise.py, lines 111–162 · score 0.60 · phase inverted, Gaussian noise, temporal length constant, stimuli
- [5] § Methods › Mask training ↔ utils_reconstruction/utils_reconstruction.py, lines 15–76 · score 0.57 · alpha blend, background video, layer, masks
- [6] § Results › Video reconstruction using state-of-the-art dynamic neural encoding models › Not all spatial and temporal frequencies are reconstructed equally ↔ scripts/analyse_reconstructions_drifting_gratings.ipynb, lines 153–289 · score 0.57 · temporal frequencies, temporal length constants, drifting, gratings, square, inverted
- [7] § Results › Video reconstruction using state-of-the-art dynamic neural encoding models ↔ scripts/predict_response_from_recon.py, lines 157–239 · score 0.55 · luminance matching, Poisson loss, full video, neurons, activity, correlation
- [8] § Results › Video reconstruction using state-of-the-art dynamic neural encoding models ↔ scripts/analyse_reconstructions_from_predicted_activity.ipynb, lines 495–575 · score 0.55 · evaluation mask threshold, Predicted activity, video correlation, diameter, ensembling, gradient
- [9] § Results › Video reconstruction using state-of-the-art dynamic neural encoding models › Not all spatial and temporal frequencies are reconstructed equally ↔ scripts/analyse_reconstructions_gaussian_noise.ipynb, lines 420–486 · score 0.54 · Gaussian noise, Shannon entropy, motion energy, temporal, frame, reconstructions
- [10] § Results › Video reconstruction using state-of-the-art dynamic neural encoding models › Not all spatial and temporal frequencies are reconstructed equally ↔ scripts/analyse_reconstructions_drifting_gratings.ipynb, lines 153–289 · score 0.53 · Reconstructed drifting grating, temporal frequencies, interleaved, ground truth, correlation, masked
- [11] § Results › Video reconstruction using state-of-the-art dynamic neural encoding models › Not all spatial and temporal frequencies are reconstructed equally ↔ scripts/analyse_reconstructions_gaussian_noise.ipynb, lines 211–349 · score 0.53 · Gaussian noise, temporal length constants, square, inverted, ground truth, ensembled
- [12] § Results › Video reconstruction using state-of-the-art dynamic neural encoding models › High-quality video reconstruction ↔ scripts/analyse_reconstructions.ipynb, lines 949–972 · score 0.51 · pupil diameter, motion energy, speed, eye, luminance, correlating
Paper
Loaded from Europe PMC by your browser, not stored by OSCR: doi.org · Europe PMC
The paper is loaded when this pane is shown.
The authors' code
Jupyter notebook · 569 lines · 29 KB · MIT · 4 matches
- # %%
- import sys
- sys.path.append('../')
- import numpy as np
- import matplotlib.pyplot as plt
- import scipy as sp
- from utils_reconstruction import image_similarity as imsim
- import tifffile
- # %%
- ## load reconstruction .npy files
- num_neurons = [7863, 7908, 8202, 7939, 8122]
- mouse_names = [
- "dynamic29515-10-12-Video-9b4f6a1a067fe51e15306b9628efea20",
- "dynamic29623-4-9-Video-9b4f6a1a067fe51e15306b9628efea20",
- "dynamic29647-19-8-Video-9b4f6a1a067fe51e15306b9628efea20",
- "dynamic29712-5-9-Video-9b4f6a1a067fe51e15306b9628efea20",
- "dynamic29755-2-8-Video-9b4f6a1a067fe51e15306b9628efea20",
- ]
- max_num_neurons = np.max(num_neurons)
- model_list = np.array([0,1,2,3,4,5,6]) # 1,2,3,4,5,6 # 0 held out!
- mice = range(0,3)
- reps = np.array([0,1,2,3,4])# range(0,5)
- spatial_length_constant = range(0,7)
- temporal_length_constant = range(0,7)
- eval_frame_skip = 30 # default 30
- mask_th = 1
- video_gt=np.nan*np.ones((len(mice),len(reps)*2,len(spatial_length_constant),len(temporal_length_constant),60,36,64))
- video_pred=np.nan*np.ones((model_list.size,len(mice),len(reps)*2,len(spatial_length_constant),len(temporal_length_constant),60,36,64))
- responses_pred_gt=np.nan*np.ones((model_list.size,len(mice),len(reps)*2,len(spatial_length_constant),len(temporal_length_constant),max_num_neurons,60))
- responses_pred_recon=np.nan*np.ones((model_list.size,len(mice),len(reps)*2,len(spatial_length_constant),len(temporal_length_constant),max_num_neurons,60))
- mask=np.nan*np.ones((len(mice),36,64))
- for model_n in model_list:
- for mouse in mice:
- for rep in range(0,len(reps)):#reps:
- for spatial_n in spatial_length_constant:
- for temporal_n in temporal_length_constant:
- datapath=f'../reconstructions/modelfold{model_n}_round4_Gausnoise/reconstruction_summary_m{mouse}_r{reps[rep]}s{spatial_n}t{temporal_n}.npy'
- print(datapath)
- data = np.load(datapath, allow_pickle=True).item()
- if model_n==model_list[0]:
- video_gt[mouse,rep,spatial_n,temporal_n] = data['video_gt']
- video_pred[model_n-1,mouse,rep,spatial_n,temporal_n] = data['video_pred']
- mask[mouse-1] = data['mask'][14:14+36,:]
- responses_pred_gt[model_n-1,mouse,rep,spatial_n,temporal_n,0:num_neurons[mouse],:] = data['responses_predicted_gt']
- responses_pred_recon[model_n-1,mouse-1,rep,spatial_n,temporal_n,0:num_neurons[mouse],:] = data['responses_predicted_full']
- # add phase inverted stimuli as additional reps
- datapath=f'../reconstructions/modelfold{model_n}_round5_Gausnoise_PhaseInverted/reconstruction_summary_m{mouse}_r{reps[rep]}s{spatial_n}t{temporal_n}.npy'
- print(datapath)
- data = np.load(datapath, allow_pickle=True).item()
- if model_n==model_list[0]:
- video_gt[mouse,rep+len(reps),spatial_n,temporal_n] = data['video_gt']
- video_pred[model_n-1,mouse,rep+len(reps),spatial_n,temporal_n] = data['video_pred']
- mask[mouse-1] = data['mask'][14:14+36,:]
- responses_pred_gt[model_n-1,mouse,rep+len(reps),spatial_n,temporal_n,0:num_neurons[mouse],:] = data['responses_predicted_gt']
- responses_pred_recon[model_n-1,mouse-1,rep+len(reps),spatial_n,temporal_n,0:num_neurons[mouse],:] = data['responses_predicted_full']
- reps = np.array([0,1,2,3,4,5,6,7,8,9])# range(0,5)
- # remove eval grace period
- video_gt = video_gt[:,:,:,:,eval_frame_skip:,:,:]
- video_pred = video_pred[:,:,:,:,:,eval_frame_skip:,:,:]
- responses_pred_gt = responses_pred_gt[:,:,:,:,:,:,eval_frame_skip:]
- responses_pred_recon = responses_pred_recon[:,:,:,:,:,:,eval_frame_skip:]
- print('video_gt: ', video_gt.shape, video_gt.min(), video_gt.max())
- print('video_pred: ', video_pred.shape, video_pred.min(), video_pred.max())
- print('mask: ', mask.shape, mask.min(), mask.max())
- video_pred = np.clip(video_pred, 0, 255) # not sure i need this... but just in case
- video_pred_Amean_all = np.nanmean(video_pred, axis=0) # mean across models, no smoothing
- # %%
- # correlation between video_gt and video_pred for each rep, spatial and temporal frequency
- print('video_gt: ', video_gt.shape, video_gt.min(), video_gt.max())
- print('video_pred_Amean_all: ', video_pred_Amean_all.shape, video_pred_Amean_all.min(), video_pred_Amean_all.max())
- all_corr = np.zeros((len(mice),len(reps),len(spatial_length_constant),len(temporal_length_constant)))
- all_corr_randvid = np.zeros((len(mice),len(reps),len(spatial_length_constant),len(temporal_length_constant),len(reps)-1))
- for mouse in mice:
- for rep in range(0,len(reps)):
- for spatial_n in spatial_length_constant:
- for temporal_n in temporal_length_constant:
- all_corr[mouse-1,rep,spatial_n,temporal_n] = imsim.reconstruction_video_corr(video_gt[mouse-1,rep,spatial_n,temporal_n],
- video_pred_Amean_all[mouse-1,rep,spatial_n,temporal_n],
- np.where(mask[mouse-1] >= mask_th,1,0))
- i = -1
- for randrep in range(0,len(reps)):
- if randrep != rep:
- i+=1
- all_corr_randvid[mouse-1,rep,spatial_n,temporal_n,i] = imsim.reconstruction_video_corr(video_gt[mouse-1,randrep,spatial_n,temporal_n],
- video_pred_Amean_all[mouse-1,rep,spatial_n,temporal_n],
- np.where(mask[mouse-1] >= mask_th,1,0))
- all_corr_randvid = np.nanmean(all_corr_randvid,axis=-1)
- # all corr across mice and reps
- all_corr = all_corr.reshape((len(mice)*len(reps),len(spatial_length_constant),len(temporal_length_constant)))
- all_corr_randvid = all_corr_randvid.reshape((len(mice)*(len(reps)),len(spatial_length_constant),len(temporal_length_constant)))
- # mean corr across mice and reps
- mean_corr_ensembled = np.nanmean(all_corr, axis=(0))
- mean_corr_randvid_ensembled = np.nanmean(all_corr_randvid, axis=(0))
- print('mean_corr: ', mean_corr_ensembled.shape)
- all_mean_corr = np.zeros((len(model_list),len(mice),len(reps),len(spatial_length_constant),len(temporal_length_constant)))
- all_mean_corr_randvid = np.zeros((len(model_list),len(mice),len(reps),len(spatial_length_constant),len(temporal_length_constant),len(reps)-1))
- for model_n in model_list:
- for mouse in mice:
- for rep in range(0,len(reps)):
- for spatial_n in spatial_length_constant:
- for temporal_n in temporal_length_constant:
- all_mean_corr[model_n-1,mouse-1,rep,spatial_n,temporal_n] = imsim.reconstruction_video_corr(video_gt[mouse-1,rep,spatial_n,temporal_n],
- video_pred[model_n-1,mouse-1,rep,spatial_n,temporal_n],
- np.where(mask[mouse-1] >= mask_th,1,0))
- i = -1
- for randrep in range(0,len(reps)):
- if randrep != rep:
- i+=1
- all_mean_corr_randvid[model_n-1,mouse-1,rep,spatial_n,temporal_n,i] = imsim.reconstruction_video_corr(video_gt[mouse-1,randrep,spatial_n,temporal_n],
- video_pred[model_n-1,mouse-1,rep,spatial_n,temporal_n],
- np.where(mask[mouse-1] >= mask_th,1,0))
- all_mean_corr_randvid = np.nanmean(all_mean_corr_randvid,axis=-1)
- # all corr across mice and reps
- all_mean_corr = np.moveaxis(np.moveaxis(all_mean_corr,(1,2),(0,1)).reshape((len(mice)*len(reps),len(model_list),len(spatial_length_constant),len(temporal_length_constant))),(0),(1))
- all_mean_corr_randvid = np.moveaxis(np.moveaxis(all_mean_corr_randvid,(1,2),(0,1)).reshape((len(mice)*len(reps),len(model_list),len(spatial_length_constant),len(temporal_length_constant))),(0),(1))
- all_mean_corr = np.nanmean(all_mean_corr, axis=(0))
- all_mean_corr_randvid = np.nanmean(all_mean_corr_randvid, axis=(0))
- mean_corr = np.nanmean(all_mean_corr, axis=(0))
- # %%
- ## stats
- # ttest between all_corr and all_corr_randvid at every spatial and temporal frequency
- pass_corr_essembled = np.zeros((len(spatial_length_constant),len(temporal_length_constant)))
- for spatial_n in spatial_length_constant:
- for temporal_n in temporal_length_constant:
- pass_corr_essembled[spatial_n,temporal_n] = sp.stats.ttest_rel(all_corr[:,spatial_n,temporal_n],all_corr_randvid[:,spatial_n,temporal_n])[1]
- print('pass_corr_essembled: ', pass_corr_essembled.shape)
- print(pass_corr_essembled<0.001)
- # test if difference is significant
- # ttest between all_corr and all_corr_randvid at every spatial and temporal frequency
- pass_corr_essembled = np.zeros((len(spatial_length_constant),len(temporal_length_constant)))
- for spatial_n in spatial_length_constant:
- for temporal_n in temporal_length_constant:
- pass_corr_essembled[spatial_n,temporal_n] = sp.stats.ttest_rel(all_corr[:,spatial_n,temporal_n],all_mean_corr[:,spatial_n,temporal_n])[1]
- print('pass_corr_essemble_improvement: ', pass_corr_essembled.shape)
- print(pass_corr_essembled<0.001)
- # %%
- # contrast adjust images
- # for each movie, take the mean image across all time points, then calculate the mean and std of that image
- # normalize the predicted images by subtracting the mean and dividing by the std
- mouse_n,trial_n,slc,tlc,frame_n, h_n, w_n = video_gt.shape[0],video_gt.shape[1],video_gt.shape[2],video_gt.shape[3],video_gt.shape[4],video_gt.shape[5],video_gt.shape[6]
- expanded_mask = np.expand_dims(np.where(mask>= mask_th,1,np.nan) ,axis=(1,2,3,4)).repeat(trial_n,axis=-6).repeat(slc,axis=-5) .repeat(tlc,axis=-4).repeat(frame_n,axis=-3)
- # get target mean and std
- video_gt_frame_mean = video_gt * expanded_mask
- target_means = np.nanmean(video_gt_frame_mean, axis=(-1,-2,-3))
- target_stds = np.nanstd(video_gt_frame_mean, axis=(-1,-2,-3))
- # get start mean and std
- video_pred_frame_mean = video_pred_Amean_all * expanded_mask
- start_means = np.nanmean(video_pred_frame_mean, axis=(-1,-2,-3))
- start_stds = np.nanstd(video_pred_frame_mean, axis=(-1,-2,-3))
- # expand dims of mean and std in time h and w
- target_means = np.expand_dims(target_means,axis=(4,5,6)).repeat(frame_n,axis=-3).repeat(h_n,axis=-2).repeat(w_n,axis=-1)
- target_stds = np.expand_dims(target_stds,axis=(4,5,6)).repeat(frame_n,axis=-3).repeat(h_n,axis=-2).repeat(w_n,axis=-1)
- start_means = np.expand_dims(start_means,axis=(4,5,6)).repeat(frame_n,axis=-3).repeat(h_n,axis=-2).repeat(w_n,axis=-1)
- start_stds = np.expand_dims(start_stds,axis=(4,5,6)).repeat(frame_n,axis=-3).repeat(h_n,axis=-2).repeat(w_n,axis=-1)
- # # z-score predicted video
- video_pred_zscore = (video_pred_Amean_all - start_means) / start_stds
- video_pred_norm = (video_pred_zscore*target_stds) + target_means
- video_pred_norm = np.clip(video_pred_norm, 0, 255)
- # reaply mask
- video_gt_masked = video_gt * expanded_mask#np.expand_dims(expanded_mask ,axis=(-3)).repeat(frame_n,axis=-3)
- video_pred_Amean_all_masked = video_pred_Amean_all * expanded_mask#p.expand_dims(expanded_mask ,axis=(-3)).repeat(frame_n,axis=-3)
- video_pred_norm_masked = video_pred_norm * expanded_mask#np.expand_dims(expanded_mask ,axis=(-3)).repeat(frame_n,axis=-3)
- video_gt_masked[np.isnan(video_gt_masked)] = 255/2
- video_pred_Amean_all_masked[np.isnan(video_pred_Amean_all_masked)] = 255/2
- video_pred_norm_masked[np.isnan(video_pred_norm_masked)] = 255/2
- # %%
- fig, axs = plt.subplots(3,2, figsize=(15,15))
- axs[1,0].imshow(mean_corr_ensembled, cmap='viridis', vmin=0, vmax=1)
- axs[1,0].invert_yaxis()
- axs[1,0].set_xticks(np.arange(7), np.array([0,1,2,4,8,16,32]).__mul__(1/30).round(2).astype(str))
- axs[1,0].set_yticks(np.arange(7), np.array([0,1,2,4,8,16,32]).__mul__(1/3.4).round(2).astype(str))
- axs[1,0].set_xlabel('Temporal [sec]')
- axs[1,0].set_ylabel('Spatial [deg]')
- #set axis square
- axs[1,0].set_box_aspect(1)
- axs[1,0].set_title('reconstruction correlation')
- axs[1,0].tick_params(bottom=True, top=True, left=True, right=True)
- for i in range(7):
- for j in range(7):
- c = mean_corr_ensembled[j,i]
- axs[1,0].text(i, j, str(round(c, 2)),
- va='center', ha='center')
- fig.colorbar(axs[1,1].imshow(mean_corr_ensembled-mean_corr, cmap='viridis', vmin=0, vmax=0.25),ax=axs)
- axs[1,1].invert_yaxis()
- axs[1,1].set_xticks(np.arange(7), np.array([0,1,2,4,8,16,32]).__mul__(1/30).round(2).astype(str))
- axs[1,1].set_yticks(np.arange(7), np.array([0,1,2,4,8,16,32]).__mul__(1/3.4).round(2).astype(str))
- axs[1,1].set_xlabel('Temporal [sec]')
- axs[1,1].set_ylabel('Spatial [deg]')
- #set axis square
- axs[1,1].set_box_aspect(1)
- axs[1,1].set_title('ensembling improvement')
- axs[1,1].tick_params(bottom=True, top=True, left=True, right=True)
- for i in range(7):
- for j in range(7):
- c = mean_corr_ensembled[j,i]-mean_corr[j,i]
- axs[1,1].text(i, j, str(round(c, 2)),
- va='center', ha='center')
- # now relative to pixels and frames
- axs[2,0].imshow(mean_corr_ensembled, cmap='viridis', vmin=0, vmax=1)
- axs[2,0].invert_yaxis()
- axs[2,0].set_xticks(np.arange(7), ['0','1','2','4','8','16','32'])
- axs[2,0].set_yticks(np.arange(7), ['0','1','2','4','8','16','32'])
- axs[2,0].set_xlabel('Temporal [frames]')
- axs[2,0].set_ylabel('Spatial [pix]')
- #set axis square
- axs[2,0].set_box_aspect(1)
- axs[2,0].tick_params(bottom=True, top=True, left=True, right=True)
- for i in range(7):
- for j in range(7):
- c = mean_corr_ensembled[j,i]
- axs[2,0].text(i, j, str(round(c, 2)),
- va='center', ha='center')
- axs[2,1].imshow(mean_corr_ensembled-mean_corr, cmap='viridis', vmin=0, vmax=0.25)
- axs[2,1].invert_yaxis()
- axs[2,1].set_xticks(np.arange(7), ['0','1','2','4','8','16','32'])
- axs[2,1].set_yticks(np.arange(7), ['0','1','2','4','8','16','32'])
- axs[2,1].set_xlabel('Temporal [frames]')
- axs[2,1].set_ylabel('Spatial [pix]')
- #set axis square
- axs[2,1].set_box_aspect(1)
- axs[2,1].tick_params(bottom=True, top=True, left=True, right=True)
- for i in range(7):
- for j in range(7):
- c = mean_corr_ensembled[j,i]-mean_corr[j,i]
- axs[2,1].text(i, j, str(round(c, 2)),
- va='center', ha='center')
- # apply crop to masks based
- mask_expanded = np.expand_dims(mask,axis=(1)).repeat(video_gt.shape[-3],axis=1)
- mask_all = np.where(np.sum(np.where(mask >= mask_th,1,0),axis=0) >= 1,1,0)
- mask_all_idx = np.where(mask_all == 1)
- h_min, h_max = np.min(mask_all_idx[0])-2, np.max(mask_all_idx[0])+2
- w_min, w_max = np.min(mask_all_idx[1])-2, np.max(mask_all_idx[1])+2
- h = h_max - h_min
- w = w_max - w_min
- # make square
- h_min, h_max = h_min - (w-h)//2, h_max + (w-h)//2
- h = h_max - h_min
- w = w_max - w_min
- print('h_min, h_max, w_min, w_max: ', h_min, h_max, w_min, w_max)
- print('h, w: ', h, w)
- vid_length = video_gt.shape[-3]
- videos_gt_tiled = video_gt[0,0,:,:,:,:,:]
- videos_gt_tiled = videos_gt_tiled[:,:,:,h_min:h_max,w_min:w_max]
- videos_gt_tiled = videos_gt_tiled[::-1,:,:,:,:] # flip spatial and temporal length constant orders
- videos_gt_tiled = np.moveaxis(np.moveaxis(videos_gt_tiled,-2,1).reshape((7*h,7,vid_length,w)),0,-2)
- videos_gt_tiled = np.moveaxis(np.moveaxis(videos_gt_tiled,-1,1).reshape((7*w,vid_length,7*h)),0,-1)
- videos_gt_tiled_masked = video_gt[0,0,:,:,:,:,:]
- videos_gt_tiled_masked = videos_gt_tiled_masked * np.where(mask_expanded[0,-1] >= mask_th,1,0) + (1-np.where(mask_expanded[0,-1] >= mask_th,1,0) )*255/2
- videos_gt_tiled_masked= videos_gt_tiled_masked[:,:,:,h_min:h_max,w_min:w_max]
- videos_gt_tiled_masked = videos_gt_tiled_masked[::-1,:,:,:,:] # flip spatial and temporal length constant orders
- videos_gt_tiled_masked = np.moveaxis(np.moveaxis(videos_gt_tiled_masked,-2,1).reshape((7*h,7,vid_length,w)),0,-2)
- videos_gt_tiled_masked = np.moveaxis(np.moveaxis(videos_gt_tiled_masked,-1,1).reshape((7*w,vid_length,7*h)),0,-1)
- videos_recon_tiled = video_pred_norm_masked[0,0,:,:,:,:,:]
- videos_recon_tiled = videos_recon_tiled * np.where(mask_expanded[0,-1] >= mask_th,1,0) + (1-np.where(mask_expanded[0,-1] >= mask_th,1,0))*255/2
- videos_recon_tiled = videos_recon_tiled[::-1,:,:,h_min:h_max,w_min:w_max]
- videos_recon_tiled = np.moveaxis(np.moveaxis(videos_recon_tiled,-2,1).reshape((7*h,7,vid_length,w)),0,-2)
- videos_recon_tiled = np.moveaxis(np.moveaxis(videos_recon_tiled,-1,1).reshape((7*w,vid_length,7*h)),0,-1)
- print('videos_gt_tiled: ', videos_gt_tiled.shape)
- axs[0,0].imshow(videos_gt_tiled_masked[-1], cmap='gray')
- axs[0,0].set_axis_off()
- axs[0,0].set_title('Ground truth')
- axs[0,1].imshow(videos_recon_tiled[-1], cmap='gray')
- axs[0,1].set_axis_off()
- axs[0,1].set_title('Reconstruction')
- fig.savefig('../reconstructions/Gaussian_noise_reconstruction.svg', format='svg', dpi=1200)
- # tiled video
- print('video_gt: ', video_gt.shape)
- videos_gt_tiled_masked = video_gt[0,:,:,:,:,:,:]
- videos_gt_tiled_masked = videos_gt_tiled_masked * np.where(mask_expanded[0,-1] >= mask_th,1,0) + (1-np.where(mask_expanded[0,-1] >= mask_th,1,0) )*255/2
- videos_gt_tiled_masked= videos_gt_tiled_masked[:,::-1,:,:,h_min:h_max,w_min:w_max]
- videos_recon_tiled = video_pred_norm_masked[0,:,:,:,:,:,:]
- videos_recon_tiled = videos_recon_tiled * np.where(mask_expanded[0,-1] >= mask_th,1,0) + (1-np.where(mask_expanded[0,-1] >= mask_th,1,0))*255/2
- videos_recon_tiled = videos_recon_tiled[:,::-1,:,:,h_min:h_max,w_min:w_max]
- videos_interleaved = np.concatenate((videos_gt_tiled_masked[:,None,:],videos_recon_tiled[:,None,:]), axis=1)
- videos_interleaved = np.moveaxis(np.moveaxis(videos_interleaved,-3,1).reshape((len(reps)*vid_length,2,7,7,h,w)),0,-3) # concatenate directions
- videos_interleaved = np.moveaxis(np.moveaxis(videos_interleaved,0,1).reshape((2*7,7,len(reps)*vid_length,h,w)),0,0) # tile gt and recon
- videos_interleaved = np.moveaxis(np.moveaxis(videos_interleaved,-2,1).reshape((2*7*h,7,len(reps)*vid_length,w)),0,-2) # tile sf
- videos_interleaved = np.moveaxis(np.moveaxis(videos_interleaved,-1,1).reshape((7*w,len(reps)*vid_length,7*h*2)),0,-1) # tile tf
- # save video as tiff
- tifffile.imwrite('../reconstructions/Gaussian_noise.tiff',
- videos_interleaved.astype('uint8'),
- imagej=True,
- metadata = {'unit': 'um','fps': 30.0,'axes': 'TYX',})
- # %%
- videos_gt_tiled_hyperstack = np.concatenate((videos_gt_tiled_masked[:,:,:,None],videos_recon_tiled[:,:,:,None]), axis=3).reshape(-1,2,30,30,31)
- videos_gt_tiled_hyperstack = np.moveaxis(videos_gt_tiled_hyperstack,(0,1,2,3,4),(1,2,0,3,4))
- print(videos_gt_tiled_hyperstack.shape)
- # # # save video as tiff
- tifffile.imwrite('../reconstructions/Gaussian_noise_hyperstack.tiff',
- videos_gt_tiled_hyperstack.astype('uint16'),
- imagej=True,
- metadata = {'unit': 'um','fps': 30.0,'axes': 'TZCYX',})
- # %% [markdown]
- # # Reconstructed entropy
- # %%
- # check this approach to calc entropy makes sense
- def video_entropy_in_space(video, mask):
- idx_inmask = mask.flatten() == 1
- img_entropy_all=[]
- for frame in range(video.shape[0]):
- video_frame = video[frame].flatten()
- video_frame = video_frame[idx_inmask]
- hist, _ = np.histogram(video_frame, bins=256//10, range=(0, 256), density=True)
- hist = hist[hist > 0]
- img_entropy = sp.stats.entropy(hist, base=2)
- img_entropy_all.append(img_entropy)
- img_entropy_all = np.array(img_entropy_all)
- return np.nanmean(img_entropy_all)#,corr_all
- def video_energy(video, mask):
- # ground_truth: (time, height, width)
- # mask: (height, width) or (time, height, width)
- # returns: (time, height, width)
- if len(mask.shape) == 3:
- mask = mask[0, :, :] # make 2D
- idx_inmask = mask.flatten() == 1
- video.swapaxes(0, -1) # height, width,time
- video = video.reshape(video.shape[0],-1) # flatten spatial dimensions
- video.swapaxes(-1, 0) # time, height*width
- video = video[:,idx_inmask] # mask spatial dimensions
- frame_energy = np.mean(np.abs(np.diff(video, axis=0)),axis=(1)) # sum of absolute differences (motion energy)
- return frame_energy
- # %%
- Entropy_in_space_gt = np.zeros((len(mice),len(reps),len(spatial_length_constant),len(temporal_length_constant)))
- # Entropy_in_timenspace_gt = np.zeros((len(mice),len(reps),len(spatial_length_constant),len(temporal_length_constant)))
- Motion_energy_gt = np.zeros((len(mice),len(reps),len(spatial_length_constant),len(temporal_length_constant)))
- Entropy_in_space_recon = np.zeros((len(mice),len(reps),len(spatial_length_constant),len(temporal_length_constant)))
- # Entropy_in_timenspace_recon = np.zeros((len(mice),len(reps),len(spatial_length_constant),len(temporal_length_constant)))
- Motion_energy_recon = np.zeros((len(mice),len(reps),len(spatial_length_constant),len(temporal_length_constant)))
- for mouse in mice:
- for rep in range(0,len(reps)):
- for spatial_n in spatial_length_constant:
- for temporal_n in temporal_length_constant:
- Entropy_in_space_gt[mouse,rep,spatial_n,temporal_n] = video_entropy_in_space(video_gt[mouse,rep,spatial_n,temporal_n,:,:,11:11+36],np.where(mask[mouse,:,11:11+36] >= 0,1,0))
- # Entropy_in_timenspace_gt[mouse,rep,spatial_n,temporal_n] = video_entropy_in_timenspace(video_gt[mouse,rep,spatial_n,temporal_n,:,:,11:11+36],np.where(mask[mouse,:,11:11+36] >= 0,1,0))
- Motion_energy_gt[mouse,rep,spatial_n,temporal_n] = video_energy(video_gt[mouse,rep,spatial_n,temporal_n,:,:,11:11+36],np.where(mask[mouse,:,11:11+36] >= 0,1,0)).mean()
- Entropy_in_space_recon[mouse,rep,spatial_n,temporal_n] = video_entropy_in_space(video_pred_norm_masked[mouse,rep,spatial_n,temporal_n],np.where(mask[mouse] >= mask_th,1,0))
- # Entropy_in_timenspace_recon[mouse,rep,spatial_n,temporal_n] = video_entropy_in_timenspace(video_pred_norm_masked[mouse,rep,spatial_n,temporal_n],np.where(mask[mouse] >= mask_th,1,0))
- Motion_energy_recon[mouse,rep,spatial_n,temporal_n] = video_energy(video_pred_norm_masked[mouse,rep,spatial_n,temporal_n],np.where(mask[mouse] >= mask_th,1,0)).mean()
- # %%
- fig, ax = plt.subplots(2,2, figsize=(10,10))
- ax[0,0].imshow(Entropy_in_space_gt.mean(axis=(0,1)), cmap='viridis', vmin=2.5, vmax=4.5)
- ax[0,0].invert_yaxis()
- ax[0,0].set_xticks(np.arange(7), ['0','1','2','4','8','16','32'])
- ax[0,0].set_yticks(np.arange(7), ['0','1','2','4','8','16','32'])
- ax[0,0].set_xlabel('Temporal [frames]')
- ax[0,0].set_ylabel('Spatial [pix]')
- #set axis square
- ax[0,0].set_box_aspect(1)
- ax[0,0].tick_params(bottom=True, top=True, left=True, right=True)
- for i in range(7):
- for j in range(7):
- c = Entropy_in_space_gt.mean(axis=(0,1))[j,i]
- ax[0,0].text(i, j, str(round(c, 2)),
- va='center', ha='center')
- ax[0,0].set_title('Shannon Entropy in space GT')
- ax[0,1].imshow(Motion_energy_gt.mean(axis=(0,1)), cmap='viridis', vmin=0, vmax=75)
- ax[0,1].invert_yaxis()
- ax[0,1].set_xticks(np.arange(7), ['0','1','2','4','8','16','32'])
- ax[0,1].set_yticks(np.arange(7), ['0','1','2','4','8','16','32'])
- ax[0,1].set_xlabel('Temporal [frames]')
- ax[0,1].set_ylabel('Spatial [pix]')
- #set axis square
- ax[0,1].set_box_aspect(1)
- ax[0,1].tick_params(bottom=True, top=True, left=True, right=True)
- for i in range(7):
- for j in range(7):
- c = Motion_energy_gt.mean(axis=(0,1))[j,i]
- ax[0,1].text(i, j, str(round(c, 2)),
- va='center', ha='center')
- ax[0,1].set_title('Motion energy GT')
- ax[1,0].imshow(Entropy_in_space_recon.mean(axis=(0,1)), cmap='viridis', vmin=2.5, vmax=4.5)
- ax[1,0].invert_yaxis()
- ax[1,0].set_xticks(np.arange(7), ['0','1','2','4','8','16','32'])
- ax[1,0].set_yticks(np.arange(7), ['0','1','2','4','8','16','32'])
- ax[1,0].set_xlabel('Temporal [frames]')
- ax[1,0].set_ylabel('Spatial [pix]')
- #se axis square
- ax[1,0].set_box_aspect(1)
- ax[1,0].tick_params(bottom=True, top=True, left=True, right=True)
- for i in range(7):
- for j in range(7):
- c = Entropy_in_space_recon.mean(axis=(0,1))[j,i]
- ax[1,0].text(i, j, str(round(c, 2)),
- va='center', ha='center')
- ax[1,0].set_title('Shannon Entropy in space Recon')
- ax[1,1].imshow(Motion_energy_recon.mean(axis=(0,1)), vmin=0, vmax=75)
- ax[1,1].invert_yaxis()
- ax[1,1].set_xticks(np.arange(7), ['0','1','2','4','8','16','32'])
- ax[1,1].set_yticks(np.arange(7), ['0','1','2','4','8','16','32'])
- ax[1,1].set_xlabel('Temporal [frames]')
- ax[1,1].set_ylabel('Spatial [pix]')
- #set axis square
- ax[1,1].set_box_aspect(1)
- ax[1,1].tick_params(bottom=True, top=True, left=True, right=True)
- for i in range(7):
- for j in range(7):
- c = Motion_energy_recon.mean(axis=(0,1))[j,i]
- ax[1,1].text(i, j, str(round(c, 2)),
- va='center', ha='center')
- ax[1,1].set_title('Motion energy recon')
- fig.savefig('../reconstructions/Gaussian_noise_entropy.svg', format='svg', dpi=1200)
- # %% [markdown]
- # # Phase inverted stimuli
- # %%
- all_corr_same_phase = np.zeros((len(mice),len(reps),len(spatial_length_constant),len(temporal_length_constant)))
- all_corr_opposite_phase = np.zeros((len(mice),len(reps),len(spatial_length_constant),len(temporal_length_constant)))
- all_corr_opposite_phase_recontorecon = np.zeros((len(mice),len(reps),len(spatial_length_constant),len(temporal_length_constant)))
- for mouse in mice:
- for rep in range(0,len(reps)):
- if rep > len(reps)//2-1: # phase 2
- rep_opposite_phase = rep - len(reps)//2
- elif rep <= len(reps)//2-1: # phase 1
- rep_opposite_phase = rep + len(reps)//2
- for spatial_n in spatial_length_constant:
- for temporal_n in temporal_length_constant:
- all_corr_same_phase[mouse-1,rep,spatial_n,temporal_n] = imsim.reconstruction_video_corr(video_gt[mouse-1,rep,spatial_n,temporal_n],
- video_pred_Amean_all[mouse-1,rep,spatial_n,temporal_n],
- np.where(mask[mouse-1] >= mask_th,1,0))
- all_corr_opposite_phase[mouse-1,rep,spatial_n,temporal_n] = imsim.reconstruction_video_corr(video_gt[mouse-1,rep_opposite_phase,spatial_n,temporal_n],
- video_pred_Amean_all[mouse-1,rep,spatial_n,temporal_n],
- np.where(mask[mouse-1] >= mask_th,1,0))
- all_corr_opposite_phase_recontorecon[mouse-1,rep,spatial_n,temporal_n] = imsim.reconstruction_video_corr(video_pred_Amean_all[mouse-1,rep_opposite_phase,spatial_n,temporal_n],
- video_pred_Amean_all[mouse-1,rep,spatial_n,temporal_n],
- np.where(mask[mouse-1] >= mask_th,1,0))
- # %%
- fig, ax = plt.subplots(2,2, figsize=(10,10))
- ax[0,0].imshow(all_corr_same_phase.mean(axis=(0,1)), cmap='RdYlGn', vmin=-1, vmax=1)
- ax[0,0].invert_yaxis()
- ax[0,0].set_xticks(np.arange(7), np.array([0,1,2,4,8,16,32]).__mul__(1/30).round(2).astype(str))
- ax[0,0].set_yticks(np.arange(7), np.array([0,1,2,4,8,16,32]).__mul__(1/3.4).round(2).astype(str))
- ax[0,0].set_xlabel('Temporal [sec]')
- ax[0,0].set_ylabel('Spatial [deg]')
- ax[0,0].set_title('corr between recon to same phase GT')
- ax[0,0].tick_params(bottom=True, top=True, left=True, right=True)
- for i in range(7):
- for j in range(7):
- c = all_corr_same_phase.mean(axis=(0,1))[j,i]
- ax[0,0].text(i, j, str(round(c, 2)),
- va='center', ha='center')
- ax[0,1].imshow(all_corr_opposite_phase.mean(axis=(0,1)), cmap='RdYlGn', vmin=-1, vmax=1)
- ax[0,1].invert_yaxis()
- ax[0,1].set_xticks(np.arange(7), np.array([0,1,2,4,8,16,32]).__mul__(1/30).round(2).astype(str))
- ax[0,1].set_yticks(np.arange(7), np.array([0,1,2,4,8,16,32]).__mul__(1/3.4).round(2).astype(str))
- ax[0,1].set_xlabel('Temporal [sec]')
- ax[0,1].set_ylabel('Spatial [deg]')
- ax[0,1].set_title('corr between recon to opposite phase GT')
- ax[0,1].tick_params(bottom=True, top=True, left=True, right=True)
- for i in range(7):
- for j in range(7):
- c = all_corr_opposite_phase.mean(axis=(0,1))[j,i]
- ax[0,1].text(i, j, str(round(c, 2)),
- va='center', ha='center')
- ax[1,0].imshow(all_corr_opposite_phase_recontorecon.mean(axis=(0,1)), cmap='RdYlGn', vmin=-1, vmax=1)
- ax[1,0].invert_yaxis()
- ax[1,0].set_xticks(np.arange(7), np.array([0,1,2,4,8,16,32]).__mul__(1/30).round(2).astype(str))
- ax[1,0].set_yticks(np.arange(7), np.array([0,1,2,4,8,16,32]).__mul__(1/3.4).round(2).astype(str))
- ax[1,0].set_xlabel('Temporal [sec]')
- ax[1,0].set_ylabel('Spatial [deg]')
- ax[1,0].set_title('corr between recon to recon of opposite phase GT')
- ax[1,0].tick_params(bottom=True, top=True, left=True, right=True)
- for i in range(7):
- for j in range(7):
- c = all_corr_opposite_phase_recontorecon.mean(axis=(0,1))[j,i]
- ax[1,0].text(i, j, str(round(c, 2)),
- va='center', ha='center')
- cbar1 = plt.colorbar(ax[1,0].images[0], ax=ax[1,0], orientation='vertical')
- fig.savefig('../reconstructions/Gaussian_noise_PhaseInversion.svg', format='svg', dpi=1200)
analyse_reconstructions_gaussian_noise.ipynb at commit eb5ad21, under MIT · at the source
Overview
- Sainsbury Wellcome Centre, University College London London United Kingdom
- Bioengineering Dept., Imperial College London United Kingdom
Abstract
The ability to reconstruct images represented by the brain has the potential to give us an intuitive understanding of what the brain sees. Reconstruction of visual input from human fMRI data has garnered significant attention in recent years. Comparatively less focus has been directed towards vision reconstruction from single-cell recordings, despite its potential to provide a more direct measure of the information represented by the brain. Here, we achieve high-quality reconstructions of natural movies presented to mice, from the activity of neurons in their visual cortex for the first time. Using our method of video optimization via backpropagation through a state-of-the-art dynamic neural encoding model, we reliably reconstruct 10 s movies at 30 Hz from two-photon calcium imaging data. We achieve a pixel-level correlation of 0.57 between ground-truth movies and single-trial reconstructions. Previous reconstructions based on awake mouse V1 neuronal responses to static images achieved a pixel-level correlation of 0.24 over a similar retinotopic area. We find that critical for high-quality reconstructions are the number of neurons in the dataset and the use of model ensembling. This paves the way for movie reconstruction to be used as a tool to investigate a variety of visual processing phenomena.
Reproduced under the paper's license (CC BY), from the paper cited above.
Repositories
Its files are read in the Code ↔ Paper reader above, with 12 matches between paragraphs and lines of code.
lRomul/sensorium
6849050e74e2843fbd70b33af110d71638aa37bb, 22 November 2023Availability: 1 check, the latest on 30 September 2026: the link answers
- 30 September 2026: the link answers
26 files
- configs/
distillation_001.py , Python, 71 lines - configs/
true_batch_001.py , Python, 67 lines - scripts/
download_data.py , Python, 61 lines - scripts/
ensemble.py , Python, 52 lines - scripts/
predict.py , Python, 87 lines - scripts/
train.py , Python, 189 lines - src/
__init__.py , Python, 1 line - src/
argus_models.py , Python, 99 lines - src/
constants.py , Python, 54 lines - src/
data.py , Python, 73 lines - src/
datasets.py , Python, 200 lines - src/
ema.py , Python, 73 lines - src/
indexes.py , Python, 39 lines - src/
inputs.py , Python, 46 lines - src/
losses.py , Python, 21 lines - src/
metrics.py , Python, 82 lines - src/
mixers.py , Python, 79 lines - src/
models/ , Python, 1 line__init__.py - src/
models/ , Python, 405 lines, 1 matchdwiseneuro.py - src/
phash.py , Python, 26 lines - src/
predictors.py , Python, 55 lines - src/
responses.py , Python, 67 lines - src/
submission.py , Python, 73 lines - src/
utils.py , Python, 71 lines - LICENSE, License, 21 lines
- README.md, Text, 349 lines
Joel-Bauer/movie_reconstruction_code
eb5ad2143b5d54aad4ca44cb26b919cfab987920, 9 January 2026Availability: 1 check, the latest on 30 September 2026: the link answers
- 30 September 2026: the link answers
18 files
- configs/
true_batch_002.py , Python, 67 lines - scripts/
RF_mapping.py , Python, 213 lines - scripts/
analyse_reconstructions. , Jupyter, 1,085 lines, 1 matchipynb - scripts/
analyse_reconstructions_ , Jupyter, 293 lines, 2 matchesdrifting_gratings.ipynb - scripts/
analyse_reconstructions_ , Jupyter, 856 lines, 1 matchfrom_predicted_activity. ipynb - scripts/
analyse_reconstructions_ , Jupyter, 569 lines, 4 matchesgaussian_noise.ipynb - scripts/
analyse_reconstructions_ , Jupyter, 312 linespopulation_reduction.ipy nb - scripts/
predict_response_from_re , Python, 241 lines, 1 matchcon.py - scripts/
reconstruct_videos_drift , Python, 446 linesing_gratings.py - scripts/
reconstruct_videos_gauss , Python, 450 lines, 1 matchian_noise.py - scripts/
reconstruct_videos_natur , Python, 586 linesal.py - scripts/
train_test_splitout.py , Python, 190 lines - scripts/
train_transparency_mask. , Python, 119 linespy - utils_reconstruction/
__init__.py , Python, 1 line - utils_reconstruction/
image_similarity.py , Python, 125 lines - utils_reconstruction/
utils_reconstruction.py , Python, 396 lines, 1 match - LICENSE, License, 21 lines
- README.md, Text, 124 lines
The paper's code and data availability statement is in the Data section.
Tracing map
Proposed by the machine: these links were found in the paper and verified at the source, without human review. The map will receive a Zenodo DOI once one of the paper's authors has validated it with their ORCID.
What the map holds:
- 2 repositories of the authors' code, each at its verified commit, with its license and how the link was found in the paper;
- 40 scripts, each with its path and the digest of its content;
- 12 matches between paragraphs of the paper and lines of the code (method lexical-v1);
- neither the text of the paper nor the code itself.
Its JSON (tracing-map.json) is deposited on Zenodo with its DOI once the map is validated.
Data
Datasets cited
- github.com/
tomgeorge1234/ , at github.com; found in the text, “Additional visual stimuli”gp_video
Data availability
The code is available at https://
The following previously published datasets were used:
FaheyP TurishchevaP HanselL FroebeR PonderK VystrcilováM QiuY WillekeK BashiriM ToliasA SinzA EckerA 2023The Dynamic Sensorium competition for predicting large-scale mouse visual cortex activity from videos - DatasetG-Node GinSensorium2023Data
FaheyP TurishchevaP HanselL FroebeR PonderK VystrcilováM QiuY WillekeK BashiriM ToliasA SinzA EckerA 2023The Dynamic Sensorium competition for predicting large-scale mouse visual cortex activity from videos - DatasetG-Node Ginsensorium_2023_data
Reproduced under the paper's license (CC BY), from the paper cited above.
Versions
The history of this record: each version stored by the harvester or made by a correction of its authors or of the maintainers of its code, and what changed in its facts. The texts of the paper (its abstract, its availability statements) are not part of it; versions that changed only those are not listed.
Version 1, 30 September 2026: the first record
Recorded: type, language, journal, volume, pages, dates, 3 authors, 7 keywords, 6 MeSH terms, 6 funders, 62 references.
Cite
This paper
Bauer, J., Margrie, T. W., & Clopath, C. (2026). Movie reconstruction from mouse visual cortex activity. eLife, 14, RP105081. https://
BibTeX
@article{bauer2026movie,
author = {Bauer, Joel and Margrie, Troy W and Clopath, Claudia},
title = {{Movie reconstruction from mouse visual cortex activity}},
journal = {eLife},
year = {2026},
month = mar,
volume = {14},
pages = {RP105081},
publisher = {eLife Sciences Publications, Ltd},
issn = {2050-084X},
doi = {10.7554/
url = {https://
pmid = {41804097},
pmcid = {PMC12975128}
}
RIS
TY - JOUR
AU - Bauer, Joel
AU - Margrie, Troy W
AU - Clopath, Claudia
TI - Movie reconstruction from mouse visual cortex activity
T2 - eLife
J2 - Elife
PY - 2026
DA - 2026/
VL - 14
SP - RP105081
SN - 2050-084X
PB - eLife Sciences Publications, Ltd
DO - 10.7554/
UR - https://
LA - en
ER -
CSL-JSON
{
"id": "10.7554/
"type": "article-journal",
"title": "Movie reconstruction from mouse visual cortex activity",
"container-title": "eLife",
"author": [
{
"family": "Bauer",
"given": "Joel"
},
{
"family": "Margrie",
"given": "Troy W"
},
{
"family": "Clopath",
"given": "Claudia"
}
],
"container-title-short":
"volume": "14",
"page": "RP105081",
"DOI": "10.7554/
"PMID": "41804097",
"PMCID": "PMC12975128",
"ISSN": "2050-084X",
"publisher": "eLife Sciences Publications, Ltd",
"URL": "https://
"language": "en",
"issued": {
"date-parts": [
[
2026,
3,
10
]
]
}
}
The tracing map gets a citation of its own once an author has validated it and it has a DOI.
Similar papers
The papers with a page that share the most with this one: the tools found in their code, their categories, datasets, cited references and authors, the rarest counting most.
- [1] doi:10.1002/advs.202520220 [code]
- Learnable Diffusion Framework for Mouse V1 Neural Decoding.Journal: Advanced science (Weinheim, Baden-Wurttemberg, Germany)In common: OpenCV, Pillow, PyTorch, 4 other tools, systems, mouse, 6 references
- [2] doi:10.1371/journal.pcbi.1014263 [code]
- MIRAGE: Robust multi-modal architectures translate fMRI-to-image models from vision to mental imagery.Journal: PLoS computational biologyIn common: OpenCV, Pillow, PyTorch, 4 other tools, 5 references
- [3] doi:10.7554/elife.107933 [code]
- Modality-agnostic decoding of vision and language from fMRI.Journal: eLifeIn common: OpenCV, Pillow, PyTorch, 4 other tools, 5 references
- [4] doi:10.1016/j.isci.2026.116206 [code]
- Gut distension evokes rapid neural dynamics in vagal and hindbrain populations of larval zebrafish.Journal: iScienceIn common: tifffile, OpenCV, Pillow, 5 other tools, optical imaging (calcium, voltage, 2-photon), systems, 2 references
- [5] doi:10.1016/j.patter.2026.101538 [code]
- A multi-modal foundation model for brain disease diagnosis and medical imaging.Journal: Patterns (New York, N.Y.)In common: tifffile, OpenCV, Pillow, 5 other tools, 2 references
- [6] doi:10.1007/s12021-026-09803-3 [code]
- NeuroFusion: A Unified Framework for Generalized Visual Stimulus Decoding from fMRI Across Datasets and Subjects.Journal: NeuroinformaticsIn common: Pillow, PyTorch, pandas, 3 other tools, 4 references
- [7] doi:10.1523/eneuro.0459-25.2026 [code]
- Open-Source Platform for Adjustable Training Regimes in Freely Moving and Head-Fixed Mice.Journal: eNeuroIn common: OpenCV, Pillow, PyTorch, 2 other tools, optical imaging (calcium, voltage, 2-photon), mouse, 3 references
- [8] doi:10.1016/j.crmeth.2026.101476 [code]
- Unsupervised deep learning enables blur-free resolution enhancement in two-photon microscopy.Journal: Cell reports methodsIn common: tifffile, OpenCV, PyTorch, 4 other tools, optical imaging (calcium, voltage, 2-photon), mouse, 2 references
- [9] doi:10.1364/boe.600665 [code]
- NeuroSeg-MF: robust neuron segmentation in two-photon Ca&
lt;sup& gt;2+& lt;/ sup& gt; imaging using multi-feature fusion and detection-guided SAM. Journal: Biomedical optics expressIn common: tifffile, OpenCV, Pillow, 5 other tools, optical imaging (calcium, voltage, 2-photon), 1 reference - [10] doi:10.1111/ejn.70582 [code]
- Multifiber Array-Based Photometry System for Multiregional Functional Mapping in the Mouse Brain.Journal: The European journal of neuroscienceIn common: tifffile, OpenCV, Pillow, 4 other tools, optical imaging (calcium, voltage, 2-photon), systems, mouse, 1 reference
Contribute
The authors of this paper can claim it, correct its record and validate its tracing map, and the maintainers of its code (its owner, or a public member of its organization) correct what it says of their repository; anyone signed in can ask for its removal. Every request goes to OSCR's own machine, which answers it; your account page follows them.
Sign in with ORCID to claim this paper as one of its authors, correct its record or validate its tracing map: when the paper's metadata lists your ORCID iD, you are recognized at once. Maintainers of its code: sign in with GitHub, then claim the repository on your account page.
Claim this paper
Correct its record
Say what each link of this record is, remove the ones that are not the paper's, add the ones that are missing. The correction becomes a new version of the record, in its Versions section.
Validate its tracing map
You validate the map as this page shows it: 2 repositories of the authors' code, each at its verified commit and with its license, 40 scripts, and 12 matches between paragraphs and code (see the Code and Map sections). It then receives a DOI on Zenodo, with you (your ORCID iD) and OSCR as its creators; the code itself is not deposited.
The map's fingerprint: sha256:c656bc5df470a16f…
Add the badge to its README
The badge links the code to this page. Copy one of these into the README of the paper's code: only you decide where it goes, and nothing is changed for you.
Markdown
[, paste the snippet at the top, then “Commit changes…” and, to review it first, “Create a new branch and start a pull request”. You open the pull request; OSCR asks for no permission.
Request its removal
To ask OSCR to remove this record, the copies of its authors' scripts or its tracing map, use the removal request page: signed in, you say who you are, what to remove and why, then review and confirm the request. Published rules decide every request (how).
Discussion, reproductions, activity
Discussion: questions and error reports about this paper and its code, from signed-in readers and its authors. It opens with sign-in.
Reproductions: reports from readers who ran the authors' code: what they reproduced, with which environment, commit and data. It opens with sign-in.
Activity: what happens around this paper: new versions of its record, its map's validation, discussions and reproductions. It opens with sign-in.
