Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)
Loading