From 24f26d049f64753d427246517e62938c8f329e66 Mon Sep 17 00:00:00 2001 From: Emiliana <38952746+emilianavt@users.noreply.github.com> Date: Thu, 12 Aug 2021 13:51:44 +0200 Subject: [PATCH 01/52] Updated README. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 58f2457..3ec75c3 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ # Overview -**Note**: This is a tracking library, **not** a stand-alone avatar puppeteering program. I'm also working on [VSeeFace](https://www.vseeface.icu/), which allows animating [VRM](https://vrm.dev/en/how_to_make_vrm/) and [VSFAvatar](https://www.youtube.com/watch?v=jhQ8DF87I5I) 3D models by using OpenSeeFace tracking. [VTube Studio](https://denchisoft.com/) uses OpenSeeFace for webcam based tracking to animate Live2D models. +**Note**: This is a tracking library, **not** a stand-alone avatar puppeteering program. I'm also working on [VSeeFace](https://www.vseeface.icu/), which allows animating [VRM](https://vrm.dev/en/how_to_make_vrm/) and [VSFAvatar](https://www.youtube.com/watch?v=jhQ8DF87I5I) 3D models by using OpenSeeFace tracking. [VTube Studio](https://denchisoft.com/) uses OpenSeeFace for webcam based tracking to animate Live2D models. A fork working with the Godot engine can be found [here](https://github.com/you-win/openseeface-gd). This project implements a facial landmark detection model based on MobileNetV3. From c5ff6a8fe1c4bb11223d7bdbd53b395a6501395f Mon Sep 17 00:00:00 2001 From: Emiliana <38952746+emilianavt@users.noreply.github.com> Date: Thu, 12 Aug 2021 13:52:45 +0200 Subject: [PATCH 02/52] Updated README. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3ec75c3..2db1fed 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ # Overview -**Note**: This is a tracking library, **not** a stand-alone avatar puppeteering program. I'm also working on [VSeeFace](https://www.vseeface.icu/), which allows animating [VRM](https://vrm.dev/en/how_to_make_vrm/) and [VSFAvatar](https://www.youtube.com/watch?v=jhQ8DF87I5I) 3D models by using OpenSeeFace tracking. [VTube Studio](https://denchisoft.com/) uses OpenSeeFace for webcam based tracking to animate Live2D models. A fork working with the Godot engine can be found [here](https://github.com/you-win/openseeface-gd). +**Note**: This is a tracking library, **not** a stand-alone avatar puppeteering program. I'm also working on [VSeeFace](https://www.vseeface.icu/), which allows animating [VRM](https://vrm.dev/en/how_to_make_vrm/) and [VSFAvatar](https://www.youtube.com/watch?v=jhQ8DF87I5I) 3D models by using OpenSeeFace tracking. [VTube Studio](https://denchisoft.com/) uses OpenSeeFace for webcam based tracking to animate Live2D models. A renderer for the Godot engine can be found [here](https://github.com/you-win/openseeface-gd). This project implements a facial landmark detection model based on MobileNetV3. From 44d97a967c701ecedc34b52532cd6e5eb2e82a07 Mon Sep 17 00:00:00 2001 From: Emiliana <38952746+emilianavt@users.noreply.github.com> Date: Sat, 11 Sep 2021 15:56:25 +0200 Subject: [PATCH 03/52] Adjusted eye landmark display threshold. --- facetracker.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/facetracker.py b/facetracker.py index 96c4ad3..803359b 100644 --- a/facetracker.py +++ b/facetracker.py @@ -305,9 +305,9 @@ try: packet.extend(bytearray(struct.pack("f", x))) if not log is None: log.write(f",{y},{x},{c}") - if pt_num == 66 and (f.eye_blink[0] < 0.30 or c < 0.30): + if pt_num == 66 and (f.eye_blink[0] < 0.30 or c < 0.20): continue - if pt_num == 67 and (f.eye_blink[1] < 0.30 or c < 0.30): + if pt_num == 67 and (f.eye_blink[1] < 0.30 or c < 0.20): continue x = int(x + 0.5) y = int(y + 0.5) From 1264cc255cb233627a62ed83607361f8132dfde2 Mon Sep 17 00:00:00 2001 From: Emiliana <38952746+emilianavt@users.noreply.github.com> Date: Sat, 11 Sep 2021 15:57:03 +0200 Subject: [PATCH 04/52] Changed gaze tracking to always use single thread to avoid excessive CPU usage. --- tracker.py | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/tracker.py b/tracker.py index a22190b..f5cbcc7 100644 --- a/tracker.py +++ b/tracker.py @@ -140,7 +140,7 @@ def worker_thread(session, frame, input, crop_info, queue, input_name, idx, trac conf, lms = tracker.landmarks(output[0], crop_info) if conf > tracker.threshold: try: - eye_state = tracker.get_eye_state(frame, lms, single=True) + eye_state = tracker.get_eye_state(frame, lms) except: eye_state = [(1.0, 0.0, 0.0, 0.0), (1.0, 0.0, 0.0, 0.0)] queue.put((session, conf, (lms, eye_state), crop_info, idx)) @@ -548,14 +548,12 @@ class Tracker(): self.input_name = self.session.get_inputs()[0].name options = onnxruntime.SessionOptions() - options.inter_op_num_threads = 1 - options.intra_op_num_threads = max(max_threads,4) + #options.intra_op_num_threads = max(max_threads,4) + options.intra_op_num_threads = 1 options.execution_mode = onnxruntime.ExecutionMode.ORT_SEQUENTIAL options.graph_optimization_level = onnxruntime.GraphOptimizationLevel.ORT_ENABLE_ALL options.log_severity_level = 3 self.gaze_model = onnxruntime.InferenceSession(os.path.join(model_base_path, "mnv3_gaze32_split_opt.onnx"), sess_options=options) - options.intra_op_num_threads = 1 - self.gaze_model_single = onnxruntime.InferenceSession(os.path.join(model_base_path, "mnv3_gaze32_split_opt.onnx"), sess_options=options) self.detection = onnxruntime.InferenceSession(os.path.join(model_base_path, "mnv3_detection_opt.onnx"), sess_options=options) self.faces = [] @@ -922,7 +920,7 @@ class Tracker(): frame = frame[y1:y2, x1:x2] return frame, lms, offset - def get_eye_state(self, frame, lms, single=False): + def get_eye_state(self, frame, lms): if self.no_gaze: return [(1.0, 0.0, 0.0, 0.0), (1.0, 0.0, 0.0, 0.0)] lms = np.array(lms) @@ -938,10 +936,7 @@ class Tracker(): return [(1.0, 0.0, 0.0, 0.0), (1.0, 0.0, 0.0, 0.0)] both_eyes = np.concatenate((right_eye, left_eye)) results = None - if single: - results = self.gaze_model_single.run([], {self.input_name: both_eyes}) - else: - results = self.gaze_model.run([], {self.input_name: both_eyes}) + results = self.gaze_model.run([], {self.input_name: both_eyes}) open = [0, 0] open[0] = 1#results[1][0].argmax() open[1] = 1#results[1][1].argmax() From e49cbdb9c01b5135982d8faa6c4369ccfd121408 Mon Sep 17 00:00:00 2001 From: Autumn Date: Fri, 1 Oct 2021 02:35:00 +1000 Subject: [PATCH 05/52] Enable the --fps option on non Windows systems & set CAP_PROP_BUFFERSIZE to 1 when using OpenCV for live capture --- facetracker.py | 7 +++---- input_reader.py | 1 + 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/facetracker.py b/facetracker.py index f7d4dcc..820c363 100644 --- a/facetracker.py +++ b/facetracker.py @@ -13,12 +13,12 @@ if os.name == 'nt': parser.add_argument("-a", "--list-dcaps", type=int, help="Set this to -1 to list all cameras and their available capabilities, set this to a camera id to list that camera's capabilities", default=None) parser.add_argument("-W", "--width", type=int, help="Set camera and raw RGB width", default=640) parser.add_argument("-H", "--height", type=int, help="Set camera and raw RGB height", default=360) - parser.add_argument("-F", "--fps", type=int, help="Set camera frames per second", default=24) parser.add_argument("-D", "--dcap", type=int, help="Set which device capability line to use or -1 to use the default camera settings", default=None) parser.add_argument("-B", "--blackmagic", type=int, help="When set to 1, special support for Blackmagic devices is enabled", default=0) else: parser.add_argument("-W", "--width", type=int, help="Set raw RGB width", default=640) parser.add_argument("-H", "--height", type=int, help="Set raw RGB height", default=360) +parser.add_argument("-F", "--fps", type=int, help="Set camera frames per second", default=24) parser.add_argument("-c", "--capture", help="Set camera ID (0, 1...) or video file", default="0") parser.add_argument("-M", "--mirror-input", action="store_true", help="Process a mirror image of the input video") parser.add_argument("-m", "--max-threads", type=int, help="Set the maximum number of threads", default=1) @@ -153,18 +153,17 @@ target_port = args.port if args.faces >= 40: print("Transmission of tracking data over network is not supported with 40 or more faces.") -fps = 0 +fps = args.fps dcap = None use_dshowcapture_flag = False if os.name == 'nt': - fps = args.fps dcap = args.dcap use_dshowcapture_flag = True if args.use_dshowcapture == 1 else False input_reader = InputReader(args.capture, args.raw_rgb, args.width, args.height, fps, use_dshowcapture=use_dshowcapture_flag, dcap=dcap) if args.dcap == -1 and type(input_reader) == DShowCaptureReader: fps = min(fps, input_reader.device.get_fps()) else: - input_reader = InputReader(args.capture, args.raw_rgb, args.width, args.height, fps, use_dshowcapture=use_dshowcapture_flag) + input_reader = InputReader(args.capture, args.raw_rgb, args.width, args.height, fps) if type(input_reader.reader) == VideoReader: fps = 0 diff --git a/input_reader.py b/input_reader.py index 30e7bb6..8a1c440 100644 --- a/input_reader.py +++ b/input_reader.py @@ -111,6 +111,7 @@ class OpenCVReader(VideoReader): super(OpenCVReader, self).__init__(capture, camera=True) self.cap.set(3, width) self.cap.set(4, height) + self.cap.set(38, 1) def is_open(self): return super(OpenCVReader, self).is_open() def is_ready(self): From 2eec12225b9af6393657ebf5c81edb3192aef79e Mon Sep 17 00:00:00 2001 From: Emiliana <38952746+emilianavt@users.noreply.github.com> Date: Wed, 6 Oct 2021 02:07:28 +0200 Subject: [PATCH 06/52] Added missing setting for onnxruntime session. --- tracker.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tracker.py b/tracker.py index f5cbcc7..97ba6c4 100644 --- a/tracker.py +++ b/tracker.py @@ -548,7 +548,7 @@ class Tracker(): self.input_name = self.session.get_inputs()[0].name options = onnxruntime.SessionOptions() - #options.intra_op_num_threads = max(max_threads,4) + options.inter_op_num_threads = 1 options.intra_op_num_threads = 1 options.execution_mode = onnxruntime.ExecutionMode.ORT_SEQUENTIAL options.graph_optimization_level = onnxruntime.GraphOptimizationLevel.ORT_ENABLE_ALL From 85ce0d5c3f7e965e5eddb6ed0d504a41e0bc2176 Mon Sep 17 00:00:00 2001 From: Zutatensuppe Date: Sat, 30 Oct 2021 15:44:04 +0200 Subject: [PATCH 07/52] add pyproject.toml and poetry.lock --- poetry.lock | 224 +++++++++++++++++++++++++++++++++++++++++++++++++ pyproject.toml | 19 +++++ 2 files changed, 243 insertions(+) create mode 100644 poetry.lock create mode 100644 pyproject.toml diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 0000000..a3c4c1b --- /dev/null +++ b/poetry.lock @@ -0,0 +1,224 @@ +[[package]] +name = "flatbuffers" +version = "2.0" +description = "The FlatBuffers serialization format for Python" +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "numpy" +version = "1.21.3" +description = "NumPy is the fundamental package for array computing with Python." +category = "main" +optional = false +python-versions = ">=3.7,<3.11" + +[[package]] +name = "onnxruntime" +version = "1.9.0" +description = "ONNX Runtime is a runtime accelerator for Machine Learning models" +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +flatbuffers = "*" +numpy = ">=1.16.6" +protobuf = "*" + +[[package]] +name = "opencv-python" +version = "4.5.4.58" +description = "Wrapper package for OpenCV python bindings." +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +numpy = ">=1.21.2" + +[[package]] +name = "pillow" +version = "8.4.0" +description = "Python Imaging Library (Fork)" +category = "main" +optional = false +python-versions = ">=3.6" + +[[package]] +name = "protobuf" +version = "3.19.1" +description = "Protocol Buffers" +category = "main" +optional = false +python-versions = ">=3.5" + +[metadata] +lock-version = "1.1" +python-versions = ">=3.7,<3.11" +content-hash = "1511681290c580145b1117beffe728052d856eee3ad8419930626c6fc6c9a09d" + +[metadata.files] +flatbuffers = [ + {file = "flatbuffers-2.0-py2.py3-none-any.whl", hash = "sha256:3751954f0604580d3219ae49a85fafec9d85eec599c0b96226e1bc0b48e57474"}, + {file = "flatbuffers-2.0.tar.gz", hash = "sha256:12158ab0272375eab8db2d663ae97370c33f152b27801fa6024e1d6105fd4dd2"}, +] +numpy = [ + {file = "numpy-1.21.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:508b0b513fa1266875524ba8a9ecc27b02ad771fe1704a16314dc1a816a68737"}, + {file = "numpy-1.21.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5dfe9d6a4c39b8b6edd7990091fea4f852888e41919d0e6722fe78dd421db0eb"}, + {file = "numpy-1.21.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8a10968963640e75cc0193e1847616ab4c718e83b6938ae74dea44953950f6b7"}, + {file = "numpy-1.21.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49c6249260890e05b8111ebfc391ed58b3cb4b33e63197b2ec7f776e45330721"}, + {file = "numpy-1.21.3-cp310-cp310-win_amd64.whl", hash = "sha256:f8f4625536926a155b80ad2bbff44f8cc59e9f2ad14cdda7acf4c135b4dc8ff2"}, + {file = "numpy-1.21.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e54af82d68ef8255535a6cdb353f55d6b8cf418a83e2be3569243787a4f4866f"}, + {file = "numpy-1.21.3-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:f41b018f126aac18583956c54544db437f25c7ee4794bcb23eb38bef8e5e192a"}, + {file = "numpy-1.21.3-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:50cd26b0cf6664cb3b3dd161ba0a09c9c1343db064e7c69f9f8b551f5104d654"}, + {file = "numpy-1.21.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4cc9b512e9fb590797474f58b7f6d1f1b654b3a94f4fa8558b48ca8b3cfc97cf"}, + {file = "numpy-1.21.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:88a5d6b268e9ad18f3533e184744acdaa2e913b13148160b1152300c949bbb5f"}, + {file = "numpy-1.21.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:3c09418a14471c7ae69ba682e2428cae5b4420a766659605566c0fa6987f6b7e"}, + {file = "numpy-1.21.3-cp37-cp37m-win32.whl", hash = "sha256:90bec6a86b348b4559b6482e2b684db4a9a7eed1fa054b86115a48d58fbbf62a"}, + {file = "numpy-1.21.3-cp37-cp37m-win_amd64.whl", hash = "sha256:043e83bfc274649c82a6f09836943e4a4aebe5e33656271c7dbf9621dd58b8ec"}, + {file = "numpy-1.21.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:75621882d2230ab77fb6a03d4cbccd2038511491076e7964ef87306623aa5272"}, + {file = "numpy-1.21.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:188031f833bbb623637e66006cf75e933e00e7231f67e2b45cf8189612bb5dc3"}, + {file = "numpy-1.21.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:160ccc1bed3a8371bf0d760971f09bfe80a3e18646620e9ded0ad159d9749baa"}, + {file = "numpy-1.21.3-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:29fb3dcd0468b7715f8ce2c0c2d9bbbaf5ae686334951343a41bd8d155c6ea27"}, + {file = "numpy-1.21.3-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:32437f0b275c1d09d9c3add782516413e98cd7c09e6baf4715cbce781fc29912"}, + {file = "numpy-1.21.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e606e6316911471c8d9b4618e082635cfe98876007556e89ce03d52ff5e8fcf0"}, + {file = "numpy-1.21.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a99a6b067e5190ac6d12005a4d85aa6227c5606fa93211f86b1dafb16233e57d"}, + {file = "numpy-1.21.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:dde972a1e11bb7b702ed0e447953e7617723760f420decb97305e66fb4afc54f"}, + {file = "numpy-1.21.3-cp38-cp38-win32.whl", hash = "sha256:fe52dbe47d9deb69b05084abd4b0df7abb39a3c51957c09f635520abd49b29dd"}, + {file = "numpy-1.21.3-cp38-cp38-win_amd64.whl", hash = "sha256:75eb7cadc8da49302f5b659d40ba4f6d94d5045fbd9569c9d058e77b0514c9e4"}, + {file = "numpy-1.21.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2a6ee9620061b2a722749b391c0d80a0e2ae97290f1b32e28d5a362e21941ee4"}, + {file = "numpy-1.21.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5c4193f70f8069550a1788bd0cd3268ab7d3a2b70583dfe3b2e7f421e9aace06"}, + {file = "numpy-1.21.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28f15209fb535dd4c504a7762d3bc440779b0e37d50ed810ced209e5cea60d96"}, + {file = "numpy-1.21.3-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:c6c2d535a7beb1f8790aaa98fd089ceab2e3dd7ca48aca0af7dc60e6ef93ffe1"}, + {file = "numpy-1.21.3-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:bffa2eee3b87376cc6b31eee36d05349571c236d1de1175b804b348dc0941e3f"}, + {file = "numpy-1.21.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc14e7519fab2a4ed87d31f99c31a3796e4e1fe63a86ebdd1c5a1ea78ebd5896"}, + {file = "numpy-1.21.3-cp39-cp39-win32.whl", hash = "sha256:dd0482f3fc547f1b1b5d6a8b8e08f63fdc250c58ce688dedd8851e6e26cff0f3"}, + {file = "numpy-1.21.3-cp39-cp39-win_amd64.whl", hash = "sha256:300321e3985c968e3ae7fbda187237b225f3ffe6528395a5b7a5407f73cf093e"}, + {file = "numpy-1.21.3-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98339aa9911853f131de11010f6dd94c8cec254d3d1f7261528c3b3e3219f139"}, + {file = "numpy-1.21.3.zip", hash = "sha256:63571bb7897a584ca3249c86dd01c10bcb5fe4296e3568b2e9c1a55356b6410e"}, +] +onnxruntime = [ + {file = "onnxruntime-1.9.0-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:48f0fcf3c9aa6836584e64abe63fa7395c02066d3259bbdeb489b4d172e0127a"}, + {file = "onnxruntime-1.9.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7f9d772a6330cb85e7723f84e357320a1603e3824a92aab4ef36fc3a41e64f16"}, + {file = "onnxruntime-1.9.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3bdb861822a63404cca7b46dce86d48bbc21c906a4b4ed13969bc89763ac7f96"}, + {file = "onnxruntime-1.9.0-cp36-cp36m-win32.whl", hash = "sha256:e3f8f7d5d4d66e3a4a2b731a000d3142a53a5403e8814e68bbd659514e815899"}, + {file = "onnxruntime-1.9.0-cp36-cp36m-win_amd64.whl", hash = "sha256:cf3edbc54bfe99a119d73cd65398a2ec68ae3af2557ab7e645976314a8d11aa1"}, + {file = "onnxruntime-1.9.0-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:c8ff9c914b2b1c3b022dedc199e3f971e340d8923a1ef42d66530508fa367bf6"}, + {file = "onnxruntime-1.9.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9d03ff4a2717c4149acc7c649fd66a67e81ec44c9e6e2a00df1d6e9ca843f1b7"}, + {file = "onnxruntime-1.9.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8a2315e2244ac371742f6e30da5367c680c3e84c31e291a35f8ddfab09c3c82"}, + {file = "onnxruntime-1.9.0-cp37-cp37m-win32.whl", hash = "sha256:fa927b1825f2851c0c8f3948515a56d76cb0686da9acd1d6f8fafe552c8d8fec"}, + {file = "onnxruntime-1.9.0-cp37-cp37m-win_amd64.whl", hash = "sha256:9ccaf6a0365f2b86efe21681416b8cfe97f084a7d53bd1cf2bf889a0aef2b0d3"}, + {file = "onnxruntime-1.9.0-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:d20ce3448babe89a77cc9d357730767deb3617e36439bddcd006f28abc72b416"}, + {file = "onnxruntime-1.9.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3fd1d6647245aa38e1099cfd355d84e807de5350d5216e84ceefd91c64ce243d"}, + {file = "onnxruntime-1.9.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f00620fc0f51bc4d90ae6d96ceb4b6538e3bd1e328178104118ac672f37c40d"}, + {file = "onnxruntime-1.9.0-cp38-cp38-win32.whl", hash = "sha256:e1c1fe3f7d960eeffc02a5f196d85529254eefd59cbeecd8abee0a9467b5c2d8"}, + {file = "onnxruntime-1.9.0-cp38-cp38-win_amd64.whl", hash = "sha256:9002214af1b2317ab3a63a2f045f7d1363c207e661d475a877aa6499ca09d606"}, + {file = "onnxruntime-1.9.0-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:7339cef9b918b88f1fec8109cfa0a8416f119c5968d00300a9186847d86e35de"}, + {file = "onnxruntime-1.9.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cdec8538eb59e63a376d0677f7ec043ceb597d52ee88f1f7e250928893a0de7f"}, + {file = "onnxruntime-1.9.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab62b29429e0e62c11478b2a8a3af2646531fba7800736e8b201d8baa50b43a8"}, + {file = "onnxruntime-1.9.0-cp39-cp39-win32.whl", hash = "sha256:4aee9a893f93637341fd0e6b56fa3ab1c430d718d08d79a358603297a1575ad9"}, + {file = "onnxruntime-1.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:bdf1327932227383b04093a51266474b2703b3fcf9c0f6f11c652d9652b76a5c"}, +] +opencv-python = [ + {file = "opencv-python-4.5.4.58.tar.gz", hash = "sha256:48288428f407bacba5f73d460feb4a1ecafe87db3d7cfc0730a49fb32f589bbf"}, + {file = "opencv_python-4.5.4.58-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0eba0bfe62c48a02a5af3a0944e872c99f57f98653bed14d51c6991a58f9e1d1"}, + {file = "opencv_python-4.5.4.58-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:9bcca50c5444b5cfb01624666b69f91ba8f2d2bf4ef37b111697aafdeb81c99f"}, + {file = "opencv_python-4.5.4.58-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:8f7886acabaebf0361bd3dbccaa0d08e3f65ab13b7c739eb11e028f01ad13582"}, + {file = "opencv_python-4.5.4.58-cp310-cp310-manylinux2014_x86_64.whl", hash = "sha256:d4b1d0b98ee72ba5dd720166790fc93ce459281e138ee79b0d41420b3da52b2e"}, + {file = "opencv_python-4.5.4.58-cp310-cp310-win32.whl", hash = "sha256:69a78e40a374ac14e4bf15a13dbb6c30fd2fbd5fcd3674d020a31b88861d5aaf"}, + {file = "opencv_python-4.5.4.58-cp310-cp310-win_amd64.whl", hash = "sha256:315c357522b6310ef7a0718d9f0c5d3110e59c19140705499a3c29bdd8c0124f"}, + {file = "opencv_python-4.5.4.58-cp36-cp36m-macosx_10_15_x86_64.whl", hash = "sha256:887a61097092dc0bf23fa24646dbc8cfeeb753649cb28a3782a93a6879e3b7d2"}, + {file = "opencv_python-4.5.4.58-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:22bcc3153a7d4f95aff79457eef81ef5e40ab1851b189e014412b5e9fbee2573"}, + {file = "opencv_python-4.5.4.58-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:92e9b2261ec764229c948d77fe0d922ee033348ca6519939b87861016c1614b3"}, + {file = "opencv_python-4.5.4.58-cp36-cp36m-win32.whl", hash = "sha256:0d6249a49122a78afc6685ddb1377a87e46414ae61c84535c4c6024397f1f3e8"}, + {file = "opencv_python-4.5.4.58-cp36-cp36m-win_amd64.whl", hash = "sha256:eaa144013b597e4dcabc8d8230edfe810319de01b5609556d415a20e2b707547"}, + {file = "opencv_python-4.5.4.58-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:26feeeb280de179f5dbb8976ebf7ceb836bd263973cb5daec8ca36e8ef7b5773"}, + {file = "opencv_python-4.5.4.58-cp37-cp37m-macosx_11_0_arm64.whl", hash = "sha256:4a13381bdfc0fb4b080efcc27c46561d0bd752f126226e9f19aa9cbcf6677f40"}, + {file = "opencv_python-4.5.4.58-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:ac852fcaac93439f2f7116ddffdc23fd366c872200ade2272446f9898180cecb"}, + {file = "opencv_python-4.5.4.58-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:02872e0a9358526646d691f390143e9c21109c210095314abaa0641211cda077"}, + {file = "opencv_python-4.5.4.58-cp37-cp37m-win32.whl", hash = "sha256:6b87bab220d17e03eeedbcc6652d9d7e7bb09886dbd0f810310697a948b4c6fd"}, + {file = "opencv_python-4.5.4.58-cp37-cp37m-win_amd64.whl", hash = "sha256:a2a7f09b8843b85f3e1b02c5ea3ddc0cb9f5ad9698380109b37069ee8db7746d"}, + {file = "opencv_python-4.5.4.58-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:c44f5c51e92322ed832607204249c190764dec6cf29e8ba6d679b10326be1c1b"}, + {file = "opencv_python-4.5.4.58-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9b2c198af083a693d42a82bddc4d1f7e6bb02c64192ff7fac1fd1d43a8cf1be6"}, + {file = "opencv_python-4.5.4.58-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:637f4d3ad81bd27f273ede4c5fa6c26afb85c097c9715baf107cc270e37f5fea"}, + {file = "opencv_python-4.5.4.58-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:2fff48a641a74d1def31c1e88f9e5ce50ba4d0f87d085dfbf8bc844e12f6cd54"}, + {file = "opencv_python-4.5.4.58-cp38-cp38-win32.whl", hash = "sha256:8ddf4dcd8199209e33f21deb0c6d8ab62b21802816bba895fefc346b6d2e522d"}, + {file = "opencv_python-4.5.4.58-cp38-cp38-win_amd64.whl", hash = "sha256:085c5fcf5a6479c34aca3fd0f59055e704083d6a44009d6583c675ff1a5a0625"}, + {file = "opencv_python-4.5.4.58-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:4abe9c4fb6fe16daa9fcdd68b5357d3530431341aa655203f8e84f394e1fe6d4"}, + {file = "opencv_python-4.5.4.58-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4b614fbd81aeda53ce28e645aaee18fda7c7f2a48eb7f1a70a7c6c3427946342"}, + {file = "opencv_python-4.5.4.58-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:215bdf069847d4e3b0447a34e9eb4046dd4ca523d41fe4381c1c55f6704fd0dc"}, + {file = "opencv_python-4.5.4.58-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc34cdbfbab463750713118c8259a5d364547adab8ed91e94ba888349f33590a"}, + {file = "opencv_python-4.5.4.58-cp39-cp39-win32.whl", hash = "sha256:9998ce60884f3cda074f02b56d2b57ee6bd863e2ddba132da2b0af3b9487d584"}, + {file = "opencv_python-4.5.4.58-cp39-cp39-win_amd64.whl", hash = "sha256:5370a11757fbe94b176771269aff599f4da8676c2a672b13bcbca043f2e3eea8"}, +] +pillow = [ + {file = "Pillow-8.4.0-cp310-cp310-macosx_10_10_universal2.whl", hash = "sha256:81f8d5c81e483a9442d72d182e1fb6dcb9723f289a57e8030811bac9ea3fef8d"}, + {file = "Pillow-8.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3f97cfb1e5a392d75dd8b9fd274d205404729923840ca94ca45a0af57e13dbe6"}, + {file = "Pillow-8.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eb9fc393f3c61f9054e1ed26e6fe912c7321af2f41ff49d3f83d05bacf22cc78"}, + {file = "Pillow-8.4.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d82cdb63100ef5eedb8391732375e6d05993b765f72cb34311fab92103314649"}, + {file = "Pillow-8.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:62cc1afda735a8d109007164714e73771b499768b9bb5afcbbee9d0ff374b43f"}, + {file = "Pillow-8.4.0-cp310-cp310-win32.whl", hash = "sha256:e3dacecfbeec9a33e932f00c6cd7996e62f53ad46fbe677577394aaa90ee419a"}, + {file = "Pillow-8.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:620582db2a85b2df5f8a82ddeb52116560d7e5e6b055095f04ad828d1b0baa39"}, + {file = "Pillow-8.4.0-cp36-cp36m-macosx_10_10_x86_64.whl", hash = "sha256:1bc723b434fbc4ab50bb68e11e93ce5fb69866ad621e3c2c9bdb0cd70e345f55"}, + {file = "Pillow-8.4.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:72cbcfd54df6caf85cc35264c77ede902452d6df41166010262374155947460c"}, + {file = "Pillow-8.4.0-cp36-cp36m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:70ad9e5c6cb9b8487280a02c0ad8a51581dcbbe8484ce058477692a27c151c0a"}, + {file = "Pillow-8.4.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:25a49dc2e2f74e65efaa32b153527fc5ac98508d502fa46e74fa4fd678ed6645"}, + {file = "Pillow-8.4.0-cp36-cp36m-win32.whl", hash = "sha256:93ce9e955cc95959df98505e4608ad98281fff037350d8c2671c9aa86bcf10a9"}, + {file = "Pillow-8.4.0-cp36-cp36m-win_amd64.whl", hash = "sha256:2e4440b8f00f504ee4b53fe30f4e381aae30b0568193be305256b1462216feff"}, + {file = "Pillow-8.4.0-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:8c803ac3c28bbc53763e6825746f05cc407b20e4a69d0122e526a582e3b5e153"}, + {file = "Pillow-8.4.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c8a17b5d948f4ceeceb66384727dde11b240736fddeda54ca740b9b8b1556b29"}, + {file = "Pillow-8.4.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1394a6ad5abc838c5cd8a92c5a07535648cdf6d09e8e2d6df916dfa9ea86ead8"}, + {file = "Pillow-8.4.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:792e5c12376594bfcb986ebf3855aa4b7c225754e9a9521298e460e92fb4a488"}, + {file = "Pillow-8.4.0-cp37-cp37m-win32.whl", hash = "sha256:d99ec152570e4196772e7a8e4ba5320d2d27bf22fdf11743dd882936ed64305b"}, + {file = "Pillow-8.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:7b7017b61bbcdd7f6363aeceb881e23c46583739cb69a3ab39cb384f6ec82e5b"}, + {file = "Pillow-8.4.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:d89363f02658e253dbd171f7c3716a5d340a24ee82d38aab9183f7fdf0cdca49"}, + {file = "Pillow-8.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0a0956fdc5defc34462bb1c765ee88d933239f9a94bc37d132004775241a7585"}, + {file = "Pillow-8.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b7bb9de00197fb4261825c15551adf7605cf14a80badf1761d61e59da347779"}, + {file = "Pillow-8.4.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:72b9e656e340447f827885b8d7a15fc8c4e68d410dc2297ef6787eec0f0ea409"}, + {file = "Pillow-8.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a5a4532a12314149d8b4e4ad8ff09dde7427731fcfa5917ff16d0291f13609df"}, + {file = "Pillow-8.4.0-cp38-cp38-win32.whl", hash = "sha256:82aafa8d5eb68c8463b6e9baeb4f19043bb31fefc03eb7b216b51e6a9981ae09"}, + {file = "Pillow-8.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:066f3999cb3b070a95c3652712cffa1a748cd02d60ad7b4e485c3748a04d9d76"}, + {file = "Pillow-8.4.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:5503c86916d27c2e101b7f71c2ae2cddba01a2cf55b8395b0255fd33fa4d1f1a"}, + {file = "Pillow-8.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4acc0985ddf39d1bc969a9220b51d94ed51695d455c228d8ac29fcdb25810e6e"}, + {file = "Pillow-8.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b052a619a8bfcf26bd8b3f48f45283f9e977890263e4571f2393ed8898d331b"}, + {file = "Pillow-8.4.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:493cb4e415f44cd601fcec11c99836f707bb714ab03f5ed46ac25713baf0ff20"}, + {file = "Pillow-8.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8831cb7332eda5dc89b21a7bce7ef6ad305548820595033a4b03cf3091235ed"}, + {file = "Pillow-8.4.0-cp39-cp39-win32.whl", hash = "sha256:5e9ac5f66616b87d4da618a20ab0a38324dbe88d8a39b55be8964eb520021e02"}, + {file = "Pillow-8.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:3eb1ce5f65908556c2d8685a8f0a6e989d887ec4057326f6c22b24e8a172c66b"}, + {file = "Pillow-8.4.0-pp36-pypy36_pp73-macosx_10_10_x86_64.whl", hash = "sha256:ddc4d832a0f0b4c52fff973a0d44b6c99839a9d016fe4e6a1cb8f3eea96479c2"}, + {file = "Pillow-8.4.0-pp36-pypy36_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9a3e5ddc44c14042f0844b8cf7d2cd455f6cc80fd7f5eefbe657292cf601d9ad"}, + {file = "Pillow-8.4.0-pp36-pypy36_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c70e94281588ef053ae8998039610dbd71bc509e4acbc77ab59d7d2937b10698"}, + {file = "Pillow-8.4.0-pp37-pypy37_pp73-macosx_10_10_x86_64.whl", hash = "sha256:3862b7256046fcd950618ed22d1d60b842e3a40a48236a5498746f21189afbbc"}, + {file = "Pillow-8.4.0-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a4901622493f88b1a29bd30ec1a2f683782e57c3c16a2dbc7f2595ba01f639df"}, + {file = "Pillow-8.4.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:84c471a734240653a0ec91dec0996696eea227eafe72a33bd06c92697728046b"}, + {file = "Pillow-8.4.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:244cf3b97802c34c41905d22810846802a3329ddcb93ccc432870243211c79fc"}, + {file = "Pillow-8.4.0.tar.gz", hash = "sha256:b8e2f83c56e141920c39464b852de3719dfbfb6e3c99a2d8da0edf4fb33176ed"}, +] +protobuf = [ + {file = "protobuf-3.19.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d80f80eb175bf5f1169139c2e0c5ada98b1c098e2b3c3736667f28cbbea39fc8"}, + {file = "protobuf-3.19.1-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:a529e7df52204565bcd33738a7a5f288f3d2d37d86caa5d78c458fa5fabbd54d"}, + {file = "protobuf-3.19.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28ccea56d4dc38d35cd70c43c2da2f40ac0be0a355ef882242e8586c6d66666f"}, + {file = "protobuf-3.19.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:8b30a7de128c46b5ecb343917d9fa737612a6e8280f440874e5cc2ba0d79b8f6"}, + {file = "protobuf-3.19.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5935c8ce02e3d89c7900140a8a42b35bc037ec07a6aeb61cc108be8d3c9438a6"}, + {file = "protobuf-3.19.1-cp36-cp36m-win32.whl", hash = "sha256:74f33edeb4f3b7ed13d567881da8e5a92a72b36495d57d696c2ea1ae0cfee80c"}, + {file = "protobuf-3.19.1-cp36-cp36m-win_amd64.whl", hash = "sha256:038daf4fa38a7e818dd61f51f22588d61755160a98db087a046f80d66b855942"}, + {file = "protobuf-3.19.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8e51561d72efd5bd5c91490af1f13e32bcba8dab4643761eb7de3ce18e64a853"}, + {file = "protobuf-3.19.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:6e8ea9173403219239cdfd8d946ed101f2ab6ecc025b0fda0c6c713c35c9981d"}, + {file = "protobuf-3.19.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db3532d9f7a6ebbe2392041350437953b6d7a792de10e629c1e4f5a6b1fe1ac6"}, + {file = "protobuf-3.19.1-cp37-cp37m-win32.whl", hash = "sha256:615b426a177780ce381ecd212edc1e0f70db8557ed72560b82096bd36b01bc04"}, + {file = "protobuf-3.19.1-cp37-cp37m-win_amd64.whl", hash = "sha256:d8919368410110633717c406ab5c97e8df5ce93020cfcf3012834f28b1fab1ea"}, + {file = "protobuf-3.19.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:71b0250b0cfb738442d60cab68abc166de43411f2a4f791d31378590bfb71bd7"}, + {file = "protobuf-3.19.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:3cd0458870ea7d1c58e948ac8078f6ba8a7ecc44a57e03032ed066c5bb318089"}, + {file = "protobuf-3.19.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:655264ed0d0efe47a523e2255fc1106a22f6faab7cc46cfe99b5bae085c2a13e"}, + {file = "protobuf-3.19.1-cp38-cp38-win32.whl", hash = "sha256:b691d996c6d0984947c4cf8b7ae2fe372d99b32821d0584f0b90277aa36982d3"}, + {file = "protobuf-3.19.1-cp38-cp38-win_amd64.whl", hash = "sha256:e7e8d2c20921f8da0dea277dfefc6abac05903ceac8e72839b2da519db69206b"}, + {file = "protobuf-3.19.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fd390367fc211cc0ffcf3a9e149dfeca78fecc62adb911371db0cec5c8b7472d"}, + {file = "protobuf-3.19.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:d83e1ef8cb74009bebee3e61cc84b1c9cd04935b72bca0cbc83217d140424995"}, + {file = "protobuf-3.19.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:36d90676d6f426718463fe382ec6274909337ca6319d375eebd2044e6c6ac560"}, + {file = "protobuf-3.19.1-cp39-cp39-win32.whl", hash = "sha256:e7b24c11df36ee8e0c085e5b0dc560289e4b58804746fb487287dda51410f1e2"}, + {file = "protobuf-3.19.1-cp39-cp39-win_amd64.whl", hash = "sha256:77d2fadcf369b3f22859ab25bd12bb8e98fb11e05d9ff9b7cd45b711c719c002"}, + {file = "protobuf-3.19.1-py2.py3-none-any.whl", hash = "sha256:e813b1c9006b6399308e917ac5d298f345d95bb31f46f02b60cd92970a9afa17"}, + {file = "protobuf-3.19.1.tar.gz", hash = "sha256:62a8e4baa9cb9e064eb62d1002eca820857ab2138440cb4b3ea4243830f94ca7"}, +] diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..de1cc7b --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,19 @@ +[tool.poetry] +name = "openseeface" +version = "1.20.4" +description = "" +authors = ["emilianavt"] +license = "BSD-2-Clause" + +[tool.poetry.dependencies] +python = ">=3.7,<3.11" +numpy = "^1.21.3" +opencv-python = "^4.5.4" +Pillow = "^8.4.0" +onnxruntime = "^1.9.0" + +[tool.poetry.dev-dependencies] + +[build-system] +requires = ["poetry-core>=1.0.0"] +build-backend = "poetry.core.masonry.api" From 2a5b5d7f7f599c86d7acc64776999ae8e2109d00 Mon Sep 17 00:00:00 2001 From: Zutatensuppe Date: Sat, 30 Oct 2021 15:55:47 +0200 Subject: [PATCH 08/52] add poetry infos in readme --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index 2db1fed..af23629 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,8 @@ A simple demonstration can be achieved by creating a new scene in Unity, adding python facetracker.py --visualize 3 --pnp-points 1 --max-threads 4 -c video.mp4 +__Note__: If dependencies were installed using [poetry](https://python-poetry.org/), they have to be launched from a `poetry shell` or have to be prefixed with `poetry run`. + This way the tracking script will output its own tracking visualization while also demonstrating the transmission of tracking data to Unity. The included `OpenSeeLauncher` component allows starting the face tracker program from Unity. It is designed to work with the pyinstaller created executable distributed in the binary release bundles. It provides three public API functions: @@ -131,6 +133,12 @@ The required libraries can be installed using pip: pip install onnxruntime opencv-python pillow numpy +Alternatively poetry can be used to +install all dependencies for this project in a separate virtual env: + + poetry install + + # References ## Training dataset From 8cba4b33bdd5e23dd234bbabb02c1d3038712c80 Mon Sep 17 00:00:00 2001 From: Zutatensuppe Date: Sat, 30 Oct 2021 16:10:59 +0200 Subject: [PATCH 09/52] fix wording in readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index af23629..f78b24e 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ A simple demonstration can be achieved by creating a new scene in Unity, adding python facetracker.py --visualize 3 --pnp-points 1 --max-threads 4 -c video.mp4 -__Note__: If dependencies were installed using [poetry](https://python-poetry.org/), they have to be launched from a `poetry shell` or have to be prefixed with `poetry run`. +__Note__: If dependencies were installed using [poetry](https://python-poetry.org/), the commands have to be executed from a `poetry shell` or have to be prefixed with `poetry run`. This way the tracking script will output its own tracking visualization while also demonstrating the transmission of tracking data to Unity. From f2f4ec0a5f4c8d6a0e835230b228694ebf60d5f5 Mon Sep 17 00:00:00 2001 From: Emiliana <38952746+emilianavt@users.noreply.github.com> Date: Wed, 3 Nov 2021 13:55:14 +0100 Subject: [PATCH 10/52] Added note on datasets. --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 2db1fed..3d5bee0 100644 --- a/README.md +++ b/README.md @@ -156,6 +156,8 @@ Additional training has been done on the WFLW dataset after reducing it to 66 po For the training the gaze and blink detection model, the [MPIIGaze](https://www.mpi-inf.mpg.de/departments/computer-vision-and-machine-learning/research/gaze-based-human-computer-interaction/appearance-based-gaze-estimation-in-the-wild/) dataset was used. Additionally, around 125000 synthetic eyes generated with [UnityEyes](https://www.cl.cam.ac.uk/research/rainbow/projects/unityeyes/) were used during training. +It should be noted that additional custom data was also used during the training process and that the reference landmarks from the original datasets have been modified in certain ways to address various issues. It is likely not possible to reproduce these models with just the original LS3D-W and WFLW datasets, however the additional data is not redistributable. + The heatmap regression based face detection model was trained on random 224x224 crops from the WIDER FACE dataset. @inproceedings{yang2016wider, From 06406f642df174a280a52def8e65d9c583d7369c Mon Sep 17 00:00:00 2001 From: Emiliana <38952746+emilianavt@users.noreply.github.com> Date: Wed, 10 Nov 2021 00:39:26 +0100 Subject: [PATCH 11/52] Added a note that setting --dcap still requires --fps to be set --- facetracker.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/facetracker.py b/facetracker.py index 5f6a973..a743e5c 100644 --- a/facetracker.py +++ b/facetracker.py @@ -13,7 +13,7 @@ if os.name == 'nt': parser.add_argument("-a", "--list-dcaps", type=int, help="Set this to -1 to list all cameras and their available capabilities, set this to a camera id to list that camera's capabilities", default=None) parser.add_argument("-W", "--width", type=int, help="Set camera and raw RGB width", default=640) parser.add_argument("-H", "--height", type=int, help="Set camera and raw RGB height", default=360) - parser.add_argument("-D", "--dcap", type=int, help="Set which device capability line to use or -1 to use the default camera settings", default=None) + parser.add_argument("-D", "--dcap", type=int, help="Set which device capability line to use or -1 to use the default camera settings (FPS still need to be set separately)", default=None) parser.add_argument("-B", "--blackmagic", type=int, help="When set to 1, special support for Blackmagic devices is enabled", default=0) else: parser.add_argument("-W", "--width", type=int, help="Set raw RGB width", default=640) From bbbd5e4ab694988eec7e389be69c5bf1f56fd4bb Mon Sep 17 00:00:00 2001 From: Emiliana <38952746+emilianavt@users.noreply.github.com> Date: Wed, 10 Nov 2021 01:29:29 +0100 Subject: [PATCH 12/52] Updated --gaze-tracking description. --- facetracker.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/facetracker.py b/facetracker.py index a743e5c..4f05c07 100644 --- a/facetracker.py +++ b/facetracker.py @@ -42,7 +42,7 @@ parser.add_argument("--log-data", help="You can set a filename to which tracking parser.add_argument("--log-output", help="You can set a filename to console output will be logged here", default="") parser.add_argument("--model", type=int, help="This can be used to select the tracking model. Higher numbers are models with better tracking quality, but slower speed, except for model 4, which is wink optimized. Models 1 and 0 tend to be too rigid for expression and blink detection. Model -2 is roughly equivalent to model 1, but faster. Model -3 is between models 0 and -1.", default=3, choices=[-3, -2, -1, 0, 1, 2, 3, 4]) parser.add_argument("--model-dir", help="This can be used to specify the path to the directory containing the .onnx model files", default=None) -parser.add_argument("--gaze-tracking", type=int, help="When set to 1, experimental blink detection and gaze tracking are enabled, which makes things slightly slower", default=1) +parser.add_argument("--gaze-tracking", type=int, help="When set to 1, gaze tracking is enabled, which makes things slightly slower", default=1) parser.add_argument("--face-id-offset", type=int, help="When set, this offset is added to all face ids, which can be useful for mixing tracking data from multiple network sources", default=0) parser.add_argument("--repeat-video", type=int, help="When set to 1 and a video file was specified with -c, the tracker will loop the video until interrupted", default=0) parser.add_argument("--dump-points", type=str, help="When set to a filename, the current face 3D points are made symmetric and dumped to the given file when quitting the visualization with the \"q\" key", default="") From baff2c0256bbed0927fe7b0eb8b183586e0714ec Mon Sep 17 00:00:00 2001 From: Emiliana <38952746+emilianavt@users.noreply.github.com> Date: Thu, 13 Jan 2022 10:56:45 +0100 Subject: [PATCH 13/52] Updated pillow version. --- poetry.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/poetry.lock b/poetry.lock index a3c4c1b..4f55f9b 100644 --- a/poetry.lock +++ b/poetry.lock @@ -40,7 +40,7 @@ numpy = ">=1.21.2" [[package]] name = "pillow" -version = "8.4.0" +version = "9.0.0" description = "Python Imaging Library (Fork)" category = "main" optional = false From 9aff3457207c48eeab14938e096e148973933714 Mon Sep 17 00:00:00 2001 From: Emiliana <38952746+emilianavt@users.noreply.github.com> Date: Tue, 15 Mar 2022 12:30:06 +0100 Subject: [PATCH 14/52] Updated poetry.lock. --- poetry.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/poetry.lock b/poetry.lock index 4f55f9b..0f791f7 100644 --- a/poetry.lock +++ b/poetry.lock @@ -40,7 +40,7 @@ numpy = ">=1.21.2" [[package]] name = "pillow" -version = "9.0.0" +version = "9.0.1" description = "Python Imaging Library (Fork)" category = "main" optional = false From 0204d8a4a79e0098e3996c984b610db4f8bf58df Mon Sep 17 00:00:00 2001 From: yamichan420 <62211673+yamichan420@users.noreply.github.com> Date: Tue, 29 Mar 2022 22:21:40 -0700 Subject: [PATCH 15/52] Add files via upload apparently, onnxruntime 1.9 and later require that the available providers be explicitly listed as an argument in InferenceSession() or i was getting that error anyway, and it was preventing OpenSeeFace from working i'm running Arch Linux using the build of python-onnxruntime available in the AUR anyway, i edited tracker.py and retinaface.py to find the list of available providers and pass that argument and that makes it work for me! yay! --- retinaface.py | 3 ++- tracker.py | 12 ++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/retinaface.py b/retinaface.py index c97c957..b1d1ae5 100644 --- a/retinaface.py +++ b/retinaface.py @@ -66,7 +66,8 @@ class RetinaFaceDetector(): options.execution_mode = onnxruntime.ExecutionMode.ORT_SEQUENTIAL options.graph_optimization_level = onnxruntime.GraphOptimizationLevel.ORT_ENABLE_ALL options.log_severity_level = 3 - self.session = onnxruntime.InferenceSession(model_path, sess_options=options) + providersList = onnxruntime.capi._pybind_state.get_available_providers() + self.session = onnxruntime.InferenceSession(model_path, sess_options=options, providers=providersList) self.res_w, self.res_h = res with open(json_path, "r") as prior_file: self.priorbox = np.array(json.loads(prior_file.read())) diff --git a/tracker.py b/tracker.py index 97ba6c4..1d845a3 100644 --- a/tracker.py +++ b/tracker.py @@ -527,8 +527,12 @@ class Tracker(): self.retinaface_scan = RetinaFaceDetector(model_path=os.path.join(model_base_path, "retinaface_640x640_opt.onnx"), json_path=os.path.join(model_base_path, "priorbox_640x640.json"), threads=2, top_k=max_faces, res=(640, 640)) self.use_retinaface = use_retinaface + # OTR 1.9 and later requires specifying providers + # explicitly as an argument in InferenceSession() + providersList = onnxruntime.capi._pybind_state.get_available_providers() + # Single face instance with multiple threads - self.session = onnxruntime.InferenceSession(os.path.join(model_base_path, model), sess_options=options) + self.session = onnxruntime.InferenceSession(os.path.join(model_base_path, model), sess_options=options, providers=providersList) # Multiple faces with single threads self.sessions = [] @@ -544,7 +548,7 @@ class Tracker(): options.intra_op_num_threads += 1 options.execution_mode = onnxruntime.ExecutionMode.ORT_SEQUENTIAL options.graph_optimization_level = onnxruntime.GraphOptimizationLevel.ORT_ENABLE_ALL - self.sessions.append(onnxruntime.InferenceSession(os.path.join(model_base_path, model), sess_options=options)) + self.sessions.append(onnxruntime.InferenceSession(os.path.join(model_base_path, model), sess_options=options, providers=providersList)) self.input_name = self.session.get_inputs()[0].name options = onnxruntime.SessionOptions() @@ -553,9 +557,9 @@ class Tracker(): options.execution_mode = onnxruntime.ExecutionMode.ORT_SEQUENTIAL options.graph_optimization_level = onnxruntime.GraphOptimizationLevel.ORT_ENABLE_ALL options.log_severity_level = 3 - self.gaze_model = onnxruntime.InferenceSession(os.path.join(model_base_path, "mnv3_gaze32_split_opt.onnx"), sess_options=options) + self.gaze_model = onnxruntime.InferenceSession(os.path.join(model_base_path, "mnv3_gaze32_split_opt.onnx"), sess_options=options, providers=providersList) - self.detection = onnxruntime.InferenceSession(os.path.join(model_base_path, "mnv3_detection_opt.onnx"), sess_options=options) + self.detection = onnxruntime.InferenceSession(os.path.join(model_base_path, "mnv3_detection_opt.onnx"), sess_options=options, providers=providersList) self.faces = [] # Image normalization constants From 018785fb068e771db61d07cd1744037cbf4ed2f8 Mon Sep 17 00:00:00 2001 From: Glitch Phoenix <78001268+GlitchPhoenix98@users.noreply.github.com> Date: Sun, 19 Jun 2022 01:47:53 +0000 Subject: [PATCH 16/52] Update README.md Outdated Godot renderer link. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f549497..4af0231 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ # Overview -**Note**: This is a tracking library, **not** a stand-alone avatar puppeteering program. I'm also working on [VSeeFace](https://www.vseeface.icu/), which allows animating [VRM](https://vrm.dev/en/how_to_make_vrm/) and [VSFAvatar](https://www.youtube.com/watch?v=jhQ8DF87I5I) 3D models by using OpenSeeFace tracking. [VTube Studio](https://denchisoft.com/) uses OpenSeeFace for webcam based tracking to animate Live2D models. A renderer for the Godot engine can be found [here](https://github.com/you-win/openseeface-gd). +**Note**: This is a tracking library, **not** a stand-alone avatar puppeteering program. I'm also working on [VSeeFace](https://www.vseeface.icu/), which allows animating [VRM](https://vrm.dev/en/how_to_make_vrm/) and [VSFAvatar](https://www.youtube.com/watch?v=jhQ8DF87I5I) 3D models by using OpenSeeFace tracking. [VTube Studio](https://denchisoft.com/) uses OpenSeeFace for webcam based tracking to animate Live2D models. A renderer for the Godot engine can be found [here](https://github.com/virtual-puppet-project/vpuppr). This project implements a facial landmark detection model based on MobileNetV3. From ae1213a29891423eed7da69059a4a37e51f28059 Mon Sep 17 00:00:00 2001 From: Glitch Phoenix <78001268+GlitchPhoenix98@users.noreply.github.com> Date: Sun, 19 Jun 2022 17:58:43 +0000 Subject: [PATCH 17/52] Added dependencies for Python 3.10 and above. Added required packages for python 3.10 and above --- README.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4af0231..4ddd8ab 100644 --- a/README.md +++ b/README.md @@ -121,9 +121,8 @@ When distributing it, you should also distribute the `Licenses` folder along wit The release builds contain a custom build of ONNX Runtime without telemetry. -# Dependencies +# Dependencies (Python 3.6 - 3.9) -* Python 3.7 * ONNX Runtime * OpenCV * Pillow @@ -137,7 +136,15 @@ Alternatively poetry can be used to install all dependencies for this project in a separate virtual env: poetry install +# Dependencies (Python 3.10 and above) +* ort-nightly +* OpenCV +* Pillow +* Numpy +The required modules can be downloaded and installed with pip: + + pip install ort-nightly opencv-python pillow numpy # References From 90e32e52294fcbd47f5333e7ad42cdd52801fa36 Mon Sep 17 00:00:00 2001 From: Emiliana <38952746+emilianavt@users.noreply.github.com> Date: Mon, 20 Jun 2022 12:15:31 +0200 Subject: [PATCH 18/52] Updated README. --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 4ddd8ab..6f9f80a 100644 --- a/README.md +++ b/README.md @@ -136,13 +136,15 @@ Alternatively poetry can be used to install all dependencies for this project in a separate virtual env: poetry install + # Dependencies (Python 3.10 and above) + * ort-nightly * OpenCV * Pillow * Numpy -The required modules can be downloaded and installed with pip: +The required libraries can be installed using pip: pip install ort-nightly opencv-python pillow numpy From 6f0ef1afb99cf474768f55c4ffcb1037392b8349 Mon Sep 17 00:00:00 2001 From: Emiliana <38952746+emilianavt@users.noreply.github.com> Date: Sun, 26 Jun 2022 00:01:59 +0200 Subject: [PATCH 19/52] Updated poetry.lock. --- poetry.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/poetry.lock b/poetry.lock index 0f791f7..554fc89 100644 --- a/poetry.lock +++ b/poetry.lock @@ -8,7 +8,7 @@ python-versions = "*" [[package]] name = "numpy" -version = "1.21.3" +version = "1.22" description = "NumPy is the fundamental package for array computing with Python." category = "main" optional = false From c0fd81384441f7974a696ef091859d8a06c01e60 Mon Sep 17 00:00:00 2001 From: Timothy Yuen Date: Tue, 9 Aug 2022 00:58:06 -0400 Subject: [PATCH 20/52] Add make_exe.sh for Linux and Mac --- make_exe.sh | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100755 make_exe.sh diff --git a/make_exe.sh b/make_exe.sh new file mode 100755 index 0000000..dd2fd70 --- /dev/null +++ b/make_exe.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +PYTHON_BINARY=$(which python3) + +if [[ -z "$PYTHON_BINARY" ]]; then + echo "python3 not found. Searching for python instead." + PYTHON_BINARY=$(which python) + if [[ -z "$PYTHON_BINARY" ]]; then + echo "Python 3 must be available on your path. Exiting." + exit 1 + fi +fi + +echo "Creating venv" + +"$PYTHON_BINARY" -m venv venv + +source venv/bin/activate + +echo "Installing packages" + +pip install onnxruntime opencv-python==4.5.4.60 pillow numpy pyinstaller + +echo "Creating binary" + +pyinstaller --clean facetracker.py + +echo "Files should be available in the dist/ folder" +echo "Done!" + From 5936b487a73c123f4c2ce77f7822d0925a7a29c7 Mon Sep 17 00:00:00 2001 From: Emiliana <38952746+emilianavt@users.noreply.github.com> Date: Mon, 5 Sep 2022 14:15:24 +0200 Subject: [PATCH 21/52] Updated readme file. --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index 6f9f80a..f4dc239 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,14 @@ If anyone is curious, the name is a silly pun on the open seas and seeing faces. An up to date sample video can be found [here](https://www.youtube.com/watch?v=AaNap_ud_3I&vq=hd1080), showing the default tracking model's performance under different noise and light levels. +# Tracking quality + +Since the landmarks used by OpenSeeFace are a bit different from those used by other approaches (they are close to iBUG 68, with two less points in the mouth corners and quasi-3D face contours instead of face contours that follow the visible outline) it is hard to numerically compare its accuracy to that of other approaches found commonly in scientific literature. + +Anecdotically, OpenSeeFace performs well in adverse conditions (low light, high noise, low resolution) and keeps tracking faces through a very wide range of head poses. Compared to MediaPipe, OpenSeeFace landmarks remain more stable in challenging conditions and it accurately represents a wider range of mouth poses. However, tracking of the eye region can be a bit worse. + +I ran OpenSeeFace on a sample clip from the video presentation for [3D Face Reconstruction with Dense Landmarks](https://microsoft.github.io/DenseLandmarks/) by Wood et al. to compare it to MediaPipe and their approach. You can watch the result [ħere](https://cdn.discordapp.com/attachments/720652345540870237/1016320201807106118/OSFMediaPipe3DFR.mp4). + # Usage A sample Unity project for VRM based avatar animation can be found [here](https://github.com/emilianavt/OpenSeeFaceSample). From 1f8b83feef983cd02aad3243312e340918c3d0b3 Mon Sep 17 00:00:00 2001 From: Emiliana <38952746+emilianavt@users.noreply.github.com> Date: Mon, 5 Sep 2022 14:15:52 +0200 Subject: [PATCH 22/52] Fixed typo. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f4dc239..17c13c3 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ Since the landmarks used by OpenSeeFace are a bit different from those used by o Anecdotically, OpenSeeFace performs well in adverse conditions (low light, high noise, low resolution) and keeps tracking faces through a very wide range of head poses. Compared to MediaPipe, OpenSeeFace landmarks remain more stable in challenging conditions and it accurately represents a wider range of mouth poses. However, tracking of the eye region can be a bit worse. -I ran OpenSeeFace on a sample clip from the video presentation for [3D Face Reconstruction with Dense Landmarks](https://microsoft.github.io/DenseLandmarks/) by Wood et al. to compare it to MediaPipe and their approach. You can watch the result [ħere](https://cdn.discordapp.com/attachments/720652345540870237/1016320201807106118/OSFMediaPipe3DFR.mp4). +I ran OpenSeeFace on a sample clip from the video presentation for [3D Face Reconstruction with Dense Landmarks](https://microsoft.github.io/DenseLandmarks/) by Wood et al. to compare it to MediaPipe and their approach. You can watch the result [here](https://cdn.discordapp.com/attachments/720652345540870237/1016320201807106118/OSFMediaPipe3DFR.mp4). # Usage From 1825b2e67e7b79beb7cacf08aecd9ef12fbd5284 Mon Sep 17 00:00:00 2001 From: Emiliana <38952746+emilianavt@users.noreply.github.com> Date: Mon, 5 Sep 2022 14:34:09 +0200 Subject: [PATCH 23/52] Updated readme file. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 17c13c3..70b051f 100644 --- a/README.md +++ b/README.md @@ -14,9 +14,9 @@ An up to date sample video can be found [here](https://www.youtube.com/watch?v=A # Tracking quality -Since the landmarks used by OpenSeeFace are a bit different from those used by other approaches (they are close to iBUG 68, with two less points in the mouth corners and quasi-3D face contours instead of face contours that follow the visible outline) it is hard to numerically compare its accuracy to that of other approaches found commonly in scientific literature. +Since the landmarks used by OpenSeeFace are a bit different from those used by other approaches (they are close to iBUG 68, with two less points in the mouth corners and quasi-3D face contours instead of face contours that follow the visible outline) it is hard to numerically compare its accuracy to that of other approaches found commonly in scientific literature. The tracking performance is also more optimized for making landmarks that are useful for animating an avatar than for exactly fitting the face image. For example, as long as the eye landmarks show whether the eyes are opened or closed, even if their location is somewhat off, they can still be useful for this purpose. -Anecdotically, OpenSeeFace performs well in adverse conditions (low light, high noise, low resolution) and keeps tracking faces through a very wide range of head poses. Compared to MediaPipe, OpenSeeFace landmarks remain more stable in challenging conditions and it accurately represents a wider range of mouth poses. However, tracking of the eye region can be a bit worse. +From general observation, OpenSeeFace performs well in adverse conditions (low light, high noise, low resolution) and keeps tracking faces through a very wide range of head poses with relatively high stability of landmark positions. Compared to MediaPipe, OpenSeeFace landmarks remain more stable in challenging conditions and it accurately represents a wider range of mouth poses. However, tracking of the eye region can be less accurate. I ran OpenSeeFace on a sample clip from the video presentation for [3D Face Reconstruction with Dense Landmarks](https://microsoft.github.io/DenseLandmarks/) by Wood et al. to compare it to MediaPipe and their approach. You can watch the result [here](https://cdn.discordapp.com/attachments/720652345540870237/1016320201807106118/OSFMediaPipe3DFR.mp4). From 1f3a01976b003630cf488e611a27b9d7272e1d03 Mon Sep 17 00:00:00 2001 From: Tim Yuen Date: Fri, 9 Sep 2022 21:32:13 -0400 Subject: [PATCH 24/52] add build workflow for windows, mac, and linux --- .github/workflows/create-binaries.yaml | 39 ++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 .github/workflows/create-binaries.yaml diff --git a/.github/workflows/create-binaries.yaml b/.github/workflows/create-binaries.yaml new file mode 100644 index 0000000..352f345 --- /dev/null +++ b/.github/workflows/create-binaries.yaml @@ -0,0 +1,39 @@ +name: Package using PyInstaller +on: + push: + tags: + - v** + workflow_dispatch: + +env: + dist-folder-path: dist/OpenSeeFace + +jobs: + build-all: + strategy: + fail-fast: false + matrix: + os: [windows-latest, ubuntu-latest, macos-latest] + runs-on: ${{ matrix.os }} + steps: + - name: Pull OpenSeeFace + uses: actions/checkout@v3 + + - name: Create binary + shell: bash + run: | + chmod +x make_exe.sh + ./make_exe.sh + + - name: Move and zip files + shell: bash # Using bash for all OSs should be fine, even on Windows + run: | + mv dist/facetracker ${{ env.dist-folder-path }} + cp -r models ${{ env.dist-folder-path }} + + - name: Upload artifact + uses: actions/upload-artifact@v3 + with: + name: ${{ matrix.os }} + path: ${{ env.dist-folder-path }} + if-no-files-found: error From d6062c9664554789fe699f697384a868ede9354e Mon Sep 17 00:00:00 2001 From: Tim Yuen Date: Sat, 10 Sep 2022 16:55:47 -0400 Subject: [PATCH 25/52] fix actions/upload-artifact generating tar bombs, change how make_exe.bat works --- .github/workflows/create-binaries.yaml | 24 +++++++++++++++++++++--- make_exe.bat | 8 ++++---- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/.github/workflows/create-binaries.yaml b/.github/workflows/create-binaries.yaml index 352f345..a705d7b 100644 --- a/.github/workflows/create-binaries.yaml +++ b/.github/workflows/create-binaries.yaml @@ -6,7 +6,8 @@ on: workflow_dispatch: env: - dist-folder-path: dist/OpenSeeFace + dist-folder-path: dist/OpenSeeFace # The directory generated by PyInstaller + artifact-path: OpenSeeFace # Needed since upload-artifacts pulls files out of parent directories jobs: build-all: @@ -19,21 +20,38 @@ jobs: - name: Pull OpenSeeFace uses: actions/checkout@v3 - - name: Create binary + - name: Create binary Unix + if: matrix.os != 'windows-latest' shell: bash run: | chmod +x make_exe.sh ./make_exe.sh + - name: Create binary Windows + if: matrix.os == 'windows-latest' + shell: cmd + run: | + choco install vcredist140 + + xcopy c:\Windows\System32\msvcp140.dll . + xcopy c:\Windows\System32\vcomp140.dll . + xcopy c:\Windows\System32\concrt140.dll . + xcopy c:\Windows\System32\vccorlib140.dll . + + make_exe.bat + - name: Move and zip files shell: bash # Using bash for all OSs should be fine, even on Windows run: | mv dist/facetracker ${{ env.dist-folder-path }} cp -r models ${{ env.dist-folder-path }} + mkdir ${{ env.artifact-path }} + mv ${{ env.dist-folder-path }} ${{ env.artifact-path }} + - name: Upload artifact uses: actions/upload-artifact@v3 with: name: ${{ matrix.os }} - path: ${{ env.dist-folder-path }} + path: ${{ env.artifact-path }} if-no-files-found: error diff --git a/make_exe.bat b/make_exe.bat index a5ad490..36c6f62 100644 --- a/make_exe.bat +++ b/make_exe.bat @@ -1,4 +1,6 @@ -pyinstaller facetracker.spec --onedir ^ +pip install onnxruntime opencv-python==4.5.4.60 pillow numpy pyinstaller + +pyinstaller facetracker.py --onedir ^ --add-binary dshowcapture/dshowcapture_x86.dll;. ^ --add-binary dshowcapture/dshowcapture_x64.dll;. ^ --add-binary dshowcapture/libminibmcapture32.dll;. ^ @@ -11,6 +13,4 @@ pyinstaller facetracker.spec --onedir ^ --add-binary vccorlib140.dll;. ^ --add-binary run.bat;. -del dist\facetracker\cv2\opencv_videoio_ffmpeg420_64.dll - -pause \ No newline at end of file +del dist\facetracker\cv2\opencv_videoio_* \ No newline at end of file From 022a0520fa7624c5225c27b5343c4d656080141b Mon Sep 17 00:00:00 2001 From: Tim Yuen Date: Sat, 10 Sep 2022 23:24:22 -0400 Subject: [PATCH 26/52] Update make_exe.bat to use a venv, explicitly add onnxruntime dll to pyinstaller binary, add debug prints during build --- .github/workflows/create-binaries.yaml | 2 +- make_exe.bat | 28 +++++++++++++++++++------- make_exe.sh | 8 +++++--- 3 files changed, 27 insertions(+), 11 deletions(-) diff --git a/.github/workflows/create-binaries.yaml b/.github/workflows/create-binaries.yaml index a705d7b..d799714 100644 --- a/.github/workflows/create-binaries.yaml +++ b/.github/workflows/create-binaries.yaml @@ -40,7 +40,7 @@ jobs: make_exe.bat - - name: Move and zip files + - name: Move files for uploading shell: bash # Using bash for all OSs should be fine, even on Windows run: | mv dist/facetracker ${{ env.dist-folder-path }} diff --git a/make_exe.bat b/make_exe.bat index 36c6f62..8c55e0b 100644 --- a/make_exe.bat +++ b/make_exe.bat @@ -1,16 +1,30 @@ +echo "Started" + +:: A venv is used so it's easy to add the onnxruntime dll to the binary + +echo "Creating venv" +python -m venv venv + +echo "Activating venv" +call venv\Scripts\activate.bat + +echo "Installing dependencies" +pip install wheel + pip install onnxruntime opencv-python==4.5.4.60 pillow numpy pyinstaller +echo "Running pyinstaller" pyinstaller facetracker.py --onedir ^ - --add-binary dshowcapture/dshowcapture_x86.dll;. ^ - --add-binary dshowcapture/dshowcapture_x64.dll;. ^ - --add-binary dshowcapture/libminibmcapture32.dll;. ^ - --add-binary dshowcapture/libminibmcapture64.dll;. ^ - --add-binary escapi/escapi_x86.dll;. ^ - --add-binary escapi/escapi_x64.dll;. ^ + --add-binary dshowcapture/*.dll;. ^ + --add-binary escapi/*.dll;. ^ + --add-binary venv/lib/site-packages/onnxruntime/capi/*.dll;onnxruntime\capi ^ --add-binary msvcp140.dll;. ^ --add-binary vcomp140.dll;. ^ --add-binary concrt140.dll;. ^ --add-binary vccorlib140.dll;. ^ --add-binary run.bat;. -del dist\facetracker\cv2\opencv_videoio_* \ No newline at end of file +echo "Deleting opencv dll" +del dist\facetracker\cv2\opencv_videoio_* + +echo "Finished" diff --git a/make_exe.sh b/make_exe.sh index dd2fd70..834d486 100755 --- a/make_exe.sh +++ b/make_exe.sh @@ -1,5 +1,7 @@ #!/bin/bash +set -e + PYTHON_BINARY=$(which python3) if [[ -z "$PYTHON_BINARY" ]]; then @@ -12,18 +14,18 @@ if [[ -z "$PYTHON_BINARY" ]]; then fi echo "Creating venv" - "$PYTHON_BINARY" -m venv venv source venv/bin/activate echo "Installing packages" +pip install wheel # Make sure this is installed beforehand pip install onnxruntime opencv-python==4.5.4.60 pillow numpy pyinstaller echo "Creating binary" - -pyinstaller --clean facetracker.py +pyinstaller --onedir --clean facetracker.py \ + --add-binary venv/lib/python3.*/site-packages/onnxruntime/capi/*.so:onnxruntime/capi echo "Files should be available in the dist/ folder" echo "Done!" From 0443549277386f720c8cd14936c7bea00f895122 Mon Sep 17 00:00:00 2001 From: Tim Yuen Date: Sun, 11 Sep 2022 13:11:03 -0400 Subject: [PATCH 27/52] Fix unix builds not having their executable bit set in ci, make windows build script perform a clean build every time --- .github/workflows/create-binaries.yaml | 6 ++++++ make_exe.bat | 3 ++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/create-binaries.yaml b/.github/workflows/create-binaries.yaml index d799714..d2214fa 100644 --- a/.github/workflows/create-binaries.yaml +++ b/.github/workflows/create-binaries.yaml @@ -49,6 +49,12 @@ jobs: mkdir ${{ env.artifact-path }} mv ${{ env.dist-folder-path }} ${{ env.artifact-path }} + # Sometimes the executable bit doesn't get set for Unix builds for some reason + - name: Set executable bit + if: matrix.os != 'windows-latest' + shell: bash + run: chmod +x ${{ env.artifact-path }}/* + - name: Upload artifact uses: actions/upload-artifact@v3 with: diff --git a/make_exe.bat b/make_exe.bat index 8c55e0b..a7b6ef8 100644 --- a/make_exe.bat +++ b/make_exe.bat @@ -14,7 +14,8 @@ pip install wheel pip install onnxruntime opencv-python==4.5.4.60 pillow numpy pyinstaller echo "Running pyinstaller" -pyinstaller facetracker.py --onedir ^ +pyinstaller facetracker.py --clean ^ + --onedir ^ --add-binary dshowcapture/*.dll;. ^ --add-binary escapi/*.dll;. ^ --add-binary venv/lib/site-packages/onnxruntime/capi/*.dll;onnxruntime\capi ^ From be48eadbc60ab3534dc4b942f66a43d76aeea882 Mon Sep 17 00:00:00 2001 From: Tim Yuen Date: Sun, 11 Sep 2022 18:42:23 -0400 Subject: [PATCH 28/52] tar files before uploading, properly set execution bit, remove redundant file moving logic, split into windows and unix jobs --- .github/workflows/create-binaries.yaml | 86 ++++++++++++++++---------- 1 file changed, 54 insertions(+), 32 deletions(-) diff --git a/.github/workflows/create-binaries.yaml b/.github/workflows/create-binaries.yaml index d2214fa..02bb4b9 100644 --- a/.github/workflows/create-binaries.yaml +++ b/.github/workflows/create-binaries.yaml @@ -5,30 +5,16 @@ on: - v** workflow_dispatch: -env: - dist-folder-path: dist/OpenSeeFace # The directory generated by PyInstaller - artifact-path: OpenSeeFace # Needed since upload-artifacts pulls files out of parent directories - jobs: - build-all: - strategy: - fail-fast: false - matrix: - os: [windows-latest, ubuntu-latest, macos-latest] - runs-on: ${{ matrix.os }} + build-windows: + env: + dist-path: dist/OpenSeeFace + runs-on: windows-latest steps: - name: Pull OpenSeeFace uses: actions/checkout@v3 - - name: Create binary Unix - if: matrix.os != 'windows-latest' - shell: bash - run: | - chmod +x make_exe.sh - ./make_exe.sh - - - name: Create binary Windows - if: matrix.os == 'windows-latest' + - name: Create binary shell: cmd run: | choco install vcredist140 @@ -41,23 +27,59 @@ jobs: make_exe.bat - name: Move files for uploading - shell: bash # Using bash for all OSs should be fine, even on Windows - run: | - mv dist/facetracker ${{ env.dist-folder-path }} - cp -r models ${{ env.dist-folder-path }} - - mkdir ${{ env.artifact-path }} - mv ${{ env.dist-folder-path }} ${{ env.artifact-path }} - - # Sometimes the executable bit doesn't get set for Unix builds for some reason - - name: Set executable bit - if: matrix.os != 'windows-latest' shell: bash - run: chmod +x ${{ env.artifact-path }}/* + run: | + # Prevents the parent dist/ directory from being included + mv dist/facetracker ${{ env.dist-path }} + cp -r models ${{ env.dist-path }} + + - name: Upload artifact + uses: actions/upload-artifact@v3 + with: + name: windows-latest + path: dist # Add the parent directory to prevent a tarbomb + if-no-files-found: error + + # Files must be packed into a tar in order for file permissions to be preserved + build-unix: + env: + artifact-path: OpenSeeFace + tar-path: OpenSeeFace.tar + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, macos-latest] + runs-on: ${{ matrix.os }} + steps: + - name: Pull OpenSeeFace + uses: actions/checkout@v3 + + - name: Create binary + shell: bash + run: | + chmod +x make_exe.sh + ./make_exe.sh + + - name: Move files for uploading + shell: bash + run: | + # Prevents the parent dist/ directory from being included + mv dist/facetracker ${{ env.artifact-path }} + cp -r models ${{ env.artifact-path }} + + - name: Fix permissions from PyInstaller + shell: bash + run: | + find ${{ env.artifact-path }} -type f -exec chmod -x {} + + chmod +x ${{ env.artifact-path }}/facetracker + + - name: Pack files into tar + shell: bash + run: tar -cvf ${{ env.tar-path }} ${{ env.artifact-path }} - name: Upload artifact uses: actions/upload-artifact@v3 with: name: ${{ matrix.os }} - path: ${{ env.artifact-path }} + path: ${{ env.tar-path }} if-no-files-found: error From 822e9e77535f3ffebc875368ebaccc27195cb5a9 Mon Sep 17 00:00:00 2001 From: Tim Yuen Date: Mon, 12 Sep 2022 14:57:51 -0400 Subject: [PATCH 29/52] add action to append date to artifact name during upload --- .../actions/upload-dated-artifact/action.yaml | 26 +++++++++++++++++++ .github/workflows/create-binaries.yaml | 16 +++++++----- 2 files changed, 35 insertions(+), 7 deletions(-) create mode 100644 .github/actions/upload-dated-artifact/action.yaml diff --git a/.github/actions/upload-dated-artifact/action.yaml b/.github/actions/upload-dated-artifact/action.yaml new file mode 100644 index 0000000..7fc3fbe --- /dev/null +++ b/.github/actions/upload-dated-artifact/action.yaml @@ -0,0 +1,26 @@ +name: Upload dated artifact +description: Uploads an artifact with a datetime + +inputs: + name: + description: The name of the artifact + required: true + path: + description: The path to the file/folder to upload + required: true + +runs: + using: composite + steps: + # https://stackoverflow.com/questions/60942067/get-current-date-and-time-in-github-workflows + - name: Get current datetime + id: date + shell: bash + run: echo "::set-output name=date::$(date '+%Y-%m-%d_%H-%M-%S')" + + - name: Upload artifact + uses: actions/upload-artifact@v3 + with: + name: ${{ inputs.name }}_${{ steps.date.outputs.date }} + path: ${{ inputs.path }} + if-no-files-found: error diff --git a/.github/workflows/create-binaries.yaml b/.github/workflows/create-binaries.yaml index 02bb4b9..26572bc 100644 --- a/.github/workflows/create-binaries.yaml +++ b/.github/workflows/create-binaries.yaml @@ -34,11 +34,10 @@ jobs: cp -r models ${{ env.dist-path }} - name: Upload artifact - uses: actions/upload-artifact@v3 + uses: ./.github/actions/upload-dated-artifact with: - name: windows-latest + name: windows path: dist # Add the parent directory to prevent a tarbomb - if-no-files-found: error # Files must be packed into a tar in order for file permissions to be preserved build-unix: @@ -48,7 +47,11 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-latest, macos-latest] + include: + - name: linux + os: ubuntu-latest + - name: mac + os: macos-latest runs-on: ${{ matrix.os }} steps: - name: Pull OpenSeeFace @@ -78,8 +81,7 @@ jobs: run: tar -cvf ${{ env.tar-path }} ${{ env.artifact-path }} - name: Upload artifact - uses: actions/upload-artifact@v3 + uses: ./.github/actions/upload-dated-artifact with: - name: ${{ matrix.os }} + name: ${{ matrix.name }} path: ${{ env.tar-path }} - if-no-files-found: error From 40119c17971c019b892b047b457c8182190acb8c Mon Sep 17 00:00:00 2001 From: Emiliana <38952746+emilianavt@users.noreply.github.com> Date: Wed, 23 Nov 2022 00:08:38 +0100 Subject: [PATCH 30/52] Updated pillow version. --- poetry.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/poetry.lock b/poetry.lock index 554fc89..78b88f7 100644 --- a/poetry.lock +++ b/poetry.lock @@ -40,7 +40,7 @@ numpy = ">=1.21.2" [[package]] name = "pillow" -version = "9.0.1" +version = "9.3.0" description = "Python Imaging Library (Fork)" category = "main" optional = false From 7df42c6ca449e20fb0ccb3ebccf6a1806075430b Mon Sep 17 00:00:00 2001 From: Robert Junkins <67753581+JustBobinAround@users.noreply.github.com> Date: Sun, 18 Dec 2022 16:37:23 -0500 Subject: [PATCH 31/52] numpy requirement changed to numpy==1.23.0 When building with the latest numpy version (v1.24.0), OpenSeeFace crashes with "AttributeError: module 'numpy' has no attribute 'float'". This is because the attribute 'float' is now deprecated in numpy v1.24. I have changed the requirements to the earlier version v1.23.0. This should probably only be a temporary fix, as I'm sure there is a good reason that float was depreciated. I would also recommend changing the requirements to a single file with a static version for each requirement that is known to work. This will help ensure the stability of the program. I may do this in another fork when I have more time if you want. --- make_exe.bat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/make_exe.bat b/make_exe.bat index a7b6ef8..762442b 100644 --- a/make_exe.bat +++ b/make_exe.bat @@ -11,7 +11,7 @@ call venv\Scripts\activate.bat echo "Installing dependencies" pip install wheel -pip install onnxruntime opencv-python==4.5.4.60 pillow numpy pyinstaller +pip install onnxruntime opencv-python==4.5.4.60 pillow numpy==1.23.0 pyinstaller echo "Running pyinstaller" pyinstaller facetracker.py --clean ^ From 624141fa6a5d048523ce8049b0e5c8433f5bc382 Mon Sep 17 00:00:00 2001 From: Robert Junkins <67753581+JustBobinAround@users.noreply.github.com> Date: Sun, 18 Dec 2022 16:39:41 -0500 Subject: [PATCH 32/52] numpy requirement changed to numpy==1.23.0 When building with the latest numpy version (v1.24.0), OpenSeeFace crashes with "AttributeError: module 'numpy' has no attribute 'float'". This is because the attribute 'float' is now deprecated in numpy v1.24. I have changed the requirements to the earlier version v1.23.0. This should probably only be a temporary fix, as I'm sure there is a good reason that float was depreciated. I would also recommend changing the requirements to a single file with a static version for each requirement that is known to work. This will help ensure the stability of the program. I may do this in another fork when I have more time if you want. --- make_exe.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/make_exe.sh b/make_exe.sh index 834d486..1963f23 100755 --- a/make_exe.sh +++ b/make_exe.sh @@ -21,7 +21,7 @@ source venv/bin/activate echo "Installing packages" pip install wheel # Make sure this is installed beforehand -pip install onnxruntime opencv-python==4.5.4.60 pillow numpy pyinstaller +pip install onnxruntime opencv-python==4.5.4.60 pillow numpy==1.23.0 pyinstaller echo "Creating binary" pyinstaller --onedir --clean facetracker.py \ From 951068c39eb1e76ac19793c407b2710055c58718 Mon Sep 17 00:00:00 2001 From: Emiliana <38952746+emilianavt@users.noreply.github.com> Date: Fri, 10 Feb 2023 23:28:40 +0100 Subject: [PATCH 33/52] Blacklisted UnityCapture based camera drivers. --- dshowcapture/dshowcapture_x64.dll | Bin 116736 -> 117248 bytes dshowcapture/dshowcapture_x86.dll | Bin 104960 -> 104960 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/dshowcapture/dshowcapture_x64.dll b/dshowcapture/dshowcapture_x64.dll index 88e3752d01d5920814f7ae9282db670eb58c7191..0d04783723396d077117c601adbda0a43aad1859 100644 GIT binary patch delta 24085 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 F{|g?Fw6*{M delta 23860 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 BaSi|g delta 19751 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 Date: Sun, 12 Feb 2023 17:29:17 +0100 Subject: [PATCH 34/52] Blacklisted 3tene virtual camera in dshowcapture. --- dshowcapture/dshowcapture_x64.dll | Bin 117248 -> 117248 bytes dshowcapture/dshowcapture_x86.dll | Bin 104960 -> 104960 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/dshowcapture/dshowcapture_x64.dll b/dshowcapture/dshowcapture_x64.dll index 0d04783723396d077117c601adbda0a43aad1859..a31c51db392bd8536232d68bd2f6c43e49a1a280 100644 GIT binary patch delta 11908 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 Date: Mon, 13 Feb 2023 11:49:15 +0100 Subject: [PATCH 35/52] Fixed np.float issue. --- tracker.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tracker.py b/tracker.py index 1d845a3..d3a1cc4 100644 --- a/tracker.py +++ b/tracker.py @@ -762,7 +762,7 @@ class Tracker(): return (avg_conf, np.array(lms)) def estimate_depth(self, face_info): - lms = np.concatenate((face_info.lms, np.array([[face_info.eye_state[0][1], face_info.eye_state[0][2], face_info.eye_state[0][3]], [face_info.eye_state[1][1], face_info.eye_state[1][2], face_info.eye_state[1][3]]], np.float)), 0) + lms = np.concatenate((face_info.lms, np.array([[face_info.eye_state[0][1], face_info.eye_state[0][2], face_info.eye_state[0][3]], [face_info.eye_state[1][1], face_info.eye_state[1][2], face_info.eye_state[1][3]]], np.float32)), 0) image_pts = np.array(lms)[face_info.contour_pts, 0:2] From f13ae8a1ec60ca97b79937f8082efd36dcd9c276 Mon Sep 17 00:00:00 2001 From: Emiliana <38952746+emilianavt@users.noreply.github.com> Date: Tue, 21 Feb 2023 19:57:14 +0100 Subject: [PATCH 36/52] Updated README. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 70b051f..e160c57 100644 --- a/README.md +++ b/README.md @@ -101,7 +101,7 @@ Four pretrained face landmark models are included. Using the `--model` switch, i FPS measurements are from running on one core of my CPU. -Pytorch weights for use with `model.py` can be found [here](https://mega.nz/file/vvYXlYQT#h7FpEg4tmOCJNxjpsDEw0JomJIkVGKwrt4OUV0RNDDU). +Pytorch weights for use with `model.py` can be found [here](https://mega.nz/file/vvYXlYQT#h7FpEg4tmOCJNxjpsDEw0JomJIkVGKwrt4OUV0RNDDU). Some unoptimized ONNX models can be found [here](https://github.com/emilianavt/OpenSeeFace/issues/48). # Results From 89e104004bbb9759cd26a640ed5f526d5ebf9702 Mon Sep 17 00:00:00 2001 From: Emiliana <38952746+emilianavt@users.noreply.github.com> Date: Mon, 20 Mar 2023 21:28:38 +0100 Subject: [PATCH 37/52] Blacklisted more virtual cameras. --- dshowcapture/dshowcapture_x64.dll | Bin 117248 -> 117760 bytes dshowcapture/dshowcapture_x86.dll | Bin 104960 -> 104960 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/dshowcapture/dshowcapture_x64.dll b/dshowcapture/dshowcapture_x64.dll index a31c51db392bd8536232d68bd2f6c43e49a1a280..e7f30fdf90d8eca67c8ae62d27e82db6e0d50ae4 100644 GIT binary patch delta 24044 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 INeapT0*Nydh5!Hn delta 18868 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 Date: Mon, 17 Apr 2023 21:16:54 +0200 Subject: [PATCH 38/52] Updated poetry.lock --- poetry.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/poetry.lock b/poetry.lock index 78b88f7..6ca372b 100644 --- a/poetry.lock +++ b/poetry.lock @@ -48,7 +48,7 @@ python-versions = ">=3.6" [[package]] name = "protobuf" -version = "3.19.1" +version = "3.19.5" description = "Protocol Buffers" category = "main" optional = false From 75b2fc6196e4e98625dafb66726d2d70be0c0b18 Mon Sep 17 00:00:00 2001 From: Emiliana <38952746+emilianavt@users.noreply.github.com> Date: Fri, 21 Apr 2023 10:42:58 +0200 Subject: [PATCH 39/52] Added commit hash to model.py. --- model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/model.py b/model.py index 2824779..3083762 100644 --- a/model.py +++ b/model.py @@ -1,7 +1,7 @@ # This file is not used by the tracking application and currently outdated import torch import torch.nn as nn -import geffnet.mobilenetv3 # geffnet.mobilenetv3._gen_mobilenet_v3 needs to be patched to return the parameters instead of instantiating the network +import geffnet.mobilenetv3 # geffnet.mobilenetv3._gen_mobilenet_v3 needs to be patched to return the parameters instead of instantiating the network, based on commit c450c12ae6ffb1757f62dde3c2765da3c10f6def from geffnet.efficientnet_builder import round_channels class DSConv2d(nn.Module): From c31c891959b0d1b238ee3bbb4094b702622bebe8 Mon Sep 17 00:00:00 2001 From: John Gebbie Date: Wed, 3 May 2023 09:02:08 +0100 Subject: [PATCH 40/52] tidy: not x is None -> x is not None --- dshowcapture.py | 6 +++--- facetracker.py | 34 +++++++++++++++++----------------- tracker.py | 2 +- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/dshowcapture.py b/dshowcapture.py index 46def39..515125c 100644 --- a/dshowcapture.py +++ b/dshowcapture.py @@ -77,7 +77,7 @@ class DShowCapture(): bm_lib.stop_capture_single.argtypes = [] bm_lib.get_json_length.argtypes = [] bm_lib.get_json.argtypes = [c_char_p, c_int] - if not bm_options is None: + if bm_options is not None: bm_lib.set_options.argtypes = [c_char_p] bm_lib.set_options(bm_options.encode()) self.lib = lib @@ -93,7 +93,7 @@ class DShowCapture(): self.type = None def __del__(self): - if not self.buffer is None: + if self.buffer is not None: del self.buffer del self.name_buffer self.destroy_capture() @@ -329,7 +329,7 @@ if __name__ == "__main__": while True: img = cap.get_frame(1000) - if not img is None: + if img is not None: cv2.imshow("DShowCapture", img) if cv2.waitKey(1) & 0xFF == ord('q'): sys.exit(0) diff --git a/facetracker.py b/facetracker.py index 4f05c07..c629835 100644 --- a/facetracker.py +++ b/facetracker.py @@ -60,12 +60,12 @@ class OutputLog(object): self.fh = fh self.output = output def write(self, buf): - if not self.fh is None: + if self.fh is not None: self.fh.write(buf) self.output.write(buf) self.flush() def flush(self): - if not self.fh is None: + if self.fh is not None: self.fh.flush() self.output.flush() output_logfile = None @@ -78,19 +78,19 @@ if os.name == 'nt': import dshowcapture if args.blackmagic == 1: dshowcapture.set_bm_enabled(True) - if not args.blackmagic_options is None: + if args.blackmagic_options is not None: dshowcapture.set_options(args.blackmagic_options) - if not args.priority is None: + if args.priority is not None: import psutil classes = [psutil.IDLE_PRIORITY_CLASS, psutil.BELOW_NORMAL_PRIORITY_CLASS, psutil.NORMAL_PRIORITY_CLASS, psutil.ABOVE_NORMAL_PRIORITY_CLASS, psutil.HIGH_PRIORITY_CLASS, psutil.REALTIME_PRIORITY_CLASS] p = psutil.Process(os.getpid()) p.nice(classes[args.priority]) -if os.name == 'nt' and (args.list_cameras > 0 or not args.list_dcaps is None): +if os.name == 'nt' and (args.list_cameras > 0 or args.list_dcaps is not None): cap = dshowcapture.DShowCapture() info = cap.get_info() unit = 10000000.; - if not args.list_dcaps is None: + if args.list_dcaps is not None: formats = {0: "Any", 1: "Unknown", 100: "ARGB", 101: "XRGB", 200: "I420", 201: "NV12", 202: "YV12", 203: "Y800", 300: "YVYU", 301: "YUY2", 302: "UYVY", 303: "HDYC (Unsupported)", 400: "MJPEG", 401: "H264" } for cam in info: if args.list_dcaps == -1: @@ -248,7 +248,7 @@ try: height, width, channels = frame.shape sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) tracker = Tracker(width, height, threshold=args.threshold, max_threads=args.max_threads, max_faces=args.faces, discard_after=args.discard_after, scan_every=args.scan_every, silent=False if args.silent == 0 else True, model_type=args.model, model_dir=args.model_dir, no_gaze=False if args.gaze_tracking != 0 and args.model != -1 else True, detection_threshold=args.detection_threshold, use_retinaface=args.scan_retinaface, max_feature_updates=args.max_feature_updates, static_model=True if args.no_3d_adapt == 1 else False, try_hard=args.try_hard == 1) - if not args.video_out is None: + if args.video_out is not None: out = cv2.VideoWriter(args.video_out, cv2.VideoWriter_fourcc('F','F','V','1'), args.video_fps, (width * args.video_scale, height * args.video_scale)) try: @@ -291,7 +291,7 @@ try: packet.extend(bytearray(struct.pack("f", f.translation[0]))) packet.extend(bytearray(struct.pack("f", f.translation[1]))) packet.extend(bytearray(struct.pack("f", f.translation[2]))) - if not log is None: + if log is not None: log.write(f"{frame_count},{now},{width},{height},{fps},{face_num},{f.id},{f.eye_blink[0]},{f.eye_blink[1]},{f.conf},{f.success},{f.pnp_error},{f.quaternion[0]},{f.quaternion[1]},{f.quaternion[2]},{f.quaternion[3]},{f.euler[0]},{f.euler[1]},{f.euler[2]},{f.rotation[0]},{f.rotation[1]},{f.rotation[2]},{f.translation[0]},{f.translation[1]},{f.translation[2]}") for (x,y,c) in f.lms: packet.extend(bytearray(struct.pack("f", c))) @@ -302,7 +302,7 @@ try: for pt_num, (x,y,c) in enumerate(f.lms): packet.extend(bytearray(struct.pack("f", y))) packet.extend(bytearray(struct.pack("f", x))) - if not log is None: + if log is not None: log.write(f",{y},{x},{c}") if pt_num == 66 and (f.eye_blink[0] < 0.30 or c < 0.20): continue @@ -310,7 +310,7 @@ try: continue x = int(x + 0.5) y = int(y + 0.5) - if args.visualize != 0 or not out is None: + if args.visualize != 0 or out is not None: if args.visualize > 3: frame = cv2.putText(frame, str(pt_num), (int(y), int(x)), cv2.FONT_HERSHEY_SIMPLEX, 0.25, (255,255,0)) color = (0, 255, 0) @@ -327,7 +327,7 @@ try: x -= 1 if not (x < 0 or y < 0 or x >= height or y >= width): frame[int(x), int(y)] = color - if args.pnp_points != 0 and (args.visualize != 0 or not out is None) and f.rotation is not None: + if args.pnp_points != 0 and (args.visualize != 0 or out is not None) and f.rotation is not None: if args.pnp_points > 1: projected = cv2.projectPoints(f.face_3d[0:66], f.rotation, f.translation, tracker.camera, tracker.dist_coeffs) else: @@ -350,7 +350,7 @@ try: packet.extend(bytearray(struct.pack("f", x))) packet.extend(bytearray(struct.pack("f", -y))) packet.extend(bytearray(struct.pack("f", -z))) - if not log is None: + if log is not None: log.write(f",{x},{-y},{-z}") if f.current_features is None: f.current_features = {} @@ -358,16 +358,16 @@ try: if not feature in f.current_features: f.current_features[feature] = 0 packet.extend(bytearray(struct.pack("f", f.current_features[feature]))) - if not log is None: + if log is not None: log.write(f",{f.current_features[feature]}") - if not log is None: + if log is not None: log.write("\r\n") log.flush() if detected and len(faces) < 40: sock.sendto(packet, (target_ip, target_port)) - if not out is None: + if out is not None: video_frame = frame if args.video_scale != 1: video_frame = cv2.resize(frame, (width * args.video_scale, height * args.video_scale), interpolation=cv2.INTER_NEAREST) @@ -378,7 +378,7 @@ try: if args.visualize != 0: cv2.imshow('OpenSeeFace Visualization', frame) if cv2.waitKey(1) & 0xFF == ord('q'): - if args.dump_points != "" and not faces is None and len(faces) > 0: + if args.dump_points != "" and faces is not None and len(faces) > 0: np.set_printoptions(threshold=sys.maxsize, precision=15) pairs = [ (0, 16), @@ -454,7 +454,7 @@ except KeyboardInterrupt: print("Quitting") input_reader.close() -if not out is None: +if out is not None: out.release() cv2.destroyAllWindows() diff --git a/tracker.py b/tracker.py index d3a1cc4..0854775 100644 --- a/tracker.py +++ b/tracker.py @@ -767,7 +767,7 @@ class Tracker(): image_pts = np.array(lms)[face_info.contour_pts, 0:2] success = False - if not face_info.rotation is None: + if face_info.rotation is not None: success, face_info.rotation, face_info.translation = cv2.solvePnP(face_info.contour, image_pts, self.camera, self.dist_coeffs, useExtrinsicGuess=True, rvec=np.transpose(face_info.rotation), tvec=np.transpose(face_info.translation), flags=cv2.SOLVEPNP_ITERATIVE) else: rvec = np.array([0, 0, 0], np.float32) From 96a9a2549af23363e08bdd3e8c6ed3219dbe5dff Mon Sep 17 00:00:00 2001 From: John Gebbie Date: Wed, 3 May 2023 09:39:36 +0100 Subject: [PATCH 41/52] tidy: use cv2.circle --- facetracker.py | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/facetracker.py b/facetracker.py index c629835..a30628e 100644 --- a/facetracker.py +++ b/facetracker.py @@ -317,16 +317,7 @@ try: if pt_num >= 66: color = (255, 255, 0) if not (x < 0 or y < 0 or x >= height or y >= width): - frame[int(x), int(y)] = color - x += 1 - if not (x < 0 or y < 0 or x >= height or y >= width): - frame[int(x), int(y)] = color - y += 1 - if not (x < 0 or y < 0 or x >= height or y >= width): - frame[int(x), int(y)] = color - x -= 1 - if not (x < 0 or y < 0 or x >= height or y >= width): - frame[int(x), int(y)] = color + cv2.circle(frame, (y, x), 1, color, -1) if args.pnp_points != 0 and (args.visualize != 0 or out is not None) and f.rotation is not None: if args.pnp_points > 1: projected = cv2.projectPoints(f.face_3d[0:66], f.rotation, f.translation, tracker.camera, tracker.dist_coeffs) From d242009e0ba20b5f0bb6614685819d991ad9c96d Mon Sep 17 00:00:00 2001 From: Kiri Date: Sun, 21 May 2023 16:46:51 -0700 Subject: [PATCH 42/52] Removed deprecated use of 'np.int' and replaced it with 'int'. Fixes numpy 1.24.0 and up compatibility. --- model.py | 2 +- tracker.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/model.py b/model.py index 3083762..8f769cd 100644 --- a/model.py +++ b/model.py @@ -251,7 +251,7 @@ def AdapWingLoss(pre_hm, gt_hm): img_dilate = cv2.morphologyEx(img_merge, cv2.MORPH_DILATE, kernel) img_dilate[img_dilate < 51] = 1 # 0*W+1 img_dilate[img_dilate >= 51] = 11 # 1*W+1 - img_dilate = np.array(img_dilate, dtype=np.int) + img_dilate = np.array(img_dilate, dtype=int) img_dilate = img_dilate.transpose(2, 0, 1) dilated = torch.from_numpy(img_dilate).float() if first: diff --git a/tracker.py b/tracker.py index 0854775..f0588c2 100644 --- a/tracker.py +++ b/tracker.py @@ -920,7 +920,7 @@ class Tracker(): x1, y1 = clamp_to_im(center - radius, h, w) x2, y2 = clamp_to_im(center + radius + 1, h, w) offset = np.array((x1, y1)) - lms = (lms[:, 0:2] - offset).astype(np.int) + lms = (lms[:, 0:2] - offset).astype(int) frame = frame[y1:y2, x1:x2] return frame, lms, offset From 5d3977934b142c51e1d8467eebd87ec28f0c5edf Mon Sep 17 00:00:00 2001 From: Emiliana <129859783+emilianavt2@users.noreply.github.com> Date: Sun, 27 Aug 2023 17:09:42 +0200 Subject: [PATCH 43/52] Updated dependencies in README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index e160c57..9b0102b 100644 --- a/README.md +++ b/README.md @@ -145,16 +145,16 @@ install all dependencies for this project in a separate virtual env: poetry install -# Dependencies (Python 3.10 and above) +# Dependencies -* ort-nightly +* onnxruntime * OpenCV * Pillow * Numpy The required libraries can be installed using pip: - pip install ort-nightly opencv-python pillow numpy + pip install onnxruntime opencv-python pillow numpy # References From ccbcae05c0acfb9da08115eb3df7f372cfabe7ff Mon Sep 17 00:00:00 2001 From: Emiliana <38952746+emilianavt@users.noreply.github.com> Date: Thu, 25 Jan 2024 12:33:50 +0100 Subject: [PATCH 44/52] Updated poetry.lock --- poetry.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/poetry.lock b/poetry.lock index 6ca372b..f0a9cf0 100644 --- a/poetry.lock +++ b/poetry.lock @@ -40,7 +40,7 @@ numpy = ">=1.21.2" [[package]] name = "pillow" -version = "9.3.0" +version = "10.2.0" description = "Python Imaging Library (Fork)" category = "main" optional = false From 2b3225f599193dbb093fdd627cf612f913b8dd5d Mon Sep 17 00:00:00 2001 From: Emiliana <38952746+emilianavt@users.noreply.github.com> Date: Sat, 1 Jun 2024 00:17:08 +0200 Subject: [PATCH 45/52] Updated video link. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9b0102b..4d17be5 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ Since the landmarks used by OpenSeeFace are a bit different from those used by o From general observation, OpenSeeFace performs well in adverse conditions (low light, high noise, low resolution) and keeps tracking faces through a very wide range of head poses with relatively high stability of landmark positions. Compared to MediaPipe, OpenSeeFace landmarks remain more stable in challenging conditions and it accurately represents a wider range of mouth poses. However, tracking of the eye region can be less accurate. -I ran OpenSeeFace on a sample clip from the video presentation for [3D Face Reconstruction with Dense Landmarks](https://microsoft.github.io/DenseLandmarks/) by Wood et al. to compare it to MediaPipe and their approach. You can watch the result [here](https://cdn.discordapp.com/attachments/720652345540870237/1016320201807106118/OSFMediaPipe3DFR.mp4). +I ran OpenSeeFace on a sample clip from the video presentation for [3D Face Reconstruction with Dense Landmarks](https://microsoft.github.io/DenseLandmarks/) by Wood et al. to compare it to MediaPipe and their approach. You can watch the result [here](https://www.vseeface.icu/assets/media/OSFMediaPipe3DFR.mp4). # Usage From de37867e1f42d6e8e63d814d5ff7638c9ca9602e Mon Sep 17 00:00:00 2001 From: Alyssa Ross Date: Fri, 20 Sep 2024 10:41:38 +0200 Subject: [PATCH 46/52] Don't destroy windows if visualization disabled This fixes the following error on exit when OpenCV is built without GUI support: Traceback (most recent call last): File "facetracker.py", line 450, in cv2.error: OpenCV(4.9.0) /build/source/modules/highgui/src/window.cpp:1266: error: (-2:Unspecified error) The function is not implemented. Rebuild the library with Windows, GTK+ 2.x or Cocoa support. If you are on Ubuntu or Debian, install libgtk2.0-dev and pkg-config, then re-run cmake or configure script in function 'cvDestroyAllWindows' [254225] Failed to execute script 'facetracker' due to unhandled exception! --- facetracker.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/facetracker.py b/facetracker.py index a30628e..bb6906c 100644 --- a/facetracker.py +++ b/facetracker.py @@ -447,7 +447,8 @@ except KeyboardInterrupt: input_reader.close() if out is not None: out.release() -cv2.destroyAllWindows() +if args.visualize != 0: + cv2.destroyAllWindows() if args.silent == 0 and tracking_frames > 0: average_tracking_time = 1000 * tracking_time / tracking_frames From dee5bb76066d062e7d80828ff407cbc5854f94f1 Mon Sep 17 00:00:00 2001 From: Emiliana <38952746+emilianavt@users.noreply.github.com> Date: Mon, 16 Jun 2025 23:56:34 +0200 Subject: [PATCH 47/52] Update poetry.lock --- poetry.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/poetry.lock b/poetry.lock index f0a9cf0..ffcd882 100644 --- a/poetry.lock +++ b/poetry.lock @@ -48,7 +48,7 @@ python-versions = ">=3.6" [[package]] name = "protobuf" -version = "3.19.5" +version = "4.25.8" description = "Protocol Buffers" category = "main" optional = false From 66e8d91b527b9df4d4a7f8a64195308bdd345db9 Mon Sep 17 00:00:00 2001 From: RanAS Date: Fri, 21 Nov 2025 13:54:07 -0300 Subject: [PATCH 48/52] feat: add fourcc / device format support on Linux, using V4L2 (Video4Linux2) --- facetracker.py | 4 ++++ input_reader.py | 27 ++++++++++++++++++++++++++- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/facetracker.py b/facetracker.py index bb6906c..0a81423 100644 --- a/facetracker.py +++ b/facetracker.py @@ -18,6 +18,8 @@ if os.name == 'nt': else: parser.add_argument("-W", "--width", type=int, help="Set raw RGB width", default=640) parser.add_argument("-H", "--height", type=int, help="Set raw RGB height", default=360) +if sys.platform == 'linux': + parser.add_argument("--dformat", type=str, help="Set which device format to use", default=None) parser.add_argument("-F", "--fps", type=int, help="Set camera frames per second", default=24) parser.add_argument("-c", "--capture", help="Set camera ID (0, 1...) or video file", default="0") parser.add_argument("-M", "--mirror-input", action="store_true", help="Process a mirror image of the input video") @@ -162,6 +164,8 @@ if os.name == 'nt': input_reader = InputReader(args.capture, args.raw_rgb, args.width, args.height, fps, use_dshowcapture=use_dshowcapture_flag, dcap=dcap) if args.dcap == -1 and type(input_reader) == DShowCaptureReader: fps = min(fps, input_reader.device.get_fps()) +elif sys.platform == 'linux' and args.dformat: + input_reader = InputReader(args.capture, args.raw_rgb, args.width, args.height, fps, dcap=args.dformat) else: input_reader = InputReader(args.capture, args.raw_rgb, args.width, args.height, fps) if type(input_reader.reader) == VideoReader: diff --git a/input_reader.py b/input_reader.py index f2a2c91..49b7a5b 100644 --- a/input_reader.py +++ b/input_reader.py @@ -13,7 +13,7 @@ class VideoReader(): def __init__(self, capture, camera=False): if os.name == 'nt' and camera: self.cap = cv2.VideoCapture(capture, cv2.CAP_DSHOW) - else: + elif self.cap is None: self.cap = cv2.VideoCapture(capture) if self.cap is None: print("The video source cannot be opened") @@ -121,6 +121,23 @@ class OpenCVReader(VideoReader): def close(self): super(OpenCVReader, self).close() +class V4L2Reader(OpenCVReader): + def __init__(self, capture, width, height, fps, dformat): + self.cap = cv2.VideoCapture(capture, cv2.CAP_V4L2) + if dformat: + fourcc = cv2.VideoWriter_fourcc(*dformat) + self.cap.set(6, fourcc) + super(V4L2Reader, self).__init__(capture, width, height, fps) + self.cap.set(5, fps) + def is_open(self): + return super(V4L2Reader, self).is_open() + def is_ready(self): + return super(V4L2Reader, self).is_ready() + def read(self): + return super(V4L2Reader, self).read() + def close(self): + super(V4L2Reader, self).close() + class RawReader: def __init__(self, width, height): self.width = int(width) @@ -232,6 +249,14 @@ class InputReader(): print(f"Escapi failed. Falling back to OpenCV. If this fails, please change your camera settings.", file=sys.stderr) self.reader = OpenCVReader(int(capture), width, height, fps) self.name = self.reader.name + elif sys.platform == 'linux': + try: + self.reader = V4L2Reader(int(capture), width, height, fps, dcap) + except: + print("V4L2 exception: ") + traceback.print_exc() + print(f"V4L2 failed. Falling back to OpenCV. If this fails, please change your camera settings.", file=sys.stderr) + self.reader = OpenCVReader(int(capture), width, height, fps) else: self.reader = OpenCVReader(int(capture), width, height, fps) except Exception as e: From f7ef854afac4876d2dc67ab8222eaef2d645d3dd Mon Sep 17 00:00:00 2001 From: RanAS Date: Mon, 24 Nov 2025 19:19:07 -0300 Subject: [PATCH 49/52] adding --dformat examples --- facetracker.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/facetracker.py b/facetracker.py index 0a81423..dc0d552 100644 --- a/facetracker.py +++ b/facetracker.py @@ -19,7 +19,7 @@ else: parser.add_argument("-W", "--width", type=int, help="Set raw RGB width", default=640) parser.add_argument("-H", "--height", type=int, help="Set raw RGB height", default=360) if sys.platform == 'linux': - parser.add_argument("--dformat", type=str, help="Set which device format to use", default=None) + parser.add_argument("--dformat", type=str, help="Set which device format to use (MJPG, YUYV, RGB3, ...)", default=None) parser.add_argument("-F", "--fps", type=int, help="Set camera frames per second", default=24) parser.add_argument("-c", "--capture", help="Set camera ID (0, 1...) or video file", default="0") parser.add_argument("-M", "--mirror-input", action="store_true", help="Process a mirror image of the input video") From 17d954338e0ff74e16c83c5679ea94c8065a49b9 Mon Sep 17 00:00:00 2001 From: RanAS Date: Mon, 24 Nov 2025 19:21:07 -0300 Subject: [PATCH 50/52] change V4L2Reader to not call OpenCVReader __init__ --- input_reader.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/input_reader.py b/input_reader.py index 49b7a5b..2344ada 100644 --- a/input_reader.py +++ b/input_reader.py @@ -13,7 +13,7 @@ class VideoReader(): def __init__(self, capture, camera=False): if os.name == 'nt' and camera: self.cap = cv2.VideoCapture(capture, cv2.CAP_DSHOW) - elif self.cap is None: + else: self.cap = cv2.VideoCapture(capture) if self.cap is None: print("The video source cannot be opened") @@ -125,9 +125,16 @@ class V4L2Reader(OpenCVReader): def __init__(self, capture, width, height, fps, dformat): self.cap = cv2.VideoCapture(capture, cv2.CAP_V4L2) if dformat: - fourcc = cv2.VideoWriter_fourcc(*dformat) + fourcc = cv2.VideoWriter.fourcc(*dformat) self.cap.set(6, fourcc) - super(V4L2Reader, self).__init__(capture, width, height, fps) + self.device = None + self.width = width + self.height = height + self.fps = fps + self.name = str(capture) + self.cap.set(3, width) + self.cap.set(4, height) + self.cap.set(38, 1) self.cap.set(5, fps) def is_open(self): return super(V4L2Reader, self).is_open() From d4af2410d416402dcf990576bb9247a6cf8f7478 Mon Sep 17 00:00:00 2001 From: shiffi meekling Date: Fri, 26 Dec 2025 23:31:30 -0800 Subject: [PATCH 51/52] lengthen log headers to match length of data I based changed the numbers based on lengths I observed with `print(len(f.lms))` and `print(len(f.pts_e3))`. Once I changed the numbers to their new values, the header became the same length as the data, which makes me think I reconstructed the intent correctly. However, since the readme says the training data had 66 key points, it raises questions about what the extra 2 and 4 keypoints respectively represent. --- facetracker.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/facetracker.py b/facetracker.py index dc0d552..205b2fb 100644 --- a/facetracker.py +++ b/facetracker.py @@ -188,9 +188,9 @@ features = ["eye_l", "eye_r", "eyebrow_steepness_l", "eyebrow_updown_l", "eyebro if args.log_data != "": log = open(args.log_data, "w") log.write("Frame,Time,Width,Height,FPS,Face,FaceID,RightOpen,LeftOpen,AverageConfidence,Success3D,PnPError,RotationQuat.X,RotationQuat.Y,RotationQuat.Z,RotationQuat.W,Euler.X,Euler.Y,Euler.Z,RVec.X,RVec.Y,RVec.Z,TVec.X,TVec.Y,TVec.Z") - for i in range(66): + for i in range(68): log.write(f",Landmark[{i}].X,Landmark[{i}].Y,Landmark[{i}].Confidence") - for i in range(66): + for i in range(70): log.write(f",Point3D[{i}].X,Point3D[{i}].Y,Point3D[{i}].Z") for feature in features: log.write(f",{feature}") From 6da0ba68dfcfc15266261517b0c416b2e78403b0 Mon Sep 17 00:00:00 2001 From: copilot Date: Mon, 14 Sep 2026 11:12:25 +0200 Subject: [PATCH 52/52] Fix PnP rotation/translation shape for modern OpenCV/NumPy. solvePnP returns (3,1); transpose made (1,3), which broke eye depth .dot() and struct.pack of translation scalars. Flatten to (3,) instead. Co-authored-by: Cursor --- tracker.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tracker.py b/tracker.py index f0588c2..26f8305 100644 --- a/tracker.py +++ b/tracker.py @@ -783,8 +783,10 @@ class Tracker(): face_info.translation = np.array([0.0, 0.0, 0.0], np.float32) return False, np.zeros(4), np.zeros(3), 99999., pts_3d, lms else: - face_info.rotation = np.transpose(face_info.rotation) - face_info.translation = np.transpose(face_info.translation) + # OpenCV returns (3,1); flatten so [0]/[1]/[2] are scalars for UDP packing + # and 1D .dot() math does not broadcast to (1,3). + face_info.rotation = np.asarray(face_info.rotation, dtype=np.float32).reshape(3) + face_info.translation = np.asarray(face_info.translation, dtype=np.float32).reshape(3) rmat, _ = cv2.Rodrigues(rotation) inverse_rotation = np.linalg.inv(rmat) @@ -833,7 +835,7 @@ class Tracker(): reference = rmat.dot(pt) reference = reference + face_info.translation reference = self.camera.dot(reference) - depth = reference[2] + depth = float(reference[2]) pt_3d = np.array([lms[66+i][0] * depth, lms[66+i][1] * depth, depth], np.float32) pt_3d = self.inverse_camera.dot(pt_3d) pt_3d = pt_3d - face_info.translation