Skip to content

Commit 5f9611f

Browse files
authored
Add hflip and vflip (#30)
* Added doctring to from_float * Added hflip * Added benchamrk * More clear benchmark * cleanup
1 parent bbe7076 commit 5f9611f

19 files changed

+527
-18
lines changed

.pre-commit-config.yaml

+2-2
Original file line numberDiff line numberDiff line change
@@ -53,13 +53,13 @@ repos:
5353
# hooks:
5454
# - id: markdownlint
5555
- repo: https://github.com/tox-dev/pyproject-fmt
56-
rev: "2.2.3"
56+
rev: "2.2.4"
5757
hooks:
5858
- id: pyproject-fmt
5959
additional_dependencies: ["tomli"]
6060
- repo: https://github.com/astral-sh/ruff-pre-commit
6161
# Ruff version.
62-
rev: v0.6.4
62+
rev: v0.6.5
6363
hooks:
6464
# Run the linter.
6565
- id: ruff

albucore/__init__.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1-
__version__ = "0.0.15"
1+
__version__ = "0.0.16"
22

33
from .functions import *
4+
from .utils import *

albucore/functions.py

+59-10
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
ValueType,
1414
clip,
1515
clipped,
16+
contiguous,
1617
convert_value,
1718
get_max_value,
1819
get_num_channels,
@@ -574,16 +575,16 @@ def to_float(img: np.ndarray, max_value: float | None = None) -> np.ndarray:
574575
return to_float_numpy(img, max_value)
575576

576577

577-
def from_float_numpy(img: np.ndarray, dtype: np.dtype, max_value: float | None = None) -> np.ndarray:
578+
def from_float_numpy(img: np.ndarray, target_dtype: np.dtype, max_value: float | None = None) -> np.ndarray:
578579
if max_value is None:
579-
max_value = get_max_value(dtype)
580-
return clip(np.rint(img * max_value), dtype)
580+
max_value = get_max_value(target_dtype)
581+
return clip(np.rint(img * max_value), target_dtype)
581582

582583

583584
@preserve_channel_dim
584-
def from_float_opencv(img: np.ndarray, dtype: np.dtype, max_value: float | None = None) -> np.ndarray:
585+
def from_float_opencv(img: np.ndarray, target_dtype: np.dtype, max_value: float | None = None) -> np.ndarray:
585586
if max_value is None:
586-
max_value = get_max_value(dtype)
587+
max_value = get_max_value(target_dtype)
587588

588589
img_float = img.astype(np.float32)
589590

@@ -592,14 +593,62 @@ def from_float_opencv(img: np.ndarray, dtype: np.dtype, max_value: float | None
592593
if num_channels > MAX_OPENCV_WORKING_CHANNELS:
593594
# For images with more than 4 channels, create a full-sized multiplier
594595
max_value_array = np.full_like(img_float, max_value)
595-
return clip(np.rint(cv2.multiply(img_float, max_value_array)), dtype)
596+
return clip(np.rint(cv2.multiply(img_float, max_value_array)), target_dtype)
596597

597598
# For images with 4 or fewer channels, use scalar multiplication
598-
return clip(np.rint(img * max_value), dtype)
599+
return clip(np.rint(img * max_value), target_dtype)
599600

600601

601-
def from_float(img: np.ndarray, dtype: np.dtype, max_value: float | None = None) -> np.ndarray:
602+
def from_float(img: np.ndarray, target_dtype: np.dtype, max_value: float | None = None) -> np.ndarray:
603+
"""Convert a floating-point image to the specified target data type.
604+
605+
This function converts an input floating-point image to the specified target data type,
606+
scaling the values appropriately based on the max_value parameter or the maximum value
607+
of the target data type.
608+
609+
Args:
610+
img (np.ndarray): Input floating-point image array.
611+
target_dtype (np.dtype): Target numpy data type for the output image.
612+
max_value (float | None, optional): Maximum value to use for scaling. If None,
613+
the maximum value of the target data type will be used. Defaults to None.
614+
615+
Returns:
616+
np.ndarray: Image converted to the target data type.
617+
618+
Notes:
619+
- If the input image is of type float32, the function uses OpenCV for faster processing.
620+
- For other input types, it falls back to a numpy-based implementation.
621+
- The function clips values to ensure they fit within the range of the target data type.
622+
"""
602623
if img.dtype == np.float32:
603-
return from_float_opencv(img, dtype, max_value)
624+
return from_float_opencv(img, target_dtype, max_value)
625+
626+
return from_float_numpy(img, target_dtype, max_value)
627+
628+
629+
@contiguous
630+
def hflip_numpy(img: np.ndarray) -> np.ndarray:
631+
return img[:, ::-1, ...]
632+
633+
634+
@preserve_channel_dim
635+
def hflip_cv2(img: np.ndarray) -> np.ndarray:
636+
return cv2.flip(img, 1)
637+
638+
639+
def hflip(img: np.ndarray) -> np.ndarray:
640+
return hflip_cv2(img)
641+
642+
643+
@preserve_channel_dim
644+
def vflip_cv2(img: np.ndarray) -> np.ndarray:
645+
return cv2.flip(img, 0)
646+
647+
648+
@contiguous
649+
def vflip_numpy(img: np.ndarray) -> np.ndarray:
650+
return img[::-1, ...]
651+
604652

605-
return from_float_numpy(img, dtype, max_value)
653+
def vflip(img: np.ndarray) -> np.ndarray:
654+
return vflip_cv2(img)

benchmark.sh

+9-2
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,20 @@ data_dir="$1"
1313
channels=(1 3 5)
1414

1515
# Define the array of image types
16-
types=("uint8" "float32")
16+
types=("float32" "uint8")
1717

1818
# Loop over each channel
1919
for ch in "${channels[@]}"; do
2020
# Nested loop over each image type
2121
for type in "${types[@]}"; do
2222
# Command to run your program, using the provided data directory
23-
python -m benchmark.benchmark --num_channels $ch --img_type $type --markdown -n 2000 --show-std -r 5 -d "$data_dir"
23+
python -m benchmark.benchmark \
24+
--num_channels $ch \
25+
--img_type $type \
26+
--markdown \
27+
-n 1000 \
28+
--show-std \
29+
-r 10 \
30+
-d "$data_dir"
2431
done
2532
done

benchmark/benchmark.py

+37-1
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ def __str__(self) -> str:
9191
return self.__class__.__name__
9292

9393
def albucore(self, img: np.ndarray) -> np.ndarray:
94-
return self.albucore_transform(img)
94+
return clip(self.albucore_transform(img), img.dtype)
9595

9696
def opencv(self, img: np.ndarray) -> np.ndarray:
9797
return clip(self.opencv_transform(img), img.dtype)
@@ -510,6 +510,40 @@ def torchvision_transform(self, img: torch.Tensor) -> torch.Tensor:
510510
return (img * MAX_VALUES_BY_DTYPE[self.dtype]).to(torch.uint8)
511511

512512

513+
class HorizontalFlip(BenchmarkTest):
514+
def __init__(self, num_channels: int) -> None:
515+
super().__init__(num_channels)
516+
517+
def albucore_transform(self, img: np.ndarray) -> np.ndarray:
518+
return albucore.hflip(img)
519+
520+
def numpy_transform(self, img: np.ndarray) -> np.ndarray:
521+
return albucore.hflip_numpy(img)
522+
523+
def opencv_transform(self, img: np.ndarray) -> np.ndarray:
524+
return albucore.hflip_cv2(img)
525+
526+
def torchvision_transform(self, img: torch.Tensor) -> torch.Tensor:
527+
return torchf.hflip(img)
528+
529+
530+
class VerticalFlip(BenchmarkTest):
531+
def __init__(self, num_channels: int) -> None:
532+
super().__init__(num_channels)
533+
534+
def albucore_transform(self, img: np.ndarray) -> np.ndarray:
535+
return albucore.vflip(img)
536+
537+
def numpy_transform(self, img: np.ndarray) -> np.ndarray:
538+
return albucore.vflip_numpy(img)
539+
540+
def opencv_transform(self, img: np.ndarray) -> np.ndarray:
541+
return albucore.vflip_cv2(img)
542+
543+
def torchvision_transform(self, img: torch.Tensor) -> torch.Tensor:
544+
return torchf.vflip(img)
545+
546+
513547
def get_images_from_dir(data_dir: Path, num_images: int, num_channels: int, dtype: str) -> list[np.ndarray]:
514548
image_paths = list(data_dir.expanduser().absolute().glob("*.*"))[:num_images]
515549
images = []
@@ -664,6 +698,8 @@ def main() -> None:
664698
MultiplyAdd,
665699
ToFloat,
666700
FromFloat,
701+
HorizontalFlip,
702+
VerticalFlip,
667703
]
668704

669705
args = parse_args()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Benchmark Results: HorizontalFlip
2+
3+
Number of images: 1000
4+
5+
## CPU Information
6+
7+
- CPU: Apple M1 Pro
8+
- Frequency: Current: 3228.00 MHz, Min: 600.00 MHz, Max: 3228.00 MHz
9+
- Physical cores: 10
10+
- Total cores: 10
11+
12+
## Package Versions
13+
14+
| Python | albucore | opencv-python-headless | numpy | torchvision |
15+
|:-----------------------------------------|:-----------|:-------------------------|:--------|:--------------|
16+
| 3.8.19 (default, Mar 20 2024, 15:27:52) | 0.0.14 | 4.9.0.80 | 1.24.4 | 0.19.1 |
17+
| [Clang 14.0.6 ] | | | | |
18+
19+
## Performance (images/second)
20+
21+
Raw data:
22+
albucore lut opencv numpy torchvision
23+
HorizontalFlip 7655 ± 491 nan 4126 ± 239 3476 ± 119 5027 ± 318
24+
25+
| | albucore | lut | opencv | numpy | torchvision |
26+
|:---------------|:-----------|------:|:-----------|:-----------|:--------------|
27+
| HorizontalFlip | 7655 ± 491 | nan | 4126 ± 239 | 3476 ± 119 | 5027 ± 318 |
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Benchmark Results: VerticalFlip
2+
3+
Number of images: 1000
4+
5+
## CPU Information
6+
7+
- CPU: Apple M1 Pro
8+
- Frequency: Current: 3228.00 MHz, Min: 600.00 MHz, Max: 3228.00 MHz
9+
- Physical cores: 10
10+
- Total cores: 10
11+
12+
## Package Versions
13+
14+
| Python | albucore | opencv-python-headless | numpy | torchvision |
15+
|:-----------------------------------------|:-----------|:-------------------------|:--------|:--------------|
16+
| 3.8.19 (default, Mar 20 2024, 15:27:52) | 0.0.14 | 4.9.0.80 | 1.24.4 | 0.19.1 |
17+
| [Clang 14.0.6 ] | | | | |
18+
19+
## Performance (images/second)
20+
21+
Raw data:
22+
albucore lut opencv numpy torchvision
23+
VerticalFlip 2602 ± 600 nan 1800 ± 527 2276 ± 884 3585 ± 1422
24+
25+
| | albucore | lut | opencv | numpy | torchvision |
26+
|:-------------|:-----------|------:|:-----------|:-----------|:--------------|
27+
| VerticalFlip | 2602 ± 600 | nan | 1800 ± 527 | 2276 ± 884 | 3585 ± 1422 |
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Benchmark Results: HorizontalFlip
2+
3+
Number of images: 1000
4+
5+
## CPU Information
6+
7+
- CPU: Apple M1 Pro
8+
- Frequency: Current: 3228.00 MHz, Min: 600.00 MHz, Max: 3228.00 MHz
9+
- Physical cores: 10
10+
- Total cores: 10
11+
12+
## Package Versions
13+
14+
| Python | albucore | opencv-python-headless | numpy | torchvision |
15+
|:-----------------------------------------|:-----------|:-------------------------|:--------|:--------------|
16+
| 3.8.19 (default, Mar 20 2024, 15:27:52) | 0.0.14 | 4.9.0.80 | 1.24.4 | 0.19.1 |
17+
| [Clang 14.0.6 ] | | | | |
18+
19+
## Performance (images/second)
20+
21+
Raw data:
22+
albucore lut opencv numpy torchvision
23+
HorizontalFlip 885 ± 424 nan 777 ± 249 253 ± 32 337 ± 104
24+
25+
| | albucore | lut | opencv | numpy | torchvision |
26+
|:---------------|:-----------|------:|:----------|:---------|:--------------|
27+
| HorizontalFlip | 885 ± 424 | nan | 777 ± 249 | 253 ± 32 | 337 ± 104 |
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Benchmark Results: VerticalFlip
2+
3+
Number of images: 1000
4+
5+
## CPU Information
6+
7+
- CPU: Apple M1 Pro
8+
- Frequency: Current: 3228.00 MHz, Min: 600.00 MHz, Max: 3228.00 MHz
9+
- Physical cores: 10
10+
- Total cores: 10
11+
12+
## Package Versions
13+
14+
| Python | albucore | opencv-python-headless | numpy | torchvision |
15+
|:-----------------------------------------|:-----------|:-------------------------|:--------|:--------------|
16+
| 3.8.19 (default, Mar 20 2024, 15:27:52) | 0.0.14 | 4.9.0.80 | 1.24.4 | 0.19.1 |
17+
| [Clang 14.0.6 ] | | | | |
18+
19+
## Performance (images/second)
20+
21+
Raw data:
22+
albucore lut opencv numpy torchvision
23+
VerticalFlip 432 ± 24 nan 364 ± 35 419 ± 56 480 ± 195
24+
25+
| | albucore | lut | opencv | numpy | torchvision |
26+
|:-------------|:-----------|------:|:---------|:---------|:--------------|
27+
| VerticalFlip | 432 ± 24 | nan | 364 ± 35 | 419 ± 56 | 480 ± 195 |
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Benchmark Results: HorizontalFlip
2+
3+
Number of images: 1000
4+
5+
## CPU Information
6+
7+
- CPU: Apple M1 Pro
8+
- Frequency: Current: 3228.00 MHz, Min: 600.00 MHz, Max: 3228.00 MHz
9+
- Physical cores: 10
10+
- Total cores: 10
11+
12+
## Package Versions
13+
14+
| Python | albucore | opencv-python-headless | numpy | torchvision |
15+
|:-----------------------------------------|:-----------|:-------------------------|:--------|:--------------|
16+
| 3.8.19 (default, Mar 20 2024, 15:27:52) | 0.0.14 | 4.9.0.80 | 1.24.4 | 0.19.1 |
17+
| [Clang 14.0.6 ] | | | | |
18+
19+
## Performance (images/second)
20+
21+
Raw data:
22+
albucore lut opencv numpy torchvision
23+
HorizontalFlip 52 ± 15 nan 179 ± 20 136 ± 40 35 ± 3
24+
25+
| | albucore | lut | opencv | numpy | torchvision |
26+
|:---------------|:-----------|------:|:---------|:---------|:--------------|
27+
| HorizontalFlip | 52 ± 15 | nan | 179 ± 20 | 136 ± 40 | 35 ± 3 |
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Benchmark Results: VerticalFlip
2+
3+
Number of images: 1000
4+
5+
## CPU Information
6+
7+
- CPU: Apple M1 Pro
8+
- Frequency: Current: 3228.00 MHz, Min: 600.00 MHz, Max: 3228.00 MHz
9+
- Physical cores: 10
10+
- Total cores: 10
11+
12+
## Package Versions
13+
14+
| Python | albucore | opencv-python-headless | numpy | torchvision |
15+
|:-----------------------------------------|:-----------|:-------------------------|:--------|:--------------|
16+
| 3.8.19 (default, Mar 20 2024, 15:27:52) | 0.0.14 | 4.9.0.80 | 1.24.4 | 0.19.1 |
17+
| [Clang 14.0.6 ] | | | | |
18+
19+
## Performance (images/second)
20+
21+
Raw data:
22+
albucore lut opencv numpy torchvision
23+
VerticalFlip 161 ± 56 nan 227 ± 11 226 ± 20 44 ± 8
24+
25+
| | albucore | lut | opencv | numpy | torchvision |
26+
|:-------------|:-----------|------:|:---------|:---------|:--------------|
27+
| VerticalFlip | 161 ± 56 | nan | 227 ± 11 | 226 ± 20 | 44 ± 8 |
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Benchmark Results: HorizontalFlip
2+
3+
Number of images: 1000
4+
5+
## CPU Information
6+
7+
- CPU: Apple M1 Pro
8+
- Frequency: Current: 3228.00 MHz, Min: 600.00 MHz, Max: 3228.00 MHz
9+
- Physical cores: 10
10+
- Total cores: 10
11+
12+
## Package Versions
13+
14+
| Python | albucore | opencv-python-headless | numpy | torchvision |
15+
|:-----------------------------------------|:-----------|:-------------------------|:--------|:--------------|
16+
| 3.8.19 (default, Mar 20 2024, 15:27:52) | 0.0.14 | 4.9.0.80 | 1.24.4 | 0.19.1 |
17+
| [Clang 14.0.6 ] | | | | |
18+
19+
## Performance (images/second)
20+
21+
Raw data:
22+
albucore lut opencv numpy torchvision
23+
HorizontalFlip 25404 ± 3064 nan 13977 ± 1410 5912 ± 312 7336 ± 366
24+
25+
| | albucore | lut | opencv | numpy | torchvision |
26+
|:---------------|:-------------|------:|:-------------|:-----------|:--------------|
27+
| HorizontalFlip | 25404 ± 3064 | nan | 13977 ± 1410 | 5912 ± 312 | 7336 ± 366 |

0 commit comments

Comments
 (0)