'''
Helper functions and classes for contour finding, drawing, analysis
'''
import numpy as np
import cv2
from . import colors as iv_colors
[docs]class Contour:
'''
Various parameters related to a contour
'''
def __init__(self, contour):
self._contour = contour
self._moments = cv2.moments(contour)
[docs] def moments(self):
'''Returns all the moments for a contour'''
return self._moments
[docs] def centroid(self):
'''Returns the centroid of a contour'''
moments = self._moments
c_x = int(moments['m10']/moments['m00'])
c_y = int(moments['m01']/moments['m00'])
return (c_x, c_y)
[docs] def area(self):
'''Returns the area of the contour'''
return cv2.contourArea(self._contour)
[docs] def perimeter(self):
'''Returns the perimeter of the contour'''
return cv2.arcLength(self._contour, True)
[docs] def approximate_polygon(self, perimeter_gap_factor=0.1):
'''Returns an approximate shape using the Douglas-Peucker algorithm'''
epsilon = perimeter_gap_factor * self.perimeter()
return cv2.approxPolyDP(self._contour, epsilon, True)
[docs] def is_convex(self):
'''Returns if the contour is convex'''
return cv2.isContourConvex(self._contour)
[docs] def convex_hull_points(self, clockwise=False):
'''Returns the points which form the convex hull of a contour
using the Sklansky's algorithm'''
return cv2.convexHull(self._contour, clockwise=clockwise)
[docs] def convex_hull_indices(self, clockwise=False):
'''Returns the indices of the points which form the convex hull of a contour
using the Sklansky's algorithm'''
return cv2.convexHull(self._contour, clockwise=clockwise, returnPoints=False)
[docs] def simple_bounding_box(self):
'''Returns the bounding box of the contour which is straight rectangle
without considering the orientation of object'''
return cv2.boundingRect(self._contour)
[docs] def best_fit_bounding_box(self):
'''Returns the rotated bounding box considering the orientation of object'''
min_rect = cv2.minAreaRect(self._contour)
box = cv2.boxPoints(min_rect)
box = np.intp(box)
return box
[docs] def best_fit_circle(self):
'''Returns the minimum enclosing circle around the contour'''
(c_x, c_y), radius = cv2.minEnclosingCircle(self._contour)
center = (c_x, c_y)
return center, radius
[docs] def best_fit_ellipse(self):
'''Returns the best fitting ellipse around the contour'''
ellipse = cv2.fitEllipse(self._contour)
return ellipse
[docs] def best_fit_line(self):
'''Returns the best fitting line around the contour'''
(v_x, v_y, x_0, y_0) = cv2.fitLine(
self._contour, cv2.DIST_L2, 0, 0.01, 0.01)
unit_vector = (v_x, v_y)
point = (x_0, y_0)
return unit_vector, point
[docs]def find_external_contours(image, method=cv2.CHAIN_APPROX_SIMPLE):
'''Finds the external outer contours in a given (grayscale) image'''
result = cv2.findContours(image, mode=cv2.RETR_EXTERNAL,
method=method)
contours = result[1]
return [Contour(contour) for contour in contours]
[docs]class Contours:
'''Helper class to work with a list of contours'''
def __init__(self, contours):
self._contours = contours
[docs] def draw_centroids(self, image, color=iv_colors.BLACK, marker_size=10, thickness=2):
'''Draws the centroids of contours on the given image'''
centroids = [contour.centroid() for contour in self._contours]
marker_type = cv2.MARKER_CROSS
for centroid in centroids:
cv2.drawMarker(image, centroid, color, marker_type,
markerSize=marker_size, thickness=thickness)
[docs] def draw_simple_bounding_boxes(self, image, color=iv_colors.BLACK, thickness=2):
'''Draws simple bounding boxes around the contours in a given image'''
bounding_boxes = [contour.simple_bounding_box()
for contour in self._contours]
for bounding_box in bounding_boxes:
left, top, width, height = bounding_box
top_left = (left, top)
bottom_right = (left + width, top + height)
cv2.rectangle(image, top_left, bottom_right,
color, thickness=thickness)
[docs] def draw_best_fit_bounding_boxes(self, image, color=iv_colors.BLACK, thickness=2):
'''Draws the best fit (rotated) bounding boxes around contours'''
bounding_boxes = [contour.best_fit_bounding_box()
for contour in self._contours]
cv2.drawContours(image, bounding_boxes, -1, color, thickness)