def main(): # Now we can use these new Ops in Scanner: db = Database() # Download an example video example_video_path = util.download_video() # Ingest it into the database [input_table], _ = db.ingest_videos([('example', example_video_path)], force=True) frame = db.sources.FrameColumn() resized_frame_fn = db.ops.resize_fn(frame=frame, width=640, height=480) resized_frame_class = db.ops.ResizeClass(frame=frame, width=320, height=240) output = db.sinks.FrameColumn(columns={ 'frame1': resized_frame_fn, 'frame2': resized_frame_class }) job = Job(op_args={ frame: input_table.column('frame'), output: 'example_python_op' }) [table] = db.run(output=output, jobs=[job], force=True) table.column('frame1').save_mp4('01_resized_fn') table.column('frame2').save_mp4('01_resized_class') print('Finished! Two videos were saved to the current directory: ' '01_resized_fn.mp4, 01_resized_class.mp4')
from scannerpy import Database, Job # The following performs the same computation as main.py, but now on a collection # of videos instead of just one db = Database() # This is the list of videos we are going to process formatted as # (table_name, video_path). videos_to_process = [('sample-clip-1', 'sample-clip-1.mp4'), ('sample-clip-2', 'sample-clip-2.mp4'), ('sample-clip-3', 'sample-clip-3.mp4')] # Ingest the videos into the database db.ingest_videos(videos_to_process) # Define the same Computation Graph frame = db.sources.FrameColumn() # Read from the database sampled_frame = db.streams.Stride(frame, 3) # Select every third frame resized = db.ops.Resize(frame=sampled_frame, width=640, height=480) # Resize input frame output_frame = db.sinks.Column(columns={'frame': resized}) # Save resized frame # Create multiple jobs now, one for each video we want to process jobs = [] for table_name, _ in videos_to_process: job = Job( op_args={ frame: db.table(table_name).column( 'frame'), # Column to read input frames from
port = sp.check_output(''' kubectl get svc/scanner-master -o json | \ jq '.spec.ports[0].nodePort' -r ''', shell=True).strip().decode('utf-8') master = '{}:{}'.format(ip, port) print('Connecting to Scanner database...') db = Database(master=master, start_cluster=False, config_path='./config.toml') print('Running Scanner job...') example_video_path = 'sample.mp4' [input_table], _ = db.ingest_videos([('example', example_video_path)], force=True, inplace=True) print(db.summarize()) frame = db.sources.FrameColumn() r_frame = db.ops.Resize(frame=frame, width=320, height=240) output_op = db.sinks.Column(columns={'frame': r_frame}) job = Job(op_args={ frame: db.table('example').column('frame'), output_op: 'example_frame' }) output_tables = db.run(output=output_op, jobs=[job], force=True) output_tables[0].column('frame').save_mp4('resized_video')
from scannerpy import Database, Job # Ingest a video into the database db = Database() db.ingest_videos([('example_table', 'sample-clip.mp4')]) # Define a Computation Graph frame = db.sources.FrameColumn() # Read from the database sampled_frame = db.ops.Stride(frame, 3) # Select every third frame resized = db.ops.Resize(frame=sampled_frame, width=640, height=480) # Resize input frame output_frame = db.sinks.Column(columns={'frame': resized}) # Save resized frame job = Job( op_args={ frame: db.table('example_table').column( 'frame'), # Column to read input frames from output_frame: 'resized_example' # Name of output table }) # Execute the computation graph and return a handle to the newly produced tables output_tables = db.run(output=output_frame, jobs=[job], force=True) # Save the resized video as an mp4 file output_tables[0].column('frame').save_mp4('resized-video')
def main(movie_path): total_start = time.time() print('Detecting shots in movie {}'.format(movie_path)) movie_name = os.path.basename(movie_path) # Use GPU kernels if we have a GPU db = Database() print('Loading movie into Scanner database...') s = time.time() if db.has_gpu(): device = DeviceType.GPU else: device = DeviceType.CPU ############ ############ ############ ############ # 0. Ingest the video into the database ############ ############ ############ ############ [movie_table], _ = db.ingest_videos([(movie_name, movie_path)], force=True) print('Time: {:.1f}s'.format(time.time() - s)) print('Number of frames in movie: {:d}'.format(movie_table.num_rows())) s = time.time() ############ ############ ############ ############ # 1. Run Histogram over the entire video in Scanner ############ ############ ############ ############ print('Computing a color histogram for each frame...') frame = db.sources.FrameColumn() histogram = db.ops.Histogram(frame=frame, device=device) output = db.sinks.Column(columns={'histogram': histogram}) job = Job(op_args={ frame: movie_table.column('frame'), output: movie_name + '_hist' }) [hists_table] = db.run(output=output, jobs=[job], force=True) print('\nTime: {:.1f}s, {:.1f} fps'.format( time.time() - s, movie_table.num_rows() / (time.time() - s))) s = time.time() ############ ############ ############ ############ # 2. Load histograms and compute shot boundaries # in python ############ ############ ############ ############ print('Computing shot boundaries...') # Read histograms from disk hists = [ h for h in hists_table.column('histogram').load(parsers.histograms) ] boundaries = compute_shot_boundaries(hists) print('Found {:d} shots.'.format(len(boundaries))) print('Time: {:.1f}s'.format(time.time() - s)) s = time.time() ############ ############ ############ ############ # 3. Create montage in Scanner ############ ############ ############ ############ print('Creating shot montage...') row_length = min(16, len(boundaries)) rows_per_item = 1 target_width = 256 # Compute partial row montages that we will stack together # at the end frame = db.sources.FrameColumn() gather_frame = frame.sample() sliced_frame = gather_frame.slice() montage = db.ops.Montage(frame=sliced_frame, num_frames=row_length * rows_per_item, target_width=target_width, frames_per_row=row_length, device=device) sampled_montage = montage.sample() output = db.sinks.Column( columns={'montage': sampled_montage.unslice().lossless()}) item_size = row_length * rows_per_item starts_remainder = len(boundaries) % item_size evenly_divisible = (starts_remainder == 0) if not evenly_divisible: boundaries = boundaries[0:len(boundaries) - starts_remainder] job = Job( op_args={ frame: movie_table.column('frame'), gather_frame: db.sampler.gather(boundaries), sliced_frame: db.partitioner.all(item_size), sampled_montage: [ db.sampler.gather([item_size - 1]) for _ in range(len(boundaries) / item_size) ], output: 'montage_image' }) [montage_table] = db.run(output=output, jobs=[job], force=True) # Stack all partial montages together montage_img = np.zeros((1, target_width * row_length, 3), dtype=np.uint8) for img in montage_table.column('montage').load(): img = np.flip(img, 2) montage_img = np.vstack((montage_img, img)) print('') print('Time: {:.1f}s'.format(time.time() - s)) ############ ############ ############ ############ # 4. Write montage to disk ############ ############ ############ ############ cv2.imwrite('shots.jpg', montage_img) print('Successfully generated shots.jpg') print('Total time: {:.2f} s'.format(time.time() - total_start))
def main(): db = Database() example_video_path = util.download_video() [input_table], _ = db.ingest_videos([('example', example_video_path)], force=True) videos = [] # Many ops simply involve applying some processing to their inputs and then # returning their outputs. But there are also many operations in video # processing that require the ability to see adjacent frames (such as for # computing optical flow), need to keep state over time (such as for tracking # objects), or need to process multiple elements for efficiency reasons (such as # batching for DNNs). # Scanner ops therefore have several optional attributes that enable them to # support these forms of operations: # 1. Device Type: # Ops can specify that they require CPUs or GPUs by declaring their device # type. By default, the device_type is DeviceType.CPU. @scannerpy.register_python_op(device_type=DeviceType.CPU) def device_resize(config, frame: FrameType) -> FrameType: return cv2.resize(frame, (config.args['width'], config.args['height'])) frame = db.sources.FrameColumn() resized_frame = db.ops.device_resize(frame=frame, width=640, height=480) output = db.sinks.FrameColumn(columns={'frame': resized_frame}) job = Job(op_args={ frame: input_table.column('frame'), output: 'example_resize' }) [table] = db.run(output=output, jobs=[job], force=True) table.column('frame').save_mp4('02_device_resize') videos.append('02_device_resize.mp4') # 2. Batch: # The Op can receive multiple elements at once to enable SIMD or # vector-style processing. @scannerpy.register_python_op(batch=10) def batch_resize(config, frame: Sequence[FrameType]) -> Sequence[FrameType]: output_frames = [] for fr in frame: output_frames.append( cv2.resize(fr, (config.args['width'], config.args['height']))) return output_frames # Here we specify that the resize op should receive a batch of 10 # input elements at once. Logically, each element is still processed # independently but multiple elements are provided to enable efficient # batch processing. If there are not enough elements left in a stream, # the Op may receive less than a batch worth of elements. frame = db.sources.FrameColumn() resized_frame = db.ops.batch_resize(frame=frame, width=640, height=480, batch=10) output = db.sinks.FrameColumn(columns={'frame': resized_frame}) job = Job(op_args={ frame: input_table.column('frame'), output: 'example_batch_resize' }) [table] = db.run(output=output, jobs=[job], force=True) table.column('frame').save_mp4('02_batch_resize') videos.append('02_batch_resize.mp4') # 3. Stencil: # The Op requires a window of input elements (for example, the # previous and next element) at the same time to produce an # output. # Here, we use the stencil attribute to write an optical flow op which # computes flow between the current and next frame. @scannerpy.register_python_op(stencil=[0, 1]) def optical_flow(config, frame: Sequence[FrameType]) -> FrameType: gray1 = cv2.cvtColor(frame[0], cv2.COLOR_BGR2GRAY) gray2 = cv2.cvtColor(frame[1], cv2.COLOR_BGR2GRAY) flow = cv2.calcOpticalFlowFarneback(gray1, gray2, None, 0.5, 3, 15, 3, 5, 1.2, 0) return flow # This op visualizes the flow field by converting it into an rgb image @scannerpy.register_python_op() def visualize_flow(config, flow: FrameType) -> FrameType: hsv = np.zeros(shape=(flow.shape[0], flow.shape[1], 3), dtype=np.uint8) hsv[..., 1] = 255 mag, ang = cv2.cartToPolar(flow[..., 0], flow[..., 1]) hsv[..., 0] = ang * 180 / np.pi / 2 hsv[..., 2] = cv2.normalize(mag, None, 0, 255, cv2.NORM_MINMAX) rgb = cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR) return rgb frame = db.sources.FrameColumn() # This next line is using a feature we'll discuss in the next tutorial, but you # can think of it as selecting a subset of elements from the stream (here, # frames 0 to 30) range_frame = db.streams.Range(frame, 0, 30) flow = db.ops.optical_flow(frame=range_frame, stencil=[0, 1]) flow_viz = db.ops.visualize_flow(flow=flow) output = db.sinks.FrameColumn(columns={'flow_viz': flow_viz}) job = Job(op_args={ frame: input_table.column('frame'), output: 'example_flow' }) [table] = db.run(output=output, jobs=[job], force=True) table.column('flow_viz').save_mp4('02_flow') videos.append('02_flow.mp4') # 4. Bounded State: # For each output, the Op requires at least W sequential # "warmup" elements before it can produce a valid output. # For example, if the output of this Op is sampled # sparsely, this guarantees that the Op can "warmup" # its state on a stream of W elements before producing the # requested output. import subprocess @scannerpy.register_python_op(bounded_state=60) class BackgroundSubtraction(scannerpy.Kernel): def __init__(self, config): self.config = config self.alpha = config.args['alpha'] self.thresh = config.args['threshold'] # Reset is called when the kernel switches to a new part of the stream # and so shouldn't maintain it's previous state def reset(self): self.average_image = None def execute(self, frame: FrameType) -> FrameType: if self.average_image is None: self.average_image = frame mask = np.abs(frame - self.average_image) < 255 * self.thresh mask = np.any(mask, axis=2) masked_image = np.copy(frame) wmask = np.where(mask) masked_image[wmask[0], wmask[1], :] = 0 self.average_image = (self.average_image * (1.0 - self.alpha) + frame * self.alpha) return masked_image # Here we wrote an op that performs background subtraction by keeping a # running average image over the past frames. We set `bounded_state=60` # to indicate that this kernel needs at least 60 frames before the output # should be considered reasonable. # First, we download a static camera video from youtube # subprocess.check_call( # 'youtube-dl -f 137 \'https://youtu.be/cVHqFqNz7eM\' -o test.mp4', # shell=True) # [static_table], _ = db.ingest_videos([('static_video', 'test.mp4')], # force=True) static_table = input_table # Then we perform background subtraction and indicate we need 60 prior # frames to produce correct output frame = db.sources.FrameColumn() masked_frame = db.ops.BackgroundSubtraction(frame=frame, alpha=0.05, threshold=0.05, bounded_state=60) # Here, we say that we only want the outputs for this range of frames sampled_frame = db.streams.Range(masked_frame, 0, 120) output = db.sinks.Column(columns={'frame': sampled_frame}) job = Job(op_args={ frame: static_table.column('frame'), output: 'masked_video', }) [table] = db.run(output=output, jobs=[job], force=True) table.column('frame').save_mp4('02_masked') videos.append('02_masked.mp4') # 5. Unbounded State: # This Op will always process all preceding elements of # its input streams before producing a requested output. # This means that sampling operations after this Op # can not change how many inputs it receives. In the next # tutorial, we will show how this can be relaxed for # sub-streams of the input. @scannerpy.register_python_op(unbounded_state=True) class Example(scannerpy.Kernel): def __init__(self, config): pass def reset(self): pass def execute(self, frame: FrameType) -> bytes: pass print('Finished! The following videos were written: {:s}'.format( ', '.join(videos)))
def main(): db = Database() example_video_path = util.download_video() [input_table], _ = db.ingest_videos([('example', example_video_path)], force=True) frame = db.sources.FrameColumn() # When working with bounded or unbounded stateful operations, it is sometimes # useful to introduce boundaries between sequences of frames which restrict # state being shared between them. For example, if you are tracking objects # in a movie, you likely do not want the same trackers when the camera changes # scenes since the objects you were tracking are no longer there! # Scanner provides support for limiting state propagation across frames through # "slicing" operations. sliced_frame = db.streams.Slice(frame, db.partitioner.all(50)) # Here, we sliced the input frame stream into chunks of 50 elements. What this # means is that any ops which process 'sliced_frame' will *only* be able to # maintain state within each chunk of 50 elements. # For example, let's say we grab the background subtraction op from the previous # tutorial (02_op_attributes) and want to run it on a static camera video which # sometimes jumps forward in time: @scannerpy.register_python_op(bounded_state=60) class BackgroundSubtraction(scannerpy.Kernel): def __init__(self, config): self.config = config self.alpha = config.args['alpha'] self.thresh = config.args['threshold'] def reset(self): self.average_image = None def execute(self, frame: FrameType) -> FrameType: if self.average_image is None: self.average_image = frame mask = np.abs(frame - self.average_image) < 255 * self.thresh mask = np.any(mask, axis=2) masked_image = np.copy(frame) wmask = np.where(mask) masked_image[wmask[0], wmask[1], :] = 0 self.average_image = (self.average_image * (1.0 - self.alpha) + frame * self.alpha) return masked_image # First, we download the static camera video from youtube # subprocess.check_call( # 'youtube-dl -f 137 \'https://youtu.be/cVHqFqNz7eM\' -o test.mp4', # shell=True) # [static_table], _ = db.ingest_videos([('static_video', 'test.mp4')], # force=True) static_table = input_table frame = db.sources.FrameColumn() # Imagine that there are scene changes at frames 1100, 1200, and 1500, To tell # scanner that we do not want background subtraction to cross these boundaries, # we can create a 'partitioner' which splits the input. scene_partitions = db.partitioner.ranges([(1100, 1200), (1200, 1500)]) # Now we slice the input frame sequence into these two partitions using a # slice operation sliced_frame = db.streams.Slice(frame, partitioner=scene_partitions) # Then we perform background subtraction and indicate we need 60 prior # frames to produce correct output masked_frame = db.ops.BackgroundSubtraction(frame=sliced_frame, alpha=0.02, threshold=0.05, bounded_state=60) # Since the background subtraction operation is done, we can unslice the # sequence to join it back into a single contiguous stream. You must unslice # sequences before feeding them back into sinks unsliced_frame = db.streams.Unslice(masked_frame) output = db.sinks.Column(columns={'frame': unsliced_frame}) job = Job(op_args={ frame: static_table.column('frame'), output: '04_masked_video', }) [table] = db.run(output=output, jobs=[job], force=True) table.column('frame').save_mp4('04_masked') videos = [] videos.append('04_masked.mp4') print('Finished! The following videos were written: {:s}'.format( ', '.join(videos)))
return frame if len(sys.argv) <= 1: print('Usage: main.py <video_file>') exit(1) movie_path = sys.argv[1] print('Detecting poses in video {}'.format(movie_path)) movie_name = os.path.splitext(os.path.basename(movie_path))[0] db = Database() video_path = movie_path if not db.has_table(movie_name): print('Ingesting video into Scanner ...') db.ingest_videos([(movie_name, video_path)], force=True) input_table = db.table(movie_name) sampler = db.streams.Range sampler_args = {'start': 120, 'end': 480} [poses_table] = pipelines.detect_poses(db, [input_table.column('frame')], sampler, sampler_args, '{:s}_poses'.format(movie_name)) print('Drawing on frames...') frame = db.sources.FrameColumn() sampled_frame = sampler(frame) poses = db.sources.Column() drawn_frame = db.ops.PoseDraw(frame=sampled_frame, poses=poses) output = db.sinks.Column(columns={'frame': drawn_frame})
import subprocess import cv2 import sys import os.path sys.path.append(os.path.dirname(os.path.abspath(__file__)) + '/../..') import util import numpy as np util.download_video() db = Database() video_path = util.download_video() if True or not db.has_table('example'): print('Ingesting video into Scanner ...') db.ingest_videos([('example', video_path)], force=True) input_table = db.table('example') descriptor = NetDescriptor.from_file(db, 'nets/faster_rcnn_coco.toml') caffe_args = db.protobufs.CaffeArgs() caffe_args.net_descriptor.CopyFrom(descriptor.as_proto()) caffe_args.batch_size = 1 frame = db.ops.FrameInput() caffe_frame = db.ops.CaffeInput(frame=frame, args=caffe_args, device=DeviceType.CPU) cls_prob, rois, fc7 = db.ops.FasterRCNN(caffe_input=caffe_frame, args=caffe_args, device=DeviceType.GPU)
masked_image = np.copy(frame) wmask = np.where(mask) masked_image[wmask[0], wmask[1], :] = 0 self.average_image = (self.average_image * (1.0 - self.alpha) + frame * self.alpha) return masked_image # First, we download the static camera video from youtube subprocess.check_call( 'youtube-dl -f 137 \'https://youtu.be/cVHqFqNz7eM\' -o test.mp4', shell=True) [static_table], _ = db.ingest_videos([('static_video', 'test.mp4')], force=True) frame = db.sources.FrameColumn() # We know that there are scene change at frames 5100, 5400, and 5730, To tell # scanner that we do not want background subtraction to cross these boundaries, # we can create a 'partitioner' which splits the input. For demonstration, we # are going to split into only two sequences (5100, 5350) and (5400, 5830). scene_partitions = db.partitioner.ranges([(5100, 5350), (5400, 5830)]) # Since the second sequence (5400, 5830) has a scene change in it at frame 5730, # we will see smearing in the output video. # Now we slice the input frame sequence into these two partitions using a # slice operation sliced_frame = db.streams.Slice(frame, partitioner=scene_partitions)
import sys import os.path sys.path.append(os.path.dirname(os.path.abspath(__file__)) + '/..') import util ################################################################################ # This tutorial provides an overview of the more advanced features of Scanner # # ops and when you would want to use them. # ################################################################################ db = Database() example_video_path = util.download_video() [input_table], _ = db.ingest_videos([('example', example_video_path)], force=True) videos = [] # Many ops simply involve applying some processing to their inputs and then # returning their outputs. But there are also many operations in video # processing that require the ability to see adjacent frames (such as for # computing optical flow), need to keep state over time (such as for tracking # objects), or need to process multiple elements for efficiency reasons (such as # batching for DNNs). # Scanner ops therefore have several optional attributes that enable them to # support these forms of operations: # 1. Device Type: # Ops can specify that they require CPUs or GPUs by declaring their device
# This file shows a sample end-to-end pipeline that ingests a video into # # Scanner, runs a computation, and extracts the results. # ################################################################################ # Initialize a connection to the Scanner database. Loads configuration from the # ~/.scanner.toml configuration file. db = Database() # Create a Scanner table from our video in the format (table name, # video path). If any videos fail to ingest, they'll show up in the failed # list. If force is true, it will overwrite existing tables of the same # name. example_video_path = util.download_video() [input_table ], failed = db.ingest_videos([('example', example_video_path), ('thisshouldfail', 'thisshouldfail.mp4')], force=True) print(db.summarize()) print('Failures:', failed) # Scanner processes videos by forming a graph of operations that operate # on input frames from a table and produce outputs to a new table. # FrameColumn declares that we want to read from a table column that # represents a video frame. frame = db.sources.FrameColumn() # These frames are input into a Histogram op that computes a color histogram # for each frame. hist = db.ops.Histogram(frame=frame)
# result = np.dstack((template, template, template))*255 out = rgb.astype(np.uint8) return out movie_path = '/home/krematas/Mountpoints/grail/data/barcelona/test.mp4' print('Detecting faces in movie {}'.format(movie_path)) movie_name = os.path.splitext(os.path.basename(movie_path))[0] mask_path = '/home/krematas/Mountpoints/grail/data/barcelona/mask.mp4' db = Database() print('Ingesting video into Scanner ...') input_tables, failed = db.ingest_videos([(movie_name, movie_path), ('mask', mask_path)], force=True) print(db.summarize()) print('Failures:', failed) cam_data = np.load('/home/krematas/Mountpoints/grail/data/barcelona/calib/00114.npy').item() # db.register_op('Calibrate', [('frame', ColumnType.Video), ('mask', ColumnType.Video)], [('resized', ColumnType.Video)]) # Custom Python kernels for ops reside in a separate file, here calibrate_kernel.py. # cwd = '/home/krematas/code/scanner/examples/apps/soccer' # db.register_python_kernel('Calibrate', DeviceType.CPU, cwd + '/calibrate_kernel.py') frame = db.sources.FrameColumn() mask = db.sources.FrameColumn()
from scannerpy import Database, DeviceType, Job from scannerpy.stdlib import parsers import os.path as osp import numpy as np db = Database() if not db.has_table('example'): db.ingest_videos([('example', 'example.mp4')]) input_table = db.table('example') frame, frame_info = input_table.as_op().all(warmup_size = 1) flow = db.ops.OpticalFlow( frame = frame, frame_info = frame_info, device=DeviceType.GPU) job = Job(columns = [flow, frame_info], name = 'example_flows') output_table = db.run(job) vid_flows = [flow for _, flow in output_table.load(['flow', 'frame_info'], parsers.flow)] np.save('flows.npy', vid_flows)
def main(): # Initialize a connection to the Scanner database. Loads configuration from the # ~/.scanner.toml configuration file. db = Database() # Create a Scanner table from our video in the format (table name, # video path). If any videos fail to ingest, they'll show up in the failed # list. If force is true, it will overwrite existing tables of the same # name. example_video_path = util.download_video() _, failed = db.ingest_videos([('example', example_video_path), ('example2', example_video_path), ('thisshouldfail', 'thisshouldfail.mp4')], force=True) print(db.summarize()) print('Failures:', failed) # Scanner processes videos by forming a graph of operations that operate # on input frames from a table and produce outputs to a new table. # FrameColumn declares that we want to read from a table column that # represents a video frame. frame = db.sources.FrameColumn() # These frames are input into a Histogram op that computes a color histogram # for each frame. hist = db.ops.Histogram(frame=frame) # Finally, any columns provided to Output will be saved to the output # table at the end of the computation. Here, 'hist' is the name of the # column for the output table. output_op = db.sinks.Column(columns={'hist': hist}) # A job defines a table you want to create. In op_args, we bind the # FrameColumn from above to the table we want to read from and name # the output table 'example_hist' by binding a string to output_op. job = Job(op_args={ frame: db.table('example').column('frame'), output_op: 'example_hist' }) job2 = Job(op_args={ frame: db.table('example2').column('frame'), output_op: 'example_hist2' }) # This executes the job and produces the output table. You'll see a progress # bar while Scanner is computing the outputs. output_tables = db.run(output=output_op, jobs=[job, job2], force=True) # Load the histograms from a column of the output table. The # readers.histograms function converts the raw bytes output by Scanner # into a numpy array for each channel. video_hists = output_tables[0].column('hist').load(readers.histograms) # Loop over the column's values, a set of 3 histograms (for each color channel) per element. num_rows = 0 for frame_hists in video_hists: assert len(frame_hists) == 3 assert frame_hists[0].shape[0] == 16 num_rows += 1 assert num_rows == db.table('example').num_rows()
'--video-path', type=str, required=True, help=('Path to video to process.')) args = p.parse_args() weights_path = args.weights_path config_path = args.config_path movie_path = args.video_path print('Detecting objects in movie {}'.format(movie_path)) movie_name = os.path.splitext(os.path.basename(movie_path))[0] db = Database() [input_table], failed = db.ingest_videos( [('example', movie_path)], force=True) frame = db.sources.FrameColumn() strided_frame = db.streams.Range(frame, 0, 60) # Call the newly created object detect op cls_boxes, cls_segms, cls_keyps = db.ops.Detectron( frame=strided_frame, config_path=config_path, weights_path=weights_path, device=DeviceType.GPU) objdet_frame = db.ops.DetectronVizualize( frame=strided_frame, cls_boxes=cls_boxes, cls_segms=cls_segms,
from scannerpy import Database, Job db = Database() # Ingest a video into the database # The input is formatted as a list of (table_name, video_path). db.ingest_videos([('sample-clip', 'sample-clip.mp4')], force=True) # Define a Computation Graph frame = db.sources.FrameColumn() # Read from the database sampled_frame = db.streams.Stride(frame, 3) # Select every third frame resized = db.ops.Resize(frame=sampled_frame, width=640, height=480) # Resize input frame output_frame = db.sinks.Column(columns={'frame': resized}) # Save resized frame # Bind arguments to the source and sink nodes job = Job( op_args={ frame: db.table(table_name).column( 'frame'), # Column to read input frames from output_frame: 'resized-{:s}'.format(table_name) # Name of output table }) # Execute the computation graph and return a handle to the newly produced tables output_tables = db.run(output=output_frame, jobs=[job], force=True) # Save the resized video as an mp4 file output_tables[0].column('frame').save_mp4(output_tables[0].name())
import os.path as osp import numpy as np import time import sys if len(sys.argv) <= 1: print('Usage: main.py <video_file>') exit(1) video_path = sys.argv[1] print('Performing optical flow on {}...'.format(video_path)) video_name = os.path.splitext(os.path.basename(video_path))[0] db = Database() if not db.has_table(video_name): db.ingest_videos([(video_name, video_path)]) input_table = db.table(video_name) frame = db.sources.FrameColumn() flow = db.ops.OpticalFlow( frame = frame, device=DeviceType.CPU) sampled_flow = db.streams.Range(flow, 0, 60) output = db.sinks.Column(columns={'flow': sampled_flow}) job = Job(op_args={ frame: input_table.column('frame'), output: input_table.name() + '_flow' }) [output_table] = db.run(output=output, jobs=[job], pipeline_instances_per_node=1, force=True)
image_paths = os.listdir(dir_name) image_paths = [os.path.join(dir_name, p) for p in image_paths] print('Ingesting images into Scanner ...') [input_table] = pipelines.ingest_images(db, image_paths, dir_name, force=True) table_name = dir_name elif os.path.isfile(sys.argv[1]): is_movie = True movie_path = sys.argv[1] print('Detecting faces in movie {}'.format(movie_path)) movie_name = os.path.splitext(os.path.basename(movie_path))[0] print('Ingesting video into Scanner ...') [input_table], _ = db.ingest_videos([(movie_name, movie_path)], force=True) table_name = movie_name else: usage() exit(1) sampler = db.streams.All sampler_args = {} print('Detecting faces...') [bboxes_table] = pipelines.detect_faces(db, [input_table.column('frame')], sampler, sampler_args, table_name + '_faces') print('Drawing faces onto frames...') frame = db.sources.FrameColumn()