2
2
Test misc data utils
3
3
"""
4
4
5
+ import os
6
+ import re
7
+ from pathlib import Path
8
+ from unittest import mock
9
+
10
+ import cv2
5
11
import numpy as np
12
+ from PIL import Image
6
13
from pyquaternion import Quaternion
7
14
from scipy .spatial .transform import Rotation
8
15
9
16
# TODO(1480) use pycolmap instead of colmap_parsing_utils
10
17
# import pycolmap
11
18
from nerfstudio .data .utils .colmap_parsing_utils import qvec2rotmat
19
+ from nerfstudio .process_data .process_data_utils import convert_video_to_images
12
20
13
21
14
22
def test_scalar_first_scalar_last_quaternions ():
@@ -39,7 +47,7 @@ def test_scalar_first_scalar_last_quaternions():
39
47
40
48
# Expected Rotation matrix
41
49
# fmt: off
42
- R_expected = np .array (
50
+ R_expected = np .array (
43
51
[
44
52
[ 0.81379768 , - 0.44096961 , 0.37852231 ],
45
53
[ 0.46984631 , 0.88256412 , 0.01802831 ],
@@ -61,3 +69,107 @@ def test_scalar_first_scalar_last_quaternions():
61
69
# R = pycolmap.qvec_to_rotmat(wxyz)
62
70
R = qvec2rotmat (wxyz )
63
71
assert np .allclose (R , R_expected )
72
+
73
+
74
+ def test_process_video_conversion_with_seed (tmp_path : Path ):
75
+ """
76
+ Test convert_video_to_images by creating a mock video and ensuring correct frame extraction with seed.
77
+ """
78
+
79
+ # Inner functions needed for the unit tests
80
+ def create_mock_video (video_path : Path , frame_dir : Path , num_frames = 10 , frame_rate = 1 ):
81
+ """Creates a mock video from a series of frames using OpenCV."""
82
+
83
+ first_frame = cv2 .imread (str (frame_dir / "frame_0.png" ))
84
+ height , width , _ = first_frame .shape
85
+ fourcc = cv2 .VideoWriter_fourcc (* "mp4v" )
86
+ out = cv2 .VideoWriter (str (video_path ), fourcc , frame_rate , (width , height ))
87
+
88
+ for i in range (num_frames ):
89
+ frame_path = frame_dir / f"frame_{ i } .png"
90
+ frame = cv2 .imread (str (frame_path ))
91
+ out .write (frame )
92
+ out .release ()
93
+
94
+ def extract_frame_numbers (ffmpeg_command : str ):
95
+ """Extracts the frame numbers from the ffmpeg command"""
96
+
97
+ pattern = r"eq\(n\\,(\d+)\)"
98
+ matches = re .findall (pattern , ffmpeg_command )
99
+ frame_numbers = [int (match ) for match in matches ]
100
+ return frame_numbers
101
+
102
+ # Create a video directory with path video
103
+ video_dir = tmp_path / "video"
104
+ video_dir .mkdir (exist_ok = True )
105
+
106
+ # Set parameters for mock video
107
+ video_path = video_dir / "mock_video.mp4"
108
+ num_frames = 10
109
+ frame_height = 150
110
+ frame_width = 100
111
+ frame_rate = 1
112
+
113
+ # Create the mock video
114
+ for i in range (num_frames ):
115
+ img = Image .new ("RGB" , (frame_width , frame_height ), (0 , 0 , 0 ))
116
+ img .save (video_dir / f"frame_{ i } .png" )
117
+ create_mock_video (video_path , video_dir , num_frames = num_frames , frame_rate = frame_rate )
118
+
119
+ # Call convert_video_to_images
120
+ image_output_dir = tmp_path / "extracted_images"
121
+ num_frames_target = 5
122
+ num_downscales = 1
123
+ crop_factor = (0.0 , 0.0 , 0.0 , 0.0 )
124
+
125
+ # Mock missing COLMAP and ffmpeg in the dev env
126
+ old_path = os .environ .get ("PATH" , "" )
127
+ os .environ ["PATH" ] = str (tmp_path / "mocked_bin" ) + f":{ old_path } "
128
+ (tmp_path / "mocked_bin" ).mkdir ()
129
+ (tmp_path / "mocked_bin" / "colmap" ).touch (mode = 0o777 )
130
+ (tmp_path / "mocked_bin" / "ffmpeg" ).touch (mode = 0o777 )
131
+
132
+ # Return value of 10 for the get_num_frames_in_video run_command call
133
+ with mock .patch ("nerfstudio.process_data.process_data_utils.run_command" , return_value = "10" ) as mock_run_func :
134
+ summary_log , extracted_frame_count = convert_video_to_images (
135
+ video_path = video_path ,
136
+ image_dir = image_output_dir ,
137
+ num_frames_target = num_frames_target ,
138
+ num_downscales = num_downscales ,
139
+ crop_factor = crop_factor ,
140
+ verbose = False ,
141
+ random_seed = 42 ,
142
+ )
143
+ assert mock_run_func .call_count == 2 , f"Expected 2 calls, but got { mock_run_func .call_count } "
144
+ first_frames = extract_frame_numbers (mock_run_func .call_args [0 ][0 ])
145
+ assert len (first_frames ) == 5 , f"Expected 5 frames, but got { len (first_frames )} "
146
+
147
+ summary_log , extracted_frame_count = convert_video_to_images (
148
+ video_path = video_path ,
149
+ image_dir = image_output_dir ,
150
+ num_frames_target = num_frames_target ,
151
+ num_downscales = num_downscales ,
152
+ crop_factor = crop_factor ,
153
+ verbose = False ,
154
+ random_seed = 42 ,
155
+ )
156
+
157
+ assert mock_run_func .call_count == 4 , f"Expected 4 total calls, but got { mock_run_func .call_count } "
158
+ second_frames = extract_frame_numbers (mock_run_func .call_args [0 ][0 ])
159
+ assert len (second_frames ) == 5 , f"Expected 5 frames, but got { len (first_frames )} "
160
+ assert first_frames == second_frames
161
+
162
+ summary_log , extracted_frame_count = convert_video_to_images (
163
+ video_path = video_path ,
164
+ image_dir = image_output_dir ,
165
+ num_frames_target = num_frames_target ,
166
+ num_downscales = num_downscales ,
167
+ crop_factor = crop_factor ,
168
+ verbose = False ,
169
+ random_seed = 52 ,
170
+ )
171
+
172
+ assert mock_run_func .call_count == 6 , f"Expected 6 total calls, but got { mock_run_func .call_count } "
173
+ third_frames = extract_frame_numbers (mock_run_func .call_args [0 ][0 ])
174
+ assert len (third_frames ) == 5 , f"Expected 5 frames, but got { len (first_frames )} "
175
+ assert first_frames != third_frames
0 commit comments