Skip to content

Commit

Permalink
Added gif visualization for videos
Browse files Browse the repository at this point in the history
  • Loading branch information
sanjanag committed Nov 28, 2023
1 parent 6490149 commit 0085be5
Showing 1 changed file with 84 additions and 86 deletions.
170 changes: 84 additions & 86 deletions src/cleanvision/videolab.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@
from __future__ import annotations


import pickle
from copy import deepcopy
from pathlib import Path
from typing import Any, Dict, List, Optional, Type, TypeVar
from typing import Any, Dict, List, Optional, TypeVar
from cleanvision.utils.frame_sampler import FrameSampler
import pandas as pd
from tqdm.auto import tqdm
Expand All @@ -14,6 +12,9 @@
from cleanvision.utils.utils import get_is_issue_colname
from cleanvision.utils.constants import DEFAULT_ISSUE_TYPES_VIDEOLAB
from cleanvision.dataset.video_dataset import VideoDataset
from PIL import Image
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation


OBJECT_FILENAME = "videolab.pkl"
Expand Down Expand Up @@ -163,7 +164,7 @@ def find_issues(

# use imagelab to find issues in frames
self.imagelab.find_issues(

Check warning on line 166 in src/cleanvision/videolab.py

View check run for this annotation

Codecov / codecov/patch

src/cleanvision/videolab.py#L166

Added line #L166 was not covered by tests
issue_types=self.issue_types, n_jobs=n_jobs, verbose=verbose
issue_types=self.issue_types, n_jobs=n_jobs, verbose=False
)

# get frame issues
Expand All @@ -184,6 +185,12 @@ def find_issues(
]
)

def _pprint_issue_summary(self, issue_summary: pd.DataFrame) -> None:
issue_summary_copy = issue_summary.copy()
issue_summary_copy.dropna(axis=1, how="all", inplace=True)
issue_summary_copy.fillna("N/A", inplace=True)
print(issue_summary_copy.to_markdown(), "\n")

Check warning on line 192 in src/cleanvision/videolab.py

View check run for this annotation

Codecov / codecov/patch

src/cleanvision/videolab.py#L189-L192

Added lines #L189 - L192 were not covered by tests

def report(
self,
issue_types: Optional[List[str]] = None,
Expand All @@ -194,92 +201,83 @@ def report(
show_id: bool = False,
) -> None:
"""Prints summary of the aggregate issues found in your dataset."""
# report on video frame samples
self.imagelab.report(
issue_types,
max_prevalence,
num_images,
verbosity,
print_summary,
show_id,
)

def get_stats(self) -> Any:
"""Returns dict of statistics computed from video frames."""
return self.imagelab.info["statistics"]

def save(self, path: str, force: bool = False) -> None:
"""Saves this Videolab instance."""
# get pathlib Path object
root_save_path = Path(path)
issue_types_to_report = (

Check warning on line 205 in src/cleanvision/videolab.py

View check run for this annotation

Codecov / codecov/patch

src/cleanvision/videolab.py#L205

Added line #L205 was not covered by tests
issue_types if issue_types else self.issue_summary["issue_type"].tolist()
)

# check if videolab root save path exists
if not root_save_path.exists():
# create otherwise
root_save_path.mkdir(parents=True, exist_ok=True)
issue_summary = self.issue_summary[

Check warning on line 209 in src/cleanvision/videolab.py

View check run for this annotation

Codecov / codecov/patch

src/cleanvision/videolab.py#L209

Added line #L209 was not covered by tests
self.issue_summary["issue_type"].isin(issue_types_to_report)
]
if len(issue_summary) > 0:
if verbosity:

Check warning on line 213 in src/cleanvision/videolab.py

View check run for this annotation

Codecov / codecov/patch

src/cleanvision/videolab.py#L213

Added line #L213 was not covered by tests
print("Issues found in videos in order of severity in the dataset\n")
if print_summary:
self._pprint_issue_summary(issue_summary)

Check warning on line 216 in src/cleanvision/videolab.py

View check run for this annotation

Codecov / codecov/patch

src/cleanvision/videolab.py#L216

Added line #L216 was not covered by tests
for issue_type in issue_types_to_report:
if (
self.issue_summary.query(f"issue_type == '{issue_type}'")[
"num_videos"
].values[0]
== 0
):
continue
print(f"{' ' + issue_type + ' videos ':-^60}\n")
print(

Check warning on line 226 in src/cleanvision/videolab.py

View check run for this annotation

Codecov / codecov/patch

src/cleanvision/videolab.py#L224-L226

Added lines #L224 - L226 were not covered by tests
f"Number of examples with this issue: {self.issues[get_is_issue_colname(issue_type)].sum()}\n"
f"Examples representing most severe instances of this issue:\n"
)
# self._visualize(
# issue_type,
# report_args["num_images"],
# report_args["cell_size"],
# show_id,
# )
else:
if not force:
raise FileExistsError("Please specify a new path or set force=True")
print(

Check warning on line 237 in src/cleanvision/videolab.py

View check run for this annotation

Codecov / codecov/patch

src/cleanvision/videolab.py#L237

Added line #L237 was not covered by tests
"WARNING: Existing files will be overwritten "
f"by newly saved files at: {root_save_path}"
"Please specify some issue_types to check for in videolab.find_issues()."
)

# create specific imagelab sub directory
imagelab_sub_dir = str(root_save_path / "imagelab")

# now save imagelab to subdir
self.imagelab.save(imagelab_sub_dir, force)

# save aggregate dataframes
self._frame_level_issues.to_csv(root_save_path / ISSUES_FILENAME)
self.frame_issue_summary.to_csv(root_save_path / ISSUE_SUMMARY_FILENAME)

# copy videolab object
videolab_copy = deepcopy(self)

# clear out dataframes
videolab_copy._frame_level_issues = None
videolab_copy.frame_issue_summary = None

# Save the imagelab object to disk.
with open(root_save_path / OBJECT_FILENAME, "wb") as f:
pickle.dump(videolab_copy, f)

print(f"Saved Videolab to folder: {root_save_path}")
print(
"The data path and dataset must be not be changed to maintain consistent "
"state when loading this Videolab"
)

@classmethod
def load(cls: Type[TVideolab], path: str) -> Videolab:
"""Loads Videolab from given path."""
# get pathlib Path object
root_save_path = Path(path)

# check if path exists
if not root_save_path.exists():
raise ValueError(f"No folder found at specified path: {path}")

with open(root_save_path / OBJECT_FILENAME, "rb") as f:
videolab: Videolab = pickle.load(f)

# Load the issues from disk.
videolab._frame_level_issues = pd.read_csv(
root_save_path / ISSUES_FILENAME, index_col=0
)
videolab.frame_issue_summary = pd.read_csv(
root_save_path / ISSUE_SUMMARY_FILENAME, index_col=0
)

# create specific imagelab sub directory
imagelab_sub_dir = str(root_save_path / "imagelab")

# store imagelab object
videolab.imagelab = Imagelab.load(imagelab_sub_dir)

# notify user
print("Successfully loaded Videolab")
def visualize(self, issue_types):
for issue_type in issue_types:
colname = get_is_issue_colname(issue_type)
video_paths = self.issues[self.issues[colname] is True].index.tolist()

Check warning on line 244 in src/cleanvision/videolab.py

View check run for this annotation

Codecov / codecov/patch

src/cleanvision/videolab.py#L243-L244

Added lines #L243 - L244 were not covered by tests
self.rev_idx = {path: i for i, path in enumerate(self.video_dataset.index)}

frames_list = []

Check warning on line 247 in src/cleanvision/videolab.py

View check run for this annotation

Codecov / codecov/patch

src/cleanvision/videolab.py#L247

Added line #L247 was not covered by tests
for path in video_paths:
frame_dir = self.video_dataset.frames_dir / str(self.rev_idx[path])

Check warning on line 249 in src/cleanvision/videolab.py

View check run for this annotation

Codecov / codecov/patch

src/cleanvision/videolab.py#L249

Added line #L249 was not covered by tests
frames_list.append(
[Image.open(frame_path) for frame_path in frame_dir.iterdir()]
)

# Define the number of animations and frames
num_animations = min(4, len(video_paths))
num_frames = 100

Check warning on line 256 in src/cleanvision/videolab.py

View check run for this annotation

Codecov / codecov/patch

src/cleanvision/videolab.py#L255-L256

Added lines #L255 - L256 were not covered by tests

# Create a figure with subplots
fig, axes = plt.subplots(1, num_animations, figsize=(8, 8))

Check warning on line 259 in src/cleanvision/videolab.py

View check run for this annotation

Codecov / codecov/patch

src/cleanvision/videolab.py#L259

Added line #L259 was not covered by tests

# Initialize data for each animation
initial_data = [frames[0] for frames in frames_list]
images = frames_list

Check warning on line 263 in src/cleanvision/videolab.py

View check run for this annotation

Codecov / codecov/patch

src/cleanvision/videolab.py#L263

Added line #L263 was not covered by tests

# Function to initialize the subplots
def init():

Check warning on line 266 in src/cleanvision/videolab.py

View check run for this annotation

Codecov / codecov/patch

src/cleanvision/videolab.py#L266

Added line #L266 was not covered by tests
for ax, data in zip(axes, initial_data):
ax.imshow(data)
ax.axis("off")
return axes

Check warning on line 270 in src/cleanvision/videolab.py

View check run for this annotation

Codecov / codecov/patch

src/cleanvision/videolab.py#L268-L270

Added lines #L268 - L270 were not covered by tests

# Function to update the subplots for each frame
def update(frame):

Check warning on line 273 in src/cleanvision/videolab.py

View check run for this annotation

Codecov / codecov/patch

src/cleanvision/videolab.py#L273

Added line #L273 was not covered by tests
for ax, image in zip(axes, images):
ax.imshow(image[frame])
return axes

Check warning on line 276 in src/cleanvision/videolab.py

View check run for this annotation

Codecov / codecov/patch

src/cleanvision/videolab.py#L275-L276

Added lines #L275 - L276 were not covered by tests

FuncAnimation(

Check warning on line 278 in src/cleanvision/videolab.py

View check run for this annotation

Codecov / codecov/patch

src/cleanvision/videolab.py#L278

Added line #L278 was not covered by tests
fig, update, frames=num_frames, init_func=init, blit=True, interval=100
)

return videolab
plt.tight_layout()
plt.show()

Check warning on line 283 in src/cleanvision/videolab.py

View check run for this annotation

Codecov / codecov/patch

src/cleanvision/videolab.py#L282-L283

Added lines #L282 - L283 were not covered by tests

0 comments on commit 0085be5

Please sign in to comment.