def get_mean_intensity(): from tierpsy.analysis.compress.selectVideoReader import selectVideoReader video_file = '/Volumes/behavgenom_archive$/Avelino/screening/David_Miller/ATR/filter/atr_Ch1_04042017_150500.hdf5' #video_file = '/Volumes/behavgenom_archive$/Avelino/screening/David_Miller/ATR/filter/atr_Ch1_04042017_150500.mjpg' vid = selectVideoReader(video_file) video_stats = [] tot_frames = 0 while 1: ret, image = vid.read() if ret == 0: break tot_frames += 1 print(tot_frames) if image.ndim == 3: image = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY) dat = image[image>1] frame_stats = np.percentile(dat, [5, 50, 95]) video_stats.append(frame_stats) video_stats = np.array(video_stats) plt.plot(video_stats)
def _init_buffer_video(self): ret = 1 frame_n = 0 vid = selectVideoReader(self.video_file) self.bgnd_buff = np.zeros((self.buff_size, vid.height, vid.width), vid.dtype) max_frames = self.buff_size*self.frame_gap while frame_n < max_frames: ret, image = vid.read() if ret==0: break if image.ndim == 3: image = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY) if self._is_update_bgnd(frame_n): self.bgnd_ind = self._get_buf_ind(frame_n) self.bgnd_buff[self.bgnd_ind] = image #print(frame_n, self.bgnd_ind, self._is_update_bgnd(frame_n), self.frame_gap) frame_n += 1 vid.release() self.last_frame = frame_n - 1 if self.bgnd_ind is None: #no valid frames read self.bgnd_buff = None elif self.bgnd_ind<(self.bgnd_ind-1): #not many frames red self.bgnd_buff = self.bgnd_buff[:(self.bgnd_ind+1)]
def get_frame_from_raw(rawvidname): from tierpsy.analysis.compress.selectVideoReader import selectVideoReader vid = selectVideoReader(str(rawvidname)) status, frame = vid.read_frame(0) assert status == 1, f'Something went wrong while reading {rawvidname}' return frame
def isGoodVideo(video_file): try: vid = selectVideoReader(video_file) # i have problems with corrupt videos that can create infinite loops... #it is better to test it before start a large taks vid.release() return True except OSError: # corrupt file, cannot read the size return False
def init_buffer(self): ret = 1 current_frame = 0 vid = selectVideoReader(self.video_file) d_info = np.iinfo(vid.dtype) if self.is_light_background: init_value = d_info.min else: init_value = d_info.max self.buffer = np.full((self.buff_size, vid.height, vid.width), init_value, vid.dtype) self.buffer_ind = -1 max_frames = self.buff_size * self.frame_gap if vid.__class__.__name__ != 'readLoopBio': # for non-loopbio videos while current_frame < max_frames: ret, image = vid.read() #if not valid frame is returned return. if ret == 0: break if image.ndim == 3: image = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY) if self.is_update_frame(current_frame): self.update_buffer(image, current_frame) current_frame += 1 self.last_frame = current_frame - 1 else: # loopbio videos: for fc in range(self.buff_size): frame_to_read = fc * self.frame_gap ret, image = vid.read_frame(frame_to_read) # if not valid frame is returned return. if ret == 0: break self.update_buffer(image, frame_to_read) self.last_frame = frame_to_read - self.frame_gap vid.release() if self.buffer_ind < 0: #no valid frames read self.buffer = None elif self.buffer_ind < (self.buff_size - 1): #not enough frames to fill the buffer, reduce its size self.buffer = self.buffer[:(self.buffer_ind + 1)]
def _init_buffer(self): ret = 1 frame_n = 0 vid = selectVideoReader(self.video_file) d_info = np.iinfo(vid.dtype) if self.is_light_background: init_value = d_info.min else: init_value = d_info.max self._buffer = np.full((self.buff_size, vid.height, vid.width), init_value, vid.dtype) max_frames = self.buff_size*self.frame_gap while frame_n < max_frames: ret, image = vid.read() #if not valid frame is returned return. if ret == 0: break if image.ndim == 3: image = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY) if self._is_update_bgnd(frame_n): if image.sum() == 0.: #here i am assuming that if there is an old black image the video finished break self._buffer_ind = self._get_buf_ind(frame_n) self._buffer[self._buffer_ind] = image frame_n += 1 vid.release() self.last_frame = frame_n - 1 if self._buffer_ind is None: #no valid frames read self._buffer = None elif self._buffer_ind<(self._buffer_ind-1): #not many frames red self._buffer = self._buffer[:(self._buffer_ind+1)]
def well_reader(hdf5_fname, well_name): """ well_reader Generator yielding the image data of a well frame by frame Parameters ---------- hdf5_fname : str or Path path to the hdf5 file (a masked metadata.hdf5 or a results metadata_featuresN.hdf5) well_name : str name of the well to read the data of Yields ------- numpy array one frame cropped at the well's boundaries """ # take hdf5 file and well name # get wall boundaries # find raw video # get the reader # while loop with generator returning only the right portion of the frame # read boundaries r_min, r_max, c_min, c_max = read_well_boundaries(hdf5_fname, well_name) # get raw video raw_fname = hdf52raw(hdf5_fname) assert os.path.exists(raw_fname), f'Cannot find {raw_fname}' # initalise reader vid = selectVideoReader(raw_fname) # start with reading a frame. # then at every iteration read the next one but do not return it yet # this avoids having an empty frame at the end when # the reader returns (0, None) status, image = vid.read() while status > 0: status, next_image = vid.read() roi = image[r_min:r_max, c_min:c_max].copy() # prep for next loop image = next_image yield roi
def init_buffer(self): ret = 1 current_frame = 0 vid = selectVideoReader(self.video_file) d_info = np.iinfo(vid.dtype) if self.is_light_background: init_value = d_info.min else: init_value = d_info.max self.buffer = np.full((self.buff_size, vid.height, vid.width), init_value, vid.dtype) self.buffer_ind = -1 max_frames = self.buff_size*self.frame_gap while current_frame < max_frames: ret, image = vid.read() #if not valid frame is returned return. if ret == 0: break if image.ndim == 3: image = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY) if self.is_update_frame(current_frame): self.update_buffer(image, current_frame) current_frame += 1 vid.release() self.last_frame = current_frame - 1 if self.buffer_ind < 0: #no valid frames read self.buffer = None elif self.buffer_ind < (self.buff_size - 1): #not enough frames to fill the buffer, reduce its size self.buffer = self.buffer[:(self.buffer_ind+1)]
def compressVideo(video_file, masked_image_file, mask_param, expected_fps=25, microns_per_pixel=None, bgnd_param={}, buffer_size=-1, save_full_interval=-1, max_frame=1e32, is_extract_timestamp=False, fovsplitter_param={}): ''' Compresses video by selecting pixels that are likely to have worms on it and making the rest of the image zero. By creating a large amount of redundant data, any lossless compression algorithm will dramatically increase its efficiency. The masked images are saved as hdf5 with gzip compression. The mask is calculated over a minimum projection of an image stack. This projection preserves darker regions (or brighter regions, in the case of fluorescent labelling) where the worm has more probability to be located. Additionally it has the advantage of reducing the processing load by only requiring to calculate the mask once per image stack. video_file -- original video file masked_image_file -- buffer_size -- size of the image stack used to calculate the minimal projection and the mask save_full_interval -- have often a full image is saved max_frame -- last frame saved (default a very large number, so it goes until the end of the video) mask_param -- parameters used to calculate the mask ''' #get the default values if there is any bad parameter output = compress_defaults(masked_image_file, expected_fps, buffer_size=buffer_size, save_full_interval=save_full_interval) buffer_size = output['buffer_size'] save_full_interval = output['save_full_interval'] if len(bgnd_param) > 0: is_bgnd_subtraction = True assert bgnd_param['buff_size'] > 0 and bgnd_param['frame_gap'] > 0 else: is_bgnd_subtraction = False if len(fovsplitter_param) > 0: is_fov_tosplit = True assert all(key in fovsplitter_param for key in ['total_n_wells', 'whichsideup', 'well_shape']) assert fovsplitter_param['total_n_wells'] > 0 else: is_fov_tosplit = False # processes identifier. base_name = masked_image_file.rpartition('.')[0].rpartition(os.sep)[-1] # select the video reader class according to the file type. vid = selectVideoReader(video_file) # delete any previous if it existed with tables.File(masked_image_file, "w") as mask_fid: pass #Extract metadata if is_extract_timestamp: # extract and store video metadata using ffprobe #NOTE: i cannot calculate /timestamp until i am sure of the total number of frames print_flush(base_name + ' Extracting video metadata...') expected_frames = store_meta_data(video_file, masked_image_file) else: expected_frames = 1 # Initialize background subtraction if required if is_bgnd_subtraction: print_flush(base_name + ' Initializing background subtraction.') bgnd_subtractor = BackgroundSubtractorVideo(video_file, **bgnd_param) # intialize some variables max_intensity, min_intensity = np.nan, np.nan frame_number = 0 full_frame_number = 0 image_prev = np.zeros([]) # Initialise FOV splitting if needed if is_bgnd_subtraction: img_fov = bgnd_subtractor.bgnd.astype(np.uint8) else: ret, img_fov = vid.read() # close and reopen the video, to restart from the beginning vid.release() vid = selectVideoReader(video_file) if is_fov_tosplit: # TODO: change class creator so it only needs the video name? by using # Tierpsy's functions such as selectVideoReader it can then read the first image by itself camera_serial = parse_camera_serial(masked_image_file) fovsplitter = FOVMultiWellsSplitter(img_fov, camera_serial=camera_serial, px2um=microns_per_pixel, **fovsplitter_param) wells_mask = fovsplitter.wells_mask else: wells_mask = None # initialize timers print_flush(base_name + ' Starting video compression.') if expected_frames == 1: progressTime = TimeCounter('Compressing video.') else: #if we know the number of frames display it in the progress progressTime = TimeCounter('Compressing video.', expected_frames) with tables.File(masked_image_file, "r+") as mask_fid: #initialize masks groups attr_params = dict(expected_fps=expected_fps, microns_per_pixel=microns_per_pixel, is_light_background=int( mask_param['is_light_background'])) mask_dataset, full_dataset, mean_intensity = initMasksGroups( mask_fid, expected_frames, vid.height, vid.width, attr_params, save_full_interval) if is_bgnd_subtraction: bg_dataset = createImgGroup(mask_fid, "/bgnd", 1, vid.height, vid.width, is_expandable=False) bg_dataset[0, :, :] = img_fov if vid.dtype != np.uint8: # this will worm as flags to be sure that the normalization took place. normalization_range = mask_fid.create_earray( '/', 'normalization_range', atom=tables.Float32Atom(), shape=(0, 2), expectedrows=expected_frames, filters=TABLE_FILTERS) while frame_number < max_frame: ret, image = vid.read() if ret != 0: # increase frame number frame_number += 1 # opencv can give an artificial rgb image. Let's get it back to # gray scale. if image.ndim == 3: image = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY) if image.dtype != np.uint8: # normalise image intensities if the data type is other # than uint8 image, img_norm_range = normalizeImage(image) normalization_range.append(img_norm_range) #limit the image range to 1 to 255, 0 is a reserved value for the background assert image.dtype == np.uint8 image = np.clip(image, 1, 255) # Add a full frame every save_full_interval if frame_number % save_full_interval == 1: full_dataset.append(image[np.newaxis, :, :]) full_frame_number += 1 # buffer index ind_buff = (frame_number - 1) % buffer_size # initialize the buffer when the index correspond to 0 if ind_buff == 0: Ibuff = np.zeros((buffer_size, vid.height, vid.width), dtype=np.uint8) # add image to the buffer Ibuff[ind_buff, :, :] = image.copy() mean_int = np.mean(image) assert mean_int >= 0 mean_intensity.append(np.array([mean_int])) else: # sometimes the last image is all zeros, control for this case if np.all(Ibuff[ind_buff] == 0): frame_number -= 1 ind_buff -= 1 # close the buffer Ibuff = Ibuff[:ind_buff + 1] # mask buffer and save data into the hdf5 file if (ind_buff == buffer_size - 1 or ret == 0) and Ibuff.size > 0: if is_bgnd_subtraction: Ibuff_b = bgnd_subtractor.apply(Ibuff, frame_number) else: Ibuff_b = Ibuff #calculate the max/min in the of the buffer img_reduce = reduceBuffer(Ibuff_b, mask_param['is_light_background']) mask = getROIMask(img_reduce, wells_mask=wells_mask, **mask_param) Ibuff *= mask # now apply the well_mask if is MWP if is_fov_tosplit: fovsplitter.apply_wells_mask( Ibuff) # Ibuff will be modified after this # add buffer to the hdf5 file frame_first_buff = frame_number - Ibuff.shape[0] mask_dataset.append(Ibuff) if frame_number % 500 == 0: # calculate the progress and put it in a string progress_str = progressTime.get_str(frame_number) print_flush(base_name + ' ' + progress_str) # finish process if ret == 0: break # now that the whole video is read, we definitely have a better estimate # for its number of frames. so set the save_interval again if is_bgnd_subtraction: # bg_dataset._v_attrs['save_interval'] = len(vid) # the above line is not accurate when using ffmpeg, # it's just safer to do: bg_dataset._v_attrs['save_interval'] = mask_dataset.shape[0] # close the video vid.release() # save fovsplitting data if is_fov_tosplit: fovsplitter.write_fov_wells_to_file(masked_image_file) if fovsplitter.is_dubious: print(f'Check {masked_image_file} for plate alignment') read_and_save_timestamp(masked_image_file) print_flush(base_name + ' Compressed video done.')