diff --git a/CUTTER_REPORT.html b/CUTTER_REPORT.html index 3aed6ba..c823559 100644 --- a/CUTTER_REPORT.html +++ b/CUTTER_REPORT.html @@ -132,5 +132,5 @@ table.ov tr:hover { background: rgba(255, 255, 255, 0.05); }
-

Cutter & Match Report

Generiert: 2026-05-08 15:07:07Trailer: BehindTheRedDoor_Trailer_REFERENCE.mp4 @ 25.000 fpsSource: BehindTheRedDoor_FTR_1080P_2398_Fixed.mp4 @ 23.976 fps
25 Beats — 23 automatisch (4 bestätigt)2 manuell.
Recent Changes:
Restore full visible Beat 14 source candidate; keep phase warning

Legende

OKBestätigt — direkt in Schnitt-Timeline übernehmen
?Vorläufig — Phase und Aktion im NLE visuell prüfen
MAN.Kein Treffer — manuell suchen oder Schwarzbild einfügen

Übersicht

BeatTrailer TC In–OutDauerSource TC InSceneScoreStatus
0000:00:00:00–00:00:03:003.00s00:00:03:1910.597?
0100:00:03:00–00:00:08:105.40s00:00:04:0910.380?
0200:00:08:10–00:00:16:248.56s00:00:35:0530.761OK
0300:00:16:24–00:00:19:032.16s01:02:19:034360.572?
0400:00:19:03–00:00:20:161.52s01:02:21:094370.728OK
0500:00:20:16–00:00:26:095.72s00:01:33:03100.499?
0600:00:26:09–00:00:29:062.88s00:01:03:0750.396?
0700:00:29:06–00:00:31:172.44s01:20:10:105530.497?
0800:00:31:17–00:00:33:161.96s00:00:51:0750.620?
0900:00:33:16–00:00:36:193.12s01:20:29:035570.674OK
1000:00:36:19–00:00:40:023.32s01:20:35:16558+559+5560.660?
1100:00:40:02–00:00:42:032.04s01:20:40:185590.636?
1200:00:42:03–00:00:50:068.12s01:14:26:06519+130.701OK
1300:00:50:06–00:00:53:213.60s00:43:19:133080.636?
1400:00:53:21–00:00:57:023.24s00:43:24:103090.626?
1500:00:57:02–00:01:01:124.40s00:02:10:0817+3090.650?
1600:01:01:12–00:01:04:123.00s01:05:12:124510.626?
1700:01:04:12–00:01:09:034.64s01:31:18:04623+720.399?
1800:01:09:03–00:01:10:191.64sMAN.
1900:01:10:19–00:01:12:131.76s00:16:48:131260.403?
2000:01:12:13–00:01:15:143.04s01:27:05:036130.417?
2100:01:15:14–00:01:17:131.96s00:23:55:001750.526?
2200:01:17:13–00:01:19:232.40s01:03:05:114420.544?
2300:01:19:23–00:01:25:145.64s01:04:35:214460.534?
2400:01:25:14–00:01:32:076.72sMAN.

Beat-Details

Beat 00

?Vorläufig
▶ Trailer  /  ▶ Source (Frame-Locked Compare)
Trailer
00:00:00:00–00:00:03:00  (3.00s)
Phase logo animation assembling from distorted shapes with motion blur
Bild centered, symmetrical, abstract black void
Source
00:00:03:19–00:00:05:09
Scene 1 · Score 0.597
⚠ Score 0.597 unter 0.65 — visuell prüfen
python cli.py rematch --beat 0

Beat 01

?Vorläufig
▶ Trailer  /  ▶ Source (Frame-Locked Compare)
Trailer
00:00:03:00–00:00:08:10  (5.40s)
Phase Dynamic motion blur and shifting optical distortions across the text
Bild Centered, symmetrical layout with overlapping circular glass-like distortions, Abstract black void
Source
00:00:04:09–00:00:06:03
Scene 1 · Score 0.380
⚠ Score 0.380 unter 0.65 — visuell prüfen
python cli.py rematch --beat 1

Beat 02

OKBestätigt
▶ Trailer  /  ▶ Source (Frame-Locked Compare)
Trailer
00:00:08:10–00:00:16:24  (8.56s)
Phase drawing a heart shape on a foggy surface
Bild extreme close-up, shifting from profile of a face to a hand interacting with a surface, indoor, obscured glass or foggy surface
Source
00:00:35:05–00:00:43:06
Scene 3 · Score 0.761
python cli.py rematch --beat 2

Beat 03

?Vorläufig
▶ Trailer  /  ▶ Source (Frame-Locked Compare)
Trailer
00:00:16:24–00:00:19:03  (2.16s)
Phase speaking and smiling slightly
Bild close-up shot, centered face, outdoor rocky environment
Source
01:02:19:03–01:02:20:20
Scene 436 · Score 0.572
⚠ Score 0.572 unter 0.65 — visuell prüfen
python cli.py rematch --beat 3

Beat 04

OKBestätigt
▶ Trailer  /  ▶ Source (Frame-Locked Compare)
Trailer
00:00:19:03–00:00:20:16  (1.52s)
Phase lifting a camera to eye level to take a photo
Bild medium shot, subject centered, shallow depth of field with blurred treeline background, outdoor forest landscape, overcast sky
Source
01:02:21:09–01:02:22:08
Scene 437 · Score 0.728
python cli.py rematch --beat 4

Beat 05

?Vorläufig
▶ Trailer  /  ▶ Source (Frame-Locked Compare)
Trailer
00:00:20:16–00:00:26:09  (5.72s)
Phase a metallic cylindrical object is brought toward and touches the skin of the forearm
Bild extreme close-up, shallow depth of field, indistinct dark interior
Source
00:01:33:03–00:01:37:09
Scene 10 · Score 0.499
⚠ Score 0.499 unter 0.65 — visuell prüfen
python cli.py rematch --beat 5

Beat 06

?Vorläufig
▶ Trailer  /  ▶ Source (Frame-Locked Compare)
Trailer
00:00:26:09–00:00:29:06  (2.88s)
Phase hand reaching toward and touching an ornate decorative box
Bild close-up, shallow depth of field, hand entering from left frame, dark interior
Source
00:01:03:07–00:01:05:03
Scene 5 · Score 0.396
⚠ Score 0.396 unter 0.65 — visuell prüfen
python cli.py rematch --beat 6

Beat 07

?Vorläufig
▶ Trailer  /  ▶ Source (Frame-Locked Compare)
Trailer
00:00:29:06–00:00:31:17  (2.44s)
Phase man appears to be engaged in conversation
Bild man in a light gray sweater and scarf, seated on a white couch, with a window in the background, indoor with a view of the ocean
Source
01:20:10:10–01:20:12:14
Scene 553 · Score 0.497
⚠ Score 0.497 unter 0.65 — visuell prüfen
python cli.py rematch --beat 7

Beat 08

?Vorläufig
▶ Trailer  /  ▶ Source (Frame-Locked Compare)
Trailer
00:00:31:17–00:00:33:16  (1.96s)
Phase static or slow drifting
Bild close-up, diagonal curve from top-left to bottom-center, dark, indistinct void
Source
00:00:51:07–00:00:53:01
Scene 5 · Score 0.620
⚠ Score 0.620 unter 0.65 — visuell prüfen
python cli.py rematch --beat 8

Beat 09

OKBestätigt
▶ Trailer  /  ▶ Source (Frame-Locked Compare)
Trailer
00:00:33:16–00:00:36:19  (3.12s)
Phase speaking, transitioning from closed eyes to open mouth and focused gaze
Bild medium close-up, subject positioned right of center, profile/three-quarter view, indoor room next to a large window overlooking a blue horizon/sea
Source
01:20:29:03–01:20:32:06
Scene 557 · Score 0.674
python cli.py rematch --beat 9

Beat 10

?Vorläufig
▶ Trailer  /  ▶ Source (Frame-Locked Compare)
Trailer
00:00:36:19–00:00:40:02  (3.32s)
Phase conversation
Bild alternating close-ups and a medium two-shot, indoor living room with large windows showing a blue exterior landscape
Source
01:20:35:16  (multi-shot)
Scene Scenes 558, 559, 556 · 3 Segmente
  • Seg 1: 01:20:35:16  dur 0.88s  @ off 0.00s  sc 558  score 0.674
  • Seg 2: 01:20:36:14  dur 1.76s  @ off 0.88s  sc 559  score 0.649
  • Seg 3: 01:20:22:14  dur 0.68s  @ off 2.64s  sc 556  score 0.672
python cli.py rematch --beat 10

Beat 11

?Vorläufig
▶ Trailer  /  ▶ Source (Frame-Locked Compare)
Trailer
00:00:40:02–00:00:42:03  (2.04s)
Phase static talking head with slight facial expression changes
Bild medium close-up, subject positioned right of center, profile/three-quarter view facing left, indoor room with a large window showing a blue sea/horizon background
Source
01:20:40:18–01:20:42:18
Scene 559 · Score 0.636
⚠ Score 0.636 unter 0.65 — visuell prüfen
python cli.py rematch --beat 11

Beat 12

OKBestätigt
▶ Trailer  /  ▶ Source (Frame-Locked Compare)
Trailer
00:00:42:03–00:00:50:06  (8.12s)
Phase static profile shot transitioning to black/darkness
Bild medium close-up, profile view, subject positioned on the right side of the frame, dark outdoor environment, blurred trees in background
Source
01:14:26:06  (multi-shot)
Scene Scenes 519, 13 · 2 Segmente
  • Seg 1: 01:14:26:06  dur 3.52s  @ off 0.16s  sc 519  score 0.721
  • Seg 2: 00:01:47:14  dur 2.88s  @ off 4.88s  sc 13  score 0.676
python cli.py rematch --beat 12

Beat 13

?Vorläufig
▶ Trailer  /  ▶ Source (Frame-Locked Compare)
Trailer
00:00:50:06–00:00:53:21  (3.60s)
Phase static conversation; woman on right is standing and holding a cup
Bild wide shot, two figures positioned on opposite sides of a round dining table, modern glass-walled sunroom or conservatory overlooking a snowy landscape
Source
00:43:19:13–00:43:23:04
Scene 308 · Score 0.636
⚠ Score 0.636 unter 0.65 — visuell prüfen
python cli.py rematch --beat 13

Beat 14

?Vorläufig
▶ Trailer  /  ▶ Source (Frame-Locked Compare)
Trailer
00:00:53:21–00:00:57:02  (3.24s)
Phase static conversation, subject holding a white cup
Bild medium shot, subject positioned on the left, vertical window frame dividing the right third of the frame, interior room with a large window overlooking a snowy pine forest
Source
00:43:24:10–00:43:27:16
Scene 309 · Score 0.626
⚠ Score 0.626 unter 0.65 — visuell prüfen
python cli.py rematch --beat 14

Beat 15

?Vorläufig
▶ Trailer  /  ▶ Source (Frame-Locked Compare)
Trailer
00:00:57:02–00:01:01:12  (4.40s)
Phase static conversation
Bild medium shot, profile view of two characters facing each other, indoor room with a large window overlooking a snowy forest
Source
00:02:10:08  (multi-shot)
Scene Scenes 17, 309 · 2 Segmente
  • Seg 1: 00:02:10:08  dur 2.80s  @ off 0.24s  sc 17  score 0.720
  • Seg 2: 00:43:38:19  dur 1.28s  @ off 3.04s  sc 309  score 0.380
python cli.py rematch --beat 15

Beat 16

?Vorläufig
▶ Trailer  /  ▶ Source (Frame-Locked Compare)
Trailer
00:01:01:12–00:01:04:12  (3.00s)
Phase man reaches out and touches the red door with a small object
Bild medium side profile shot, subject on left, door on right, indoor dim environment, adjacent to a red wooden door
Source
01:05:12:12–01:05:15:07
Scene 451 · Score 0.626
⚠ Score 0.626 unter 0.65 — visuell prüfen
python cli.py rematch --beat 16

Beat 17

?Vorläufig
▶ Trailer  /  ▶ Source (Frame-Locked Compare)
Trailer
00:01:04:12–00:01:09:03  (4.64s)
Phase Static intimacy transitioning to a spatial arrangement of figures
Bild Medium shot, eye-level. First two frames: static shot of couple in bed. Third frame: wide shot of women among white blocks, Bedroom with bedside table and lamp; transition to a white minimalist interior with pedestals
Source
01:31:18:04  (multi-shot)
Scene Scenes 623, 72 · 3 Segmente
  • Seg 1: 01:31:18:04  dur 1.92s  @ off 0.24s  sc 623  score 0.384
  • Seg 2: 00:09:06:13  dur 1.04s  @ off 2.80s  sc 72  score 0.434
  • Seg 3: 00:09:07:18  dur 0.50s  @ off 4.00s  sc 72  score 0.384
⚠ Score 0.399 unter 0.65 — visuell prüfen
python cli.py rematch --beat 17

Beat 18

MAN.Kein Treffer
Trailer 18
— manuell setzen —
Trailer
00:01:09:03–00:01:10:19  (1.64s)
Phase Woman in foreground turns her head from profile to face the camera while speaking
Bild Medium shot, three-quarter profile of woman in foreground left, two women positioned behind her to the right, Indoors, minimalist dark background
— kein automatischer Treffer —
python cli.py rematch --beat 18

Beat 19

?Vorläufig
▶ Trailer  /  ▶ Source (Frame-Locked Compare)
Trailer
00:01:10:19–00:01:12:13  (1.76s)
Phase static conversation, subtle facial expression change
Bild medium close-up, over-the-shoulder shot with a blurred figure in the foreground right, outdoor dark forest or wooded area
Source
00:16:48:13–00:16:49:10
Scene 126 · Score 0.403
⚠ Score 0.403 unter 0.65 — visuell prüfen
python cli.py rematch --beat 19

Beat 20

?Vorläufig
▶ Trailer  /  ▶ Source (Frame-Locked Compare)
Trailer
00:01:12:13–00:01:15:14  (3.04s)
Phase man kisses woman's forehead, then they pull back slightly to face each other
Bild extreme close-up, profile view, faces facing each other, indoor, blurred background
Source
01:27:05:03–01:27:06:00
Scene 613 · Score 0.417
⚠ Score 0.417 unter 0.65 — visuell prüfen
python cli.py rematch --beat 20

Beat 21

?Vorläufig
▶ Trailer  /  ▶ Source (Frame-Locked Compare)
Trailer
00:01:15:14–00:01:17:13  (1.96s)
Phase hand raised to mouth, slight facial movement
Bild extreme close-up, face partially obscured by shadow, dark interior
Source
00:23:55:00–00:23:56:23
Scene 175 · Score 0.526
⚠ Score 0.526 unter 0.65 — visuell prüfen
python cli.py rematch --beat 21

Beat 22

?Vorläufig
▶ Trailer  /  ▶ Source (Frame-Locked Compare)
Trailer
00:01:17:13–00:01:19:23  (2.40s)
Phase man looks up and speaks, transitioning from downward gaze to forward gaze
Bild close-up, profile to three-quarter view, outdoor rocky environment, blurred background
Source
01:03:05:11–01:03:07:07
Scene 442 · Score 0.544
⚠ Score 0.544 unter 0.65 — visuell prüfen
python cli.py rematch --beat 22

Beat 23

?Vorläufig
▶ Trailer  /  ▶ Source (Frame-Locked Compare)
Trailer
00:01:19:23–00:01:25:14  (5.64s)
Phase static posture, head tilted upwards looking at the sky
Bild medium shot, subject positioned on the left third, facing away from camera towards the water, rocky shoreline next to a body of water under an overcast sky
Source
01:04:35:21–01:04:41:02
Scene 446 · Score 0.534
⚠ Score 0.534 unter 0.65 — visuell prüfen
python cli.py rematch --beat 23

Beat 24

MAN.Kein Treffer
Trailer 24
— manuell setzen —
Trailer
00:01:25:14–00:01:32:07  (6.72s)
— kein automatischer Treffer —
python cli.py rematch --beat 24
+

Cutter & Match Report

Generiert: 2026-05-09 05:09:38Trailer: BehindTheRedDoor_Trailer_REFERENCE.mp4 @ 25.000 fpsSource: BehindTheRedDoor_FTR_1080P_2398_Fixed.mp4 @ 23.976 fps
25 Beats — 23 automatisch (4 bestätigt)2 manuell.
Recent Changes:
Retune weak multi-shot segment phases instead of hiding them

Legende

OKBestätigt — direkt in Schnitt-Timeline übernehmen
?Vorläufig — Phase und Aktion im NLE visuell prüfen
MAN.Kein Treffer — manuell suchen oder Schwarzbild einfügen

Übersicht

BeatTrailer TC In–OutDauerSource TC InSceneScoreStatus
0000:00:00:00–00:00:03:003.00s00:00:03:1910.597?
0100:00:03:00–00:00:08:105.40s00:00:04:0910.380?
0200:00:08:10–00:00:16:248.56s00:00:35:0530.761OK
0300:00:16:24–00:00:19:032.16s01:02:19:034360.572?
0400:00:19:03–00:00:20:161.52s01:02:21:094370.728OK
0500:00:20:16–00:00:26:095.72s00:01:33:03100.499?
0600:00:26:09–00:00:29:062.88s00:01:03:0750.396?
0700:00:29:06–00:00:31:172.44s01:20:10:105530.497?
0800:00:31:17–00:00:33:161.96s00:00:51:0750.620?
0900:00:33:16–00:00:36:193.12s01:20:29:035570.674OK
1000:00:36:19–00:00:40:023.32s01:20:35:16558+559+5560.660?
1100:00:40:02–00:00:42:032.04s01:20:40:185590.636?
1200:00:42:03–00:00:50:068.12s01:14:26:06519+130.701OK
1300:00:50:06–00:00:53:213.60s00:43:19:133080.636?
1400:00:53:21–00:00:57:023.24s00:43:24:103090.626?
1500:00:57:02–00:01:01:124.40s00:02:10:0817+3090.621?
1600:01:01:12–00:01:04:123.00s01:05:12:124510.626?
1700:01:04:12–00:01:09:034.64s01:31:18:04623+720.399?
1800:01:09:03–00:01:10:191.64sMAN.
1900:01:10:19–00:01:12:131.76s00:16:48:131260.403?
2000:01:12:13–00:01:15:143.04s01:27:05:036130.417?
2100:01:15:14–00:01:17:131.96s00:23:55:001750.526?
2200:01:17:13–00:01:19:232.40s01:03:05:114420.544?
2300:01:19:23–00:01:25:145.64s01:04:35:214460.534?
2400:01:25:14–00:01:32:076.72sMAN.

Beat-Details

Beat 00

?Vorläufig
▶ Trailer  /  ▶ Source (Frame-Locked Compare)
Trailer
00:00:00:00–00:00:03:00  (3.00s)
Phase logo animation assembling from distorted shapes with motion blur
Bild centered, symmetrical, abstract black void
Source
00:00:03:19–00:00:05:09
Scene 1 · Score 0.597
⚠ Score 0.597 unter 0.65 — visuell prüfen
python cli.py rematch --beat 0

Beat 01

?Vorläufig
▶ Trailer  /  ▶ Source (Frame-Locked Compare)
Trailer
00:00:03:00–00:00:08:10  (5.40s)
Phase Dynamic motion blur and shifting optical distortions across the text
Bild Centered, symmetrical layout with overlapping circular glass-like distortions, Abstract black void
Source
00:00:04:09–00:00:06:03
Scene 1 · Score 0.380
⚠ Score 0.380 unter 0.65 — visuell prüfen
python cli.py rematch --beat 1

Beat 02

OKBestätigt
▶ Trailer  /  ▶ Source (Frame-Locked Compare)
Trailer
00:00:08:10–00:00:16:24  (8.56s)
Phase drawing a heart shape on a foggy surface
Bild extreme close-up, shifting from profile of a face to a hand interacting with a surface, indoor, obscured glass or foggy surface
Source
00:00:35:05–00:00:43:06
Scene 3 · Score 0.761
python cli.py rematch --beat 2

Beat 03

?Vorläufig
▶ Trailer  /  ▶ Source (Frame-Locked Compare)
Trailer
00:00:16:24–00:00:19:03  (2.16s)
Phase speaking and smiling slightly
Bild close-up shot, centered face, outdoor rocky environment
Source
01:02:19:03–01:02:20:20
Scene 436 · Score 0.572
⚠ Score 0.572 unter 0.65 — visuell prüfen
python cli.py rematch --beat 3

Beat 04

OKBestätigt
▶ Trailer  /  ▶ Source (Frame-Locked Compare)
Trailer
00:00:19:03–00:00:20:16  (1.52s)
Phase lifting a camera to eye level to take a photo
Bild medium shot, subject centered, shallow depth of field with blurred treeline background, outdoor forest landscape, overcast sky
Source
01:02:21:09–01:02:22:08
Scene 437 · Score 0.728
python cli.py rematch --beat 4

Beat 05

?Vorläufig
▶ Trailer  /  ▶ Source (Frame-Locked Compare)
Trailer
00:00:20:16–00:00:26:09  (5.72s)
Phase a metallic cylindrical object is brought toward and touches the skin of the forearm
Bild extreme close-up, shallow depth of field, indistinct dark interior
Source
00:01:33:03–00:01:37:09
Scene 10 · Score 0.499
⚠ Score 0.499 unter 0.65 — visuell prüfen
python cli.py rematch --beat 5

Beat 06

?Vorläufig
▶ Trailer  /  ▶ Source (Frame-Locked Compare)
Trailer
00:00:26:09–00:00:29:06  (2.88s)
Phase hand reaching toward and touching an ornate decorative box
Bild close-up, shallow depth of field, hand entering from left frame, dark interior
Source
00:01:03:07–00:01:05:03
Scene 5 · Score 0.396
⚠ Score 0.396 unter 0.65 — visuell prüfen
python cli.py rematch --beat 6

Beat 07

?Vorläufig
▶ Trailer  /  ▶ Source (Frame-Locked Compare)
Trailer
00:00:29:06–00:00:31:17  (2.44s)
Phase man appears to be engaged in conversation
Bild man in a light gray sweater and scarf, seated on a white couch, with a window in the background, indoor with a view of the ocean
Source
01:20:10:10–01:20:12:14
Scene 553 · Score 0.497
⚠ Score 0.497 unter 0.65 — visuell prüfen
python cli.py rematch --beat 7

Beat 08

?Vorläufig
▶ Trailer  /  ▶ Source (Frame-Locked Compare)
Trailer
00:00:31:17–00:00:33:16  (1.96s)
Phase static or slow drifting
Bild close-up, diagonal curve from top-left to bottom-center, dark, indistinct void
Source
00:00:51:07–00:00:53:01
Scene 5 · Score 0.620
⚠ Score 0.620 unter 0.65 — visuell prüfen
python cli.py rematch --beat 8

Beat 09

OKBestätigt
▶ Trailer  /  ▶ Source (Frame-Locked Compare)
Trailer
00:00:33:16–00:00:36:19  (3.12s)
Phase speaking, transitioning from closed eyes to open mouth and focused gaze
Bild medium close-up, subject positioned right of center, profile/three-quarter view, indoor room next to a large window overlooking a blue horizon/sea
Source
01:20:29:03–01:20:32:06
Scene 557 · Score 0.674
python cli.py rematch --beat 9

Beat 10

?Vorläufig
▶ Trailer  /  ▶ Source (Frame-Locked Compare)
Trailer
00:00:36:19–00:00:40:02  (3.32s)
Phase conversation
Bild alternating close-ups and a medium two-shot, indoor living room with large windows showing a blue exterior landscape
Source
01:20:35:16  (multi-shot)
Scene Scenes 558, 559, 556 · 3 Segmente
  • Seg 1: 01:20:35:16  dur 0.88s  @ off 0.00s  sc 558  score 0.674
  • Seg 2: 01:20:36:14  dur 1.76s  @ off 0.88s  sc 559  score 0.649
  • Seg 3: 01:20:22:14  dur 0.68s  @ off 2.64s  sc 556  score 0.672
python cli.py rematch --beat 10

Beat 11

?Vorläufig
▶ Trailer  /  ▶ Source (Frame-Locked Compare)
Trailer
00:00:40:02–00:00:42:03  (2.04s)
Phase static talking head with slight facial expression changes
Bild medium close-up, subject positioned right of center, profile/three-quarter view facing left, indoor room with a large window showing a blue sea/horizon background
Source
01:20:40:18–01:20:42:18
Scene 559 · Score 0.636
⚠ Score 0.636 unter 0.65 — visuell prüfen
python cli.py rematch --beat 11

Beat 12

OKBestätigt
▶ Trailer  /  ▶ Source (Frame-Locked Compare)
Trailer
00:00:42:03–00:00:50:06  (8.12s)
Phase static profile shot transitioning to black/darkness
Bild medium close-up, profile view, subject positioned on the right side of the frame, dark outdoor environment, blurred trees in background
Source
01:14:26:06  (multi-shot)
Scene Scenes 519, 13 · 2 Segmente
  • Seg 1: 01:14:26:06  dur 3.52s  @ off 0.16s  sc 519  score 0.721
  • Seg 2: 00:01:47:14  dur 2.88s  @ off 4.88s  sc 13  score 0.676
python cli.py rematch --beat 12

Beat 13

?Vorläufig
▶ Trailer  /  ▶ Source (Frame-Locked Compare)
Trailer
00:00:50:06–00:00:53:21  (3.60s)
Phase static conversation; woman on right is standing and holding a cup
Bild wide shot, two figures positioned on opposite sides of a round dining table, modern glass-walled sunroom or conservatory overlooking a snowy landscape
Source
00:43:19:13–00:43:23:04
Scene 308 · Score 0.636
⚠ Score 0.636 unter 0.65 — visuell prüfen
python cli.py rematch --beat 13

Beat 14

?Vorläufig
▶ Trailer  /  ▶ Source (Frame-Locked Compare)
Trailer
00:00:53:21–00:00:57:02  (3.24s)
Phase static conversation, subject holding a white cup
Bild medium shot, subject positioned on the left, vertical window frame dividing the right third of the frame, interior room with a large window overlooking a snowy pine forest
Source
00:43:24:10–00:43:27:16
Scene 309 · Score 0.626
⚠ Score 0.626 unter 0.65 — visuell prüfen
python cli.py rematch --beat 14

Beat 15

?Vorläufig
▶ Trailer  /  ▶ Source (Frame-Locked Compare)
Trailer
00:00:57:02–00:01:01:12  (4.40s)
Phase static conversation
Bild medium shot, profile view of two characters facing each other, indoor room with a large window overlooking a snowy forest
Source
00:02:10:08  (multi-shot)
Scene Scenes 17, 309 · 2 Segmente
  • Seg 1: 00:02:10:08  dur 2.80s  @ off 0.24s  sc 17  score 0.720
  • Seg 2: 00:45:27:10  dur 1.28s  @ off 3.04s  sc 309  score 0.380
python cli.py rematch --beat 15

Beat 16

?Vorläufig
▶ Trailer  /  ▶ Source (Frame-Locked Compare)
Trailer
00:01:01:12–00:01:04:12  (3.00s)
Phase man reaches out and touches the red door with a small object
Bild medium side profile shot, subject on left, door on right, indoor dim environment, adjacent to a red wooden door
Source
01:05:12:12–01:05:15:07
Scene 451 · Score 0.626
⚠ Score 0.626 unter 0.65 — visuell prüfen
python cli.py rematch --beat 16

Beat 17

?Vorläufig
▶ Trailer  /  ▶ Source (Frame-Locked Compare)
Trailer
00:01:04:12–00:01:09:03  (4.64s)
Phase Static intimacy transitioning to a spatial arrangement of figures
Bild Medium shot, eye-level. First two frames: static shot of couple in bed. Third frame: wide shot of women among white blocks, Bedroom with bedside table and lamp; transition to a white minimalist interior with pedestals
Source
01:31:18:04  (multi-shot)
Scene Scenes 623, 72 · 3 Segmente
  • Seg 1: 01:31:18:04  dur 1.92s  @ off 0.24s  sc 623  score 0.384
  • Seg 2: 00:09:06:13  dur 1.04s  @ off 2.80s  sc 72  score 0.434
  • Seg 3: 00:09:07:18  dur 0.50s  @ off 4.00s  sc 72  score 0.384
⚠ Score 0.399 unter 0.65 — visuell prüfen
python cli.py rematch --beat 17

Beat 18

MAN.Kein Treffer
Trailer 18
— manuell setzen —
Trailer
00:01:09:03–00:01:10:19  (1.64s)
Phase Woman in foreground turns her head from profile to face the camera while speaking
Bild Medium shot, three-quarter profile of woman in foreground left, two women positioned behind her to the right, Indoors, minimalist dark background
— kein automatischer Treffer —
python cli.py rematch --beat 18

Beat 19

?Vorläufig
▶ Trailer  /  ▶ Source (Frame-Locked Compare)
Trailer
00:01:10:19–00:01:12:13  (1.76s)
Phase static conversation, subtle facial expression change
Bild medium close-up, over-the-shoulder shot with a blurred figure in the foreground right, outdoor dark forest or wooded area
Source
00:16:48:13–00:16:49:10
Scene 126 · Score 0.403
⚠ Score 0.403 unter 0.65 — visuell prüfen
python cli.py rematch --beat 19

Beat 20

?Vorläufig
▶ Trailer  /  ▶ Source (Frame-Locked Compare)
Trailer
00:01:12:13–00:01:15:14  (3.04s)
Phase man kisses woman's forehead, then they pull back slightly to face each other
Bild extreme close-up, profile view, faces facing each other, indoor, blurred background
Source
01:27:05:03–01:27:06:00
Scene 613 · Score 0.417
⚠ Score 0.417 unter 0.65 — visuell prüfen
python cli.py rematch --beat 20

Beat 21

?Vorläufig
▶ Trailer  /  ▶ Source (Frame-Locked Compare)
Trailer
00:01:15:14–00:01:17:13  (1.96s)
Phase hand raised to mouth, slight facial movement
Bild extreme close-up, face partially obscured by shadow, dark interior
Source
00:23:55:00–00:23:56:23
Scene 175 · Score 0.526
⚠ Score 0.526 unter 0.65 — visuell prüfen
python cli.py rematch --beat 21

Beat 22

?Vorläufig
▶ Trailer  /  ▶ Source (Frame-Locked Compare)
Trailer
00:01:17:13–00:01:19:23  (2.40s)
Phase man looks up and speaks, transitioning from downward gaze to forward gaze
Bild close-up, profile to three-quarter view, outdoor rocky environment, blurred background
Source
01:03:05:11–01:03:07:07
Scene 442 · Score 0.544
⚠ Score 0.544 unter 0.65 — visuell prüfen
python cli.py rematch --beat 22

Beat 23

?Vorläufig
▶ Trailer  /  ▶ Source (Frame-Locked Compare)
Trailer
00:01:19:23–00:01:25:14  (5.64s)
Phase static posture, head tilted upwards looking at the sky
Bild medium shot, subject positioned on the left third, facing away from camera towards the water, rocky shoreline next to a body of water under an overcast sky
Source
01:04:35:21–01:04:41:02
Scene 446 · Score 0.534
⚠ Score 0.534 unter 0.65 — visuell prüfen
python cli.py rematch --beat 23

Beat 24

MAN.Kein Treffer
Trailer 24
— manuell setzen —
Trailer
00:01:25:14–00:01:32:07  (6.72s)
— kein automatischer Treffer —
python cli.py rematch --beat 24
diff --git a/CUTTER_REPORT.md b/CUTTER_REPORT.md index 9d746f6..902e111 100644 --- a/CUTTER_REPORT.md +++ b/CUTTER_REPORT.md @@ -277,9 +277,9 @@ Trailer-TC in Trailer-Framerate, Source-TC in Source-Framerate. ### Beat 15 — ? / Vorläufig - **Trailer**: 00:00:57:02 – 00:01:01:12 (4.40 s) -- **Source** : 00:02:10:08 – 00:02:13:03 (scenes 17, 309 (2 Segmente), score 0.650) +- **Source** : 00:02:10:08 – 00:02:13:03 (scenes 17, 309 (2 Segmente), score 0.621) - Seg 1: TC 00:02:10:08 dur 2.80s @ Trailer-Offset 0.24s (scene 17) - - Seg 2: TC 00:43:38:19 dur 1.28s @ Trailer-Offset 3.04s (scene 309) + - Seg 2: TC 00:45:27:10 dur 1.28s @ Trailer-Offset 3.04s (scene 309, retuned phase) - **Rematch**: `python cli.py rematch --beat 15` - **Phase**: static conversation - **Bild**: medium shot, profile view of two characters facing each other, indoor room with a large window overlooking a snowy forest diff --git a/cli.py b/cli.py index 3f3bdd4..0e2459d 100644 --- a/cli.py +++ b/cli.py @@ -270,9 +270,38 @@ def _normalize_cached_results(beats: list, results: list, cfg) -> list: for result in results: beat = beats_by_id.get(result.beat_id) if getattr(result, "segments", ()): - segment_duration = sum(max(0.0, float(s.duration_s)) for s in result.segments) + segment_threshold = cfg.cv.deep_scan.multi_shot_segment_threshold + repaired_segments = [] + for segment in result.segments: + if float(segment.match_score) < segment_threshold: + scene = _scene_by_id_light(scenes, segment.scene_id) + if beat is not None and scene is not None: + segment_beat = replace( + beat, + start_s=beat.start_s + float(segment.trailer_offset_s), + end_s=beat.start_s + float(segment.trailer_offset_s) + float(segment.duration_s), + ) + probe = _phase_probe_segment_in_scene( + segment_beat, + scene, + float(segment.in_point_s), + cfg, + ) + if probe is not None: + in_point_s, _phase_score = probe + segment = replace( + segment, + in_point_s=in_point_s, + out_point_s=in_point_s + float(segment.duration_s), + ) + repaired_segments.append(segment) + + valid_segments = tuple(repaired_segments) + if not valid_segments: + continue + segment_duration = sum(max(0.0, float(s.duration_s)) for s in valid_segments) weighted_score = ( - sum(max(0.0, float(s.duration_s)) * float(s.match_score) for s in result.segments) + sum(max(0.0, float(s.duration_s)) * float(s.match_score) for s in valid_segments) / segment_duration if segment_duration > 0 else result.match_score ) @@ -287,7 +316,15 @@ def _normalize_cached_results(beats: list, results: list, cfg) -> list: coverage = segment_duration / coverage_target if coverage < cfg.cv.deep_scan.min_duration_coverage: continue - normalized.append(replace(result, match_score=weighted_score)) + first_segment = valid_segments[0] + normalized.append(replace( + result, + scene_id=first_segment.scene_id, + in_point_s=first_segment.in_point_s, + out_point_s=first_segment.out_point_s, + match_score=weighted_score, + segments=valid_segments, + )) continue if result.match_score < cfg.cv.deep_scan.provisional_match_threshold: @@ -1363,6 +1400,39 @@ def _attach_visual_segments(results: list, beats: list, cfg) -> list: if not segment_matches: continue seg = segment_matches[0] + if seg.match_score < cfg.cv.deep_scan.multi_shot_segment_threshold: + repaired = _local_same_scene_segment_match( + segment_beat, + beat, + start_s, + cached + expanded, + cfg, + ) + if ( + repaired is None + or repaired.match_score + < max( + cfg.cv.deep_scan.multi_shot_segment_threshold, + seg.match_score + cfg.cv.deep_scan.duration_tie_break_score_delta, + ) + ): + scenes = _load_scene_cache_light(cfg) + scene = _scene_by_id_light(scenes, seg.scene_id) + probe = ( + _phase_probe_segment_in_scene(segment_beat, scene, seg.in_point_s, cfg) + if scene is not None else None + ) + if probe is None: + continue + in_point_s, _phase_score = probe + from dataclasses import replace as _replace + seg = _replace( + seg, + in_point_s=in_point_s, + out_point_s=in_point_s + seg.duration_s, + ) + else: + seg = repaired seg_dur = min(max(0.0, end_s - start_s), max(0.0, seg.duration_s)) segments.append( MatchSegment( @@ -1484,7 +1554,10 @@ def _match_unmatched_visual_segments( if recovered: rec = recovered[0] seg_dur = min(max(0.0, end_s - start_s), max(0.0, rec.duration_s)) - if seg_dur > 0: + if ( + seg_dur > 0 + and rec.match_score >= cfg.cv.deep_scan.multi_shot_segment_threshold + ): segments.append(MatchSegment( trailer_offset_s=start_s, duration_s=seg_dur, @@ -1506,6 +1579,8 @@ def _match_unmatched_visual_segments( segments.append(local_segment) continue seg = segment_matches[0] + if seg.match_score < cfg.cv.deep_scan.multi_shot_segment_threshold: + continue seg_dur = min(max(0.0, end_s - start_s), max(0.0, seg.duration_s)) segments.append( MatchSegment( @@ -1577,7 +1652,13 @@ def _local_same_scene_segment_match(segment_beat, beat, segment_offset_s: float, cfg.cv.deep_scan.provisional_content_threshold * 0.70, cfg.cv.deep_scan.provisional_match_threshold, ) - step_s = max(1.0 / cfg.export.edl_frame_rate, 0.04) + # Coarse repair scan over already plausible neighbouring scenes. A frame-step + # sweep across long dialogue scenes is slow and can overfit static layouts. + step_s = max( + cfg.vision.local_scan_step_s, + cfg.cv.deep_scan.content_align_sample_step_s, + 0.25, + ) best: tuple[float, float, int] | None = None with open_video(cfg.paths.source_movie) as cap: for scene_id in scene_ids: @@ -1586,12 +1667,14 @@ def _local_same_scene_segment_match(segment_beat, beat, segment_offset_s: float, continue start_s = max(0.0, float(scene["start_s"]) - 0.25) end_s = max(start_s, float(scene["end_s"]) - max(0.04, segment_beat.duration_s) + 0.25) + max_points = max(4, min(48, int(cfg.vision.local_scan_max_points_per_scene))) + scene_step_s = max(step_s, (end_s - start_s) / max_points) t = start_s while t <= end_s: score = _content_alignment_score(cap, t, templates, cfg) if best is None or score > best[0]: best = (score, t, int(scene_id)) - t = round(t + step_s, 6) + t = round(t + scene_step_s, 6) if best is None or best[0] < min_score: return None @@ -1609,6 +1692,73 @@ def _local_same_scene_segment_match(segment_beat, beat, segment_offset_s: float, ) +def _phase_probe_segment_in_scene(segment_beat, scene: dict, original_in_s: float, cfg): + """Retune a weak multi-shot segment inside its own scene using cheap frame features.""" + import cv2 + import numpy as np + + offsets = [0.0, 0.28, 0.56, 0.84, 1.12] + size = (160, 90) + + def feature(frame): + if frame is None: + return None + h, w = frame.shape[:2] + frame = frame.copy() + frame[: int(h * 0.16), : int(w * 0.28)] = 0 + gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) + gray = cv2.resize(gray, size) + edges = cv2.Canny(gray, 40, 120) + vec = np.concatenate([ + gray.reshape(-1).astype("float32") / 255.0, + edges.reshape(-1).astype("float32") / 255.0, + ]) + return (vec - vec.mean()) / (vec.std() + 1e-6) + + def frame_at(cap, t_s): + cap.set(cv2.CAP_PROP_POS_MSEC, t_s * 1000.0) + ok, frame = cap.read() + return frame if ok else None + + trailer_cap = cv2.VideoCapture(str(cfg.paths.reference_trailer)) + refs = [ + feature(frame_at(trailer_cap, segment_beat.start_s + offset)) + for offset in offsets + if offset <= segment_beat.duration_s + 0.04 + ] + refs = [ref for ref in refs if ref is not None] + if len(refs) < 3: + return None + + scene_start = float(scene["start_s"]) + scene_end = float(scene["end_s"]) + scan_end = max(scene_start, scene_end - max(0.04, segment_beat.duration_s)) + max_points = 96 + step_s = max(0.08, (scan_end - scene_start) / max_points) + + source_cap = cv2.VideoCapture(str(cfg.paths.source_movie)) + candidates: list[tuple[float, float, float]] = [] + t = scene_start + while t <= scan_end: + vals = [] + for offset, ref in zip(offsets, refs): + src = feature(frame_at(source_cap, t + offset)) + if src is not None: + vals.append(float(np.dot(ref, src) / len(ref))) + if len(vals) >= 3: + candidates.append((sum(vals) / len(vals), min(vals), t)) + t = round(t + step_s, 6) + + if not candidates: + return None + + candidates.sort(reverse=True) + best_score = candidates[0][0] + near_tie = [c for c in candidates if c[0] >= best_score - 0.01] + chosen = min(near_tie, key=lambda c: abs(c[2] - original_in_s)) + return chosen[2], chosen[0] + + def cmd_match(args: argparse.Namespace, cfg) -> list: from src.pipeline.matcher import run_matching from dataclasses import replace diff --git a/config.toml b/config.toml index cbc1689..38503a5 100644 --- a/config.toml +++ b/config.toml @@ -87,6 +87,9 @@ coarse_score_weight = 0.10 duration_score_weight = 0.20 duration_tie_break_score_delta = 0.03 min_duration_coverage = 0.55 +# Every visible sub-shot in a multi-shot beat must pass this stricter gate. +# A weak segment is left unmatched instead of being hidden by a strong neighbor. +multi_shot_segment_threshold = 0.50 continuity_seed_offsets_s = [-1.0, 0.0, 0.5, 1.0, 1.5, 2.0, 3.0] scene_seed_top_k = 30 scene_seed_points_per_scene = 6 diff --git a/docs/ALGORITHM.md b/docs/ALGORITHM.md index 7e27b98..17be4e3 100644 --- a/docs/ALGORITHM.md +++ b/docs/ALGORITHM.md @@ -131,13 +131,25 @@ bereits auf die sichtbare Aktionsphase ausgerichtet. Der Segment-Offset zählt nur über vorherige scorebare Bildinseln, nicht über schwarze oder blendige Lücken. Nach dem Retiming wird die nutzbare Source- -Dauer erneut geschätzt; läuft die Source am Ende in eine sichtbar andere`r`nAktionsphase, wird der Treffer im Cutter-Report klar als phasenkritisch markiert.`r`nSchwarz/Placeholder wird nur für wirklich ungematchte Trailer-Bereiche oder Fades`r`nverwendet, nicht um sichtbare Kandidatenbewegung im Review zu verstecken. +Dauer erneut geschätzt; läuft die Source am Ende in eine sichtbar andere +Aktionsphase, wird der Treffer im Cutter-Report klar als phasenkritisch +markiert. Schwarz/Placeholder wird nur für wirklich ungematchte Trailer- +Bereiche oder Fades verwendet, nicht um sichtbare Kandidatenbewegung im Review +zu verstecken. Diese Span-Schätzung ist strenger als der grobe Suchscore: Ein fast stehender Anfang darf einen Match nicht retten, wenn spätere Frames sichtbar in eine andere Gestik, Körperposition oder eintretende Figur driften. Stabile Score-Plateaus dürfen nur verlängern, wenn sie noch nah genug am Anfangsniveau -liegen; sonst bleibt der Treffer vorläufig und muss neu gesucht oder visuell`r`ngeprüft werden. Der Review-Clip zeigt den Kandidaten weiterhin sichtbar, damit`r`nPhasenfehler nicht durch Schwarz verdeckt werden. +liegen; sonst bleibt der Treffer vorläufig und muss neu gesucht oder visuell +geprüft werden. Der Review-Clip zeigt den Kandidaten weiterhin sichtbar, damit +Phasenfehler nicht durch Schwarz verdeckt werden. + +Für Multi-Shot-Beats gilt zusätzlich eine Segment-Schwelle pro sichtbarer +Einstellung. Ein gutes erstes Segment darf kein zweites Segment mit schwachem +Score mitziehen. Segmente unter `multi_shot_segment_threshold` werden nicht als +Source-Material ausgegeben; der entsprechende Beat-Bereich bleibt im +Cutter-Report offen, bis ein eigenständig belastbarer Treffer gefunden wird. ## Vision-Seeds vs. Vollscan diff --git a/output/cutter_clips/beat_15_compare.mp4 b/output/cutter_clips/beat_15_compare.mp4 index 574ff42..9a59905 100644 Binary files a/output/cutter_clips/beat_15_compare.mp4 and b/output/cutter_clips/beat_15_compare.mp4 differ diff --git a/output/cutter_clips/beat_15_source.mp4 b/output/cutter_clips/beat_15_source.mp4 index e7fc6c4..0a86755 100644 Binary files a/output/cutter_clips/beat_15_source.mp4 and b/output/cutter_clips/beat_15_source.mp4 differ diff --git a/src/core/config.py b/src/core/config.py index 6965b8f..1755601 100644 --- a/src/core/config.py +++ b/src/core/config.py @@ -64,6 +64,7 @@ class DeepScanConfig: duration_score_weight: float duration_tie_break_score_delta: float min_duration_coverage: float + multi_shot_segment_threshold: float continuity_seed_offsets_s: tuple[float, ...] scene_seed_top_k: int scene_seed_points_per_scene: int @@ -267,6 +268,7 @@ def load_config( duration_score_weight=float(cv_raw["deep_scan"].get("duration_score_weight", 0.20)), duration_tie_break_score_delta=float(cv_raw["deep_scan"].get("duration_tie_break_score_delta", 0.03)), min_duration_coverage=float(cv_raw["deep_scan"].get("min_duration_coverage", 0.65)), + multi_shot_segment_threshold=float(cv_raw["deep_scan"].get("multi_shot_segment_threshold", 0.50)), continuity_seed_offsets_s=tuple( float(v) for v in cv_raw["deep_scan"].get( "continuity_seed_offsets_s",