dynamo-figures 0.3.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dynamo_figures-0.3.2/PKG-INFO +139 -0
- dynamo_figures-0.3.2/README.md +116 -0
- dynamo_figures-0.3.2/pyproject.toml +48 -0
- dynamo_figures-0.3.2/setup.cfg +4 -0
- dynamo_figures-0.3.2/src/dynamo_figures/__init__.py +13 -0
- dynamo_figures-0.3.2/src/dynamo_figures/__main__.py +6 -0
- dynamo_figures-0.3.2/src/dynamo_figures/blur_faces/__init__.py +18 -0
- dynamo_figures-0.3.2/src/dynamo_figures/blur_faces/__main__.py +6 -0
- dynamo_figures-0.3.2/src/dynamo_figures/blur_faces/cli.py +150 -0
- dynamo_figures-0.3.2/src/dynamo_figures/blur_faces/core.py +277 -0
- dynamo_figures-0.3.2/src/dynamo_figures/blur_faces/detectors.py +220 -0
- dynamo_figures-0.3.2/src/dynamo_figures/blur_faces/models/face_detection_yunet_2023mar.onnx +0 -0
- dynamo_figures-0.3.2/src/dynamo_figures/blur_faces/obscure.py +115 -0
- dynamo_figures-0.3.2/src/dynamo_figures/blur_faces/tracking.py +125 -0
- dynamo_figures-0.3.2/src/dynamo_figures/blur_faces/video_io.py +153 -0
- dynamo_figures-0.3.2/src/dynamo_figures/composite_image.py +233 -0
- dynamo_figures-0.3.2/src/dynamo_figures/pic_from_video.py +217 -0
- dynamo_figures-0.3.2/src/dynamo_figures/qr_code.py +349 -0
- dynamo_figures-0.3.2/src/dynamo_figures/tex2img.py +409 -0
- dynamo_figures-0.3.2/src/dynamo_figures/video_to_gif.py +453 -0
- dynamo_figures-0.3.2/src/dynamo_figures.egg-info/PKG-INFO +139 -0
- dynamo_figures-0.3.2/src/dynamo_figures.egg-info/SOURCES.txt +24 -0
- dynamo_figures-0.3.2/src/dynamo_figures.egg-info/dependency_links.txt +1 -0
- dynamo_figures-0.3.2/src/dynamo_figures.egg-info/entry_points.txt +7 -0
- dynamo_figures-0.3.2/src/dynamo_figures.egg-info/requires.txt +21 -0
- dynamo_figures-0.3.2/src/dynamo_figures.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: dynamo-figures
|
|
3
|
+
Version: 0.3.2
|
|
4
|
+
Summary: A Python package for figure generation
|
|
5
|
+
Author: Dynamic Mobility Lab at Georgia Tech
|
|
6
|
+
Author-email: Neil Janwani <njanwani@gatech.edu>
|
|
7
|
+
Requires-Python: >=3.8
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
Requires-Dist: opencv-python>=4.0.0
|
|
10
|
+
Requires-Dist: numpy>=1.20.0
|
|
11
|
+
Requires-Dist: tqdm>=4.0.0
|
|
12
|
+
Requires-Dist: Pillow>=8.0.0
|
|
13
|
+
Requires-Dist: qrcode>=7.0.0
|
|
14
|
+
Provides-Extra: gpu
|
|
15
|
+
Requires-Dist: onnxruntime>=1.17; sys_platform == "darwin" and extra == "gpu"
|
|
16
|
+
Requires-Dist: onnxruntime-gpu[cuda,cudnn]>=1.21; sys_platform != "darwin" and extra == "gpu"
|
|
17
|
+
Provides-Extra: svg
|
|
18
|
+
Requires-Dist: cairosvg>=2.5.0; extra == "svg"
|
|
19
|
+
Provides-Extra: dev
|
|
20
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
21
|
+
Requires-Dist: black>=22.0.0; extra == "dev"
|
|
22
|
+
Requires-Dist: flake8>=4.0.0; extra == "dev"
|
|
23
|
+
|
|
24
|
+
# Dynamo Figures
|
|
25
|
+
|
|
26
|
+
A Python package for creating composite images from videos. This tool extracts frames from a video and merges them using various composition modes to create stunning visual effects.
|
|
27
|
+
|
|
28
|
+
## Installation
|
|
29
|
+
|
|
30
|
+
### Install from Git
|
|
31
|
+
```bash
|
|
32
|
+
# Install directly from GitHub
|
|
33
|
+
pip install git+ssh://git@github.com/dynamicmobility/dynamo_figures.git
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Install from Local Directory
|
|
37
|
+
```bash
|
|
38
|
+
# From within the project directory
|
|
39
|
+
git clone git@github.com:dynamicmobility/dynamo_figures.git
|
|
40
|
+
cd dynamo_figures
|
|
41
|
+
pip install -e .
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Usage
|
|
45
|
+
|
|
46
|
+
### Command-Line Interface
|
|
47
|
+
|
|
48
|
+
After installation, you can use the `dynamo-composite-image` command:
|
|
49
|
+
|
|
50
|
+
#### 1. VAR Mode (Recommended)
|
|
51
|
+
Uses pixels that are furthest from the mean of the image, creating dynamic composite effects.
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
dynamo-composite-image --video_path ./example/video.mp4 --start_t 0.0 --end_t 99.0 --skip_frame 2 --mode VAR --alpha 0.4 --output ./example/composite.png
|
|
55
|
+
```
|
|
56
|
+

|
|
57
|
+
|
|
58
|
+
#### 2. MIN Mode
|
|
59
|
+
Keeps the darkest pixels from all frames.
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
dynamo-composite-image --video_path ./example/video.mp4 --start_t 0.0 --end_t 99.0 --skip_frame 2 --mode MIN --output ./example/composite.png
|
|
63
|
+
```
|
|
64
|
+

|
|
65
|
+
|
|
66
|
+
#### 3. MAX Mode
|
|
67
|
+
Keeps the lightest pixels from all frames.
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
dynamo-composite-image --video_path ./example/video.mp4 --start_t 0.0 --end_t 99.0 --skip_frame 2 --mode MAX --output ./example/composite.png
|
|
71
|
+
```
|
|
72
|
+

|
|
73
|
+
|
|
74
|
+
### Python API
|
|
75
|
+
|
|
76
|
+
You can also use the package programmatically in your Python scripts:
|
|
77
|
+
|
|
78
|
+
```python
|
|
79
|
+
from dynamo_figures import CompositeImage, CompositeMode
|
|
80
|
+
import cv2
|
|
81
|
+
|
|
82
|
+
# Create a composite image with VAR mode
|
|
83
|
+
merger = CompositeImage(
|
|
84
|
+
mode=CompositeMode.MAX_VARIATION,
|
|
85
|
+
video_path="./example/video.mp4",
|
|
86
|
+
start_t=0.0,
|
|
87
|
+
end_t=99.0,
|
|
88
|
+
skip_frame=2,
|
|
89
|
+
alpha=0.4,
|
|
90
|
+
disable_pbar=False # Set to True to disable the progress bar
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
# Generate the composite
|
|
94
|
+
result = merger.merge_images()
|
|
95
|
+
|
|
96
|
+
# Save the result
|
|
97
|
+
cv2.imwrite("output.jpg", result)
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Alternative Command-Line Methods
|
|
101
|
+
|
|
102
|
+
If you haven't installed the package, you can still run it:
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
# Run as a Python module
|
|
106
|
+
python -m dynamo_figures.composite_image --video_path ./example_video.mp4 --mode VAR
|
|
107
|
+
|
|
108
|
+
# Or run directly
|
|
109
|
+
python src/dynamo_figures/composite_image.py --video_path ./example_video.mp4 --mode VAR
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Parameters
|
|
113
|
+
|
|
114
|
+
* `--video_path` (required): Path to the input video file
|
|
115
|
+
* `--start_t`: Start time in seconds (default: 0)
|
|
116
|
+
* `--end_t`: End time in seconds (default: 999999)
|
|
117
|
+
* `--skip_frame`: Number of frames to skip when extracting frames. Use `1` to process every frame (default: 1)
|
|
118
|
+
* `--mode`: Composition mode, three options available:
|
|
119
|
+
* `VAR` (Recommended): Uses pixels furthest from the mean, creating dynamic variation effects
|
|
120
|
+
* `MAX`: Keeps the lightest pixels across all frames
|
|
121
|
+
* `MIN`: Keeps the darkest pixels across all frames
|
|
122
|
+
* `--alpha`: Alpha blending factor for intermediate frames, range 0.0-1.0 (default: 0.5)
|
|
123
|
+
* `--disable_pbar`: Disable the progress bar when merging images (flag, no value needed)
|
|
124
|
+
* `--output`: Custom output file path (default: saves as `<video_name>.jpg` in the same directory as the input video)
|
|
125
|
+
|
|
126
|
+
## Dependencies
|
|
127
|
+
|
|
128
|
+
- Python >= 3.8
|
|
129
|
+
- opencv-python >= 4.0.0
|
|
130
|
+
- numpy >= 1.20.0
|
|
131
|
+
- tqdm >= 4.0.0
|
|
132
|
+
|
|
133
|
+
## License
|
|
134
|
+
|
|
135
|
+
All Rights Reserved 2023
|
|
136
|
+
|
|
137
|
+
## Credits
|
|
138
|
+
|
|
139
|
+
Original Author: renyunfan (renyf@connect.hku.hk)
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# Dynamo Figures
|
|
2
|
+
|
|
3
|
+
A Python package for creating composite images from videos. This tool extracts frames from a video and merges them using various composition modes to create stunning visual effects.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
### Install from Git
|
|
8
|
+
```bash
|
|
9
|
+
# Install directly from GitHub
|
|
10
|
+
pip install git+ssh://git@github.com/dynamicmobility/dynamo_figures.git
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
### Install from Local Directory
|
|
14
|
+
```bash
|
|
15
|
+
# From within the project directory
|
|
16
|
+
git clone git@github.com:dynamicmobility/dynamo_figures.git
|
|
17
|
+
cd dynamo_figures
|
|
18
|
+
pip install -e .
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Usage
|
|
22
|
+
|
|
23
|
+
### Command-Line Interface
|
|
24
|
+
|
|
25
|
+
After installation, you can use the `dynamo-composite-image` command:
|
|
26
|
+
|
|
27
|
+
#### 1. VAR Mode (Recommended)
|
|
28
|
+
Uses pixels that are furthest from the mean of the image, creating dynamic composite effects.
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
dynamo-composite-image --video_path ./example/video.mp4 --start_t 0.0 --end_t 99.0 --skip_frame 2 --mode VAR --alpha 0.4 --output ./example/composite.png
|
|
32
|
+
```
|
|
33
|
+

|
|
34
|
+
|
|
35
|
+
#### 2. MIN Mode
|
|
36
|
+
Keeps the darkest pixels from all frames.
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
dynamo-composite-image --video_path ./example/video.mp4 --start_t 0.0 --end_t 99.0 --skip_frame 2 --mode MIN --output ./example/composite.png
|
|
40
|
+
```
|
|
41
|
+

|
|
42
|
+
|
|
43
|
+
#### 3. MAX Mode
|
|
44
|
+
Keeps the lightest pixels from all frames.
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
dynamo-composite-image --video_path ./example/video.mp4 --start_t 0.0 --end_t 99.0 --skip_frame 2 --mode MAX --output ./example/composite.png
|
|
48
|
+
```
|
|
49
|
+

|
|
50
|
+
|
|
51
|
+
### Python API
|
|
52
|
+
|
|
53
|
+
You can also use the package programmatically in your Python scripts:
|
|
54
|
+
|
|
55
|
+
```python
|
|
56
|
+
from dynamo_figures import CompositeImage, CompositeMode
|
|
57
|
+
import cv2
|
|
58
|
+
|
|
59
|
+
# Create a composite image with VAR mode
|
|
60
|
+
merger = CompositeImage(
|
|
61
|
+
mode=CompositeMode.MAX_VARIATION,
|
|
62
|
+
video_path="./example/video.mp4",
|
|
63
|
+
start_t=0.0,
|
|
64
|
+
end_t=99.0,
|
|
65
|
+
skip_frame=2,
|
|
66
|
+
alpha=0.4,
|
|
67
|
+
disable_pbar=False # Set to True to disable the progress bar
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
# Generate the composite
|
|
71
|
+
result = merger.merge_images()
|
|
72
|
+
|
|
73
|
+
# Save the result
|
|
74
|
+
cv2.imwrite("output.jpg", result)
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Alternative Command-Line Methods
|
|
78
|
+
|
|
79
|
+
If you haven't installed the package, you can still run it:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
# Run as a Python module
|
|
83
|
+
python -m dynamo_figures.composite_image --video_path ./example_video.mp4 --mode VAR
|
|
84
|
+
|
|
85
|
+
# Or run directly
|
|
86
|
+
python src/dynamo_figures/composite_image.py --video_path ./example_video.mp4 --mode VAR
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Parameters
|
|
90
|
+
|
|
91
|
+
* `--video_path` (required): Path to the input video file
|
|
92
|
+
* `--start_t`: Start time in seconds (default: 0)
|
|
93
|
+
* `--end_t`: End time in seconds (default: 999999)
|
|
94
|
+
* `--skip_frame`: Number of frames to skip when extracting frames. Use `1` to process every frame (default: 1)
|
|
95
|
+
* `--mode`: Composition mode, three options available:
|
|
96
|
+
* `VAR` (Recommended): Uses pixels furthest from the mean, creating dynamic variation effects
|
|
97
|
+
* `MAX`: Keeps the lightest pixels across all frames
|
|
98
|
+
* `MIN`: Keeps the darkest pixels across all frames
|
|
99
|
+
* `--alpha`: Alpha blending factor for intermediate frames, range 0.0-1.0 (default: 0.5)
|
|
100
|
+
* `--disable_pbar`: Disable the progress bar when merging images (flag, no value needed)
|
|
101
|
+
* `--output`: Custom output file path (default: saves as `<video_name>.jpg` in the same directory as the input video)
|
|
102
|
+
|
|
103
|
+
## Dependencies
|
|
104
|
+
|
|
105
|
+
- Python >= 3.8
|
|
106
|
+
- opencv-python >= 4.0.0
|
|
107
|
+
- numpy >= 1.20.0
|
|
108
|
+
- tqdm >= 4.0.0
|
|
109
|
+
|
|
110
|
+
## License
|
|
111
|
+
|
|
112
|
+
All Rights Reserved 2023
|
|
113
|
+
|
|
114
|
+
## Credits
|
|
115
|
+
|
|
116
|
+
Original Author: renyunfan (renyf@connect.hku.hk)
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "dynamo-figures"
|
|
7
|
+
version = "0.3.2"
|
|
8
|
+
authors = [
|
|
9
|
+
{ name="Dynamic Mobility Lab at Georgia Tech" },
|
|
10
|
+
{ name="Neil Janwani", email="njanwani@gatech.edu" },
|
|
11
|
+
]
|
|
12
|
+
description = "A Python package for figure generation"
|
|
13
|
+
readme = "README.md"
|
|
14
|
+
requires-python = ">=3.8"
|
|
15
|
+
dependencies = [
|
|
16
|
+
"opencv-python>=4.0.0",
|
|
17
|
+
"numpy>=1.20.0",
|
|
18
|
+
"tqdm>=4.0.0",
|
|
19
|
+
"Pillow>=8.0.0",
|
|
20
|
+
"qrcode>=7.0.0",
|
|
21
|
+
]
|
|
22
|
+
[project.scripts]
|
|
23
|
+
dynamo-composite-image = "dynamo_figures.composite_image:main"
|
|
24
|
+
dynamo-pic-from-video = "dynamo_figures.pic_from_video:main"
|
|
25
|
+
dynamo-video-to-gif = "dynamo_figures.video_to_gif:main"
|
|
26
|
+
dynamo-qr-code = "dynamo_figures.qr_code:main"
|
|
27
|
+
dynamo-blur-faces = "dynamo_figures.blur_faces.cli:main"
|
|
28
|
+
dynamo-tex2img = "dynamo_figures.tex2img:main"
|
|
29
|
+
|
|
30
|
+
[project.optional-dependencies]
|
|
31
|
+
gpu = [
|
|
32
|
+
"onnxruntime>=1.17; sys_platform == 'darwin'",
|
|
33
|
+
"onnxruntime-gpu[cuda,cudnn]>=1.21; sys_platform != 'darwin'",
|
|
34
|
+
]
|
|
35
|
+
svg = [
|
|
36
|
+
"cairosvg>=2.5.0",
|
|
37
|
+
]
|
|
38
|
+
dev = [
|
|
39
|
+
"pytest>=7.0.0",
|
|
40
|
+
"black>=22.0.0",
|
|
41
|
+
"flake8>=4.0.0",
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
[tool.setuptools.package-data]
|
|
45
|
+
dynamo_figures = ["blur_faces/models/*.onnx"]
|
|
46
|
+
|
|
47
|
+
[tool.setuptools.packages.find]
|
|
48
|
+
where = ["src"]
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""
|
|
2
|
+
dynamo_figures - A Python package for dynamic figure generation
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
__version__ = "0.3.2"
|
|
6
|
+
|
|
7
|
+
from dynamo_figures.composite_image import CompositeImage, CompositeMode
|
|
8
|
+
from dynamo_figures.video_to_gif import VideoToGif
|
|
9
|
+
from dynamo_figures.qr_code import QRCode
|
|
10
|
+
from dynamo_figures.blur_faces import FaceBlur
|
|
11
|
+
from dynamo_figures.tex2img import TexToImage
|
|
12
|
+
|
|
13
|
+
__all__ = ["CompositeImage", "CompositeMode", "VideoToGif", "QRCode", "FaceBlur", "TexToImage", "__version__"]
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Package: dynamo_figures.blur_faces
|
|
3
|
+
Description: Anonymize faces in photos and videos, fully locally.
|
|
4
|
+
|
|
5
|
+
Modules:
|
|
6
|
+
core FaceBlur, the high-level image/video API
|
|
7
|
+
detectors YuNet detection on CPU (OpenCV) or GPU (ONNX Runtime)
|
|
8
|
+
tracking Frame-to-frame box smoothing and hold for videos
|
|
9
|
+
obscure Blur / pixelate / fill rendering
|
|
10
|
+
video_io Threaded frame reading and ffmpeg encoding
|
|
11
|
+
cli The dynamo-blur-faces command-line tool
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from dynamo_figures.blur_faces.core import FaceBlur
|
|
15
|
+
from dynamo_figures.blur_faces.detectors import gpu_provider
|
|
16
|
+
from dynamo_figures.blur_faces.tracking import FaceTracker
|
|
17
|
+
|
|
18
|
+
__all__ = ["FaceBlur", "FaceTracker", "gpu_provider"]
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
"""
|
|
2
|
+
File: cli.py
|
|
3
|
+
Description: Command-line interface for the dynamo-blur-faces tool.
|
|
4
|
+
Blurs, pixelates, or covers faces in a photo or video, fully locally.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import argparse
|
|
8
|
+
import sys
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
from dynamo_figures.blur_faces.core import FaceBlur
|
|
12
|
+
|
|
13
|
+
IMAGE_EXTENSIONS = {'.jpg', '.jpeg', '.png', '.bmp', '.tif', '.tiff', '.webp'}
|
|
14
|
+
VIDEO_EXTENSIONS = {'.mp4', '.mov', '.avi', '.mkv', '.m4v', '.webm', '.wmv'}
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def main():
|
|
18
|
+
"""Main function for command-line interface."""
|
|
19
|
+
parser = argparse.ArgumentParser(
|
|
20
|
+
prog='dynamo-blur-faces',
|
|
21
|
+
description='Blur, pixelate, or cover faces in a photo or video. Runs fully locally.',
|
|
22
|
+
epilog='-'
|
|
23
|
+
)
|
|
24
|
+
parser.add_argument('--input', type=str, required=True,
|
|
25
|
+
help='path of input image or video file.')
|
|
26
|
+
parser.add_argument('--output', type=str, default=None,
|
|
27
|
+
help='output file path (default: same directory as input with _blurred suffix)')
|
|
28
|
+
parser.add_argument('--style', default='blur', choices=FaceBlur.STYLES,
|
|
29
|
+
help='how to obscure faces (default: blur)')
|
|
30
|
+
parser.add_argument('--shape', default='ellipse', choices=FaceBlur.SHAPES,
|
|
31
|
+
help='shape of the obscured region (default: ellipse)')
|
|
32
|
+
parser.add_argument('--padding', type=float, default=0.25,
|
|
33
|
+
help='fraction to enlarge each face box on every side (default: 0.25)')
|
|
34
|
+
parser.add_argument('--blur_strength', type=float, default=0.5,
|
|
35
|
+
help='blur kernel size as a fraction of face size, for --style blur (default: 0.5)')
|
|
36
|
+
parser.add_argument('--pixel_blocks', type=int, default=10,
|
|
37
|
+
help='number of mosaic blocks across each face, for --style pixelate (default: 10)')
|
|
38
|
+
parser.add_argument('--fill_color', type=str, default='black',
|
|
39
|
+
help='color name or hex code, for --style fill (default: black)')
|
|
40
|
+
parser.add_argument('--score_threshold', type=float, default=0.6,
|
|
41
|
+
help='minimum detection confidence 0..1; lower catches more faces but more false positives (default: 0.6)')
|
|
42
|
+
parser.add_argument('--nms_threshold', type=float, default=0.3,
|
|
43
|
+
help='overlap threshold for merging duplicate detections (default: 0.3)')
|
|
44
|
+
parser.add_argument('--detect_max_dim', type=int, default=2048,
|
|
45
|
+
help='downscale so the longest side is at most this before detection; '
|
|
46
|
+
'raise for tiny faces, lower for speed, 0 = full resolution (default: 2048)')
|
|
47
|
+
parser.add_argument('--device', default='auto', choices=FaceBlur.DEVICES,
|
|
48
|
+
help='detection device: gpu needs onnxruntime (CoreML) or onnxruntime-gpu (CUDA); '
|
|
49
|
+
'auto uses the GPU when available (default: auto)')
|
|
50
|
+
parser.add_argument('--batch_size', type=int, default=8,
|
|
51
|
+
help='video only: frames detected per batch (default: 8)')
|
|
52
|
+
parser.add_argument('--workers', type=int, default=None,
|
|
53
|
+
help='video only: CPU threads for detection/blurring (default: number of cores)')
|
|
54
|
+
parser.add_argument('--hold_frames', type=int, default=5,
|
|
55
|
+
help='video only: keep obscuring a face for this many frames after it is lost (default: 5)')
|
|
56
|
+
parser.add_argument('--smoothing', type=float, default=0.5,
|
|
57
|
+
help='video only: box smoothing between frames, 0..1 (0 = off; higher is steadier '
|
|
58
|
+
'but lags; the raw detection is always covered) (default: 0.5)')
|
|
59
|
+
parser.add_argument('--start_t', type=float, default=None,
|
|
60
|
+
help='video only: trim the output to start this many seconds into the input '
|
|
61
|
+
'(default: start of video)')
|
|
62
|
+
parser.add_argument('--end_t', type=float, default=None,
|
|
63
|
+
help='video only: trim the output to end this many seconds into the input '
|
|
64
|
+
'(default: end of video)')
|
|
65
|
+
parser.add_argument('--no_audio', action='store_true',
|
|
66
|
+
help='video only: drop the audio track')
|
|
67
|
+
parser.add_argument('--crf', type=int, default=18,
|
|
68
|
+
help='video only: H.264 quality, lower is better (default: 18)')
|
|
69
|
+
parser.add_argument('--draw_boxes', action='store_true',
|
|
70
|
+
help='draw detection boxes and scores instead of obscuring (for tuning)')
|
|
71
|
+
parser.add_argument('--disable_pbar', action='store_true',
|
|
72
|
+
help='disable progress bar when processing videos')
|
|
73
|
+
|
|
74
|
+
args = parser.parse_args()
|
|
75
|
+
|
|
76
|
+
input_path = Path(args.input)
|
|
77
|
+
if not input_path.exists():
|
|
78
|
+
print(f"Error: Input file '{input_path}' not found.")
|
|
79
|
+
sys.exit(1)
|
|
80
|
+
|
|
81
|
+
ext = input_path.suffix.lower()
|
|
82
|
+
if ext in IMAGE_EXTENSIONS:
|
|
83
|
+
is_video = False
|
|
84
|
+
elif ext in VIDEO_EXTENSIONS:
|
|
85
|
+
is_video = True
|
|
86
|
+
else:
|
|
87
|
+
print(f"Error: Unsupported file type '{ext}'.")
|
|
88
|
+
sys.exit(1)
|
|
89
|
+
|
|
90
|
+
if args.output:
|
|
91
|
+
output_path = args.output
|
|
92
|
+
else:
|
|
93
|
+
out_ext = '.mp4' if is_video else ext
|
|
94
|
+
output_path = str(input_path.parent / f'{input_path.stem}_blurred{out_ext}')
|
|
95
|
+
|
|
96
|
+
print(" -- Load Param: input", input_path)
|
|
97
|
+
print(" -- Load Param: output", output_path)
|
|
98
|
+
print(" -- Load Param: style", args.style)
|
|
99
|
+
print(" -- Load Param: shape", args.shape)
|
|
100
|
+
print(" -- Load Param: score_threshold", args.score_threshold)
|
|
101
|
+
print(" -- Load Param: device", args.device)
|
|
102
|
+
|
|
103
|
+
if not 0 <= args.smoothing < 1:
|
|
104
|
+
print("Error: --smoothing must be in [0, 1).")
|
|
105
|
+
sys.exit(1)
|
|
106
|
+
|
|
107
|
+
if not is_video and (args.start_t is not None or args.end_t is not None):
|
|
108
|
+
print("Error: --start_t/--end_t only apply to videos.")
|
|
109
|
+
sys.exit(1)
|
|
110
|
+
|
|
111
|
+
if args.start_t is not None and args.start_t < 0:
|
|
112
|
+
print("Error: --start_t must be >= 0.")
|
|
113
|
+
sys.exit(1)
|
|
114
|
+
|
|
115
|
+
if args.end_t is not None and args.end_t <= (args.start_t or 0.0):
|
|
116
|
+
print("Error: --end_t must be greater than --start_t.")
|
|
117
|
+
sys.exit(1)
|
|
118
|
+
|
|
119
|
+
blurrer = FaceBlur(
|
|
120
|
+
style=args.style,
|
|
121
|
+
shape=args.shape,
|
|
122
|
+
padding=args.padding,
|
|
123
|
+
score_threshold=args.score_threshold,
|
|
124
|
+
nms_threshold=args.nms_threshold,
|
|
125
|
+
detect_max_dim=args.detect_max_dim,
|
|
126
|
+
blur_strength=args.blur_strength,
|
|
127
|
+
pixel_blocks=args.pixel_blocks,
|
|
128
|
+
fill_color=args.fill_color,
|
|
129
|
+
hold_frames=args.hold_frames,
|
|
130
|
+
smoothing=args.smoothing,
|
|
131
|
+
draw_boxes=args.draw_boxes,
|
|
132
|
+
disable_pbar=args.disable_pbar,
|
|
133
|
+
device=args.device,
|
|
134
|
+
batch_size=args.batch_size,
|
|
135
|
+
workers=args.workers,
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
if is_video:
|
|
139
|
+
success = blurrer.process_video(str(input_path), output_path,
|
|
140
|
+
keep_audio=not args.no_audio, crf=args.crf,
|
|
141
|
+
start_t=args.start_t, end_t=args.end_t)
|
|
142
|
+
else:
|
|
143
|
+
success = blurrer.process_image(str(input_path), output_path)
|
|
144
|
+
|
|
145
|
+
if not success:
|
|
146
|
+
sys.exit(1)
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
if __name__ == "__main__":
|
|
150
|
+
main()
|