Checks that a video is real by reading the power grid in the flicker of the room lights.
Video · Live app · Judge guide · Technical report · Architecture · Responsible use
Entry for the OpenCV AI Competition 2026 (OpenCV 5 + AWS).
Anyone can now make a video that looks real. Viewers, newsrooms and courts need a way to check a recording that does not depend on trusting the person who sent it. Most tools guess from how pixels look. GRIDPRINT uses a physical witness instead: the electric grid.
Mains-powered lights flicker at twice the grid frequency. The grid frequency drifts a little all the time, and the drift is the same across the whole grid. This drift is the electric network frequency (ENF). A phone camera with a rolling shutter reads the sensor one row at a time, so the flicker shows as faint horizontal bands in the video. GRIDPRINT reads those bands with OpenCV 5, rebuilds the ENF track, and compares it with a recorded log of the real grid.
The result is always one of three verdicts:
| Verdict | Meaning |
|---|---|
VERIFIED |
The flicker in the video matches the grid log for the claimed time and place. |
CONTRADICTED |
The flicker clearly disagrees with the grid log. Final only after a human reviewer approves it. |
INCONCLUSIVE |
The signal is too weak or absent to decide. A missing signal never counts against a video. |
GRIDPRINT is not an AI-content detector and is not cryptographic proof. It gives evidence, with every step traced.
- Capture. Record with any phone, or with the GRIDPRINT Capture Android app, which saves a sidecar file with the camera timing.
- Upload. Send the video to the Verify web app. The file goes to Amazon S3 and a job goes on Amazon SQS.
- Analyze. A Graviton4 worker runs the OpenCV 5 engine. An agent on Amazon Bedrock picks the next engine tool. Code-enforced policies keep the verdict deterministic.
- Decide. The engine matches the ENF track to the grid log and returns a verdict, a PDF report, plots and the full agent trace.
flowchart LR
A["Frames"] --> B["Linear light"]
B --> C["Readout time"]
C --> D["Motion mask"]
D --> E["Light patches"]
E --> F["Row signal"]
F --> G["Phase fit<br/>cv2.solve"]
G --> H["ENF track"]
H --> I["Match grid log"]
I --> J["Continuity check"]
J --> K["Verdict"]
All signal math runs in float32 or float64 on linear light. The engine never interpolates across the rolling-shutter idle gap between frames.
flowchart LR
subgraph Clients
U["User browser<br/>Verify web app"]
CAP["Capture app<br/>Android"]
REV["Reviewer"]
end
subgraph Edge["AWS entry"]
APIGW["Amazon API Gateway"]
VPCL["VPC link"]
ALB["Application Load Balancer"]
end
subgraph Core["AWS core"]
API["AWS Fargate API<br/>arm64"]
S3["Amazon S3<br/>uploads and results<br/>AWS KMS"]
SQS["Amazon SQS<br/>jobs queue + DLQ"]
DDB["Amazon DynamoDB<br/>jobs and grid log"]
COG["Amazon Cognito<br/>reviewers"]
end
subgraph Worker["Amazon ECS worker on Graviton4 c8g"]
ORCH["Agent orchestrator"]
MCP["MCP server<br/>12 tools"]
ENG["OpenCV 5 engine<br/>15 stages"]
end
subgraph AI["Amazon Bedrock"]
NOVA["Amazon Nova Lite planner<br/>guarded by policies"]
end
subgraph Grid["Grid reference"]
NODE["Grid Node<br/>ESP32 + GPS"]
IOT["AWS IoT Core"]
LAM["AWS Lambda"]
end
subgraph Ops["Operations"]
CW["Amazon CloudWatch<br/>logs, metrics, alarms"]
ECR["Amazon ECR<br/>arm64 images"]
CDK["AWS CDK<br/>all stacks"]
end
U --> APIGW
CAP --> APIGW
REV --> COG
COG --> APIGW
APIGW --> VPCL --> ALB --> API
API --> S3
API --> SQS
API --> DDB
SQS --> ORCH
ORCH <--> NOVA
ORCH <--> MCP
MCP <--> ENG
ENG --> S3
ORCH --> DDB
NODE --> IOT --> LAM --> DDB
ENG -. reads grid log .-> DDB
Worker -.-> CW
API -.-> CW
ECR -.-> Worker
ECR -.-> API
CDK -.-> Core
9 AWS CDK stacks are deployed in us-east-1. The API runs on AWS Fargate linux/arm64; the engine workers
run on Graviton4 c8g instances fed by Amazon SQS. Full detail: docs/ARCHITECTURE.md and
technical report §6.
- Real iPhone 13 recording on the live deployment: job
cd65b6ea0c20ran end to end on a Graviton4 worker. The stock camera app's anti-banding had removed the flicker bands, so the engine reportedINCONCLUSIVE(SIGNAL_ABSENT) instead of guessing, and the agent adapted by asking for the original file and the camera model. - Every step is traced: each AWS run stores its result, agent trace, report PDF and plots under
results/aws/(results/aws/<job_id>/trace.json).
| Metric | x86 c7i.2xlarge |
Graviton4 c8g.2xlarge |
|---|---|---|
| Throughput, video-s per wall-s | 0.92 | 1.20 |
| Cost per video-hour | $0.390 | $0.266 |
Same engine, same input, five runs per configuration. Graviton4 processes more video per second at a lower cost per hour of video (technical report §7).
- 0 false
CONTRADICTEDon authentic clips of the frozen-threshold test split (SYNTHETIC simulator clips). - Agent traces for each behaviour:
results/agent_traces/. - Full SYNTHETIC tables and the real-recording runs: technical report §9.
SYNTHETIC results are labeled SYNTHETIC and are never presented as real-world accuracy. Every reported number
lives under results/ with a source tag (SPEC 14.3).
| Upload and verify | Job result |
|---|---|
![]() |
![]() |
| Agent trace | Reviewer view |
![]() |
![]() |
| Layer | Technology |
|---|---|
| Vision engine | OpenCV 5 (cv2.LUT, calcOpticalFlowPyrLK, findHomography USAC_MAGSAC, DISOpticalFlow, cv2.dnn, warpPerspective, cv2.solve, cv2.dft), NumPy, PyAV |
| Agent | Amazon Bedrock (Amazon Nova Lite), Model Context Protocol server gridprint-engine, code-enforced policies |
| API and web | FastAPI on AWS Fargate arm64, React web app |
| Compute | Amazon ECS on Graviton4 c8g, Amazon SQS |
| Data | Amazon S3 with AWS KMS, Amazon DynamoDB |
| Identity and ops | Amazon Cognito, Amazon CloudWatch, Amazon ECR, AWS CDK v2 |
| Edge hardware | Grid Node (ESP32 + GPS) through AWS IoT Core and AWS Lambda; Capture Android app (Camera2) |
Requirements: Python 3.11, uv, FFmpeg on PATH, Node.js 24 (for the web app).
make setup # install dependencies
python -m eval.make_demo_inputs # create sample input videos
make local # serve API + web app at http://127.0.0.1:8000make local uses local file storage and the deterministic agent planner. The reviewer token for local use is
written to work/local_reviewer_token.txt. On Windows without GNU make, use ./make <target> (Git Bash) or
make.cmd <target>.
More commands:
make test # unit and integration tests
make eval # evaluation (SYNTHETIC split)
make bench # Graviton vs x86 benchmark
make final-check # prints ALL CHECKS PASSED only when every SPEC 17.3 item holds- Complete human task H1 in docs/HUMAN_TASKS.md (CLI profile
gridprint). - Build the arm64 images (no local Docker needed):
python infra/build_images.py. - Deploy all stacks:
make deploy. Remove everything:make destroy.
engine/ OpenCV 5 engine, stages S1-S15 (engine/gridprint_engine/)
agent/ Agent planner, policies and trace
mcp_server/ MCP tool server gridprint-engine
api/ FastAPI service and job worker
web/ Verify web app (React)
infra/ AWS CDK v2 stacks and image build
eval/ Simulator, datasets and evaluation
bench/ Graviton vs x86 benchmark
capture-android/ Capture Android app
node/ Grid-frequency Node: hardware, firmware, ingest
calibration_rig/ Camera calibration rig
docs/ Report, architecture, guides, build logs
results/ Every reported number, with its source
| Document | What it covers |
|---|---|
| Technical report | Method, AWS design, benchmark and evaluation in full |
| Architecture | Components, data flow and diagrams (docs/diagrams/) |
| Judge guide | Step-by-step walkthrough of the live app |
| Responsible use | How to use GRIDPRINT verdicts correctly |
| SPEC.md | The single source of truth for the product |
For reviewers who want the full trail, the build logs are also in docs/:
PROGRESS, DECISIONS, VERIFICATION,
REQUIREMENTS_TRACE and HUMAN_TASKS.
A verdict is evidence, not a final judgment. CONTRADICTED always needs a human reviewer. Read
docs/RESPONSIBLE_USE.md before you use GRIDPRINT results in any decision.
Built for the OpenCV AI Competition 2026 with OpenCV 5 and AWS. Thanks to the OpenCV team and the AWS Graviton, Amazon Bedrock and AWS CDK teams for the tools this project stands on.
Licensed under Apache-2.0. See LICENSE.





