def testPaddingMatch(self): tests = [ ("mixed/seq.#.ext", "mixed/seq.-1-5#.ext"), ("mixed/seq.@@.ext", "mixed/seq.-1-5@@.ext"), ("mixed/seq.@@@@@.ext", "mixed/seq.-1-5@@@@@.ext"), ("mixed/[email protected]", "mixed/[email protected]"), ("mixed/seq.##.ext", None), ("mixed/seq.%04d.ext", "mixed/seq.-1-5#.ext"), ("mixed/seq.%02d.ext", "mixed/seq.-1-5@@.ext"), ("mixed/seq.%05d.ext", "mixed/seq.-1-5@@@@@.ext"), ("mixed/seq.%01d.ext", "mixed/[email protected]"), ("mixed/seq.%08d.ext", None), ] for pattern, expected in tests: if expected is None: with self.assertRaises(FileSeqException): findSequenceOnDisk(pattern, strictPadding=True) continue seq = findSequenceOnDisk(pattern, strictPadding=True) self.assertTrue(isinstance(seq, FileSequence)) actual = str(seq) self.assertEqual(actual, expected)
def testStrictPadding(self): tests = [ ("seq/bar#.exr", "seq/bar1000-1002,1004-1006#.exr"), ("seq/bar@@@@.exr", "seq/bar1000-1002,1004-1006@@@@.exr"), ("seq/bar@@@.exr", "seq/bar1000-1002,1004-1006@@@.exr"), ("seq/bar@@.exr", "seq/bar1000-1002,1004-1006@@.exr"), ("seq/[email protected]", "seq/bar1000-1002,[email protected]"), ("seq/bar@@@@@.exr", None), ("seq/bar#@.exr", None), ("seq/foo.#.exr", "seq/foo.1-5#.exr"), ("seq/foo.#.jpg", "seq/foo.1-5#.jpg"), ("seq/foo.#.exr", "seq/foo.1-5#.exr"), ("seq/foo.debug.#.exr", "seq/foo.debug.1-5#.exr"), ("seq/#.exr", "seq/1-3#.exr"), ("seq/foo_#.exr", "seq/foo_1#.exr"), ("seq/foo_#_extra.exr", None), ("seq/foo_##.exr", None), ("seq/[email protected]", None), ("seq/big.#.ext", "seq/big.999-1003#.ext"), ("seq/big.@@@.ext", "seq/big.1000-1003@@@.ext"), ("seq/[email protected]", "seq/[email protected]"), ("seq/big.#@.ext", None), ] for pattern, expected in tests: if expected is None: with self.assertRaises(FileSeqException): findSequenceOnDisk(pattern, strictPadding=True) continue seq = findSequenceOnDisk(pattern, strictPadding=True) self.assertTrue(isinstance(seq, FileSequence)) actual = str(seq) self.assertEqual(actual, expected)
def testPaddingMatch(self): tests = [ ("mixed/seq.#.ext", "mixed/seq.-1-5#.ext"), ("mixed/seq.@@.ext", "mixed/seq.-1-5@@.ext"), ("mixed/seq.@@@@@.ext", "mixed/seq.-1-5@@@@@.ext"), ("mixed/[email protected]", "mixed/[email protected]"), ("mixed/seq.##.ext", None), ("mixed/seq.%04d.ext", "mixed/seq.-1-5#.ext"), ("mixed/seq.%02d.ext", "mixed/seq.-1-5@@.ext"), ("mixed/seq.%05d.ext", "mixed/seq.-1-5@@@@@.ext"), ("mixed/seq.%01d.ext", "mixed/[email protected]"), ("mixed/seq.%08d.ext", None), ] for pattern, expected in tests: if expected is None: with self.assertRaises(FileSeqException): findSequenceOnDisk(pattern, strictPadding=True) continue seq = findSequenceOnDisk(pattern, strictPadding=True) self.assertTrue(isinstance(seq, FileSequence)) actual = str(seq) self.assertEqual(actual, expected)
def testStrictPadding(self): tests = [ ("seq/bar#.exr", "seq/bar1000-1002,1004-1006#.exr"), ("seq/bar@@@@.exr", "seq/bar1000-1002,1004-1006#.exr"), ("seq/bar@@@.exr", None), ("seq/foo.#.exr", "seq/foo.1-5#.exr"), ("seq/foo.#.jpg", "seq/foo.1-5#.jpg"), ("seq/foo.#.exr", "seq/foo.1-5#.exr"), ("seq/foo.debug.#.exr", "seq/foo.debug.1-5#.exr"), ("seq/#.exr", "seq/1-3#.exr"), ("seq/foo_#.exr", "seq/foo_1#.exr"), ("seq/foo_#_extra.exr", "seq/foo_1#_extra.exr"), ("seq/foo_##.exr", None), ("seq/[email protected]", None), ] for pattern, expected in tests: if expected is None: with self.assertRaises(fileseq.FileSeqException): findSequenceOnDisk(pattern, strictPadding=True) return seq = findSequenceOnDisk(pattern, strictPadding=True) self.assertTrue(isinstance(seq, FileSequence)) actual = str(seq) self.assertEqual(actual, expected)
def fitting(self): img_seq = None for d in self.fso.props.dirs: p = d.__str__() exr_name = f'{self.fso.props.shot_name}.#.exr' exr_ver_name = f'{self.fso.props.shot_name}_v{self.fso.props.version}.#.exr' seq_path = path.join(p, exr_name) seq_ver_path = path.join(p, exr_ver_name) dir_seq = None try: dir_seq = fileseq.findSequenceOnDisk(seq_path) except: pass try: dir_seq = fileseq.findSequenceOnDisk(seq_ver_path) except: pass if not dir_seq: break img_seq = dir_seq # if if img_seq: self.fso.props.img_seq = img_seq else: self.fso.props.error = (f'Secuencia de imgágenes no encontrado') self.state.raise_error()
def readOPPJsonSequence(jsonSequencePattern, imageSequencePattern, inputVideoFilename): print("Reading json sequence:", imageSequencePattern) sequenceObj = fileseq.findSequenceOnDisk(jsonSequencePattern) print("Sequence frame-range: [", str(sequenceObj.start()), ", ", str(sequenceObj.end()), "]") cap = None imageSeqObj = None # extract image height from the first frame in the sequence if len(inputVideoFilename) > 0: cap = cv2.VideoCapture(inputVideoFilename) numFrames = cap.get(cv2.CAP_PROP_FRAME_COUNT) if numFrames != (sequenceObj.end() - sequenceObj.start() + 1): raise ValueError('Video has %s frames but detections contain %s frames' % ( numFrames, (sequenceObj.end() - sequenceObj.start() + 1))) cap.set(cv2.CAP_PROP_POS_FRAMES, sequenceObj.start()) status, img = cap.read() else: imageSeqObj = fileseq.findSequenceOnDisk(imageSequencePattern) imageFilename = imageSeqObj.frame(sequenceObj.start()) # 1 means Color image to cv2.imread, 0 is grayscale, -1 is unchanged. img = cv2.imread(imageFilename, 1) height, width, channels = img.shape confidence = 0.15 framesData = {} for frameNum in range(sequenceObj.start(), sequenceObj.end() + 1): frameJsonFile = sequenceObj.frame(frameNum) with open(frameJsonFile) as jsonStream: try: jsonContent = json.load(jsonStream) except: print("Cannot open file: ", frameJsonFile) sys.exit(1) if frameNum % 100 == 0: print("Reading", frameJsonFile) frameData = [] for person in jsonContent['people']: keyPoints = np.array(person['pose_keypoints_2d']) undetectedPoints = keyPoints == 0 keyPoints[undetectedPoints] = np.nan detection = {} detection['KeyPoints'] = keyPoints.tolist() frameData.append(detection) # In Natron, videos begin at frame 1, not 0 framesData[str(frameNum+1)] = frameData ret = {} framesDataOrdered = OrderedDict( sorted(framesData.items(), key=lambda x: int(x[0]))) ret['Frames'] = framesDataOrdered return ret
def testCrossPlatformPathSep(self): tests = [ ("seq/bar#.exr", "seq\\bar1000-1002,1004-1006#.exr"), ("seq/foo.#.exr", "seq\\foo.1-5#.exr"), ("seq/foo.#.jpg", "seq\\foo.1-5#.jpg"), ("seq/foo.0002.jpg", "seq\\foo.1-5#.jpg"), ("seq/foo.#.exr", "seq\\foo.1-5#.exr"), ("seq/foo.debug.#.exr", "seq\\foo.debug.1-5#.exr"), ("seq/#.exr", "seq\\1-3#.exr"), ("seq/bar1001.exr", "seq/bar1001.exr"), ("seq/foo_0001.exr", "seq/foo_0001.exr"), ] import ntpath _path = os.path os.path = ntpath try: self.assertEqual(os.path.join('a', 'b'), 'a\\b') for pattern, expected in tests: seq = findSequenceOnDisk(pattern) self.assertTrue(isinstance(seq, FileSequence)) actual = str(seq) self.assertEqual(actual, expected) finally: os.path = _path
def testCrossPlatformPathSep(self): tests = [ ("seq/bar#.exr", "seq\\bar1000-1002,1004-1006#.exr"), ("seq/foo.#.exr", "seq\\foo.1-5#.exr"), ("seq/foo.#.jpg", "seq\\foo.1-5#.jpg"), ("seq/foo.0002.jpg", "seq\\foo.1-5#.jpg"), ("seq/foo.#.exr", "seq\\foo.1-5#.exr"), ("seq/foo.debug.#.exr", "seq\\foo.debug.1-5#.exr"), ("seq/#.exr", "seq\\1-3#.exr"), ("seq/bar1001.exr", "seq/bar1001.exr"), ("seq/foo_0001.exr", "seq/foo_0001.exr"), ] import ntpath _path = os.path os.path = ntpath try: self.assertEqual(os.path.join('a', 'b'), 'a\\b') for pattern, expected in tests: seq = findSequenceOnDisk(pattern) self.assertTrue(isinstance(seq, FileSequence)) actual = str(seq) self.assertEqual(actual, expected) finally: os.path = _path
def _parseFileSeqs(self): if self._readPoly: try: polySeq = findSequenceOnDisk(self.outputDir + '/[email protected]') self._minFramePoly = polySeq.start() self._maxFramePoly = polySeq.end() except FileSeqException: raise IOError("Could not locate any polymer configuration files in '%s'" % self.outputDir) if self._readLiq: try: liqSeq = findSequenceOnDisk(self.outputDir + '/[email protected]') self._minFrameLiq = liqSeq.start() self._maxFrameLiq = liqSeq.end() except FileSeqException: raise IOError("Could not locate any liquid configuration files in '%s'" % self.outputDir)
def testFindSequenceOnDisk(self): tests = [ ("seq/bar#.exr", "seq/bar1000-1002,1004-1006#.exr"), ("seq/foo.#.exr", "seq/foo.1-5#.exr"), ("seq/foo.#.jpg", "seq/foo.1-5#.jpg"), ] for pattern, expected in tests: seq = fileseq.findSequenceOnDisk(pattern) self.assertTrue(isinstance(seq, fileseq.FileSequence)) actual = str(seq) self.assertEqual(actual, expected)
def testFindSequenceOnDisk(self): tests = [ ("seq/bar#.exr", "seq/bar1000-1002,1004-1006#.exr"), ("seq/foo.#.exr", "seq/foo.1-5#.exr"), ("seq/foo.#.jpg", "seq/foo.1-5#.jpg"), ] for pattern, expected in tests: seq = fileseq.findSequenceOnDisk(pattern) self.assertTrue(isinstance(seq, fileseq.FileSequence)) actual = str(seq) self.assertEqual(actual, expected)
def move_file_sequence(source, destination): """ Moves a sequence of files from source to destination Args: source (str): Sequence filepath, eg, /path/to/file.####.png destination (str): Destination, using a single # for frames, eg, /path/to/renamed.#.png """ src_sequence = fileseq.findSequenceOnDisk(source) dst_sequence = fileseq.FileSequence(destination.replace("#", "1-1#")) dst_sequence.setFrameSet(src_sequence.frameSet()) for src_frame, dst_frame in zip(src_sequence, dst_sequence): shutil.move(src_frame, dst_frame)
def testFindSequenceOnDisk(self): tests = [ ("seq/bar#.exr", "seq/bar1000-1002,1004-1006#.exr"), ("seq/foo.#.exr", "seq/foo.1-5#.exr"), ("seq/foo.#.jpg", "seq/foo.1-5#.jpg"), ("seq/foo.0002.jpg", "seq/foo.1-5#.jpg"), ("seq/foo.#.exr", "seq/foo.1-5#.exr"), ("seq/foo.debug.#.exr", "seq/foo.debug.1-5#.exr"), ("seq/#.exr", "seq/1-3#.exr"), ("seq/bar1001.exr", "seq/bar1001.exr"), ("seq/foo_0001.exr", "seq/foo_0001.exr"), ] for pattern, expected in tests: seq = findSequenceOnDisk(pattern, strictPadding=False) self.assertTrue(isinstance(seq, FileSequence)) actual = str(seq) self.assertEqual(actual, expected)
def testFindSequenceOnDisk(self): tests = [ ("seq/bar#.exr", "seq/bar1000-1002,1004-1006#.exr"), ("seq/foo.#.exr", "seq/foo.1-5#.exr"), ("seq/foo.#.jpg", "seq/foo.1-5#.jpg"), ("seq/foo.0002.jpg", "seq/foo.1-5#.jpg"), ("seq/foo.#.exr", "seq/foo.1-5#.exr"), ("seq/foo.debug.#.exr", "seq/foo.debug.1-5#.exr"), ("seq/#.exr", "seq/1-3#.exr"), ("seq/bar1001.exr", "seq/bar1001.exr"), ("seq/foo_0001.exr", "seq/foo_0001.exr"), ] for pattern, expected in tests: seq = findSequenceOnDisk(pattern, strictPadding=False) self.assertTrue(isinstance(seq, FileSequence)) actual = str(seq) self.assertEqual(actual, expected)
def stamp_image(self, source, output, config_dict=None): res_x = image.get_image_width(source) res_y = image.get_image_height(source) top_band = config_dict.get('top_band', None) bottom_band = config_dict.get('bottom_band', None) # font_file = config_dict.get('text_font', 'Arial.ttf') font_file = 'Arial.ttf' font_family = config_dict.get('text_font_family', 'Regular') text_margin_x = config_dict.get('text_margin_x', 300) text_margin_y = config_dict.get('text_margin_y', 100) framecode = config_dict.get('framecode', '00:00:00:00') top_band_height = 0 if top_band and os.path.isfile(top_band): top_band_height = image.get_image_height(top_band) res_y += top_band_height bottom_band_height = 0 if bottom_band and os.path.isfile(bottom_band): bottom_band_height = image.get_image_height(bottom_band) res_y += bottom_band_height font_db = QFontDatabase() font_db.addApplicationFont(font_file) text_font = QFont(font_family) font_size = 32 font_height = QFontMetrics(text_font).height() user = str(artellapipe.Tracker().get_user_name()) shot_name = config_dict.get('shot_name', '') or '' task_name = config_dict.get('task_name', '') or '' task_comment = str(config_dict.get('task_comment', '')) if artellapipe.Tracker().is_tracking_available(): fps = artellapipe.Tracker().get_project_fps() else: fps = 24 camera = str(config_dict.get('camera', 'No camera')) start_frame = str(config_dict.get('start_frame', None)) focal_length = None if camera and camera != 'No camera' and tp.Dcc.object_exists(camera): focal_length = tp.Dcc.get_camera_focal_length(camera) sequence = fileseq.findSequenceOnDisk(source) frames_dict = OrderedDict() total_frames = len(sequence) for i in range(total_frames): sequence_frame = sequence[i] empty_frame_path = self._get_temp_file_path( sequence_frame, 'empty') empty_frame = image.create_empty_image( empty_frame_path, resolution_x=res_x, resolution_y=res_y, background_color=[92, 92, 92]) frames_dict[sequence_frame] = empty_frame frame_outputs = dict() for i, (frame, empty_frame) in enumerate(frames_dict.items()): # Overlay playblast stream = ffmpeglib.overlay_inputs(empty_frame, frame, y=top_band_height) # Overlay top and bottom bands if top_band: stream = ffmpeglib.overlay_inputs(stream, top_band) if bottom_band: stream = ffmpeglib.overlay_inputs(stream, bottom_band, y=res_y - bottom_band_height) # Draw task and comment texts stream = ffmpeglib.draw_text(stream, task_name, x=40, y=text_margin_y + font_height, font_file=font_file, font_size=font_size) stream = ffmpeglib.draw_text(stream, task_comment, x=40, y=text_margin_y + (font_height * 2) + 25, font_file=font_file, font_size=font_size) # Draw frame current_frame = int(float(start_frame)) + i fps_text = '{} ({})'.format(current_frame, i + 1) stream = ffmpeglib.draw_text(stream, fps_text, x=40, y=res_y - font_height - text_margin_y - 70, font_file=font_file, font_size=font_size) # Draw camera name and focal length texts camera_text_width = QFontMetrics(text_font).width(camera) stream = ffmpeglib.draw_text(stream, camera, x=res_x / 2 - camera_text_width, y=res_y - font_height - text_margin_y - 70, font_file=font_file, font_size=font_size) fps_text = 'FPS: {}'.format(str(int(float(fps)))) if focal_length: fps_text = ' Focal Length: {}'.format(focal_length) fps_focal_length_width = QFontMetrics(text_font).width( str(fps_text)) stream = ffmpeglib.draw_text(stream, fps_text, x=res_x / 2 - fps_focal_length_width, y=res_y - font_height - text_margin_y - 20, font_file=font_file, font_size=font_size) # Draw user and shot texts user_text_width = QFontMetrics(text_font).width(user) shot_text_width = QFontMetrics(text_font).width(shot_name) user_shot_text_width = max(user_text_width, shot_text_width) stream = ffmpeglib.draw_text( stream, user, x=res_x - user_shot_text_width - text_margin_x, y=res_y - font_height - text_margin_y - 70, font_file=font_file, font_size=font_size) stream = ffmpeglib.draw_text( stream, shot_name, x=res_x - user_shot_text_width - text_margin_x, y=res_y - font_height - text_margin_y - 20, font_file=font_file, font_size=font_size) new_file_path = self._get_temp_file_path(empty_frame, 'main', index=i) frame_save = ffmpeglib.save_to_file(stream, new_file_path) frame_outputs[new_file_path] = frame_save if not frame_outputs: return frame_paths = frame_outputs.keys() frame_outs = frame_outputs.values() ffmpeglib.run_multiples_outputs_at_once(frame_outs) for frame_path in frame_paths: if not frame_path or not os.path.isfile(frame_path): LOGGER.warning( 'Some frames were not generated properly. Aborting operation ...' ) return video_file_path = self._get_temp_file_path(source, 'video') if not video_file_path.endswith('.mp4'): video_file_path_split = os.path.splitext(video_file_path) video_file_path = '{}.mp4'.format(video_file_path_split[0]) ffmpeglib.create_video_from_sequence_file(frame_paths[0], video_file_path) if not os.path.isfile(video_file_path): LOGGER.error('Error while stamping playblast video ...') return # scale = ffmpeglib.scale_video(video_file_path, 1920, 1080) # ffmpeglib.save_to_file(scale, output, run_stream=True) draw_timestamp_stream = ffmpeglib.draw_timestamp_on_video( video_file_path, text='Time: ', x=40, y=res_y - font_height - text_margin_y - 20, font_file=font_file, font_size=font_size, timecode_rate=fps, timecode=framecode) ffmpeglib.save_to_file(draw_timestamp_stream, output, run_stream=True) return output
def testFindSequenceOnDisk(self): seq = fileseq.findSequenceOnDisk("seq/bar#.exr") self.assertTrue(isinstance(seq, fileseq.FileSequence)) self.assertEqual(str(seq), "seq/bar1000-1002,1004-1006#.exr")