Skip to content

Commit

Permalink
[scene_manager] Fix save_images not working with UTF-8 paths #450 (#460)
Browse files Browse the repository at this point in the history
  • Loading branch information
Breakthrough authored Nov 24, 2024
1 parent 95d20dd commit a477f9d
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 15 deletions.
10 changes: 8 additions & 2 deletions scenedetect/scene_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ def on_new_scene(frame_img: numpy.ndarray, frame_num: int):
import sys
import threading
from enum import Enum
from pathlib import Path
from typing import Callable, Dict, Iterable, List, Optional, TextIO, Tuple, Union

import cv2
Expand Down Expand Up @@ -587,8 +588,13 @@ def save_images(
frame_im = cv2.resize(
frame_im, (0, 0), fx=scale, fy=scale, interpolation=interpolation.value
)

cv2.imwrite(get_and_create_path(file_path, output_dir), frame_im, imwrite_param)
path = Path(get_and_create_path(file_path, output_dir))
(is_ok, encoded) = cv2.imencode(f".{image_extension}", frame_im, imwrite_param)
if is_ok:
encoded.tofile(path)
else:
logger.error(f"Failed to encode image for {file_path}")
#
else:
completed = False
break
Expand Down
34 changes: 27 additions & 7 deletions tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from pathlib import Path

import cv2
import numpy as np
import pytest

from scenedetect.video_splitter import is_ffmpeg_available, is_mkvmerge_available
Expand Down Expand Up @@ -455,17 +456,35 @@ def test_cli_save_images(tmp_path: Path):
)
== 0
)
images = [image for image in tmp_path.glob("*.jpg")]
# Should detect two scenes and generate 3 images per scene with above params.
assert len(images) == 6
# Open one of the created images and make sure it has the correct resolution.
# TODO: Also need to test that the right number of images was generated, and compare with
# expected frames from the actual video.
images = glob.glob(os.path.join(tmp_path, "*.jpg"))
assert images
image = cv2.imread(images[0])
assert image.shape == (544, 1280, 3)


def test_cli_save_images_path_handling(tmp_path: Path):
"""Test `save-images` ability to handle UTF-8 paths."""
assert (
invoke_scenedetect(
"-i {VIDEO} -s {STATS} time {TIME} {DETECTOR} save-images -f %s"
% ("電腦檔案-$SCENE_NUMBER-$IMAGE_NUMBER"),
output_dir=tmp_path,
)
== 0
)
images = [image for image in tmp_path.glob("電腦檔案-*.jpg")]
# Should detect two scenes and generate 3 images per scene with above params.
assert len(images) == 6
# Check the created images can be read and have the correct size.
# We can't use `cv2.imread` here since it doesn't seem to work correctly with UTF-8 paths.
image = cv2.imdecode(np.fromfile(images[0], dtype=np.uint8), cv2.IMREAD_UNCHANGED)
assert image.shape == (544, 1280, 3)


# TODO(#134): This works fine with OpenCV currently, but needs to be supported for PyAV and MoviePy.
def test_cli_save_images_rotation(rotated_video_file, tmp_path):
def test_cli_save_images_rotation(rotated_video_file, tmp_path: Path):
"""Test that `save-images` command rotates images correctly with the default backend."""
assert (
invoke_scenedetect(
Expand All @@ -475,8 +494,9 @@ def test_cli_save_images_rotation(rotated_video_file, tmp_path):
)
== 0
)
images = glob.glob(os.path.join(tmp_path, "*.jpg"))
assert images
images = [image for image in tmp_path.glob("*.jpg")]
# Should detect two scenes and generate 3 images per scene with above params.
assert len(images) == 6
image = cv2.imread(images[0])
# Note same resolution as in test_cli_save_images but rotated 90 degrees.
assert image.shape == (1280, 544, 3)
Expand Down
13 changes: 7 additions & 6 deletions website/pages/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -583,19 +583,20 @@ Development

## PySceneDetect 0.6.5 (TBD)

- [bugfix] Fix new detectors not working with `default-detector` config option
- [bugfix] Fix crash when using `save-images`/`save_images()` with OpenCV backend [#455](https://github.com/Breakthrough/PySceneDetect/issues/455)
- [bugfix] Fix `SyntaxWarning` due to incorrect escaping [#400](https://github.com/Breakthrough/PySceneDetect/issues/400)
- [bugfix] Fix `ContentDetector` crash when using callbacks [#416](https://github.com/Breakthrough/PySceneDetect/issues/416) [#420](https://github.com/Breakthrough/PySceneDetect/issues/420)
- [feature] Add ability to configure CSV separators for rows/columns in config file [#423](https://github.com/Breakthrough/PySceneDetect/issues/423)
- [feature] Add new `--show` flag to `export-html` command to launch browser after processing [#442](https://github.com/Breakthrough/PySceneDetect/issues/442)
- [general] Timecodes of the form `MM:SS[.nnn]` are now processed correctly [#443](https://github.com/Breakthrough/PySceneDetect/issues/443)
- [feature] Add new `--show` flag to `export-html` command to launch browser after processing (#442)
- [bugfix] Fix `save-images`/`save_images()` not working correctly with UTF-8 paths [#450](https://github.com/Breakthrough/PySceneDetect/issues/455)
- [bugfix] Fix crash when using `save-images`/`save_images()` with OpenCV backend [#455](https://github.com/Breakthrough/PySceneDetect/issues/455)
- [bugfix] Fix new detectors not working with `default-detector` config option
- [improvement] The `export-html` command now implicitly invokes `save-images` with default parameters
- The output of the `export-html` command will always use the result of the `save-images` command that *precedes* it
- [general] Updates to Windows distributions:
- The MoviePy backend is now included with Windows distributions
- Bundled Python interpreter is now Python 3.13
- Updated PyAV 10 -> 13.1.0 and OpenCV 4.10.0.82 -> 4.10.0.84
- [improvement] `save_to_csv` now works with paths from `pathlib`
- [bugfix] Fix `SyntaxWarning` due to incorrect escaping [#400](https://github.com/Breakthrough/PySceneDetect/issues/400)
- [bugfix] Fix `ContentDetector` crash when using callbacks [#416](https://github.com/Breakthrough/PySceneDetect/issues/416) [#420](https://github.com/Breakthrough/PySceneDetect/issues/420)
- [api] The `save_to_csv` function now works correctly with paths from the `pathlib` module
- [api] Add `col_separator` and `row_separator` args to `write_scene_list` function in `scenedetect.scene_manager`
- [feature] Add ability to configure CSV separators for rows/columns in config file [#423](https://github.com/Breakthrough/PySceneDetect/issues/423)

0 comments on commit a477f9d

Please sign in to comment.