distant-frames 0.1.0__tar.gz → 0.2.0__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.
- {distant_frames-0.1.0 → distant_frames-0.2.0}/PKG-INFO +2 -1
- distant_frames-0.2.0/RELEASE_NOTES.md +83 -0
- distant_frames-0.2.0/distant_frames/cli.py +49 -0
- {distant_frames-0.1.0 → distant_frames-0.2.0}/distant_frames/core.py +28 -18
- {distant_frames-0.1.0 → distant_frames-0.2.0}/pyproject.toml +3 -2
- {distant_frames-0.1.0 → distant_frames-0.2.0}/uv.lock +103 -2
- distant_frames-0.1.0/debug_import.py +0 -9
- distant_frames-0.1.0/distant_frames/cli.py +0 -15
- {distant_frames-0.1.0 → distant_frames-0.2.0}/.github/workflows/ci.yml +0 -0
- {distant_frames-0.1.0 → distant_frames-0.2.0}/.github/workflows/publish.yml +0 -0
- {distant_frames-0.1.0 → distant_frames-0.2.0}/.gitignore +0 -0
- {distant_frames-0.1.0 → distant_frames-0.2.0}/.python-version +0 -0
- {distant_frames-0.1.0 → distant_frames-0.2.0}/CONTRIBUTING.md +0 -0
- {distant_frames-0.1.0 → distant_frames-0.2.0}/LICENSE +0 -0
- {distant_frames-0.1.0 → distant_frames-0.2.0}/PUBLISHING.md +0 -0
- {distant_frames-0.1.0 → distant_frames-0.2.0}/README.md +0 -0
- {distant_frames-0.1.0 → distant_frames-0.2.0}/distant_frames/__init__.py +0 -0
- {distant_frames-0.1.0 → distant_frames-0.2.0}/extracted_frames/.gitkeep +0 -0
- {distant_frames-0.1.0 → distant_frames-0.2.0}/generate_test_video.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: distant-frames
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: Smart video frame extraction tool
|
|
5
5
|
Project-URL: Homepage, https://github.com/yubraaj11/distant-frames
|
|
6
6
|
Project-URL: Repository, https://github.com/yubraaj11/distant-frames
|
|
@@ -18,6 +18,7 @@ Classifier: Topic :: Multimedia :: Video
|
|
|
18
18
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
19
19
|
Requires-Python: >=3.12
|
|
20
20
|
Requires-Dist: opencv-python>=4.10.0
|
|
21
|
+
Requires-Dist: typer>=0.9.0
|
|
21
22
|
Description-Content-Type: text/markdown
|
|
22
23
|
|
|
23
24
|
# Distant Frames
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# Release Notes
|
|
2
|
+
|
|
3
|
+
## Version 0.2.0 (Upcoming)
|
|
4
|
+
|
|
5
|
+
### 🎨 Enhanced CLI Interface
|
|
6
|
+
|
|
7
|
+
We've completely redesigned the command-line interface using **Typer** for a significantly improved user experience!
|
|
8
|
+
|
|
9
|
+
#### ✨ New Features
|
|
10
|
+
|
|
11
|
+
- **Rich Terminal Output**: Beautiful, formatted help text with tables and color-coded sections
|
|
12
|
+
- **Short Option Flags**: Added convenient shortcuts:
|
|
13
|
+
- `-o` for `--output`
|
|
14
|
+
- `-t` for `--threshold`
|
|
15
|
+
- **Automatic Validation**: Built-in input validation with helpful error messages
|
|
16
|
+
- File existence checking before processing
|
|
17
|
+
- Threshold range validation (0.0-1.0)
|
|
18
|
+
- Readable file verification
|
|
19
|
+
|
|
20
|
+
#### 🔧 Improvements
|
|
21
|
+
|
|
22
|
+
- **Better Help Messages**: Clear, comprehensive help text with detailed parameter descriptions
|
|
23
|
+
- **Type Safety**: Full type hints for all CLI parameters with automatic validation
|
|
24
|
+
- **Enhanced Error Handling**: User-friendly error messages with suggestions and proper formatting
|
|
25
|
+
- **Cleaner Code**: More maintainable and declarative CLI implementation
|
|
26
|
+
|
|
27
|
+
#### 📦 Dependencies
|
|
28
|
+
|
|
29
|
+
- Added `typer>=0.9.0` for improved CLI functionality
|
|
30
|
+
|
|
31
|
+
#### 🎯 Usage Examples
|
|
32
|
+
|
|
33
|
+
**Basic usage:**
|
|
34
|
+
```bash
|
|
35
|
+
distant-frames video.mp4
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
**With custom output directory:**
|
|
39
|
+
```bash
|
|
40
|
+
distant-frames video.mp4 -o my_frames
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
**With custom threshold:**
|
|
44
|
+
```bash
|
|
45
|
+
distant-frames video.mp4 -t 0.8
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
**Combined options:**
|
|
49
|
+
```bash
|
|
50
|
+
distant-frames video.mp4 -o output_frames -t 0.7
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
**View help:**
|
|
54
|
+
```bash
|
|
55
|
+
distant-frames --help
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
#### 🐛 Bug Fixes
|
|
59
|
+
|
|
60
|
+
- Improved error messages when video file is not found
|
|
61
|
+
- Better validation for threshold parameter values
|
|
62
|
+
|
|
63
|
+
#### ⚠️ Breaking Changes
|
|
64
|
+
|
|
65
|
+
None - the CLI interface remains backward compatible with existing usage patterns.
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Version 0.1.2
|
|
70
|
+
|
|
71
|
+
### Features
|
|
72
|
+
|
|
73
|
+
- Smart frame extraction with similarity-based deduplication
|
|
74
|
+
- Fallback mechanism for gradual scene changes
|
|
75
|
+
- Verbose logging for debugging
|
|
76
|
+
- HSV-based histogram comparison for robust similarity detection
|
|
77
|
+
|
|
78
|
+
### Core Functionality
|
|
79
|
+
|
|
80
|
+
- Extract frames at 1-second intervals
|
|
81
|
+
- Skip similar frames based on configurable threshold
|
|
82
|
+
- Automatic output directory creation
|
|
83
|
+
- Detailed frame-by-frame logging
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import typer
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing_extensions import Annotated
|
|
4
|
+
from distant_frames.core import extract_frames
|
|
5
|
+
|
|
6
|
+
app = typer.Typer(
|
|
7
|
+
help="Smart video frame extraction tool with similarity-based deduplication.",
|
|
8
|
+
add_completion=False,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
@app.command()
|
|
12
|
+
def main(
|
|
13
|
+
video_path: Annotated[
|
|
14
|
+
Path,
|
|
15
|
+
typer.Argument(
|
|
16
|
+
help="Path to the input video file",
|
|
17
|
+
exists=True,
|
|
18
|
+
file_okay=True,
|
|
19
|
+
dir_okay=False,
|
|
20
|
+
readable=True,
|
|
21
|
+
)
|
|
22
|
+
],
|
|
23
|
+
output: Annotated[
|
|
24
|
+
str,
|
|
25
|
+
typer.Option(
|
|
26
|
+
"--output", "-o",
|
|
27
|
+
help="Output directory for extracted frames"
|
|
28
|
+
)
|
|
29
|
+
] = "extracted_frames",
|
|
30
|
+
threshold: Annotated[
|
|
31
|
+
float,
|
|
32
|
+
typer.Option(
|
|
33
|
+
"--threshold", "-t",
|
|
34
|
+
min=0.0,
|
|
35
|
+
max=1.0,
|
|
36
|
+
help="Similarity threshold (0.0-1.0). Higher values mean stricter deduplication (fewer frames saved)."
|
|
37
|
+
)
|
|
38
|
+
] = 0.65,
|
|
39
|
+
):
|
|
40
|
+
"""
|
|
41
|
+
Extract distinct frames from a video file based on visual similarity.
|
|
42
|
+
|
|
43
|
+
The tool samples the video at 1-second intervals and compares consecutive frames.
|
|
44
|
+
Frames that are too similar to previously saved frames are automatically skipped.
|
|
45
|
+
"""
|
|
46
|
+
extract_frames(str(video_path), output, threshold)
|
|
47
|
+
|
|
48
|
+
if __name__ == "__main__":
|
|
49
|
+
app()
|
|
@@ -32,7 +32,7 @@ def calculate_similarity(frame1, frame2):
|
|
|
32
32
|
similarity = cv2.compareHist(hist1, hist2, cv2.HISTCMP_CORREL)
|
|
33
33
|
return similarity
|
|
34
34
|
|
|
35
|
-
def extract_frames(video_path, output_folder, threshold=0.
|
|
35
|
+
def extract_frames(video_path, output_folder, threshold=0.65):
|
|
36
36
|
"""Extracts distinct frames from a video file based on visual similarity.
|
|
37
37
|
|
|
38
38
|
The function samples the video at 1-second intervals. It compares the current
|
|
@@ -50,7 +50,7 @@ def extract_frames(video_path, output_folder, threshold=0.9):
|
|
|
50
50
|
threshold (float, optional): Similarity threshold (0.0 to 1.0).
|
|
51
51
|
Frames with similarity higher than this value regarding the last
|
|
52
52
|
saved frame will be dropped. Higher values mean stricter
|
|
53
|
-
deduplication (fewer frames saved). Defaults to 0.
|
|
53
|
+
deduplication (fewer frames saved). Defaults to 0.65.
|
|
54
54
|
|
|
55
55
|
Returns:
|
|
56
56
|
None
|
|
@@ -80,8 +80,9 @@ def extract_frames(video_path, output_folder, threshold=0.9):
|
|
|
80
80
|
current_frame_idx = 0
|
|
81
81
|
saved_count = 0
|
|
82
82
|
last_saved_frame = None
|
|
83
|
-
|
|
84
|
-
|
|
83
|
+
last_saved_timestamp = None
|
|
84
|
+
skip_reference_frame = None
|
|
85
|
+
skip_reference_timestamp = None
|
|
85
86
|
|
|
86
87
|
while True:
|
|
87
88
|
# Set position to the next second
|
|
@@ -98,35 +99,44 @@ def extract_frames(video_path, output_folder, threshold=0.9):
|
|
|
98
99
|
if last_saved_frame is None:
|
|
99
100
|
should_save = True
|
|
100
101
|
similarity = 0.0 # No previous frame
|
|
102
|
+
print(f"[{timestamp:.1f}s] First frame → SAVE")
|
|
101
103
|
else:
|
|
102
104
|
# Determine reference frame
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
105
|
+
# If we have a skip reference (from previous skip), use that
|
|
106
|
+
# Otherwise use the last saved frame
|
|
107
|
+
if skip_reference_frame is not None:
|
|
108
|
+
reference_frame = skip_reference_frame
|
|
109
|
+
ref_timestamp = skip_reference_timestamp
|
|
110
|
+
ref_label = "skip_ref"
|
|
111
|
+
else:
|
|
112
|
+
reference_frame = last_saved_frame
|
|
113
|
+
ref_timestamp = last_saved_timestamp
|
|
114
|
+
ref_label = "last"
|
|
109
115
|
|
|
110
116
|
similarity = calculate_similarity(reference_frame, frame)
|
|
117
|
+
|
|
111
118
|
if similarity < threshold:
|
|
112
119
|
should_save = True
|
|
120
|
+
print(f"[{timestamp:.1f}s] vs {ref_label}@{ref_timestamp:.1f}s | sim={similarity:.3f} → SAVE")
|
|
121
|
+
# Clear skip reference when we save
|
|
122
|
+
skip_reference_frame = None
|
|
123
|
+
skip_reference_timestamp = None
|
|
113
124
|
else:
|
|
114
|
-
print(f"
|
|
115
|
-
|
|
125
|
+
print(f"[{timestamp:.1f}s] vs {ref_label}@{ref_timestamp:.1f}s | sim={similarity:.3f} → SKIP")
|
|
126
|
+
# When we skip, set the skip reference to the last saved frame
|
|
127
|
+
# so next comparison uses this same reference
|
|
128
|
+
skip_reference_frame = last_saved_frame
|
|
129
|
+
skip_reference_timestamp = last_saved_timestamp
|
|
116
130
|
|
|
117
131
|
if should_save:
|
|
118
132
|
output_filename = os.path.join(output_folder, f"frame_{timestamp:.2f}.jpg")
|
|
119
133
|
cv2.imwrite(output_filename, frame)
|
|
120
134
|
|
|
121
|
-
# Update
|
|
122
|
-
prev_saved_frame = last_saved_frame
|
|
135
|
+
# Update last saved frame
|
|
123
136
|
last_saved_frame = frame
|
|
124
|
-
|
|
125
|
-
# Reset fallback flag because we just saved a new distinct frame
|
|
126
|
-
force_fallback_to_prev = False
|
|
137
|
+
last_saved_timestamp = timestamp
|
|
127
138
|
|
|
128
139
|
saved_count += 1
|
|
129
|
-
print(f"Saved {output_filename} (Similarity: {similarity:.4f})")
|
|
130
140
|
|
|
131
141
|
current_frame_idx += frame_interval
|
|
132
142
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "distant-frames"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.2.0"
|
|
4
4
|
description = "Smart video frame extraction tool"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.12"
|
|
@@ -20,6 +20,7 @@ classifiers = [
|
|
|
20
20
|
]
|
|
21
21
|
dependencies = [
|
|
22
22
|
"opencv-python>=4.10.0",
|
|
23
|
+
"typer>=0.9.0",
|
|
23
24
|
]
|
|
24
25
|
|
|
25
26
|
[project.urls]
|
|
@@ -28,7 +29,7 @@ Repository = "https://github.com/yubraaj11/distant-frames"
|
|
|
28
29
|
Issues = "https://github.com/yubraaj11/distant-frames/issues"
|
|
29
30
|
|
|
30
31
|
[project.scripts]
|
|
31
|
-
distant-frames = "distant_frames.cli:
|
|
32
|
+
distant-frames = "distant_frames.cli:app"
|
|
32
33
|
|
|
33
34
|
[build-system]
|
|
34
35
|
requires = ["hatchling"]
|
|
@@ -2,16 +2,62 @@ version = 1
|
|
|
2
2
|
revision = 3
|
|
3
3
|
requires-python = ">=3.12"
|
|
4
4
|
|
|
5
|
+
[[package]]
|
|
6
|
+
name = "click"
|
|
7
|
+
version = "8.3.1"
|
|
8
|
+
source = { registry = "https://pypi.org/simple" }
|
|
9
|
+
dependencies = [
|
|
10
|
+
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
|
11
|
+
]
|
|
12
|
+
sdist = { url = "https://files.pythonhosted.org/packages/3d/fa/656b739db8587d7b5dfa22e22ed02566950fbfbcdc20311993483657a5c0/click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a", size = 295065, upload-time = "2025-11-15T20:45:42.706Z" }
|
|
13
|
+
wheels = [
|
|
14
|
+
{ url = "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6", size = 108274, upload-time = "2025-11-15T20:45:41.139Z" },
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
[[package]]
|
|
18
|
+
name = "colorama"
|
|
19
|
+
version = "0.4.6"
|
|
20
|
+
source = { registry = "https://pypi.org/simple" }
|
|
21
|
+
sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" }
|
|
22
|
+
wheels = [
|
|
23
|
+
{ url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" },
|
|
24
|
+
]
|
|
25
|
+
|
|
5
26
|
[[package]]
|
|
6
27
|
name = "distant-frames"
|
|
7
|
-
version = "0.
|
|
28
|
+
version = "0.2.0"
|
|
8
29
|
source = { editable = "." }
|
|
9
30
|
dependencies = [
|
|
10
31
|
{ name = "opencv-python" },
|
|
32
|
+
{ name = "typer" },
|
|
11
33
|
]
|
|
12
34
|
|
|
13
35
|
[package.metadata]
|
|
14
|
-
requires-dist = [
|
|
36
|
+
requires-dist = [
|
|
37
|
+
{ name = "opencv-python", specifier = ">=4.10.0" },
|
|
38
|
+
{ name = "typer", specifier = ">=0.9.0" },
|
|
39
|
+
]
|
|
40
|
+
|
|
41
|
+
[[package]]
|
|
42
|
+
name = "markdown-it-py"
|
|
43
|
+
version = "4.0.0"
|
|
44
|
+
source = { registry = "https://pypi.org/simple" }
|
|
45
|
+
dependencies = [
|
|
46
|
+
{ name = "mdurl" },
|
|
47
|
+
]
|
|
48
|
+
sdist = { url = "https://files.pythonhosted.org/packages/5b/f5/4ec618ed16cc4f8fb3b701563655a69816155e79e24a17b651541804721d/markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3", size = 73070, upload-time = "2025-08-11T12:57:52.854Z" }
|
|
49
|
+
wheels = [
|
|
50
|
+
{ url = "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147", size = 87321, upload-time = "2025-08-11T12:57:51.923Z" },
|
|
51
|
+
]
|
|
52
|
+
|
|
53
|
+
[[package]]
|
|
54
|
+
name = "mdurl"
|
|
55
|
+
version = "0.1.2"
|
|
56
|
+
source = { registry = "https://pypi.org/simple" }
|
|
57
|
+
sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" }
|
|
58
|
+
wheels = [
|
|
59
|
+
{ url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" },
|
|
60
|
+
]
|
|
15
61
|
|
|
16
62
|
[[package]]
|
|
17
63
|
name = "numpy"
|
|
@@ -67,3 +113,58 @@ wheels = [
|
|
|
67
113
|
{ url = "https://files.pythonhosted.org/packages/02/96/213fea371d3cb2f1d537612a105792aa0a6659fb2665b22cad709a75bd94/opencv_python-4.12.0.88-cp37-abi3-win32.whl", hash = "sha256:ff554d3f725b39878ac6a2e1fa232ec509c36130927afc18a1719ebf4fbf4357", size = 30284131, upload-time = "2025-07-07T09:14:08.819Z" },
|
|
68
114
|
{ url = "https://files.pythonhosted.org/packages/fa/80/eb88edc2e2b11cd2dd2e56f1c80b5784d11d6e6b7f04a1145df64df40065/opencv_python-4.12.0.88-cp37-abi3-win_amd64.whl", hash = "sha256:d98edb20aa932fd8ebd276a72627dad9dc097695b3d435a4257557bbb49a79d2", size = 39000307, upload-time = "2025-07-07T09:14:16.641Z" },
|
|
69
115
|
]
|
|
116
|
+
|
|
117
|
+
[[package]]
|
|
118
|
+
name = "pygments"
|
|
119
|
+
version = "2.19.2"
|
|
120
|
+
source = { registry = "https://pypi.org/simple" }
|
|
121
|
+
sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" }
|
|
122
|
+
wheels = [
|
|
123
|
+
{ url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" },
|
|
124
|
+
]
|
|
125
|
+
|
|
126
|
+
[[package]]
|
|
127
|
+
name = "rich"
|
|
128
|
+
version = "14.2.0"
|
|
129
|
+
source = { registry = "https://pypi.org/simple" }
|
|
130
|
+
dependencies = [
|
|
131
|
+
{ name = "markdown-it-py" },
|
|
132
|
+
{ name = "pygments" },
|
|
133
|
+
]
|
|
134
|
+
sdist = { url = "https://files.pythonhosted.org/packages/fb/d2/8920e102050a0de7bfabeb4c4614a49248cf8d5d7a8d01885fbb24dc767a/rich-14.2.0.tar.gz", hash = "sha256:73ff50c7c0c1c77c8243079283f4edb376f0f6442433aecb8ce7e6d0b92d1fe4", size = 219990, upload-time = "2025-10-09T14:16:53.064Z" }
|
|
135
|
+
wheels = [
|
|
136
|
+
{ url = "https://files.pythonhosted.org/packages/25/7a/b0178788f8dc6cafce37a212c99565fa1fe7872c70c6c9c1e1a372d9d88f/rich-14.2.0-py3-none-any.whl", hash = "sha256:76bc51fe2e57d2b1be1f96c524b890b816e334ab4c1e45888799bfaab0021edd", size = 243393, upload-time = "2025-10-09T14:16:51.245Z" },
|
|
137
|
+
]
|
|
138
|
+
|
|
139
|
+
[[package]]
|
|
140
|
+
name = "shellingham"
|
|
141
|
+
version = "1.5.4"
|
|
142
|
+
source = { registry = "https://pypi.org/simple" }
|
|
143
|
+
sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310, upload-time = "2023-10-24T04:13:40.426Z" }
|
|
144
|
+
wheels = [
|
|
145
|
+
{ url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755, upload-time = "2023-10-24T04:13:38.866Z" },
|
|
146
|
+
]
|
|
147
|
+
|
|
148
|
+
[[package]]
|
|
149
|
+
name = "typer"
|
|
150
|
+
version = "0.20.1"
|
|
151
|
+
source = { registry = "https://pypi.org/simple" }
|
|
152
|
+
dependencies = [
|
|
153
|
+
{ name = "click" },
|
|
154
|
+
{ name = "rich" },
|
|
155
|
+
{ name = "shellingham" },
|
|
156
|
+
{ name = "typing-extensions" },
|
|
157
|
+
]
|
|
158
|
+
sdist = { url = "https://files.pythonhosted.org/packages/6d/c1/933d30fd7a123ed981e2a1eedafceab63cb379db0402e438a13bc51bbb15/typer-0.20.1.tar.gz", hash = "sha256:68585eb1b01203689c4199bc440d6be616f0851e9f0eb41e4a778845c5a0fd5b", size = 105968, upload-time = "2025-12-19T16:48:56.302Z" }
|
|
159
|
+
wheels = [
|
|
160
|
+
{ url = "https://files.pythonhosted.org/packages/c8/52/1f2df7e7d1be3d65ddc2936d820d4a3d9777a54f4204f5ca46b8513eff77/typer-0.20.1-py3-none-any.whl", hash = "sha256:4b3bde918a67c8e03d861aa02deca90a95bbac572e71b1b9be56ff49affdb5a8", size = 47381, upload-time = "2025-12-19T16:48:53.679Z" },
|
|
161
|
+
]
|
|
162
|
+
|
|
163
|
+
[[package]]
|
|
164
|
+
name = "typing-extensions"
|
|
165
|
+
version = "4.15.0"
|
|
166
|
+
source = { registry = "https://pypi.org/simple" }
|
|
167
|
+
sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" }
|
|
168
|
+
wheels = [
|
|
169
|
+
{ url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" },
|
|
170
|
+
]
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import argparse
|
|
2
|
-
from distant_frames.core import extract_frames
|
|
3
|
-
|
|
4
|
-
def main():
|
|
5
|
-
parser = argparse.ArgumentParser(description="Extract frames from video with similarity check.")
|
|
6
|
-
parser.add_argument("video_path", help="Path to the input video file")
|
|
7
|
-
parser.add_argument("--output", default="extracted_frames", help="Output directory for frames")
|
|
8
|
-
parser.add_argument("--threshold", type=float, default=0.65, help="Similarity threshold (0-1). Higher value means stricter similarity check (more frames dropped).")
|
|
9
|
-
|
|
10
|
-
args = parser.parse_args()
|
|
11
|
-
|
|
12
|
-
extract_frames(args.video_path, args.output, args.threshold)
|
|
13
|
-
|
|
14
|
-
if __name__ == "__main__":
|
|
15
|
-
main()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|