2023-10-30 13:13:29 -07:00
|
|
|
from unittest.mock import patch
|
|
|
|
|
|
|
|
import cv2
|
2023-10-05 00:41:38 -07:00
|
|
|
import numpy as np
|
|
|
|
import pytest
|
|
|
|
|
2023-10-30 13:13:29 -07:00
|
|
|
from unstructured.partition.utils import xycut
|
2023-10-05 00:41:38 -07:00
|
|
|
|
|
|
|
|
|
|
|
def test_projection_by_bboxes():
|
|
|
|
boxes = np.array([[10, 20, 50, 60], [30, 40, 70, 80]])
|
|
|
|
|
|
|
|
# Test case 1: Horizontal projection
|
2023-10-30 13:13:29 -07:00
|
|
|
result_horizontal = xycut.projection_by_bboxes(boxes, 0)
|
2023-10-05 00:41:38 -07:00
|
|
|
expected_result_horizontal = np.array(
|
|
|
|
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
|
|
|
|
)
|
|
|
|
assert np.array_equal(result_horizontal[:30], expected_result_horizontal)
|
|
|
|
|
|
|
|
# Test case 2: Vertical projection
|
2023-10-30 13:13:29 -07:00
|
|
|
result_vertical = xycut.projection_by_bboxes(boxes, 1)
|
2023-10-05 00:41:38 -07:00
|
|
|
expected_result_vertical = np.array(
|
|
|
|
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
|
|
|
|
)
|
|
|
|
assert np.array_equal(result_vertical[:30], expected_result_vertical)
|
|
|
|
|
|
|
|
|
|
|
|
def test_split_projection_profile():
|
|
|
|
# Test case 1: Sample projection profile with given min_value and min_gap
|
|
|
|
arr_values = np.array([0, 0, 3, 4, 0, 0, 2, 0, 0, 0, 5, 6, 7, 0, 0, 0])
|
|
|
|
min_value = 0
|
|
|
|
min_gap = 1
|
2023-10-30 13:13:29 -07:00
|
|
|
result = xycut.split_projection_profile(arr_values, min_value, min_gap)
|
2023-10-05 00:41:38 -07:00
|
|
|
expected_result = (np.array([2, 6, 10]), np.array([4, 7, 13]))
|
|
|
|
assert np.array_equal(result, expected_result)
|
|
|
|
|
|
|
|
# Test case 2: Another sample projection profile with different parameters
|
|
|
|
arr_values = np.array([0, 2, 0, 0, 0, 3, 0, 0, 4, 5, 6, 0, 0, 0])
|
|
|
|
min_value = 1
|
|
|
|
min_gap = 2
|
2023-10-30 13:13:29 -07:00
|
|
|
result = xycut.split_projection_profile(arr_values, min_value, min_gap)
|
2023-10-05 00:41:38 -07:00
|
|
|
expected_result = (np.array([1, 5, 8]), np.array([2, 6, 11]))
|
|
|
|
assert np.array_equal(result, expected_result)
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
|
|
("recursive_func", "expected"),
|
|
|
|
[
|
2023-10-30 13:13:29 -07:00
|
|
|
(xycut.recursive_xy_cut, [0, 1, 2]),
|
|
|
|
(xycut.recursive_xy_cut_swapped, [0, 2, 1]),
|
2023-10-05 00:41:38 -07:00
|
|
|
],
|
|
|
|
)
|
|
|
|
def test_recursive_xy_cut(recursive_func, expected):
|
|
|
|
boxes = np.array([[0, 0, 20, 20], [200, 0, 230, 30], [0, 40, 50, 50]])
|
|
|
|
indices = np.array([0, 1, 2])
|
|
|
|
res = []
|
|
|
|
recursive_func(boxes, indices, res)
|
|
|
|
assert res == expected
|
2023-10-30 13:13:29 -07:00
|
|
|
|
|
|
|
|
|
|
|
def test_points_to_bbox():
|
|
|
|
# Test a valid case
|
|
|
|
points = [10, 20, 30, 40, 50, 60, 70, 80]
|
|
|
|
result = xycut.points_to_bbox(points)
|
|
|
|
assert result == [10, 20, 70, 80]
|
|
|
|
|
|
|
|
# Test a case where points are unordered
|
|
|
|
points = [30, 40, 10, 20, 70, 80, 50, 60]
|
|
|
|
result = xycut.points_to_bbox(points)
|
|
|
|
assert result == [10, 20, 70, 80]
|
|
|
|
|
|
|
|
# Test a case where all points are negative
|
|
|
|
points = [-10, -20, -30, -40, -50, -60, -70, -80]
|
|
|
|
result = xycut.points_to_bbox(points)
|
|
|
|
assert result == [0, 0, 0, 0]
|
|
|
|
|
|
|
|
# Test a case with invalid number of points
|
|
|
|
with pytest.raises(AssertionError):
|
|
|
|
points = [10, 20, 30, 40, 50, 60] # Missing two points
|
|
|
|
xycut.points_to_bbox(points)
|
|
|
|
|
|
|
|
|
|
|
|
def test_bbox2points():
|
|
|
|
# Test a valid case
|
|
|
|
bbox = [10, 20, 70, 80]
|
|
|
|
result = xycut.bbox2points(bbox)
|
|
|
|
assert result == [10, 20, 70, 20, 70, 80, 10, 80]
|
|
|
|
|
|
|
|
# Test a case where the top and bottom are the same
|
|
|
|
bbox = [10, 20, 70, 20]
|
|
|
|
result = xycut.bbox2points(bbox)
|
|
|
|
assert result == [10, 20, 70, 20, 70, 20, 10, 20]
|
|
|
|
|
|
|
|
# Test a case where left and right are the same
|
|
|
|
bbox = [10, 20, 10, 80]
|
|
|
|
result = xycut.bbox2points(bbox)
|
|
|
|
assert result == [10, 20, 10, 20, 10, 80, 10, 80]
|
|
|
|
|
|
|
|
# Test a case where the bbox is a point (left and right are the same,
|
|
|
|
# top and bottom are the same)
|
|
|
|
bbox = [10, 20, 10, 20]
|
|
|
|
result = xycut.bbox2points(bbox)
|
|
|
|
assert result == [10, 20, 10, 20, 10, 20, 10, 20]
|
|
|
|
|
|
|
|
|
|
|
|
def test_vis_polygon():
|
|
|
|
img = np.ones((200, 200, 3), dtype=np.uint8) * 255
|
|
|
|
points = [(50, 50), (150, 50), (150, 150), (50, 150)]
|
|
|
|
color = (0, 0, 255) # Red color
|
|
|
|
thickness = 2
|
|
|
|
|
|
|
|
result_img = xycut.vis_polygon(img, points, thickness, color)
|
|
|
|
|
|
|
|
# Define the expected image with the square drawn
|
|
|
|
expected_img = np.copy(img)
|
|
|
|
cv2.line(expected_img, points[0], points[1], color, thickness)
|
|
|
|
cv2.line(expected_img, points[1], points[2], color, thickness)
|
|
|
|
cv2.line(expected_img, points[2], points[3], color, thickness)
|
|
|
|
cv2.line(expected_img, points[3], points[0], color, thickness)
|
|
|
|
|
|
|
|
assert np.array_equal(result_img, expected_img)
|
|
|
|
|
|
|
|
|
|
|
|
def test_vis_points():
|
|
|
|
img = np.ones((200, 200, 3), dtype=np.uint8) * 255
|
|
|
|
points = [[10, 20, 30, 20, 30, 40, 10, 40], [50, 60, 70, 60, 70, 80, 50, 80]]
|
|
|
|
texts = ["Label1", "Label2"]
|
|
|
|
color = (0, 200, 0)
|
|
|
|
|
|
|
|
result_img = xycut.vis_points(img, points, texts, color)
|
|
|
|
|
|
|
|
# Check if the resulting image contains the expected shapes and labels
|
|
|
|
expected_img = np.copy(img)
|
|
|
|
|
|
|
|
# Draw polygons and labels for each set of points
|
|
|
|
for i, _points in enumerate(points):
|
|
|
|
xycut.vis_polygon(expected_img, np.array(_points).reshape(-1, 2), thickness=2, color=color)
|
|
|
|
bbox = xycut.points_to_bbox(_points)
|
|
|
|
left, top, right, bottom = bbox
|
|
|
|
cx = (left + right) // 2
|
|
|
|
cy = (top + bottom) // 2
|
|
|
|
txt = texts[i]
|
|
|
|
|
|
|
|
# Draw a filled rectangle for the label background
|
|
|
|
cat_size = cv2.getTextSize(txt, cv2.FONT_HERSHEY_SIMPLEX, 0.5, 2)[0]
|
|
|
|
expected_img = cv2.rectangle(
|
|
|
|
expected_img,
|
|
|
|
(cx - 5 * len(txt), cy - cat_size[1] - 5),
|
|
|
|
(cx - 5 * len(txt) + cat_size[0], cy - 5),
|
|
|
|
color,
|
|
|
|
-1,
|
|
|
|
)
|
|
|
|
|
|
|
|
# Draw the label text
|
|
|
|
expected_img = cv2.putText(
|
|
|
|
expected_img,
|
|
|
|
txt,
|
|
|
|
(cx - 5 * len(txt), cy - 5),
|
|
|
|
cv2.FONT_HERSHEY_SIMPLEX,
|
|
|
|
0.5,
|
|
|
|
(255, 255, 255),
|
|
|
|
thickness=1,
|
|
|
|
lineType=cv2.LINE_AA,
|
|
|
|
)
|
|
|
|
|
|
|
|
assert np.array_equal(result_img, expected_img)
|
|
|
|
|
|
|
|
|
|
|
|
def test_vis_polygons_with_index():
|
|
|
|
img = np.ones((200, 200, 3), dtype=np.uint8) * 255
|
|
|
|
points = [[10, 20, 30, 20, 30, 40, 10, 40], [50, 60, 70, 60, 70, 80, 50, 80]]
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
"unstructured.partition.utils.xycut.vis_points", return_value=img
|
|
|
|
) as mock_vis_points:
|
|
|
|
result_img = xycut.vis_polygons_with_index(img, points)
|
|
|
|
|
|
|
|
# Check if vis_points was called with the correct arguments
|
|
|
|
mock_vis_points.assert_called_once()
|
|
|
|
|
|
|
|
assert np.array_equal(result_img, img)
|