Skip to content

Commit cd83919

Browse files
committed
feat: v0.0.2 release
1 parent 58aa558 commit cd83919

7 files changed

Lines changed: 343 additions & 176 deletions

File tree

main.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from ns_vfs.config.loader import load_config
44
from ns_vfs.model.vision.grounding_dino import GroundingDino
55
from ns_vfs.processor.video_processor import (
6-
VideoFrameProcessor,
6+
VideoFrameWindowProcessor,
77
)
88
from ns_vfs.video_to_automaton import VideotoAutomaton
99

@@ -20,14 +20,14 @@
2020
weight_path=config.GROUNDING_DINO.GROUNDING_DINO_CHECKPOINT_PATH,
2121
config_path=config.GROUNDING_DINO.GROUNDING_DINO_CONFIG_PATH,
2222
),
23-
video_processor=VideoFrameProcessor(
23+
video_processor=VideoFrameWindowProcessor(
2424
video_path=sample_video_path,
2525
artifact_dir=config.VERSION_AND_PATH.ARTIFACTS_PATH,
2626
),
27-
proposition_set=["face", "person", "car"],
27+
proposition_set=["person", "drink"],
2828
artifact_dir=config.VERSION_AND_PATH.ARTIFACTS_PATH,
2929
)
3030

31-
frame_window_automata = frame2automaton.start()
31+
frame_window_automata = frame2automaton.run()
3232

3333
print("Development is in progress.")

ns_vfs/data/frame.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,33 +5,33 @@
55

66
@dataclasses.dataclass
77
class Frame:
8+
"""Frame class."""
9+
810
frame_index: int
911
frame_image: np.ndarray
1012
propositional_probability: dict = dataclasses.field(default_factory=dict)
1113

1214

1315
@dataclasses.dataclass
1416
class FrameWindow:
17+
"""Frame window class."""
18+
1519
frame_window_idx: int
1620
frame_image_set: list = dataclasses.field(default_factory=list)
1721
states: list = dataclasses.field(default_factory=list)
1822
transitions: list = dataclasses.field(default_factory=list)
23+
verification_result: bool = False
1924

2025
def get_propositional_confidence(self):
2126
propositional_confidence = [
22-
[]
23-
for i in range(
24-
len(self.frame_image_set[0].propositional_probability.keys())
25-
)
27+
[] for i in range(len(self.frame_image_set[0].propositional_probability.keys()))
2628
]
2729
propositional_confidence
2830
for frame in self.frame_image_set:
2931
frame: Frame
3032
idx = 0
3133
for prop in frame.propositional_probability.keys():
32-
propositional_confidence[idx].append(
33-
frame.propositional_probability[prop]
34-
)
34+
propositional_confidence[idx].append(frame.propositional_probability[prop])
3535
idx += 1
3636
self.propositional_confidence = propositional_confidence
3737
return propositional_confidence

ns_vfs/processor/video_processor.py

Lines changed: 118 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,13 @@
99
import numpy as np
1010

1111
from 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

1515
class VideoProcessor(abc.ABC):
1616
@abc.abstractmethod
1717
def import_video(self, video_path) -> any:
1818
"""Read video from video_path."""
19-
pass
2019

2120

2221
class 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

Comments
 (0)