Skip to content

Commit 4d9e677

Browse files
authored
fix: small fixes (#33)
1 parent 041a60e commit 4d9e677

File tree

6 files changed

+29
-26
lines changed

6 files changed

+29
-26
lines changed

README.md

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,13 +53,20 @@ usage: movie-barcodes [-h] -i INPUT_VIDEO_PATH [-d [DESTINATION_PATH]] [-t {hori
5353
5454
- `-w`, `--workers`: Number of parallel workers for processing. By default, the script will use all available CPU cores. Setting this to 1 will use sequential processing. (Optional, type: int)
5555
56-
- `--width`: The output image's width in pixels. If not specified, the width will be the same as the input video. (Optional, type: int)
56+
- `--width`: For horizontal barcodes, sets both (1) the number of sampled frames and (2) the output image width in pixels. If not specified, defaults to the input video width. For circular barcodes, this flag is ignored (see notes). (Optional, type: int)
5757
5858
- `--height`: The output image's height in pixels. If not specified, the height will be the same as the input video. (Optional, type: int)
5959
6060
- `-n`, `--output_name`: Custom name for the output barcode image. If not provided, a name will be automatically generated. (Optional, type: str)
6161
62-
- `-a`, `--all_methods`: If set to True, all methods for color extraction will be employed, overriding the --method argument. Default is False. (Optional, type: bool)
62+
- `-a`, `--all_methods`: If set, all extraction methods will be run. This overrides `--method` and produces one image per method. Default is False. (Optional, type: bool)
63+
64+
Notes:
65+
- Circular barcode sizing: circular barcode diameter uses the input video width by default. `--width`/`--height` do not apply to circular barcodes.
66+
- Destination paths:
67+
- If a relative path is provided, it is resolved relative to the project root.
68+
- If only a filename (basename) is provided, it is saved in the project root.
69+
- Parent directories are created automatically when saving the image.
6370
6471
# Examples
6572
## Sequential Processing

src/movie_barcodes/__init__.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,13 @@
33
This package provides CLI and library functions to generate movie color barcodes.
44
"""
55

6-
from . import barcode_generation as barcode
76
from . import barcode_generation as barcode_generation
87
from . import color_extraction
98
from . import video_processing
109
from .cli import main as main
1110
from . import utility
1211

1312
__all__ = [
14-
"barcode",
1513
"barcode_generation",
1614
"color_extraction",
1715
"video_processing",

src/movie_barcodes/barcode_generation.py

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ def generate_circular_barcode(colors: list, img_size: int, scale_factor: int = 1
1010
"""
1111
Generate a circular barcode from the list of colors or smoothed frames.
1212
13-
:param list colors: List of RGB colors or smoothed frames.
13+
:param list colors: List of BGR colors or smoothed frames.
1414
:param int img_size: The size of the square image (both width and height).
1515
:param int scale_factor: The scale factor to use when generating the barcode. Default is 10.
16-
:return: np.ndarray: Circular barcode image.
16+
:return: np.ndarray: Circular barcode image (BGRA; converted to RGBA when saving).
1717
"""
1818
high_res_img_size = img_size * scale_factor
1919

@@ -26,13 +26,7 @@ def generate_circular_barcode(colors: list, img_size: int, scale_factor: int = 1
2626
max_radius = center # The largest circle's radius will be half of the image size
2727
radius_increment = max_radius / total_circles
2828

29-
for idx, color in tqdm(
30-
enumerate(colors),
31-
desc="Generating Barcode",
32-
total=len(colors),
33-
unit="%",
34-
bar_format="{l_bar}{bar}| {percentage:3.0f}% [{elapsed}<{remaining}]",
35-
):
29+
for idx, color in tqdm(enumerate(colors), desc="Generating Barcode", total=len(colors), unit="it"):
3630
radius = (idx + 1) * radius_increment
3731

3832
# Handle both simple BGR tuples and smoothed frames
@@ -61,11 +55,12 @@ def generate_barcode(
6155
) -> np.ndarray:
6256
"""
6357
Generate a barcode image based on dominant colors or smoothed frames of video frames.
64-
:param list colors: List of dominant colors or smoothed frames from video frames.
58+
Colors are treated as BGR internally and converted to RGB once at save-time.
59+
:param list colors: List of dominant BGR colors or smoothed frames from video frames.
6560
:param int frame_height: The height of the barcode image.
6661
:param int frame_count: The total number of frames in the video.
6762
:param Optional[int] frame_width: The width of the barcode image. If not specified, defaults to frame_count.
68-
:return: np.ndarray: A barcode image.
63+
:return: np.ndarray: A barcode image (BGR).
6964
"""
7065
if frame_width is None:
7166
frame_width = frame_count
@@ -74,13 +69,7 @@ def generate_barcode(
7469

7570
step = max(1, len(colors) // frame_width)
7671
sampled_colors = [colors[i] for i in range(0, len(colors), step)]
77-
for i, color in tqdm(
78-
enumerate(sampled_colors),
79-
desc="Generating Barcode",
80-
total=len(sampled_colors),
81-
unit="%",
82-
bar_format="{l_bar}{bar}| {percentage:3.0f}% [{elapsed}<{remaining}]",
83-
):
72+
for i, color in tqdm(enumerate(sampled_colors), desc="Generating Barcode", total=len(sampled_colors), unit="it"):
8473
if i < frame_width:
8574
if isinstance(color, np.ndarray) and color.ndim == 3 and color.shape[1] == 1:
8675
# For smoothed frames

src/movie_barcodes/utility.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,9 @@ def save_barcode_image(barcode: np.ndarray, base_name: str, args: argparse.Names
153153
destination_path = args.destination_path
154154
if not path.isabs(destination_path):
155155
destination_path = path.join(project_root, destination_path)
156+
# Ensure parent directory exists if user provided a custom path
157+
parent_dir = path.dirname(destination_path) or "."
158+
ensure_directory(parent_dir)
156159

157160
if barcode.shape[2] == 4: # If the image has an alpha channel (RGBA)
158161
# Convert BGRA -> RGBA once at save-time

src/movie_barcodes/video_processing.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,9 +128,10 @@ def extract_colors(
128128

129129
for _ in tqdm(range(target_frames or total_frames), desc="Processing frames"):
130130
ret, frame = video.read() # Read the first or next frame
131-
if ret:
132-
dominant_color = color_extractor(frame)
133-
colors.append(dominant_color)
131+
if not ret:
132+
break
133+
dominant_color = color_extractor(frame)
134+
colors.append(dominant_color)
134135
for _ in range(frame_skip - 1):
135136
video.grab() # Skip frames
136137

tests/test_utility.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -366,11 +366,16 @@ def test_save_barcode_image_with_relative_destination_path(
366366
When a relative destination_path is provided, ensure it is resolved relative to project root.
367367
"""
368368
mock_abspath.return_value = "/fake/root/src/movie_barcodes/utility.py"
369-
# save_barcode_image calls dirname three times: dirname(abspath(...)) and dirname(dirname(current_dir))
369+
# save_barcode_image calls dirname four times:
370+
# 1) dirname(abspath(...)) => current_dir
371+
# 2) dirname(current_dir)
372+
# 3) dirname(<above>) => project root
373+
# 4) dirname(resolved destination_path) => parent dir
370374
mock_dirname.side_effect = [
371375
"/fake/root/src/movie_barcodes", # dirname of abspath
372376
"/fake/root/src", # inner dirname(current_dir)
373377
"/fake/root", # outer dirname(<above>) => project root
378+
"/fake/root/relative", # parent dir of destination_path
374379
]
375380
mock_isabs.return_value = False
376381
mock_path_join.side_effect = lambda *args: "/".join(args)

0 commit comments

Comments
 (0)