-
-
Notifications
You must be signed in to change notification settings - Fork 19
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
support polygon coordinate list (#19)
- Loading branch information
1 parent
3488058
commit 414f2c4
Showing
14 changed files
with
338 additions
and
83 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,3 @@ | ||
from .lir import lir | ||
from .lir import lir, pt1, pt2 | ||
|
||
__version__ = "0.1.1" | ||
__version__ = "0.2.0" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,19 +1,39 @@ | ||
from .lir_basis import largest_interior_rectangle as lir_basis | ||
from .lir_within_contour import largest_interior_rectangle \ | ||
as lir_within_contour | ||
from .lir_within_polygon import largest_interior_rectangle \ | ||
as lir_within_polygon | ||
|
||
|
||
def lir(grid, contour=None): | ||
def lir(data, contour=None): | ||
""" | ||
Returns the Largest Interior Rectangle of a binary grid. | ||
:param grid: 2D ndarray containing data with `bool` type. | ||
:param contour: (optional) 2D ndarray with shape (n, 2) containing | ||
xy values of a specific contour where the rectangle could start | ||
(in all directions). | ||
Computes the Largest Interior Rectangle. | ||
:param data: Can be | ||
1. a 2D ndarray with shape (n, m) of type boolean. The lir is found within all True cells | ||
2. a 3D ndarray with shape (1, n, 2) with integer xy coordinates of a polygon in which the lir should be found | ||
:param contour: (optional) 2D ndarray with shape (n, 2) containing xy values of a specific contour where the rectangle could start (in all directions). Only needed for case 1. | ||
:return: 1D ndarray with lir specification: x, y, width, height | ||
:rtype: ndarray | ||
""" | ||
if len(data.shape) == 3: | ||
return lir_within_polygon(data) | ||
if contour is None: | ||
return lir_basis(grid) | ||
return lir_basis(data) | ||
else: | ||
return lir_within_contour(grid, contour) | ||
return lir_within_contour(data, contour) | ||
|
||
|
||
def pt1(lir): | ||
""" | ||
Helper function to compute pt1 of OpenCVs rectangle() from a lir | ||
""" | ||
assert lir.shape == (4,) | ||
return (lir[0], lir[1]) | ||
|
||
|
||
def pt2(lir): | ||
""" | ||
Helper function to compute pt2 of OpenCVs rectangle() from a lir | ||
""" | ||
assert lir.shape == (4,) | ||
return (lir[0] + lir[2] - 1, lir[1] + lir[3] - 1) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import numpy as np | ||
|
||
from .lir_within_contour import largest_interior_rectangle as lir_contour | ||
|
||
cv = None # as an optional dependency opencv will only be imported if needed | ||
|
||
|
||
def largest_interior_rectangle(polygon): | ||
check_for_opencv() | ||
origin, mask = create_mask_from_polygon(polygon) | ||
contours, _ = cv.findContours(mask, cv.RETR_TREE, cv.CHAIN_APPROX_NONE) | ||
contour = contours[0][:, 0, :] | ||
mask = mask > 0 | ||
lir = lir_contour(mask, contour) | ||
lir = lir.astype(np.int32) | ||
lir[0:2] = lir[0:2] + origin | ||
return lir | ||
|
||
|
||
def create_mask_from_polygon(polygon): | ||
assert polygon.shape[0] == 1 | ||
assert polygon.shape[1] > 2 | ||
assert polygon.shape[2] == 2 | ||
check_for_opencv() | ||
bbox = cv.boundingRect(polygon) | ||
mask = np.zeros([bbox[3], bbox[2]], dtype=np.uint8) | ||
zero_centered_x = polygon[:, :, 0] - bbox[0] | ||
zero_centered_y = polygon[:, :, 1] - bbox[1] | ||
polygon = np.dstack((zero_centered_x, zero_centered_y)) | ||
cv.fillPoly(mask, polygon, 255) | ||
origin = bbox[0:2] | ||
return origin, mask | ||
|
||
|
||
def check_for_opencv(): | ||
global cv | ||
if cv is None: | ||
try: | ||
import cv2 | ||
cv = cv2 | ||
except Exception: | ||
raise ImportError('Missing optional dependency \'opencv-python\' to compute lir based on polygon. Use pip or conda to install it.') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
import unittest | ||
import os | ||
|
||
import numpy as np | ||
import cv2 as cv | ||
|
||
from .context import lir_basis as lir | ||
|
||
TEST_DIR = os.path.abspath(os.path.dirname(__file__)) | ||
|
||
|
||
class TestLIRbasis(unittest.TestCase): | ||
|
||
def test_lir(self): | ||
|
||
grid = np.array([[0, 0, 1, 0, 0, 0, 0, 0, 0], | ||
[0, 0, 1, 0, 1, 1, 0, 0, 0], | ||
[0, 0, 1, 1, 1, 1, 1, 0, 0], | ||
[0, 0, 1, 1, 1, 1, 1, 1, 0], | ||
[0, 0, 1, 1, 1, 1, 1, 1, 0], | ||
[0, 1, 1, 1, 1, 1, 1, 0, 0], | ||
[0, 0, 1, 1, 1, 1, 0, 0, 0], | ||
[0, 0, 1, 1, 1, 1, 0, 0, 0], | ||
[1, 1, 1, 1, 1, 1, 0, 0, 0], | ||
[1, 1, 0, 0, 0, 1, 1, 1, 1], | ||
[0, 0, 0, 0, 0, 0, 0, 0, 0]]) | ||
grid = grid > 0 | ||
|
||
h = lir.horizontal_adjacency(grid) | ||
v = lir.vertical_adjacency(grid) | ||
span_map = lir.span_map(grid, h, v) | ||
rect = lir.biggest_span_in_span_map(span_map) | ||
rect2 = lir.largest_interior_rectangle(grid) | ||
|
||
np.testing.assert_array_equal(rect, np.array([2, 2, 4, 7])) | ||
np.testing.assert_array_equal(rect, rect2) | ||
|
||
def test_spans(self): | ||
grid = np.array([[1, 1, 1], | ||
[1, 1, 0], | ||
[1, 0, 0], | ||
[1, 0, 0], | ||
[1, 0, 0], | ||
[1, 1, 1]]) | ||
grid = grid > 0 | ||
|
||
h = lir.horizontal_adjacency(grid) | ||
v = lir.vertical_adjacency(grid) | ||
v_vector = lir.v_vector(v, 0, 0) | ||
h_vector = lir.h_vector(h, 0, 0) | ||
spans = lir.spans(h_vector, v_vector) | ||
|
||
np.testing.assert_array_equal(v_vector, np.array([6, 2, 1])) | ||
np.testing.assert_array_equal(h_vector, np.array([3, 2, 1])) | ||
np.testing.assert_array_equal(spans, np.array([[3, 1], | ||
[2, 2], | ||
[1, 6]])) | ||
|
||
def test_vector_size(self): | ||
t0 = np.array([1, 1, 1, 1], dtype=np.uint32) | ||
t1 = np.array([1, 1, 1, 0], dtype=np.uint32) | ||
t2 = np.array([1, 1, 0, 1, 1, 0], dtype=np.uint32) | ||
t3 = np.array([0, 0, 0, 0], dtype=np.uint32) | ||
t4 = np.array([0, 1, 1, 1], dtype=np.uint32) | ||
t5 = np.array([], dtype=np.uint32) | ||
|
||
self.assertEqual(lir.predict_vector_size(t0), 4) | ||
self.assertEqual(lir.predict_vector_size(t1), 3) | ||
self.assertEqual(lir.predict_vector_size(t2), 2) | ||
self.assertEqual(lir.predict_vector_size(t3), 0) | ||
self.assertEqual(lir.predict_vector_size(t4), 0) | ||
self.assertEqual(lir.predict_vector_size(t5), 0) | ||
|
||
def test_img(self): | ||
grid = cv.imread(os.path.join(TEST_DIR, "testdata", "mask.png"), 0) | ||
grid = grid > 0 | ||
rect = lir.largest_interior_rectangle(grid) | ||
np.testing.assert_array_equal(rect, np.array([4, 20, 834, 213])) | ||
|
||
|
||
def starttest(): | ||
unittest.main() | ||
|
||
|
||
if __name__ == "__main__": | ||
starttest() |
Oops, something went wrong.