def parse(self, file): """ :param file: path to a video file. :return: self """ container = av.open(file) step = int(self.delay) # every 100 frames of video warn("Video delay: ", str(step)) currentframe = 0 for packet in container.demux(): for frame in packet.decode(): currentframe += 1 if currentframe >= step: self.images.append(misc.fromimage(frame.to_image())) currentframe = 0 return self
def process(self, canvasimg, images, img_areas, allocs): """ :param canvasimg: packed canvas img :param images: frames of animation :param img_areas: changes :param allocs: position of changes :return: """ imgpath = os.path.join(self.path, "packed.png") # save packed image misc.imsave(imgpath, canvasimg) # try pngquant # Don't completely fail if we don't have pngcrush if os.system("pngquant --ext=.png --force %s" % imgpath) != 0: console.warn( "pngquant not found", 'Try installing pngquant for better results (http://pngquant.org/)' ) # Generate JSON to represent the data timeline = [] for i in range(len(images)): src_rects = img_areas[i] dst_rects = allocs[i] blitlist = [] for j in range(len(src_rects)): assert isinstance(j, object) metadata = computemeta(src_rects[j], dst_rects[j]) blitlist.append(metadata) timeline.append(blitlist) metadata = {} metadata['size'] = { "width": timeline[0][0][2], "height": timeline[0][0][3] } metadata['frames'] = timeline filemeta = open(os.path.join(self.path, "timeline.json"), 'wb') timeline = json.dumps(metadata, filemeta) filemeta.write(bytes(timeline, 'UTF-8')) filemeta.close() filemeta = open(os.path.join(self.path, 'example/example.timeline.js'), 'wb') filemeta.write(bytes("_timeline = ", 'UTF-8')) timeline = json.dumps(metadata, filemeta) filemeta.write(bytes(timeline, 'UTF-8')) filemeta.close() shutil.copyfile( os.path.join( os.path.split(os.path.abspath(os.path.dirname(__file__)))[0], './player/example.html' ), os.path.join(self.path, 'example/example.html') ) shutil.copyfile( os.path.join( os.path.split(os.path.abspath(os.path.dirname(__file__)))[0], '../../player/dist/jquery.html5anim.min.js' ), os.path.join(self.path, 'example/jquery.html5anim.min.js') ) console.success('Animation generated.', 'Check out output path: %s' % self.path)
def generate(self, export): """ Generate from self.images[] animation and send it to export :param export: Export class :return: """ zero = self.images[0] - self.images[0] pairs = zip([zero] + self.images[:-1], self.images) diffs = [sign((b - a).max(2)) for a, b in pairs] if self.talk: console.warn("Looking for diffs") # Find different objects for each frame img_areas = [me.find_objects(me.label(d)[0]) for d in diffs] # Simplify areas img_areas = [simplify(x, SIMPLIFICATION_TOLERANCE) for x in img_areas] if self.talk: console.warn("Areas found and simplified") ih, iw, _ = shape(self.images[0]) # Generate a packed image allocator = Allocator2D(MAX_PACKED_HEIGHT, iw) packed = zeros((MAX_PACKED_HEIGHT, iw, 3), dtype=uint8) # Sort the rects to be packed by largest size first, to improve the packing rects_by_size = [] for i in range(len(self.images)): src_rects = img_areas[i] for j in range(len(src_rects)): rects_by_size.append((slice_tuple_size(src_rects[j]), i, j)) rects_by_size.sort(reverse=True) if self.talk: console.warn("Areas sorted by size") allocs = [[None] * len(src_rects) for src_rects in img_areas] console.warn( "Packing", "num rects: {0} num frames: {1}".format(len(rects_by_size), len(self.images))) t0 = time() counter = 0 for size, i, j in rects_by_size: src = self.images[i] src_rects = img_areas[i] a, b = src_rects[j] sx, sy = b.start, a.start w, h = b.stop - b.start, a.stop - a.start # finding matching rectangle is very expensive and its disabled for now. # existing = find_matching_rect( # allocator.bitmap, # allocator.num_used_rows, # packed, # src, # sx, # sy, # w, # h # ) # if existing: # dy, dx = existing # allocs[i][j] = (dy, dx) # else: counter += 1 if self.talk: console.warn( "Allocation area ({0}/{1}): ".format( counter, len(rects_by_size)), "{0}x{1} ({2})".format(i, j, size)) dy, dx = allocator.allocate(w, h) allocs[i][j] = (dy, dx) packed[dy:dy + h, dx:dx + w] = src[sy:sy + h, sx:sx + w] console.success("Packing finished", "took: %s" % (time() - t0)) packed = packed[0:allocator.num_used_rows] export.process(packed, self.images, img_areas, allocs)
def generate(self, export): """ Generate from self.images[] animation and send it to export :param export: Export class :return: """ zero = self.images[0] - self.images[0] pairs = zip([zero] + self.images[:-1], self.images) diffs = [sign((b - a).max(2)) for a, b in pairs] if self.talk: console.warn("Looking for diffs") # Find different objects for each frame img_areas = [me.find_objects(me.label(d)[0]) for d in diffs] # Simplify areas img_areas = [simplify(x, SIMPLIFICATION_TOLERANCE) for x in img_areas] if self.talk: console.warn("Areas found and simplified") ih, iw, _ = shape(self.images[0]) # Generate a packed image allocator = Allocator2D(MAX_PACKED_HEIGHT, iw) packed = zeros((MAX_PACKED_HEIGHT, iw, 3), dtype=uint8) # Sort the rects to be packed by largest size first, to improve the packing rects_by_size = [] for i in range(len(self.images)): src_rects = img_areas[i] for j in range(len(src_rects)): rects_by_size.append((slice_tuple_size(src_rects[j]), i, j)) rects_by_size.sort(reverse=True) if self.talk: console.warn("Areas sorted by size") allocs = [[None] * len(src_rects) for src_rects in img_areas] console.warn( "Packing", "num rects: {0} num frames: {1}".format( len(rects_by_size), len(self.images) ) ) t0 = time() counter = 0 for size, i, j in rects_by_size: src = self.images[i] src_rects = img_areas[i] a, b = src_rects[j] sx, sy = b.start, a.start w, h = b.stop - b.start, a.stop - a.start # finding matching rectangle is very expensive and its disabled for now. # existing = find_matching_rect( # allocator.bitmap, # allocator.num_used_rows, # packed, # src, # sx, # sy, # w, # h # ) # if existing: # dy, dx = existing # allocs[i][j] = (dy, dx) # else: counter += 1 if self.talk: console.warn("Allocation area ({0}/{1}): ".format( counter, len(rects_by_size) ), "{0}x{1} ({2})".format(i, j, size)) dy, dx = allocator.allocate(w, h) allocs[i][j] = (dy, dx) packed[dy:dy+h, dx:dx+w] = src[sy:sy+h, sx:sx+w] console.success("Packing finished", "took: %s" % (time() - t0)) packed = packed[0:allocator.num_used_rows] export.process(packed, self.images, img_areas, allocs)