Skip to content

Commit

Permalink
✨ Add scaled_bbox_centroid and add tests.
Browse files Browse the repository at this point in the history
  • Loading branch information
lanzani committed Aug 2, 2024
1 parent 7d13844 commit 6195b64
Show file tree
Hide file tree
Showing 8 changed files with 269 additions and 129 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -288,3 +288,5 @@ pyrightconfig.json

# End of https://www.toptal.com/developers/gitignore/api/pycharm,python
/.python-version

*.png
25 changes: 23 additions & 2 deletions common_image_tools/operation.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,7 @@ def scale_bboxes(bboxes: list[tuple], scale_factor: float) -> list[tuple]:


def bbox_centroid(bbox: tuple[int, int, int, int]) -> tuple[int, int]:
"""
Calculate the centroid coordinates of a bounding box.
"""Calculate the centroid coordinates of a bounding box.
Parameters:
bbox (tuple): A tuple representing the bounding box in the format (x, y, width, height).
Expand All @@ -83,3 +82,25 @@ def bbox_centroid(bbox: tuple[int, int, int, int]) -> tuple[int, int]:
center_x = x + (w / 2)
center_y = y + (h / 2)
return int(center_x), int(center_y)


def scaled_bbox_centroid(image: np.ndarray, bbox: tuple[float, float, float, float]) -> tuple[int, int]:
"""Calculate the centroid coordinates of a bounding box and scale them to the image size.
Parameters:
image (numpy.ndarray): The image to get the shape of. (To scale the bounding box)
bbox (tuple): A tuple representing the bounding box in the format (x, y, width, height).
Returns:
tuple: A tuple containing the coordinates of the centroid as integers (center_x, center_y).
"""
x, y, w, h = bbox

x_scaled = int(round(x * image.shape[1]))
y_scaled = int(round(y * image.shape[0]))
w_scaled = int(round(w * image.shape[1]))
h_scaled = int(round(h * image.shape[0]))

center_x = x_scaled + (w_scaled / 2)
center_y = y_scaled + (h_scaled / 2)
return int(center_x), int(center_y)
15 changes: 14 additions & 1 deletion poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ opencv-python = "^4.8.0.0"
color-transfer = "^0.1"
scikit-image = "^0.21.0"
loguru = "^0.7.0"
#dlib = { version = "19.24.2", optional = true }
dlib = { version = "19.24.2", optional = true }


[tool.poetry.group.dev.dependencies]
Expand All @@ -27,8 +27,8 @@ mypy = "^1.9.0"
pre-commit = "^3.8.0"
ruff = "^0.4.0"

#[tool.poetry.extras]
#dlib = ["dlib"]
[tool.poetry.extras]
dlib = ["dlib"]

[tool.ruff]
line-length = 120
Expand Down
2 changes: 1 addition & 1 deletion reports/coverage/coverage-badge.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
218 changes: 109 additions & 109 deletions tests/test_conversion.py
Original file line number Diff line number Diff line change
@@ -1,110 +1,110 @@
# -*- coding: utf-8 -*-
# import pytest
# import numpy as np
# from PIL import Image
# import cv2
# import dlib
# from unittest.mock import Mock, patch
# from common_image_tools.conversion import tuple_to_rect, rect_to_tuple, pil_to_cv2, cv2_to_pil
#
#
# class TestTupleToRect:
# @pytest.mark.parametrize(
# "bbox, expected_rect",
# [
# ((0, 0, 10, 10), dlib.rectangle(0, 0, 10, 10)),
# ((-5, -5, 10, 10), dlib.rectangle(-5, -5, 5, 5)),
# ((100, 200, 30, 40), dlib.rectangle(100, 200, 130, 240)),
# ],
# )
# def test_valid_bboxes(self, bbox, expected_rect):
# rect = tuple_to_rect(bbox)
# assert rect == expected_rect
#
#
# class TestRectToTuple:
# @pytest.mark.parametrize(
# "rect, expected_tuple",
# [
# (dlib.rectangle(0, 0, 10, 10), (0, 0, 10, 10)), # Test case 1
# (dlib.rectangle(-5, -5, 5, 5), (-5, -5, 10, 10)), # Test case 2
# (dlib.rectangle(100, 200, 130, 240), (100, 200, 30, 40)), # Test case 3
# # Add more test cases for other scenarios
# ],
# )
# def test_rect_to_tuple(self, rect, expected_tuple):
# assert rect_to_tuple(rect) == expected_tuple
#
#
# # Test pil_to_cv2 function
# def test_pil_to_cv2_rgb():
# mock_pil_image = Mock(spec=Image.Image)
# mock_np_array = np.array([[[1, 2, 3]]])
#
# with patch("numpy.array", return_value=mock_np_array):
# with patch("cv2.cvtColor", return_value="cv2_image") as mock_cvtColor:
# result = pil_to_cv2(mock_pil_image)
#
# assert result == "cv2_image"
# mock_cvtColor.assert_called_once_with(mock_np_array, cv2.COLOR_RGB2BGR)
#
#
# def test_pil_to_cv2_rgba():
# mock_pil_image = Mock(spec=Image.Image)
# mock_np_array = np.array([[[1, 2, 3, 4]]])
#
# with patch("numpy.array", return_value=mock_np_array):
# with patch("cv2.cvtColor", return_value="cv2_image") as mock_cvtColor:
# result = pil_to_cv2(mock_pil_image)
#
# assert result == "cv2_image"
# mock_cvtColor.assert_called_once_with(mock_np_array, cv2.COLOR_RGBA2BGRA)
#
#
# # Test cv2_to_pil function
# def test_cv2_to_pil_rgb():
# mock_cv2_image = np.array([[[1, 2, 3]]])
#
# with patch("cv2.cvtColor", return_value="rgb_image") as mock_cvtColor:
# with patch("PIL.Image.fromarray", return_value="pil_image") as mock_fromarray:
# result = cv2_to_pil(mock_cv2_image)
#
# assert result == "pil_image"
# mock_cvtColor.assert_called_once_with(mock_cv2_image, cv2.COLOR_BGR2RGB)
# mock_fromarray.assert_called_once_with("rgb_image")
#
#
# def test_cv2_to_pil_rgba():
# mock_cv2_image = np.array([[[1, 2, 3, 4]]])
#
# with patch("cv2.cvtColor", return_value="rgba_image") as mock_cvtColor:
# with patch("PIL.Image.fromarray", return_value="pil_image") as mock_fromarray:
# result = cv2_to_pil(mock_cv2_image)
#
# assert result == "pil_image"
# mock_cvtColor.assert_called_once_with(mock_cv2_image, cv2.COLOR_BGRA2RGBA)
# mock_fromarray.assert_called_once_with("rgba_image")
#
#
# # Test rect_to_tuple function
# def test_rect_to_tuple():
# mock_rect = Mock(spec=dlib.rectangle)
# mock_rect.left.return_value = 10
# mock_rect.top.return_value = 20
# mock_rect.right.return_value = 30
# mock_rect.bottom.return_value = 50
#
# result = rect_to_tuple(mock_rect)
#
# assert result == (10, 20, 20, 30)
#
#
# # Test tuple_to_rect function
# def test_tuple_to_rect():
# bbox = (10, 20, 30, 40)
#
# with patch("dlib.rectangle", return_value="dlib_rectangle") as mock_rectangle:
# result = tuple_to_rect(bbox)
#
# assert result == "dlib_rectangle"
# mock_rectangle.assert_called_once_with(10, 20, 40, 60)
import pytest
import numpy as np
from PIL import Image
import cv2
import dlib
from unittest.mock import Mock, patch
from common_image_tools.conversion import tuple_to_rect, rect_to_tuple, pil_to_cv2, cv2_to_pil


class TestTupleToRect:
@pytest.mark.parametrize(
"bbox, expected_rect",
[
((0, 0, 10, 10), dlib.rectangle(0, 0, 10, 10)),
((-5, -5, 10, 10), dlib.rectangle(-5, -5, 5, 5)),
((100, 200, 30, 40), dlib.rectangle(100, 200, 130, 240)),
],
)
def test_valid_bboxes(self, bbox, expected_rect):
rect = tuple_to_rect(bbox)
assert rect == expected_rect


class TestRectToTuple:
@pytest.mark.parametrize(
"rect, expected_tuple",
[
(dlib.rectangle(0, 0, 10, 10), (0, 0, 10, 10)), # Test case 1
(dlib.rectangle(-5, -5, 5, 5), (-5, -5, 10, 10)), # Test case 2
(dlib.rectangle(100, 200, 130, 240), (100, 200, 30, 40)), # Test case 3
# Add more test cases for other scenarios
],
)
def test_rect_to_tuple(self, rect, expected_tuple):
assert rect_to_tuple(rect) == expected_tuple


# Test pil_to_cv2 function
def test_pil_to_cv2_rgb():
mock_pil_image = Mock(spec=Image.Image)
mock_np_array = np.array([[[1, 2, 3]]])

with patch("numpy.array", return_value=mock_np_array):
with patch("cv2.cvtColor", return_value="cv2_image") as mock_cvtColor:
result = pil_to_cv2(mock_pil_image)

assert result == "cv2_image"
mock_cvtColor.assert_called_once_with(mock_np_array, cv2.COLOR_RGB2BGR)


def test_pil_to_cv2_rgba():
mock_pil_image = Mock(spec=Image.Image)
mock_np_array = np.array([[[1, 2, 3, 4]]])

with patch("numpy.array", return_value=mock_np_array):
with patch("cv2.cvtColor", return_value="cv2_image") as mock_cvtColor:
result = pil_to_cv2(mock_pil_image)

assert result == "cv2_image"
mock_cvtColor.assert_called_once_with(mock_np_array, cv2.COLOR_RGBA2BGRA)


# Test cv2_to_pil function
def test_cv2_to_pil_rgb():
mock_cv2_image = np.array([[[1, 2, 3]]])

with patch("cv2.cvtColor", return_value="rgb_image") as mock_cvtColor:
with patch("PIL.Image.fromarray", return_value="pil_image") as mock_fromarray:
result = cv2_to_pil(mock_cv2_image)

assert result == "pil_image"
mock_cvtColor.assert_called_once_with(mock_cv2_image, cv2.COLOR_BGR2RGB)
mock_fromarray.assert_called_once_with("rgb_image")


def test_cv2_to_pil_rgba():
mock_cv2_image = np.array([[[1, 2, 3, 4]]])

with patch("cv2.cvtColor", return_value="rgba_image") as mock_cvtColor:
with patch("PIL.Image.fromarray", return_value="pil_image") as mock_fromarray:
result = cv2_to_pil(mock_cv2_image)

assert result == "pil_image"
mock_cvtColor.assert_called_once_with(mock_cv2_image, cv2.COLOR_BGRA2RGBA)
mock_fromarray.assert_called_once_with("rgba_image")


# Test rect_to_tuple function
def test_rect_to_tuple():
mock_rect = Mock(spec=dlib.rectangle)
mock_rect.left.return_value = 10
mock_rect.top.return_value = 20
mock_rect.right.return_value = 30
mock_rect.bottom.return_value = 50

result = rect_to_tuple(mock_rect)

assert result == (10, 20, 20, 30)


# Test tuple_to_rect function
def test_tuple_to_rect():
bbox = (10, 20, 30, 40)

with patch("dlib.rectangle", return_value="dlib_rectangle") as mock_rectangle:
result = tuple_to_rect(bbox)

assert result == "dlib_rectangle"
mock_rectangle.assert_called_once_with(10, 20, 40, 60)
Loading

0 comments on commit 6195b64

Please sign in to comment.