srobo / competition-simulator

A simulator for Student Robotics Virtual Competitions
https://studentrobotics.org/docs/simulator/
MIT License
8 stars 2 forks source link

Marker colours are hard to see in the last frame of the video #386

Closed Adimote closed 1 year ago

Adimote commented 1 year ago

image

In addition to them being hard to see (#385) tokens are especially hard to see in the last frame of the video, due to the red lighting

Adimote commented 1 year ago

Proposed solution for this: use ffmpeg magic to duplicate the last frame for 1-2 seconds, then fade into the end-game screenshot.

Adimote commented 1 year ago

@PeterJCLaw and I worked on an ffmpeg command to extend the last frame by N seconds, then fade to the end-game screenshot;

In this case we start fading the video for 1 second at the 7 second mark. In the actual script, we'd want to do it after 150 seconds, plus 1 or 2 seconds for the red light to show.

ffmpeg -i "recordings/match-0.mp4" -loop 1 -t 1 -i "recordings/match-0.jpg" -filter_complex "[1]fade=d=1:t=in:alpha=1,setpts=PTS-STARTPTS+7/TB[faded];[0][faded]overlay" out.mp4

PeterJCLaw commented 1 year ago

Sooo, you're not going to like it, but here's a way to capture the frame that we actually want -- the one right before the lights go red:

diff --git a/controllers/competition_supervisor/competition_supervisor.py b/controllers/competition_supervisor/competition_supervisor.py
index a4022f7..28799c2 100644
--- a/controllers/competition_supervisor/competition_supervisor.py
+++ b/controllers/competition_supervisor/competition_supervisor.py
@@ -222,7 +222,20 @@ def run_match(supervisor: Supervisor) -> None:
     time_step = int(supervisor.getBasicTimeStep())
     duration = controller_utils.get_match_duration_seconds()
     duration_ms = time_step * int(1000 * duration // time_step)
-    supervisor.step(duration_ms)
+
+    START_AT = 15
+    SAVE = 11
+    STOP_BEFORE = 6
+    supervisor.step(duration_ms - time_step * START_AT)
+
+    for i in range(-START_AT, -STOP_BEFORE):
+        if i == -SAVE:
+            supervisor.exportImage(f'/tmp/bees-{i}.jpg', 100)
+        else:
+            supervisor.exportImage('/tmp/throwaway.jpg', 100)
+        supervisor.step(time_step)
+
+    supervisor.step(time_step * STOP_BEFORE)

     print("==================")
     print("Game over, pausing")

I tried a bunch of things to end up at this -- initially capturing frames for each of the last 50 timesteps then whittling it down. Unfortunately if we try to capture just the frame of interest then we don't actually get the scene we want -- instead we end up with the red-lit scene. It seems that we need some scenes either side of the one we care about to force it to capture the right one.

I've tested this on very short matches (5 & 7 seconds) as well as the a full match for this year. Happily the offset numbers above seem consistent regardless of the length of the video.

Likely the code can be improved, but I suggest that we do go with something like this (and then maybe drop the other image capture and lighting changes).

PeterJCLaw commented 1 year ago

Fixed by https://github.com/srobo/competition-simulator/pull/392.

PeterJCLaw commented 1 year ago

Script to help extract the final image from the video & brighten it: https://gist.github.com/PeterJCLaw/69b81b16efb0f5d6a7d2b79a9a7972e6