Adding Random Seed for Frame Processing (#3416)

* Adding Random Seed for Frame Processing

* Added Unit Tests

* Updating Unit Tests for Ffmpeg

* Make Logs More Detailed

---------

Co-authored-by: Anthony-Tafoya <anthonytafoya@berkeley.edu>
Co-authored-by: J.Y. <132313008+jb-ye@users.noreply.github.com>
This commit is contained in:
authored and GitHub committed 2024-09-17 15:32:09 +00:00
1 parent 27b8e14798
commit 3e638da635
3 files changed
+133 -6

No files matched your search

+113 -1
View File
@@ -2,13 +2,21 @@
Test misc data utils
"""
import os
import re
from pathlib import Path
from unittest import mock
import cv2
import numpy as np
from PIL import Image
from pyquaternion import Quaternion
from scipy.spatial.transform import Rotation
# TODO(1480) use pycolmap instead of colmap_parsing_utils
# import pycolmap
from nerfstudio.data.utils.colmap_parsing_utils import qvec2rotmat
from nerfstudio.process_data.process_data_utils import convert_video_to_images
def test_scalar_first_scalar_last_quaternions():
@@ -39,7 +47,7 @@ def test_scalar_first_scalar_last_quaternions():
# Expected Rotation matrix
# fmt: off
R_expected = np.array(
R_expected = np.array(
[
[ 0.81379768, -0.44096961, 0.37852231],
[ 0.46984631, 0.88256412, 0.01802831],
@@ -61,3 +69,107 @@ def test_scalar_first_scalar_last_quaternions():
# R = pycolmap.qvec_to_rotmat(wxyz)
R = qvec2rotmat(wxyz)
assert np.allclose(R, R_expected)
def test_process_video_conversion_with_seed(tmp_path: Path):
"""
Test convert_video_to_images by creating a mock video and ensuring correct frame extraction with seed.
"""
# Inner functions needed for the unit tests
def create_mock_video(video_path: Path, frame_dir: Path, num_frames=10, frame_rate=1):
"""Creates a mock video from a series of frames using OpenCV."""
first_frame = cv2.imread(str(frame_dir / "frame_0.png"))
height, width, _ = first_frame.shape
fourcc = cv2.VideoWriter_fourcc(*"mp4v")
out = cv2.VideoWriter(str(video_path), fourcc, frame_rate, (width, height))
for i in range(num_frames):
frame_path = frame_dir / f"frame_{i}.png"
frame = cv2.imread(str(frame_path))
out.write(frame)
out.release()
def extract_frame_numbers(ffmpeg_command: str):
"""Extracts the frame numbers from the ffmpeg command"""
pattern = r"eq\(n\\,(\d+)\)"
matches = re.findall(pattern, ffmpeg_command)
frame_numbers = [int(match) for match in matches]
return frame_numbers
# Create a video directory with path video
video_dir = tmp_path / "video"
video_dir.mkdir(exist_ok=True)
# Set parameters for mock video
video_path = video_dir / "mock_video.mp4"
num_frames = 10
frame_height = 150
frame_width = 100
frame_rate = 1
# Create the mock video
for i in range(num_frames):
img = Image.new("RGB", (frame_width, frame_height), (0, 0, 0))
img.save(video_dir / f"frame_{i}.png")
create_mock_video(video_path, video_dir, num_frames=num_frames, frame_rate=frame_rate)
# Call convert_video_to_images
image_output_dir = tmp_path / "extracted_images"
num_frames_target = 5
num_downscales = 1
crop_factor = (0.0, 0.0, 0.0, 0.0)
# Mock missing COLMAP and ffmpeg in the dev env
old_path = os.environ.get("PATH", "")
os.environ["PATH"] = str(tmp_path / "mocked_bin") + f":{old_path}"
(tmp_path / "mocked_bin").mkdir()
(tmp_path / "mocked_bin" / "colmap").touch(mode=0o777)
(tmp_path / "mocked_bin" / "ffmpeg").touch(mode=0o777)
# Return value of 10 for the get_num_frames_in_video run_command call
with mock.patch("nerfstudio.process_data.process_data_utils.run_command", return_value="10") as mock_run_func:
summary_log, extracted_frame_count = convert_video_to_images(
video_path=video_path,
image_dir=image_output_dir,
num_frames_target=num_frames_target,
num_downscales=num_downscales,
crop_factor=crop_factor,
verbose=False,
random_seed=42,
)
assert mock_run_func.call_count == 2, f"Expected 2 calls, but got {mock_run_func.call_count}"
first_frames = extract_frame_numbers(mock_run_func.call_args[0][0])
assert len(first_frames) == 5, f"Expected 5 frames, but got {len(first_frames)}"
summary_log, extracted_frame_count = convert_video_to_images(
video_path=video_path,
image_dir=image_output_dir,
num_frames_target=num_frames_target,
num_downscales=num_downscales,
crop_factor=crop_factor,
verbose=False,
random_seed=42,
)
assert mock_run_func.call_count == 4, f"Expected 4 total calls, but got {mock_run_func.call_count}"
second_frames = extract_frame_numbers(mock_run_func.call_args[0][0])
assert len(second_frames) == 5, f"Expected 5 frames, but got {len(first_frames)}"
assert first_frames == second_frames
summary_log, extracted_frame_count = convert_video_to_images(
video_path=video_path,
image_dir=image_output_dir,
num_frames_target=num_frames_target,
num_downscales=num_downscales,
crop_factor=crop_factor,
verbose=False,
random_seed=52,
)
assert mock_run_func.call_count == 6, f"Expected 6 total calls, but got {mock_run_func.call_count}"
third_frames = extract_frame_numbers(mock_run_func.call_args[0][0])
assert len(third_frames) == 5, f"Expected 5 frames, but got {len(first_frames)}"
assert first_frames != third_frames