def pims_transform_anime(global_config: dict, video_config: dict, video): """ Apply transformations to an anime video, using pims pipelines. """ video = preprocess_anime(global_config, video_config, video) trans = [pims.pipeline(lambda img: resize(img, (ANIME_SIZE, ANIME_SIZE))), pims.pipeline(skimage.img_as_ubyte) ] return transform(trans, video)
def test_composed_pipelines(self): color_channel = pims.pipeline(_color_channel) rescale = pims.pipeline(_rescale) composed = rescale(color_channel(self.v, 0)) expected = _rescale(_color_channel(self.v[0], 0)) assert_image_equal(composed[0], expected)
def processVideo(videoPath, outputFolder, shape='circle'): """ Pipeline containing function to trim, mask and crop a video (provided by the process.csv file) shape: 'circle' or 'polygon' """ print('processVideo called with: ', videoPath, outputFolder) outputFilename = os.path.join( outputFolder, os.path.split(videoPath)[-1].strip(".mp4") + "_processed.mp4") if os.path.exists(outputFilename): print(outputFilename, "already exists. Terminating!") return None # get the required data from the process.csv file df = pd.read_csv(os.path.join(os.path.split(videoPath)[0], "process.csv"), index_col=0) start = df.loc[os.path.split(videoPath)[-1], 'start'] end = df.loc[os.path.split(videoPath)[-1], 'end'] # Shorten processed videos to 1h if end - start > 3600: end = 3600 + start if shape == 'circle': circle = literal_eval(df.loc[os.path.split(videoPath)[-1], 'circle']) # elif shape == 'polygon': # vertices = np.array(literal_eval(df.loc[os.path.split(videoPath)[-1], 'vertices'])) crop = literal_eval(df.loc[os.path.split(videoPath)[-1], 'crop']) video = pims.ImageIOReader(videoPath) fps = video.frame_rate # pipelines # masking pipeline masking_pipeline = pims.pipeline(maskFrame_circle) masking_kwargs = dict(circle=circle) masked_video = masking_pipeline(video, **masking_kwargs) # cropping pipeline cropping_pipeline = pims.pipeline(crop_frame) cropping_kwargs = dict(crop=crop) cropped_video = cropping_pipeline(masked_video, **cropping_kwargs) # writing to disk try: os.mkdir(outputFolder) except OSError: print( outputFolder, "already exists! Continuing with the process without creating it.") start_frame = int(start * fps) end_frame = int(end * fps) imageio.mimwrite(outputFilename, cropped_video[start_frame:end_frame], fps=fps) print('Completed: processVideo with parameters: ', videoPath, outputFolder)
def maskVideo_rect(videoPath, outputFolder, reader='ImageIO'): """Function containing a pipeline which masks a desired ROI in a given video (provided by the maskROIs.csv file) and saves the result""" # get the maskCoords from the csv file df = pd.read_csv(os.path.join(os.path.split(videoPath)[0], "maskROIs.csv"), index_col=0) maskCoords = tuple(df.loc[os.path.split(videoPath)[-1]]) # reader if reader == 'ImageIO': video = pims.ImageIOReader(videoPath) elif reader == 'PyAV': video = pims.Video(videoPath) fps = video.frame_rate # pipeline r = maskCoords masking_pipeline = pims.pipeline(maskFrame_rect) kwargs = dict(maskCoords=r) processed_video = masking_pipeline(video, **kwargs) # writing to disk try: os.mkdir(outputFolder) except OSError: print( outputFolder, "already exists! Continuing with the process without creating it.") outputFilename = os.path.join( outputFolder, os.path.split(videoPath)[-1].strip(".mp4") + "_masked.mp4") imageio.mimwrite(outputFilename, processed_video, fps=fps)
def get_frames(file_path, frames, gaussian_filter_width=None, roi = None): """ opens the video and returns the requested frames as numpy array Args: file_path: path to video file frames: integer or list of integers of the frames to be returned gaussian_filter_width: if not None apply Gaussian filter roi: region of interest, this allows to limit the search to a region of interest with the frame, the structure is roi = [roi_center, roi_dimension], where roi_center = [ro, co], roi_dimension = [h, w], where ro, co is the center of the roi (row, columns) and w, h is the width and the height of the roi Note that roi dimensions w, h should be odd numbers! """ images = [] if not hasattr(frames, '__len__'): frames = [frames] if not roi is None: [roi_center, roi_dimension] = roi v = pims.Video(file_path) video = rgb2gray_pipeline(v) if not gaussian_filter_width is None: gaussian_filter_pipeline = pipeline(gaussian_filter) video = gaussian_filter_pipeline(video, gaussian_filter_width) frame_shape = np.shape(video[frames[0]]) for frame in frames: image = video[frame] # reduce image to roi if not roi is None: [roi_center, roi_dimension] = roi image_roi = image[ int(roi_center[0] - (roi_dimension[0] - 1) / 2): int( roi_center[0] + (roi_dimension[0] + 1) / 2), int(roi_center[1] - (roi_dimension[1] - 1) / 2): int(roi_center[1] + (roi_dimension[1] + 1) / 2) ] else: image_roi = image images.append(image_roi) return images
def test_pipeline_with_args(self): color_channel = pims.pipeline(_color_channel) red = color_channel(self.v, 0) green = color_channel(self.v, 1) assert_image_equal(red[0], _color_channel(self.frame0, 0)) assert_image_equal(green[0], _color_channel(self.frame0, 1)) # Multiple pipelines backed by the same data are indep, # so this call to red is unaffected by green above. assert_image_equal(red[0], _color_channel(self.frame0, 0))
def transform_manga(config: dict, frames): """ Apply transformations to a sequence of manga pages. """ # crop whitespace from the edges # top, bottom, left, right, color things box = config["crop"] trans = [lambda frames: pims.process.crop(frames, ((box[0], box[1]), (box[2], box[3]), (0, 0))), # apply greyscale transformation pims.as_grey, # resize images pims.pipeline(lambda img: resize(img, (MANGA_SIZE, MANGA_SIZE))), to_ubyte ] return transform(trans, frames)
def export_video(self, filename=None, rate=None, **kwargs): """For a list of kwargs, see pims.export""" # TODO Save the canvas instead of the reader (including annotations) presets = dict(avi=dict(codec='libx264', quality=23), mp4=dict(codec='mpeg4', quality=5), mov=dict(codec='mpeg4', quality=5), wmv=dict(codec='wmv2', quality=0.005)) str_filter = ";;".join(['All files (*.*)', 'H264 video (*.avi)', 'MPEG4 video (*.mp4 *.mov)', 'Windows Media Player video (*.wmv)']) if filename is None: try: cur_dir = os.path.dirname(self.reader.filename) except AttributeError: cur_dir = '' filename = QtWidgets.QFileDialog.getSaveFileName(self, "Export Movie", cur_dir, str_filter) if isinstance(filename, tuple): # Handle discrepancy between PyQt4 and PySide APIs. filename = filename[0] ext = os.path.splitext(filename)[-1] if ext[0] == '.': ext = ext[1:] try: _kwargs = presets[ext] except KeyError: raise ValueError("Extension '.{}' is not a known format.".format(ext)) _kwargs.update(kwargs) if rate is None: try: rate = float(self.reader.frame_rate) except AttributeError or ValueError: rate = 25. self.reader.iter_axes = 't' self.status = 'Saving to {}'.format(filename) # PIMS v0.4 export() has a bug having to do with float precision # fix that here using limit_denominator() from fractions export(pipeline(to_rgb_uint8)(self.reader, autoscale=self.autoscale, force_color=self.force_color), filename, Fraction(rate).limit_denominator(66535), **kwargs) self.status = 'Done saving {}'.format(filename)
def test_pipeline_simple(self): rescale = pims.pipeline(_rescale) rescaled_v = rescale(self.v[:1]) assert_image_equal(rescaled_v[0], _rescale(self.frame0))
def extract_motion(filepath, target_path=None, gaussian_filter_width=2, use_trackpy =False, show_progress = True, trackpy_parameters = None, min_frames = 0, max_frames = None, roi = None, dynamic_roi = False, center_of_mass=False): """ Takes in a bead video, and saves the bead's extracted position in every frame in a csv, and (optionally) an uncorrupted version of the video filepath: path to an avi file of the bead target_path: (optional) if None same as video path gaussian_filter_width: width (in pixels) of the gaussian used to smooth the video use_trackpy: if True use Trackpy to better localize the brightest point, need to provid trackpy_parameters show_progress: if True show progress (use when called from ipython notebook) trackpy_parameters: parameters for trackpy (only needed if use_trackpy is True) min_frames: first frame to analyze, usefull for debugging, if start from first frame max_frames: max number of frames to analyze, usefull for debugging, if none do entire video roi: region of interest, this allows to limit the search to a region of interest with the frame, the structure is roi = [roi_center, roi_dimension], where roi_center = [ro, co], roi_dimension = [h, w], where ro, co is the center of the roi (row, columns) and w, h is the width and the height of the roi Note that roi dimensions w, h should be odd numbers! Note that the order of the dimensions is vertical, horizontal, that is NOT x,y! dynamic_roi: if True, dynamically track the roi, ie. the center of the roi of the next frame is the detected position of the currenrt frame. If false the roi is static center_of_mass: calculate the position from the center of mass returns: path to .csv file """ if target_path is None: target_path = os.path.dirname(filepath) assert os.path.isdir(target_path) if use_trackpy: assert 'diameter' in trackpy_parameters if not 'minmass' in trackpy_parameters: trackpy_parameters['minmass'] = None trackpy_parameters['missing_frames'] = [] target_filename = os.path.join(target_path, os.path.basename(filepath).replace('.avi', '_data_globalmax.csv')) v = pims.Video(filepath) processed_v = rgb2gray_pipeline(v) gaussian_filter_pipeline = pipeline(gaussian_filter) filtered = gaussian_filter_pipeline(processed_v, gaussian_filter_width) if max_frames is None: max_frames=len(filtered) else: # make sure max_frames is integer max_frames =int(max_frames) if show_progress: f = FloatProgress(min=min_frames, max=max_frames) # instantiate the bar display(f) # display the bar start_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') print('start time:\t{:s}'.format(start_time)) image_size = np.shape(filtered[0]) # size of image # find the maximum brightness pixel for every frame, corresponding to some consistent point at the bead max_coors = [] skipped_frames_idx = [] if not roi is None: [roi_center, roi_dimension] = roi for i in [0, 1]: # assert that roi fits in the image assert roi_center[i] + (roi_dimension[i]+1) / 2 <= image_size[i] assert roi_center[i] - (roi_dimension[i]+1) / 2 >= 0 # assert that roi_dimension are odd assert roi_dimension[i] % 2 == 1 cols = ['y bright', 'x bright'] if center_of_mass: cols = cols + ['x com', 'y com'] if use_trackpy: cols = cols + ['x tp', 'y tp'] # we use range in this loop so that we can catch the CannotReadFrameError in the line where we try to access the next image for index in range(min_frames, max_frames): try: image = filtered[index] except CannotReadFrameError: skipped_frames_idx.append(index) po, roi = get_position(image, roi, dynamic_roi=dynamic_roi, center_of_mass=center_of_mass, use_trackpy=use_trackpy, trackpy_parameters=trackpy_parameters) if po is None: trackpy_parameters['missing_frames'].append(index) else: max_coors.append(po) if index % 1000 == 0: if show_progress: f.value += 1000 if not max_frames is None: if index>max_frames: break df = pd.DataFrame(max_coors, columns=cols) df.to_csv(target_filename) end_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') print('end time:\t{:s}'.format(end_time)) print('file written to:\n{:s}'.format(target_filename)) info = { 'filename_xy_position': target_filename, 'image_size':np.shape(filtered[0]), 'gaussian_filter_width':gaussian_filter_width, 'N_frames':len(filtered), 'use_trackpy':use_trackpy, 'center_of_mass':center_of_mass, 'start_time':start_time, 'end_time':end_time, 'max_frames':max_frames, 'skipped_frames_idx':skipped_frames_idx, 'N_skipped_frames': len(skipped_frames_idx), 'roi' : roi } # convert time back to datetime so that we can calculate the duration start_time = datetime.datetime.strptime(start_time, '%Y-%m-%d %H:%M:%S') end_time = datetime.datetime.strptime(end_time, '%Y-%m-%d %H:%M:%S') info['extract. duration (min)'] = (end_time - start_time).seconds / 60 if use_trackpy: info.update({ 'trackpy_parameters': trackpy_parameters }) if info['N_skipped_frames']>100: print('WARNING: more than 100 frames corrupted in this video!!') return info
import numpy as np import pandas as pd import os import matplotlib.pyplot as plt import scipy.optimize as sopt import glob from tqdm import tqdm import pims from pims import pipeline from skimage.color import rgb2gray rgb2gray_pipeline = pipeline(rgb2gray) from scipy.ndimage.filters import gaussian_filter from scipy.ndimage.measurements import center_of_mass import trackpy as tp # status bar from IPython.display import display from imageio.core import CannotReadFrameError import datetime import yaml import sys import subprocess
import numpy as np import pandas as pd import os import matplotlib.pyplot as plt import scipy.optimize as sopt import pims import scipy.spatial import scipy.ndimage from collections import Counter import glob import trackpy as tp from pims import pipeline from skimage.color import rgb2gray rgb2gray_pipeline = pipeline(rgb2gray) from joblib import Parallel, delayed import multiprocessing num_cores = multiprocessing.cpu_count() def get_maxcoors(image, image_size): pixel_max = np.argmax(image) return(pixel_max%image_size, pixel_max/image_size) def get_maxcoors_array(image_array, image_size): maxes = [] for image in image_array: pixel_max = np.argmax(image)