mcdonald 0.2.4__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.
- mcdonald-0.2.4/LICENSE +28 -0
- mcdonald-0.2.4/MANIFEST.in +3 -0
- mcdonald-0.2.4/PKG-INFO +102 -0
- mcdonald-0.2.4/README-technical.md +441 -0
- mcdonald-0.2.4/README.md +68 -0
- mcdonald-0.2.4/docs/agents.md +406 -0
- mcdonald-0.2.4/docs/install.md +112 -0
- mcdonald-0.2.4/docs/method.md +313 -0
- mcdonald-0.2.4/pyproject.toml +69 -0
- mcdonald-0.2.4/setup.cfg +4 -0
- mcdonald-0.2.4/setup.py +23 -0
- mcdonald-0.2.4/src/mcdonald/__init__.py +33 -0
- mcdonald-0.2.4/src/mcdonald/actions.py +266 -0
- mcdonald-0.2.4/src/mcdonald/autolink.py +701 -0
- mcdonald-0.2.4/src/mcdonald/case_cli.py +56 -0
- mcdonald-0.2.4/src/mcdonald/catalog.py +200 -0
- mcdonald-0.2.4/src/mcdonald/cli.py +112 -0
- mcdonald-0.2.4/src/mcdonald/clip.py +345 -0
- mcdonald-0.2.4/src/mcdonald/comotion.py +317 -0
- mcdonald-0.2.4/src/mcdonald/figures.py +360 -0
- mcdonald-0.2.4/src/mcdonald/find_qt.py +325 -0
- mcdonald-0.2.4/src/mcdonald/flicker.py +340 -0
- mcdonald-0.2.4/src/mcdonald/forensics.py +885 -0
- mcdonald-0.2.4/src/mcdonald/groups.py +386 -0
- mcdonald-0.2.4/src/mcdonald/gui.py +135 -0
- mcdonald-0.2.4/src/mcdonald/icons/mcdonald-128.png +0 -0
- mcdonald-0.2.4/src/mcdonald/icons/mcdonald-16.png +0 -0
- mcdonald-0.2.4/src/mcdonald/icons/mcdonald-24.png +0 -0
- mcdonald-0.2.4/src/mcdonald/icons/mcdonald-256.png +0 -0
- mcdonald-0.2.4/src/mcdonald/icons/mcdonald-32.png +0 -0
- mcdonald-0.2.4/src/mcdonald/icons/mcdonald-48.png +0 -0
- mcdonald-0.2.4/src/mcdonald/icons/mcdonald-512.png +0 -0
- mcdonald-0.2.4/src/mcdonald/icons/mcdonald-64.png +0 -0
- mcdonald-0.2.4/src/mcdonald/icons/mcdonald-small.svg +15 -0
- mcdonald-0.2.4/src/mcdonald/icons/mcdonald.icns +0 -0
- mcdonald-0.2.4/src/mcdonald/icons/mcdonald.ico +0 -0
- mcdonald-0.2.4/src/mcdonald/icons/mcdonald.svg +19 -0
- mcdonald-0.2.4/src/mcdonald/integrity.py +810 -0
- mcdonald-0.2.4/src/mcdonald/kinematics.py +559 -0
- mcdonald-0.2.4/src/mcdonald/kinematics_cli.py +103 -0
- mcdonald-0.2.4/src/mcdonald/layers.py +500 -0
- mcdonald-0.2.4/src/mcdonald/look.py +411 -0
- mcdonald-0.2.4/src/mcdonald/mark.py +639 -0
- mcdonald-0.2.4/src/mcdonald/mark_qt.py +2908 -0
- mcdonald-0.2.4/src/mcdonald/measure_qt.py +763 -0
- mcdonald-0.2.4/src/mcdonald/progress.py +116 -0
- mcdonald-0.2.4/src/mcdonald/propose.py +902 -0
- mcdonald-0.2.4/src/mcdonald/pursue_videos.csv +145 -0
- mcdonald-0.2.4/src/mcdonald/readme_cli.py +53 -0
- mcdonald-0.2.4/src/mcdonald/reel.py +201 -0
- mcdonald-0.2.4/src/mcdonald/report.py +540 -0
- mcdonald-0.2.4/src/mcdonald/run.py +83 -0
- mcdonald-0.2.4/src/mcdonald/scale.py +175 -0
- mcdonald-0.2.4/src/mcdonald/setup_cli.py +174 -0
- mcdonald-0.2.4/src/mcdonald/stages.py +626 -0
- mcdonald-0.2.4/src/mcdonald/storage.py +86 -0
- mcdonald-0.2.4/src/mcdonald/symbology.py +725 -0
- mcdonald-0.2.4/src/mcdonald/tracksheet.py +230 -0
- mcdonald-0.2.4/src/mcdonald/update.py +250 -0
- mcdonald-0.2.4/src/mcdonald.egg-info/PKG-INFO +102 -0
- mcdonald-0.2.4/src/mcdonald.egg-info/SOURCES.txt +69 -0
- mcdonald-0.2.4/src/mcdonald.egg-info/dependency_links.txt +1 -0
- mcdonald-0.2.4/src/mcdonald.egg-info/entry_points.txt +5 -0
- mcdonald-0.2.4/src/mcdonald.egg-info/requires.txt +10 -0
- mcdonald-0.2.4/src/mcdonald.egg-info/top_level.txt +1 -0
- mcdonald-0.2.4/tests/test_cli.py +599 -0
- mcdonald-0.2.4/tests/test_golden.py +224 -0
- mcdonald-0.2.4/tests/test_gui.py +2054 -0
- mcdonald-0.2.4/tests/test_measurement.py +1471 -0
- mcdonald-0.2.4/tests/test_published.py +252 -0
- mcdonald-0.2.4/tests/test_reduction.py +809 -0
mcdonald-0.2.4/LICENSE
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026, Jacob Haqq Misra
|
|
4
|
+
|
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
|
6
|
+
modification, are permitted provided that the following conditions are met:
|
|
7
|
+
|
|
8
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
9
|
+
list of conditions and the following disclaimer.
|
|
10
|
+
|
|
11
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
12
|
+
this list of conditions and the following disclaimer in the documentation
|
|
13
|
+
and/or other materials provided with the distribution.
|
|
14
|
+
|
|
15
|
+
3. Neither the name of the copyright holder nor the names of its
|
|
16
|
+
contributors may be used to endorse or promote products derived from
|
|
17
|
+
this software without specific prior written permission.
|
|
18
|
+
|
|
19
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
20
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
21
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
22
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
23
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
24
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
25
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
26
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
27
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
28
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
mcdonald-0.2.4/PKG-INFO
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mcdonald
|
|
3
|
+
Version: 0.2.4
|
|
4
|
+
Summary: Measurement tools for single-sensor video of unidentified objects: background layers, clip integrity, symbology, angular scale, kinematics, co-motion
|
|
5
|
+
Author-email: Jacob Haqq Misra <jacob@bmsis.org>
|
|
6
|
+
License-Expression: BSD-3-Clause
|
|
7
|
+
Project-URL: Homepage, https://github.com/haqqmisra/mcdonald
|
|
8
|
+
Project-URL: Repository, https://github.com/haqqmisra/mcdonald
|
|
9
|
+
Project-URL: Documentation, https://github.com/haqqmisra/mcdonald/blob/main/README-technical.md
|
|
10
|
+
Project-URL: Installing, https://github.com/haqqmisra/mcdonald/blob/main/docs/install.md
|
|
11
|
+
Keywords: uap,video-forensics,photogrammetry,kinematics,remote-sensing
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Science/Research
|
|
14
|
+
Classifier: Topic :: Scientific/Engineering :: Image Processing
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
17
|
+
Classifier: Operating System :: MacOS
|
|
18
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
19
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
20
|
+
Classifier: Environment :: X11 Applications :: Qt
|
|
21
|
+
Classifier: Environment :: Console
|
|
22
|
+
Requires-Python: >=3.10
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
License-File: LICENSE
|
|
25
|
+
Requires-Dist: numpy>=1.24
|
|
26
|
+
Requires-Dist: scipy>=1.10
|
|
27
|
+
Requires-Dist: matplotlib>=3.7
|
|
28
|
+
Requires-Dist: pillow>=9.5
|
|
29
|
+
Provides-Extra: dev
|
|
30
|
+
Requires-Dist: pytest>=7; extra == "dev"
|
|
31
|
+
Provides-Extra: gui
|
|
32
|
+
Requires-Dist: PySide6-Essentials>=6.6; extra == "gui"
|
|
33
|
+
Dynamic: license-file
|
|
34
|
+
|
|
35
|
+
<picture>
|
|
36
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/haqqmisra/mcdonald/main/docs/logo-dark.png">
|
|
37
|
+
<img alt="mcDonald UAP Toolkit" src="https://raw.githubusercontent.com/haqqmisra/mcdonald/main/docs/logo-light.png" width="420">
|
|
38
|
+
</picture>
|
|
39
|
+
|
|
40
|
+
**mcdonald** is a frame-by-frame analysis toolkit for measuring the kinematics of an unknown
|
|
41
|
+
object in a single-camera video.
|
|
42
|
+
|
|
43
|
+
> "Science is in default for having failed to mount any truly adequate studies of this problem."
|
|
44
|
+
>
|
|
45
|
+
> — James E. McDonald
|
|
46
|
+
|
|
47
|
+
**Status:** early test version (0.2.4), tried on Linux and macOS; Windows is next.
|
|
48
|
+
|
|
49
|
+
## Install
|
|
50
|
+
|
|
51
|
+
1. Prerequisite: make sure **ffmpeg** is installed:
|
|
52
|
+
`brew install ffmpeg` (Mac), `winget install Gyan.FFmpeg` (Windows),
|
|
53
|
+
`sudo apt install ffmpeg` or `sudo dnf install ffmpeg` (Linux).
|
|
54
|
+
2. Install **mcdonald** (needs Python 3.10 or newer):
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
python3 -m pip install "mcdonald[gui]"
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
3. Check your setup, which also provides instructions on what to do next:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
mcdonald setup
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
When a newer version is out, `mcdonald-gui` offers to update itself when it starts, and the
|
|
67
|
+
command line prints the command to update with.
|
|
68
|
+
|
|
69
|
+
New to Python or the terminal? [docs/install.md](https://github.com/haqqmisra/mcdonald/blob/main/docs/install.md) walks through each step in
|
|
70
|
+
detail.
|
|
71
|
+
|
|
72
|
+
## Use
|
|
73
|
+
|
|
74
|
+
**mcdonald** has a graphical interface and a command-line interface. The software is intended
|
|
75
|
+
to be driven by human users and/or AI agents.
|
|
76
|
+
|
|
77
|
+
The graphical interface is designed to prompt human users through the steps of analysis. To
|
|
78
|
+
start the graphical interface:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
mcdonald-gui
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
The command-line interface is designed for developers, advanced users, and AI agents. To start
|
|
85
|
+
the command-line interface and see a summary of options:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
mcdonald
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Prompting an agent
|
|
92
|
+
|
|
93
|
+
You can invoke an AI agent to assist at any point in the analysis, whether before or after a
|
|
94
|
+
human has looked at the video. Here is a sample prompt that you can pass to your favorite
|
|
95
|
+
command-line AI model:
|
|
96
|
+
|
|
97
|
+
> Please use the mcdonald toolkit to analyze the PR144 video released under PURSUE. Run
|
|
98
|
+
> `mcdonald readme` to get started.
|
|
99
|
+
|
|
100
|
+
## License
|
|
101
|
+
|
|
102
|
+
Copyright (c) 2026 Jacob Haqq Misra. Released under the [BSD 3-Clause License](https://github.com/haqqmisra/mcdonald/blob/main/LICENSE).
|
|
@@ -0,0 +1,441 @@
|
|
|
1
|
+
# McDonald UAP Toolkit: the technical README
|
|
2
|
+
|
|
3
|
+
**For AI agents and technical users**: every command, how each step works, what the tests hold it to,
|
|
4
|
+
and why. For installing it and using the window, [README.md](README.md) is shorter.
|
|
5
|
+
|
|
6
|
+
Measurement tools for single-sensor video of unidentified objects.
|
|
7
|
+
|
|
8
|
+
Point it at a clip and it will tell you how the background moves and in how many
|
|
9
|
+
layers, whether the clip behaves like the output of one sensor chain, whether
|
|
10
|
+
the object in it behaves like imagery or like something laid over imagery, and
|
|
11
|
+
whether your track is actually on the object in every frame.
|
|
12
|
+
|
|
13
|
+
It will also, frequently, tell you that a question cannot be answered from the
|
|
14
|
+
clip you have. That is the intended behaviour, not a shortfall. Most released
|
|
15
|
+
sensor video does not contain enough information to state a speed, and a tool
|
|
16
|
+
that always returns a number is worse than useless on this subject.
|
|
17
|
+
|
|
18
|
+
> Named for James E. McDonald, who argued that the subject deserved ordinary
|
|
19
|
+
> scientific instruments rather than either credulity or dismissal.
|
|
20
|
+
|
|
21
|
+
**Status: alpha (0.2.4).** The full pipeline: eight stages from a file to a
|
|
22
|
+
case report, plus each stage as its own command. See [Roadmap](#roadmap) for
|
|
23
|
+
what is still missing.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Install
|
|
28
|
+
|
|
29
|
+
Three steps, the same on macOS, Windows and Linux ([docs/install.md](docs/install.md) goes
|
|
30
|
+
through each one slowly, for each system):
|
|
31
|
+
|
|
32
|
+
1. **ffmpeg**, which mcdonald reads video with: `brew install ffmpeg` (macOS),
|
|
33
|
+
`winget install Gyan.FFmpeg` (Windows), `sudo dnf install ffmpeg` or `sudo apt install ffmpeg` (Linux).
|
|
34
|
+
2. **mcdonald**, with its window (Python 3.10 or newer):
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
python3 -m pip install "mcdonald[gui]"
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
3. **Check this computer**, which also says what to type next:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
mcdonald setup
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Then `mcdonald-gui` opens the window, and `mcdonald run PR149` does the whole job on the
|
|
47
|
+
command line (downloading PR149 the first time).
|
|
48
|
+
|
|
49
|
+
**Updates.** A copy installed this way asks PyPI, at most once a day, what the newest version
|
|
50
|
+
is (one small request; no account). If it is newer, the window asks whether to update: on a yes
|
|
51
|
+
it closes, pip installs the new version, and it opens again. The command line never stops to
|
|
52
|
+
ask; it prints one line on stderr (stdout stays JSON) with the pip command. A copy installed
|
|
53
|
+
from GitHub (`pip install "mcdonald[gui] @ git+https://github.com/haqqmisra/mcdonald"`, as
|
|
54
|
+
before 0.2.4) asks GitHub's main instead and updates from there; a working copy
|
|
55
|
+
(`pip install -e`) is never checked, and `MCDONALD_NO_UPDATE_CHECK=1` turns it off
|
|
56
|
+
(`mcdonald.update`).
|
|
57
|
+
|
|
58
|
+
### What it needs, and how long it takes
|
|
59
|
+
|
|
60
|
+
- **Python 3.10 or newer, and ffmpeg**, on macOS, Windows or Linux. The window needs a desktop;
|
|
61
|
+
the command line does not.
|
|
62
|
+
- **Disk**: each frame worked on is saved once, losslessly: about 0.75 MB a frame at 1920×1080,
|
|
63
|
+
so a 3-second segment is ~70 MB and a whole 3-minute video ~4 GB. Downloaded PURSUE videos are
|
|
64
|
+
2 MB to 3 GB (most under 100 MB). Both go in one folder you choose on the first screen.
|
|
65
|
+
- **Memory**: 8 GB is enough for a segment of a few hundred frames; more for whole videos.
|
|
66
|
+
- **Time.** mcdonald compares frames pixel by pixel, and some steps are slow. On the machine it
|
|
67
|
+
was built on (a 2012 six-core Xeon workstation, 2 GHz, 32 GB), for a 1080p segment:
|
|
68
|
+
|
|
69
|
+
| step | about |
|
|
70
|
+
|---|---|
|
|
71
|
+
| saving the frames (once) | a few seconds per 100 frames |
|
|
72
|
+
| Find the object | 25 s + 0.2 s a frame (a 3-second segment: under a minute) |
|
|
73
|
+
| Follow it | seconds to a minute |
|
|
74
|
+
| Measure, without the two slow checks | under a minute |
|
|
75
|
+
| Measure: the *layers* check | about 1.7 s per pair of frames (3 s: ~2 minutes) |
|
|
76
|
+
| Measure: the *integrity* check | about 2.6 s per pair of frames + 90 s (3 s: ~5 minutes) |
|
|
77
|
+
|
|
78
|
+
So **open only the part of the video with the object in it**, plus a second or two either side:
|
|
79
|
+
the window asks which part, and says what it will cost before it starts. A whole 3-minute video
|
|
80
|
+
measured with every check is hours. Each step shows its progress, and can be stopped.
|
|
81
|
+
|
|
82
|
+
### Working on the code
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
git clone https://github.com/haqqmisra/mcdonald.git
|
|
86
|
+
cd mcdonald
|
|
87
|
+
python3 -m pip install -e ".[gui]"
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Verify the install measures correctly before you trust a number from it:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
python3 tests/test_measurement.py # measurement: masks, registration, layers, detection
|
|
94
|
+
python3 tests/test_reduction.py # reduction: symbology, kinematics, scale, marks, report
|
|
95
|
+
python3 tests/test_published.py # every number in the Technical Note and the PR144 notes
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Together those are the checks against cases whose answers are known by
|
|
99
|
+
construction — a known rigid shift, two backgrounds moving at different rates,
|
|
100
|
+
planted repeated frames, an object on a known path, the published PR113
|
|
101
|
+
reduction, the PR149 scale-bar bound — confirming the library recovers each
|
|
102
|
+
one. They need no video data, take a few minutes, and each should end
|
|
103
|
+
`ALL PASS`.
|
|
104
|
+
|
|
105
|
+
`test_published.py` adds 32 more, walking the Technical Note's and the PR144
|
|
106
|
+
notes' quantitative claims one at a time, so a change that would move a number
|
|
107
|
+
in a manuscript fails here first. `tests/test_golden.py` goes further and
|
|
108
|
+
re-measures real clips, but needs the video files; it skips cleanly and says
|
|
109
|
+
so when they are absent.
|
|
110
|
+
|
|
111
|
+
`python3 tests/test_gui.py` presses every key and button of both `mcdonald mark`
|
|
112
|
+
windows — the Qt one, and the matplotlib one under each interactive backend the
|
|
113
|
+
machine can open — runs the same checks against each, and compares the files
|
|
114
|
+
they save. It skips what cannot open here and says why, which also makes it the
|
|
115
|
+
quickest way to find out whether `mcdonald mark` will open a window at all.
|
|
116
|
+
|
|
117
|
+
## Use
|
|
118
|
+
|
|
119
|
+
Everything at once, into one report:
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
mcdonald run CLIP.mp4 --track track.csv
|
|
123
|
+
mcdonald run CLIP.mp4 --marks CLIP/clip_marks.json # or from two clicks: the track is linked first
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
That walks the clip through ingest → survey → track → **verify** → layers →
|
|
127
|
+
scale → kinematics → integrity → report, and writes `<tag>_case.md` and
|
|
128
|
+
`.json`. A stage that has nothing to work with says so and the run continues;
|
|
129
|
+
nothing is silently skipped. Each stage is the function the stage's own command
|
|
130
|
+
calls (`mcdonald.stages`), so a number in the case report is the number
|
|
131
|
+
`mcdonald layers` or `mcdonald kinematics` would give. With a track, the layers
|
|
132
|
+
stage is the whole measurement — the object against each background layer, about
|
|
133
|
+
a second per frame pair — and `--skip layers,integrity` is the quick run.
|
|
134
|
+
|
|
135
|
+
Or one question at a time:
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
# How does the background move -- and is it one background?
|
|
139
|
+
mcdonald layers CLIP.mp4 --auto-track --validate
|
|
140
|
+
|
|
141
|
+
# Has the clip been altered? Was the object added?
|
|
142
|
+
mcdonald integrity CLIP.mp4 --track track.csv
|
|
143
|
+
|
|
144
|
+
# Is my track on the object in every frame?
|
|
145
|
+
mcdonald tracksheet CLIP.mp4 --track track.csv
|
|
146
|
+
|
|
147
|
+
# Find the object and click it on a couple of frames (opens a window)
|
|
148
|
+
mcdonald mark CLIP.mp4 # the whole clip
|
|
149
|
+
mcdonald mark CLIP.mp4 --n0 400 --n1 420 # or a window of it
|
|
150
|
+
|
|
151
|
+
# ...and hand those clicks to the pipeline: the track is linked from them
|
|
152
|
+
mcdonald layers CLIP.mp4 --marks CLIP/clip_marks.json
|
|
153
|
+
|
|
154
|
+
# The same with no window, for something that cannot click: see the clip, then say where
|
|
155
|
+
mcdonald look CLIP.mp4 --n0 1 --n1 120 --propose # what moves against the background, best first, as strips
|
|
156
|
+
mcdonald look CLIP.mp4 # an overview sheet; --n0/--n1 narrow it
|
|
157
|
+
mcdonald look CLIP.mp4 --frame 408 --size 21 --dark # a frame's candidates, ringed, numbered, enlarged
|
|
158
|
+
mcdonald mark CLIP.mp4 --n0 400 --n1 420 --no-window --link \
|
|
159
|
+
--set object@408=1010.9,313.0 --set object@411=702.4,604.2 --why "candidate 1 of 6 at 21 px dark; the one that moves"
|
|
160
|
+
|
|
161
|
+
# Boresight, north pointer, corner brackets -- the overlay's own readings
|
|
162
|
+
mcdonald symbology CLIP.mp4
|
|
163
|
+
|
|
164
|
+
# v_px -> omega -> what the motion permits (with --ladder when k is unknown)
|
|
165
|
+
mcdonald kinematics CLIP.mp4 --track track.csv --ladder
|
|
166
|
+
|
|
167
|
+
# Does the object move WITH the texture around it, or THROUGH it?
|
|
168
|
+
mcdonald comotion CLIP.mp4 --track track.csv --diameter 72
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
`CLIP` is a path to any video file. Results go to a **case directory** —
|
|
172
|
+
`--out DIR`, otherwise `./<name>/` under your working directory. Nothing is ever
|
|
173
|
+
written next to the installed code.
|
|
174
|
+
|
|
175
|
+
**Two ways in, and each does the whole job.** A person with no terminal starts
|
|
176
|
+
`mcdonald-gui` (below), marks and links the object, and measures it from the
|
|
177
|
+
window's Measure menu, which is `mcdonald run` with a form in place of the
|
|
178
|
+
options. An agent with no display uses `look` and `mark --set`: `docs/agents.md`
|
|
179
|
+
is PR113 done start to finish that way, to 141.4 px/frame against the published
|
|
180
|
+
142. A mark placed with `--set` is recorded
|
|
181
|
+
as an agent's, with its `--why`, never counts as a hand mark, and a case report
|
|
182
|
+
built on it says so above its bottom line — which thing is the object is a
|
|
183
|
+
judgment, and the files say who made it.
|
|
184
|
+
|
|
185
|
+
Every command takes `--json`: one object alone on stdout — `command`, `inputs`,
|
|
186
|
+
`clip`, `files`, `results`, `no_power`, `needs`, `notes`, `exit`, `error` — and
|
|
187
|
+
everything meant for a person on stderr. Every command has its results as
|
|
188
|
+
fields — numbers with the unit in the name, never a sentence to parse — and what
|
|
189
|
+
it printed for a person beside them as `results.said`, written *from* those
|
|
190
|
+
fields. Each measuring command is a command line over one function, and `run`
|
|
191
|
+
calls the same ones (`mcdonald.stages`), so a number in a case report is the
|
|
192
|
+
number the stage's own command gives: `tests/test_cli.py` holds them equal to
|
|
193
|
+
the last digit, and `tests/test_gui.py` does the same for the window. Exit
|
|
194
|
+
codes tell an expected failure from a bug: 0 done, 1 a traceback (a bug), 2 the
|
|
195
|
+
command line was wrong, 3 the machine lacks ffmpeg or a window, 4 the input is
|
|
196
|
+
not there or is not a video, 5 nothing to work on (no marks; the link acquired
|
|
197
|
+
nothing). `mcdonald --help` lists them.
|
|
198
|
+
|
|
199
|
+
A track CSV needs a frame column (`frame`, `n` or `frame_n`) and an x/y column
|
|
200
|
+
pair in video pixels (`x_px,y_px` or `x,y`). `--auto-track` will attempt one for
|
|
201
|
+
you, but **look at the track sheet before building anything on it**: on the clip
|
|
202
|
+
this toolkit was developed against, the first automatic tracker spent seven
|
|
203
|
+
frames locked to a cloud feature 100 px from the object.
|
|
204
|
+
|
|
205
|
+
Long clips: `--n0/--n1` take a frame window and keep the absolute numbering.
|
|
206
|
+
Frames are extracted losslessly and are ~2 MB each, so point `--workdir`
|
|
207
|
+
somewhere with room if `/tmp` is small or a tmpfs.
|
|
208
|
+
|
|
209
|
+
### Marking the object
|
|
210
|
+
|
|
211
|
+
Nothing here can decide which thing in the frame is the object, and it does
|
|
212
|
+
not pretend to. `mcdonald mark` opens a window on the extracted frames; two
|
|
213
|
+
clicks give the linker its seed and the velocity it cannot acquire on its own,
|
|
214
|
+
after which the automatic track covers the rest. It writes a marks JSON, a
|
|
215
|
+
track CSV the other commands read, and a magnified contact strip with the
|
|
216
|
+
marks drawn back onto the pixels — which is how a coordinate gets checked
|
|
217
|
+
rather than trusted.
|
|
218
|
+
|
|
219
|
+
On DOW-UAP-PR113 that is the entire human input: two clicks reproduce the
|
|
220
|
+
published 142 px/frame.
|
|
221
|
+
|
|
222
|
+
There are two windows over the same marks, and `--gui auto` (the default) takes
|
|
223
|
+
the first that will open.
|
|
224
|
+
|
|
225
|
+
- **The Qt window** (`pip install -e ".[gui]"`) is for the clip you have not
|
|
226
|
+
seen. A timeline over the whole clip, playback at true speed — it holds
|
|
227
|
+
30 frames/s on lossless 1080p, skipping frames rather than stretching time if
|
|
228
|
+
it ever cannot, and saying how many — an overview of the clip as tiles (`o`),
|
|
229
|
+
the detector's candidates drawn on the frame (`c`), a loupe under the cursor,
|
|
230
|
+
and undo. The candidates are there to be looked at, not trusted: on PR148 the
|
|
231
|
+
detector ranks the reticle's corner marks alongside the ship.
|
|
232
|
+
|
|
233
|
+
Then **`l` links**: an automatic track through the marks, drawn over the clip
|
|
234
|
+
as it grows, with the linked frames shown on the timeline and the track strip
|
|
235
|
+
put in front of you at the end. The detector's scale and polarity are chosen
|
|
236
|
+
from the marks. Every mark is a seed: between two marks the track is linked
|
|
237
|
+
forward from one and backward from the other, and a frame where the two
|
|
238
|
+
disagree is drawn amber rather than settled quietly; before the first mark
|
|
239
|
+
and after the last it runs until the object is lost, and stops there rather
|
|
240
|
+
than starting again on the brightest thing in the frame. So after a loss,
|
|
241
|
+
mark the object where it reappears and press `l` again — the detector's work
|
|
242
|
+
is kept, and only new frames are computed. `object` and `object #2` are
|
|
243
|
+
linked together. `s` then also writes `<tag>_autotrack.csv`, which the other
|
|
244
|
+
commands take as `--track`. On PR113 the two documented clicks choose 21 px
|
|
245
|
+
dark, link frames 408–411 onto the vendored positions to 0.005 px, and give
|
|
246
|
+
back 141.4 px/frame against the published 142 — in the window, in about a
|
|
247
|
+
minute. The same step without a window is `mcdonald.autolink`, and
|
|
248
|
+
`layers`, `integrity` and `run` take a marks file directly as `--marks`:
|
|
249
|
+
from the command line that is the only way to track an object too fast for
|
|
250
|
+
`--auto-track`, which links 1 of PR113's frames where `--marks` links all 4.
|
|
251
|
+
|
|
252
|
+
For placing a mark finely: `ctrl`+arrows nudge it a pixel (`ctrl+shift`, a
|
|
253
|
+
tenth), and `shift`+click snaps it to the detector's nearest candidate. A
|
|
254
|
+
snapped mark says so, in the window, the JSON, the CSV and the contact strip:
|
|
255
|
+
it agrees with the detector because it *is* the detector's, so it must never
|
|
256
|
+
be mistaken for an independent hand mark.
|
|
257
|
+
|
|
258
|
+
A clip it has not seen is extracted first, behind a progress bar with a
|
|
259
|
+
Cancel on it. Where `--n0/--n1` do not say which part, it asks, and what it
|
|
260
|
+
asks with is a player: play the clip forward or backward at its true speed or
|
|
261
|
+
slower, step a frame or ten, drag the bar, press "Start here" and "End here"
|
|
262
|
+
at the frame on the screen, and read what that part will cost before anything
|
|
263
|
+
is extracted. Nothing is extracted to watch it: the frames come from an ffmpeg
|
|
264
|
+
pipe (`mcdonald/reel.py`) under the numbers extraction will give them. A long
|
|
265
|
+
clip is asked about even when it is all on disk already, because opening the
|
|
266
|
+
whole of it costs nothing and measuring the whole of it costs hours.
|
|
267
|
+
|
|
268
|
+
**It can look first.** Track → Find the object (`f`; `mcdonald look --propose`
|
|
269
|
+
from a command line) looks for what moves against the background — a double
|
|
270
|
+
difference on the registered background, compact residual peaks, chains at
|
|
271
|
+
constant velocity, marked down where several things go the same way at once,
|
|
272
|
+
which is a layer or a scale that scrolls, and where the frame itself shows an
|
|
273
|
+
edge or a stroke and not a spot with background all round it — and lists what
|
|
274
|
+
it finds, best first, each as a strip of the clip's own pixels. It shows the
|
|
275
|
+
best few and says how many more it kept (`--more`). "This is it" places marks
|
|
276
|
+
along one and links from them; a click is then the correction rather than the
|
|
277
|
+
first step. It proposes and does not decide: no detector can say which thing
|
|
278
|
+
is the object, so a mark taken from a proposal is recorded as `proposed`,
|
|
279
|
+
never counts as a hand mark, and a report built on it says the suggestion was
|
|
280
|
+
the detector's and the yes a person's. Against every clip with a recorded
|
|
281
|
+
track: on PR149 the contact is the one strong proposal (0.4 px from the hand
|
|
282
|
+
workup; taken and linked, 20.1 px/frame for the published 20.2); on PR144,
|
|
283
|
+
where the sensor follows the object and only the background moves, on PR142
|
|
284
|
+
and on PR148, likewise, the second row scoring a fiftieth of the first; on
|
|
285
|
+
PR113, a four-frame transit past a scrolling heading tape under a pan, it is
|
|
286
|
+
first by a narrow margin, and weak — it was sixth to eleventh until the frame
|
|
287
|
+
was asked whether each thing is a spot — and taken, links to the vendored
|
|
288
|
+
track exactly; on PR055 at its true size, a black disc 24 px across that
|
|
289
|
+
moves 1.5 px a frame, it is first and strong, and its marks are on the disc's
|
|
290
|
+
centre and not on its rim, because a proposal's positions are the thing's
|
|
291
|
+
own (`propose.thing_at`) and not the residual's — the ×3 copy of the same
|
|
292
|
+
scene, a 72 px disc, still cancels in the double difference and is not on the
|
|
293
|
+
list. A proposal's marks are for the linker: `tools/find_rank.py --link`
|
|
294
|
+
holds Find and the link from its marks against every clip with a recorded
|
|
295
|
+
track, and is what to run after any change. About 0.2 s a frame, shown as
|
|
296
|
+
it goes.
|
|
297
|
+
|
|
298
|
+
**With no terminal.** `mcdonald-gui` starts the same window the other way
|
|
299
|
+
round: it asks for the clip (a file, or a catalog id: a PURSUE video not on
|
|
300
|
+
the computer yet is downloaded, after asking), asks which part, keeps its
|
|
301
|
+
cases in the storage folder (`Documents/mcdonald/<tag>` until changed on the
|
|
302
|
+
first screen) and shows where, and says what goes
|
|
303
|
+
wrong in a dialog instead of printing it. Everything a flag does is in the
|
|
304
|
+
File menu — Open a video, Open by catalog name, Open marks (`--load`), Save to
|
|
305
|
+
a different folder (`--out`) — and every key is in the menus and under Help →
|
|
306
|
+
Keys and mouse, which are made from one table (`mcdonald/actions.py`) together
|
|
307
|
+
with `mcdonald mark --help`. What the window says is written in plain words,
|
|
308
|
+
for someone outside the field: a video, not a clip; a spot the computer found,
|
|
309
|
+
not a detector's candidate; "frame", "mark", "track" and "link" are the four
|
|
310
|
+
words of the trade it keeps, and Help → Getting started says what each means
|
|
311
|
+
first. (The case report and the lines each stage prints are the measurement's
|
|
312
|
+
own words, and are not part of that yet.) **Measure → Measure this video** is the rest of the
|
|
313
|
+
job: it saves the marks and the link, asks what you know that the pixels cannot
|
|
314
|
+
say (the form is made from the rows `mcdonald run`'s options are made from),
|
|
315
|
+
says what the slow stages will cost, and makes the case on a thread of its own.
|
|
316
|
+
While it runs there is a bar that counts where the step can count (frame
|
|
317
|
+
pairs, tiles) and runs to and fro where it cannot, the stage it is on, the time
|
|
318
|
+
gone and the time left in the step, and a Stop that ends the step under way;
|
|
319
|
+
and it measures the frames round the track unless asked for everything that is
|
|
320
|
+
open, because someone who opened a whole clip to find a four-frame transit has
|
|
321
|
+
hours of frames open. (The command line says the same on stderr.)
|
|
322
|
+
The track sheet is put on the screen first, with the question every number
|
|
323
|
+
after it depends on — is the circle on the object in every frame? — and
|
|
324
|
+
closing it unanswered is a no, which the report records as provisional. The
|
|
325
|
+
case report opens beside the window when it is done, and Measure → Open the
|
|
326
|
+
case folder finds the files. `mcdonald-gui --desktop-entry`, or Help in the
|
|
327
|
+
window, adds it to the applications menu on Linux. It needs the `gui` extra
|
|
328
|
+
installed once. On macOS every suite passes on GitHub's runner
|
|
329
|
+
(`.github/workflows/platforms.yml`, run by hand or by `git push -f origin HEAD:macos-ci`);
|
|
330
|
+
it has not yet been run on Windows.
|
|
331
|
+
- **The matplotlib window** (`--gui mpl`) needs nothing beyond what the package
|
|
332
|
+
already depends on. It steps at about 11 frames/s on 1080p, which is ample
|
|
333
|
+
when you already know which frames to look at.
|
|
334
|
+
|
|
335
|
+
Both keep every mark in the same `MarkSet`, save through the same function, and
|
|
336
|
+
are held to the same checks by `tests/test_gui.py`. In both, a frame is a
|
|
337
|
+
lossless PNG named by its frame number; there is no video element to disagree
|
|
338
|
+
with ffmpeg about which frame is on screen, playback included.
|
|
339
|
+
|
|
340
|
+
### The gate
|
|
341
|
+
|
|
342
|
+
`run` makes a track sheet — every frame tiled with the tracked object circled —
|
|
343
|
+
and treats looking at it as a prerequisite, not an option. Without
|
|
344
|
+
`--i-looked`, every object measurement in the report is stamped
|
|
345
|
+
**provisional**. There is no flag that skips making the sheet.
|
|
346
|
+
|
|
347
|
+
This is not ceremony. On the clip this toolkit was developed against, the first
|
|
348
|
+
automatic tracker spent seven frames locked to a cloud feature 100 px from the
|
|
349
|
+
object and produced a clean, plausible, wrong rate. The sheet is how that is
|
|
350
|
+
caught, and it takes about ten seconds to look at.
|
|
351
|
+
|
|
352
|
+
### Reading the results
|
|
353
|
+
|
|
354
|
+
`docs/method.md` is the method note: what each measurement means, how each one
|
|
355
|
+
fails, and the traps the library is built around. Read it before quoting a
|
|
356
|
+
number. The short version of the three that matter most:
|
|
357
|
+
|
|
358
|
+
1. **Never quote a rate "against the background" without naming the layer.** Sea
|
|
359
|
+
and cloud tops moved 98 px/s apart on the clip this came from; a single
|
|
360
|
+
consensus returns a blend and names neither.
|
|
361
|
+
2. **Pixels per second become metres per second only through an angular scale
|
|
362
|
+
*k* and a range *R*.** Neither is usually recoverable from a clip. A speed
|
|
363
|
+
quoted without both sourced is not a measurement.
|
|
364
|
+
3. **NO POWER is a verdict.** A clip that cannot decide a test has not passed
|
|
365
|
+
it, and those tests are reported, never dropped.
|
|
366
|
+
|
|
367
|
+
### Provenance, and the PURSUE videos
|
|
368
|
+
|
|
369
|
+
The tools run on any file. The package also carries the list of the U.S. DoW
|
|
370
|
+
PURSUE release's videos (war.gov/UFO), so a record id works with nothing set up:
|
|
371
|
+
the first time a video is named, it is downloaded from DVIDS into the storage
|
|
372
|
+
folder (below), and the integrity report quotes the releasing body's own words,
|
|
373
|
+
including any alteration statement, alongside the pixel tests:
|
|
374
|
+
|
|
375
|
+
```bash
|
|
376
|
+
mcdonald integrity PR144 # downloads PR144 the first time (31 MB)
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
A mirror of your own, or a catalog of another release, is named instead with
|
|
380
|
+
`MCDONALD_CATALOG` (`none` for no catalog at all):
|
|
381
|
+
|
|
382
|
+
```bash
|
|
383
|
+
export MCDONALD_CATALOG=/path/to/pursue_index/records.csv
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
Writing another backend is a subclass with one method; see
|
|
387
|
+
`src/mcdonald/catalog.py`. A clip that is not in the catalog gets "no record
|
|
388
|
+
for this file": nothing is borrowed from someone else's release.
|
|
389
|
+
|
|
390
|
+
### Where the large files go
|
|
391
|
+
|
|
392
|
+
Downloaded videos and each video's frames (a lossless 1080p frame is most of a
|
|
393
|
+
megabyte, so a whole clip is gigabytes) go in one storage folder:
|
|
394
|
+
`Documents/mcdonald` unless `MCDONALD_HOME` says otherwise, with `videos/` and
|
|
395
|
+
`frames/` inside it. In the window it is shown on the first screen, with a
|
|
396
|
+
button to change it. `--workdir DIR` puts one command's frames somewhere else.
|
|
397
|
+
|
|
398
|
+
This matters more than it looks. On a disclosed digital recreation, every pixel
|
|
399
|
+
test returned NO POWER or INCONCLUSIVE — **the record identified the clip, not
|
|
400
|
+
the pixels.** Custody and disclosure are not things pixel forensics can replace.
|
|
401
|
+
|
|
402
|
+
## What it cannot do
|
|
403
|
+
|
|
404
|
+
`integrity` shows whether a clip and the object in it behave like the output of
|
|
405
|
+
one sensor chain. It catches an object pasted, AI-inserted or animated onto
|
|
406
|
+
footage that already existed. **It cannot exclude a composite made upstream of
|
|
407
|
+
the symbology by someone who modelled exposure, shake, gain and parallax.**
|
|
408
|
+
Nothing in the pixels can; that is a custody question — the original recording
|
|
409
|
+
with its metadata, and the mission report. Say so whenever you quote a result.
|
|
410
|
+
|
|
411
|
+
The synthetic-insert self-test is what gives a PASS its meaning: the tool
|
|
412
|
+
animates a fake object over the same frames and runs the same tests on it. If
|
|
413
|
+
the fake passes too, that test has no discriminating power on your clip,
|
|
414
|
+
whatever its verdict says. Note the honest limit: no clip with a *known real*
|
|
415
|
+
insert was available to validate against, so the synthetic stands in for one,
|
|
416
|
+
and it models a naive overlay rather than a match-moved physical composite.
|
|
417
|
+
|
|
418
|
+
## Roadmap
|
|
419
|
+
|
|
420
|
+
Working (0.2): the `run` driver and the case report; background layers; clip
|
|
421
|
+
integrity; track verification; symbology (boresight, north pointer, corner
|
|
422
|
+
brackets); angular scale (graticule, in-frame reference, zoom chain, the FOV
|
|
423
|
+
ladder); the kinematic reduction; object-versus-texture co-motion; one figure
|
|
424
|
+
style; a catalog, with the PURSUE videos' list shipped and downloaded on demand.
|
|
425
|
+
|
|
426
|
+
Next: automatic tracking good enough to trust without hand marks (the current
|
|
427
|
+
`--auto-track` needs its sheet checked every time); the mode annunciator and
|
|
428
|
+
the data bar; batch mode over a whole catalog; the dimensionless-number
|
|
429
|
+
reduction.
|
|
430
|
+
|
|
431
|
+
## License
|
|
432
|
+
|
|
433
|
+
**BSD 3-Clause** ([LICENSE](LICENSE)), copyright Jacob Haqq Misra, chosen
|
|
434
|
+
2026-09-25 when the repository went public: the scientific-Python norm, and
|
|
435
|
+
its third clause keeps the author's name off a derived version's promotion
|
|
436
|
+
without permission, which matters on this subject.
|
|
437
|
+
|
|
438
|
+
A dependency's licence could have constrained that choice: anything GPL linked
|
|
439
|
+
into the package would have forced the package GPL. That is why the marking GUI
|
|
440
|
+
uses **PySide6 (LGPL)** rather than PyQt (GPL or commercial), and only as an
|
|
441
|
+
optional extra — see `docs/handoff-gui.md`. Keep it that way.
|
mcdonald-0.2.4/README.md
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
<picture>
|
|
2
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/haqqmisra/mcdonald/main/docs/logo-dark.png">
|
|
3
|
+
<img alt="mcDonald UAP Toolkit" src="https://raw.githubusercontent.com/haqqmisra/mcdonald/main/docs/logo-light.png" width="420">
|
|
4
|
+
</picture>
|
|
5
|
+
|
|
6
|
+
**mcdonald** is a frame-by-frame analysis toolkit for measuring the kinematics of an unknown
|
|
7
|
+
object in a single-camera video.
|
|
8
|
+
|
|
9
|
+
> "Science is in default for having failed to mount any truly adequate studies of this problem."
|
|
10
|
+
>
|
|
11
|
+
> — James E. McDonald
|
|
12
|
+
|
|
13
|
+
**Status:** early test version (0.2.4), tried on Linux and macOS; Windows is next.
|
|
14
|
+
|
|
15
|
+
## Install
|
|
16
|
+
|
|
17
|
+
1. Prerequisite: make sure **ffmpeg** is installed:
|
|
18
|
+
`brew install ffmpeg` (Mac), `winget install Gyan.FFmpeg` (Windows),
|
|
19
|
+
`sudo apt install ffmpeg` or `sudo dnf install ffmpeg` (Linux).
|
|
20
|
+
2. Install **mcdonald** (needs Python 3.10 or newer):
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
python3 -m pip install "mcdonald[gui]"
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
3. Check your setup, which also provides instructions on what to do next:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
mcdonald setup
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
When a newer version is out, `mcdonald-gui` offers to update itself when it starts, and the
|
|
33
|
+
command line prints the command to update with.
|
|
34
|
+
|
|
35
|
+
New to Python or the terminal? [docs/install.md](https://github.com/haqqmisra/mcdonald/blob/main/docs/install.md) walks through each step in
|
|
36
|
+
detail.
|
|
37
|
+
|
|
38
|
+
## Use
|
|
39
|
+
|
|
40
|
+
**mcdonald** has a graphical interface and a command-line interface. The software is intended
|
|
41
|
+
to be driven by human users and/or AI agents.
|
|
42
|
+
|
|
43
|
+
The graphical interface is designed to prompt human users through the steps of analysis. To
|
|
44
|
+
start the graphical interface:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
mcdonald-gui
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
The command-line interface is designed for developers, advanced users, and AI agents. To start
|
|
51
|
+
the command-line interface and see a summary of options:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
mcdonald
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Prompting an agent
|
|
58
|
+
|
|
59
|
+
You can invoke an AI agent to assist at any point in the analysis, whether before or after a
|
|
60
|
+
human has looked at the video. Here is a sample prompt that you can pass to your favorite
|
|
61
|
+
command-line AI model:
|
|
62
|
+
|
|
63
|
+
> Please use the mcdonald toolkit to analyze the PR144 video released under PURSUE. Run
|
|
64
|
+
> `mcdonald readme` to get started.
|
|
65
|
+
|
|
66
|
+
## License
|
|
67
|
+
|
|
68
|
+
Copyright (c) 2026 Jacob Haqq Misra. Released under the [BSD 3-Clause License](https://github.com/haqqmisra/mcdonald/blob/main/LICENSE).
|