118 lines
2.9 KiB
Python
118 lines
2.9 KiB
Python
# SPDX-License-Identifier: MIT
|
|
# Copyright (c) 2019 Akumatic
|
|
|
|
import cv2, imutils, numpy
|
|
from . import utils
|
|
|
|
######################
|
|
# Contour operations #
|
|
######################
|
|
|
|
def find_contours (
|
|
image: numpy.ndarray,
|
|
mode: int = cv2.RETR_LIST,
|
|
method: int = cv2.CHAIN_APPROX_SIMPLE
|
|
) -> list:
|
|
""" Find all contours of the filtered image
|
|
|
|
Args:
|
|
image (ndarray):
|
|
the filtered image
|
|
|
|
Returns:
|
|
A list containing contour data
|
|
"""
|
|
cnts = cv2.findContours(image.copy(), mode, method)
|
|
return imutils.grab_contours(cnts)
|
|
|
|
def find_boxes (
|
|
contours: list,
|
|
thres_area: int = 500,
|
|
pad_ratio: float = 0.05
|
|
) -> (list, list):
|
|
""" Find contours that resemble a box
|
|
|
|
Args:
|
|
contours (list):
|
|
a list containing contour data
|
|
|
|
Returns:
|
|
A list containing the box contours
|
|
"""
|
|
boxes = list()
|
|
for c in contours:
|
|
area = cv2.contourArea(c)
|
|
perimeter = cv2.arcLength(c, True)
|
|
shape_factor = utils.circularity(area, perimeter)
|
|
|
|
if 0.7 < shape_factor < 0.85 and area >= thres_area:
|
|
boxes.append(c)
|
|
|
|
return boxes
|
|
|
|
def find_center (
|
|
contours: list
|
|
) -> list:
|
|
""" Find the center coordinates of all given contours.
|
|
|
|
Args:
|
|
contours (list):
|
|
A list containing contour data
|
|
|
|
Returns:
|
|
A list containing the center coordinates and the contour as tuples
|
|
(x, y, contour).
|
|
"""
|
|
centers = []
|
|
for contour in contours:
|
|
m = cv2.moments(contour)
|
|
try:
|
|
x = int(m["m10"] / m["m00"])
|
|
y = int(m["m01"] / m["m00"])
|
|
centers.append((x, y, contour))
|
|
except ZeroDivisionError:
|
|
pass
|
|
return centers
|
|
|
|
def filter_centers (
|
|
coords: list,
|
|
radius: int
|
|
):
|
|
""" Removes all but one entry in circles given by coordinates and radius
|
|
|
|
Args:
|
|
coords (list):
|
|
a list containing tuples of coordinates (x, y)
|
|
radius (float):
|
|
the radius around a center where no other center should be
|
|
"""
|
|
a = 0
|
|
|
|
while a < len(coords):
|
|
b = a + 1
|
|
while b < len(coords):
|
|
if utils.distance(coords[a][:2], coords[b][:2]) <= radius:
|
|
del coords[b]
|
|
else:
|
|
b += 1
|
|
a += 1
|
|
|
|
def dist_center_topleft (
|
|
contour: numpy.ndarray,
|
|
center: tuple
|
|
) -> float:
|
|
""" Calculates the distance from the center of a given contour to it's
|
|
top left corner
|
|
|
|
Args:
|
|
contour (ndarray):
|
|
The contour data
|
|
center (tuple):
|
|
A tuple containing the center coordinates (x, y)
|
|
|
|
Returns:
|
|
A float with the distance from center to the top left corner as value
|
|
"""
|
|
x, y, _, _ = cv2.boundingRect(contour)
|
|
return utils.distance((x, y), center[:2])
|