99import numpy as np
1010
1111from ns_vfs .data .frame import Frame , FrameWindow
12- from ns_vfs .verification import build_label_func , build_trans_matrix
12+ from ns_vfs .verification import check_automaton
1313
1414
1515class VideoProcessor (abc .ABC ):
1616 @abc .abstractmethod
1717 def import_video (self , video_path ) -> any :
1818 """Read video from video_path."""
19- pass
2019
2120
2221class VideoFrameProcessor (VideoProcessor ):
@@ -27,22 +26,27 @@ def __init__(self, video_path: str, artifact_dir: str) -> None:
2726
2827 Args:
2928 video_path (str): Path to video file.
29+ artifact_dir (str): Path to artifact directory.
3030 """
3131 self ._video_path = video_path
3232 self ._artifact_dir = os .path .join (artifact_dir , "video_frame_processor" )
3333 self ._processed_frames = None
3434 self ._frame_window = None
3535 self .import_video (video_path )
3636
37- def import_video (self , video_path ):
38- """Read video from video_path."""
39- self ._cap = cv2 .VideoCapture (video_path )
40- self .original_video_height = self ._cap .get (cv2 .CAP_PROP_FRAME_HEIGHT )
41- self .original_video_width = self ._cap .get (cv2 .CAP_PROP_FRAME_WIDTH )
42- self .original_vidoe_fps = self ._cap .get (cv2 .CAP_PROP_FPS )
43- self .original_frame_count = self ._cap .get (cv2 .CAP_PROP_FRAME_COUNT )
37+ def _resize_frame (
38+ self , frame_img : np .ndarray , frame_scale : int
39+ ) -> np .ndarray :
40+ """Resize frame image.
41+
42+ Args:
43+ frame_img (np.ndarray): Frame image.
44+ frame_scale (int): Scale of frame.
4445
45- def _resize_frame (self , frame_img , frame_scale ):
46+
47+ Returns:
48+ np.ndarray: Resized frame image.
49+ """
4650 return cv2 .resize (
4751 frame_img ,
4852 (
@@ -51,7 +55,76 @@ def _resize_frame(self, frame_img, frame_scale):
5155 ),
5256 )
5357
54- def build_frame_synchronously (
58+ def import_video (self , video_path : str ) -> None :
59+ """Read video from video_path.
60+
61+ Args:
62+ video_path (str): Path to video file.
63+ """
64+ self ._cap = cv2 .VideoCapture (video_path )
65+ self .original_video_height = self ._cap .get (cv2 .CAP_PROP_FRAME_HEIGHT )
66+ self .original_video_width = self ._cap .get (cv2 .CAP_PROP_FRAME_WIDTH )
67+ self .original_vidoe_fps = self ._cap .get (cv2 .CAP_PROP_FPS )
68+ self .original_frame_count = self ._cap .get (cv2 .CAP_PROP_FRAME_COUNT )
69+
70+ def get_video_by_frame (
71+ self ,
72+ frame_scale : int = 5 ,
73+ frame_duration_sec : int = 2 ,
74+ return_format : str = "ndarray" ,
75+ ) -> np .ndarray | list :
76+ """Get video frames by frame_scale and second_per_frame.
77+
78+ Args:
79+ frame_scale (int, optional): Scale of frame. Defaults to 5.
80+ second_per_frame (int, optional): Second per frame. Defaults to 2.
81+ return_format (str, optional): Return format. Defaults to "npndarray".
82+
83+ Returns:
84+ any: Video frames.
85+ """
86+ frames = list ()
87+ frame_counter = 0
88+ frame_per_sec = int (round (self .original_vidoe_fps ) * frame_duration_sec )
89+ while self ._cap .isOpened ():
90+ ret , frame_img = self ._cap .read ()
91+ if not ret :
92+ break
93+ if frame_counter % frame_per_sec == 0 :
94+ if frame_scale is not None :
95+ frame_img = self ._resize_frame (frame_img , frame_scale )
96+
97+ frames .append (frame_img )
98+ if cv2 .waitKey (1 ) & 0xFF == ord ("q" ): # on press of q break
99+ break
100+ frame_counter += 1
101+ self ._cap .release ()
102+ cv2 .destroyAllWindows ()
103+ if return_format == "npndarray" :
104+ self ._processed_frames = np .array (frames )
105+ return np .array (frames )
106+ else :
107+ self ._processed_frames = frames
108+ return frames
109+
110+
111+ class VideoFrameWindowProcessor (VideoFrameProcessor ):
112+ """Video Frame Window Processor.
113+
114+ It processes video frame, build automaton and verification
115+ concurretnly by sliding window.
116+ """
117+
118+ def __init__ (self , video_path : str , artifact_dir : str ) -> None :
119+ """Video Frame Processor.
120+
121+ Args:
122+ video_path (str): Path to video file.
123+ artifact_dir (str): Path to artifact directory.
124+ """
125+ super ().__init__ (video_path , artifact_dir )
126+
127+ def build_frame_window_synchronously (
55128 self ,
56129 proposition_set : list ,
57130 calculate_propositional_confidence : callable ,
@@ -60,10 +133,25 @@ def build_frame_synchronously(
60133 frame_scale : int | None = None ,
61134 sliding_window_size : int = 5 ,
62135 save_image : bool = False ,
63- ):
136+ ) -> None :
137+ """Build frame window synchronously.
138+
139+ It processes video frame, build automaton and verification
140+ concurrently by sliding window.
141+
142+ Args:
143+ proposition_set (list): List of propositions.
144+ calculate_propositional_confidence (callable): Calculate propositional confidence.
145+ build_automaton (callable): Build automaton.
146+ frame_duration_sec (int, optional): Second per frame. Defaults to 2.
147+ frame_scale (int | None, optional): Scale of frame. Defaults to None.
148+ sliding_window_size (int, optional): Size of sliding window. Defaults to 5.
149+ save_image (bool, optional): Save image. Defaults to False.
150+ """
64151 frame_window_idx = 0
65152 frame_counter = 0
66153 frame_idx = 0
154+
67155 # Calculate the frame skip rate
68156 frame_window = dict (frame_window_idx = 0 )
69157 temp_frame_set = list ()
@@ -118,60 +206,19 @@ def build_frame_synchronously(
118206 states , transitions = build_automaton (
119207 frame_set , propositional_confidence
120208 )
121- frame_window [frame_window_idx ].states = states
122- frame_window [frame_window_idx ].transitions = transitions
123209
124210 # Verification - Build Transition Matrix
125- transition_matrix = build_trans_matrix (
126- transitions = transitions , states = states
211+ verification_result = check_automaton (
212+ transitions = transitions ,
213+ states = states ,
214+ proposition_set = proposition_set ,
127215 )
128- state_labeling = build_label_func (states , proposition_set )
129- transition_matrix
130- state_labeling
131-
132- frame_window_idx += 1
133- temp_frame_set .pop (0 )
134-
135- frame_idx += 1
136- frame_counter += 1
137-
138- self ._cap .release ()
139- self ._frame_window = frame_window
140- return frame_window
141-
142- def get_frame_by_sliding_window (
143- self ,
144- frame_duration_sec : int = 2 ,
145- frame_scale : int | None = None ,
146- sliding_window_size : int = 5 ,
147- ):
148- frame_window_idx = 0
149- frame_counter = 0
150- frame_idx = 0
151- # Calculate the frame skip rate
152- frame_window = dict (frame_window_idx = 0 )
153- temp_frame_set = list ()
216+ frame_window [frame_window_idx ].states = states
217+ frame_window [frame_window_idx ].transitions = transitions
218+ frame_window [
219+ frame_window_idx
220+ ].verification_result = verification_result
154221
155- while self ._cap .isOpened ():
156- ret , frame_img = self ._cap .read ()
157- if not ret :
158- break
159- if (
160- frame_counter
161- % int (frame_duration_sec * self .original_vidoe_fps )
162- == 0
163- ):
164- if frame_scale is not None :
165- frame_img = self ._resize_frame (frame_img , frame_scale )
166- Frame
167- temp_frame_set .append (
168- Frame (frame_index = frame_idx , frame_image = frame_img )
169- )
170- if len (temp_frame_set ) == sliding_window_size :
171- frame_window [frame_window_idx ] = FrameWindow (
172- frame_window_idx = frame_window_idx ,
173- frame_image_set = temp_frame_set .copy (),
174- )
175222 frame_window_idx += 1
176223 temp_frame_set .pop (0 )
177224
@@ -182,53 +229,21 @@ def get_frame_by_sliding_window(
182229 self ._frame_window = frame_window
183230 return frame_window
184231
185- def get_frame (
186- self ,
187- frame_scale : int = 5 ,
188- second_per_frame : int = 2 ,
189- return_format : str = "ndarray" ,
190- ) -> np .ndarray | list :
191- """Get video frames by frame_scale and second_per_frame.
192-
193- Args:
194- frame_scale (int, optional): Scale of frame. Defaults to 5.
195- second_per_frame (int, optional): Second per frame. Defaults to 2.
196- return_format (str, optional): Return format. Defaults to "npndarray".
197-
198- Returns:
199- any: Video frames.
200- """
201- frames = list ()
202- frame_counter = 0
203- frame_per_sec = int (round (self .original_vidoe_fps )) * second_per_frame
204- while self ._cap .isOpened ():
205- ret , frame_img = self ._cap .read ()
206- if not ret :
207- break
208- if frame_counter % frame_per_sec == 0 :
209- if frame_scale is not None :
210- frame_img = self ._resize_frame (frame_img , frame_scale )
211-
212- frames .append (frame_img )
213- if cv2 .waitKey (1 ) & 0xFF == ord ("q" ): # on press of q break
214- break
215- frame_counter += 1
216- self ._cap .release ()
217- cv2 .destroyAllWindows ()
218- if return_format == "npndarray" :
219- self ._processed_frames = np .array (frames )
220- return np .array (frames )
221- else :
222- self ._processed_frames = frames
223- return frames
224-
225232 def replay_and_save (
226233 self ,
227234 frames : list [Frame ],
228235 frame_rate = 2 ,
229236 is_imshow : bool = False ,
230237 output_dir : str | None = None ,
231- ):
238+ ) -> None :
239+ """Replay and save frames.
240+
241+ Args:
242+ frames (list[Frame]): List of frames.
243+ frame_rate (int, optional): Frame rate. Defaults to 2.
244+ is_imshow (bool, optional): Show image. Defaults to False.
245+ output_dir (str | None, optional): Output directory. Defaults to None.
246+ """
232247 if output_dir is None :
233248 output_dir = os .path .join (self ._artifact_dir , "replay_frames" )
234249
@@ -247,16 +262,3 @@ def replay_and_save(
247262 int (1000 / frame_rate )
248263 ) # wait for specified milliseconds
249264 cv2 .destroyAllWindows
250-
251- @property
252- def original_video_num_of_frames (self ):
253- """Get number of frames in video."""
254- return self .original_frame_count
255-
256- @property
257- def number_of_frames (self ):
258- """Get number of frames in video."""
259- if self ._processed_frames is None :
260- return self .original_frame_count
261- else :
262- return len (self ._processed_frames )
0 commit comments