Skip to content

Commit e407607

Browse files
committed
[scene_manager] Fix save_images not working with UTF-8 paths #450
1 parent 95d20dd commit e407607

File tree

3 files changed

+42
-15
lines changed

3 files changed

+42
-15
lines changed

scenedetect/scene_manager.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ def on_new_scene(frame_img: numpy.ndarray, frame_num: int):
8686
import sys
8787
import threading
8888
from enum import Enum
89+
from pathlib import Path
8990
from typing import Callable, Dict, Iterable, List, Optional, TextIO, Tuple, Union
9091

9192
import cv2
@@ -587,8 +588,13 @@ def save_images(
587588
frame_im = cv2.resize(
588589
frame_im, (0, 0), fx=scale, fy=scale, interpolation=interpolation.value
589590
)
590-
591-
cv2.imwrite(get_and_create_path(file_path, output_dir), frame_im, imwrite_param)
591+
path = Path(get_and_create_path(file_path, output_dir))
592+
(is_ok, encoded) = cv2.imencode(f".{image_extension}", frame_im, imwrite_param)
593+
if is_ok:
594+
encoded.tofile(path)
595+
else:
596+
logger.error(f"Failed to encode image for {file_path}")
597+
#
592598
else:
593599
completed = False
594600
break

tests/test_cli.py

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
from pathlib import Path
1818

1919
import cv2
20+
import numpy as np
2021
import pytest
2122

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

466466

467+
def test_cli_save_images_path_handling(tmp_path: Path):
468+
"""Test `save-images` ability to handle UTF-8 paths."""
469+
assert (
470+
invoke_scenedetect(
471+
"-i {VIDEO} -s {STATS} time {TIME} {DETECTOR} save-images -f %s"
472+
% ("電腦檔案-$SCENE_NUMBER-$IMAGE_NUMBER"),
473+
output_dir=tmp_path,
474+
)
475+
== 0
476+
)
477+
images = [image for image in tmp_path.glob("電腦檔案-*.jpg")]
478+
# Should detect two scenes and generate 3 images per scene with above params.
479+
assert len(images) == 6
480+
# Check the created images can be read and have the correct size.
481+
# We can't use `cv2.imread` here since it doesn't seem to work correctly with UTF-8 paths.
482+
image = cv2.imdecode(np.fromfile(images[0], dtype=np.uint8), cv2.IMREAD_UNCHANGED)
483+
assert image.shape == (544, 1280, 3)
484+
485+
467486
# TODO(#134): This works fine with OpenCV currently, but needs to be supported for PyAV and MoviePy.
468-
def test_cli_save_images_rotation(rotated_video_file, tmp_path):
487+
def test_cli_save_images_rotation(rotated_video_file, tmp_path: Path):
469488
"""Test that `save-images` command rotates images correctly with the default backend."""
470489
assert (
471490
invoke_scenedetect(
@@ -475,8 +494,9 @@ def test_cli_save_images_rotation(rotated_video_file, tmp_path):
475494
)
476495
== 0
477496
)
478-
images = glob.glob(os.path.join(tmp_path, "*.jpg"))
479-
assert images
497+
images = [image for image in tmp_path.glob("*.jpg")]
498+
# Should detect two scenes and generate 3 images per scene with above params.
499+
assert len(images) == 6
480500
image = cv2.imread(images[0])
481501
# Note same resolution as in test_cli_save_images but rotated 90 degrees.
482502
assert image.shape == (1280, 544, 3)

website/pages/changelog.md

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -583,19 +583,20 @@ Development
583583

584584
## PySceneDetect 0.6.5 (TBD)
585585

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

0 commit comments

Comments
 (0)