"""
.. module:: helpers
:synopsis: Helper functions
.. moduleauthor:: tom hoag <tomhoag@gmail.com>
Helper functions and probably not much use outside the scope of nms
"""
import cv2
import math
import numpy as np
[docs]def createImage(width=800, height=800, depth=3):
""" Return a black image with an optional scale on the edge
:param width: width of the returned image
:type width: int
:param height: height of the returned image
:type height: int
:param depth: either 3 (rgb/bgr) or 1 (mono). If 1, no scale is drawn
:type depth: int
:return: A zero'd out matrix/black image of size (width, height)
:rtype: :class:`numpy.ndarray`
"""
# create a black image and put a scale on the edge
assert depth == 3 or depth == 1
assert width > 0
assert height > 0
hashDistance = 50
hashLength = 20
img = np.zeros((int(height), int(width), depth), np.uint8)
if(depth == 3):
for x in range(0, int(width / hashDistance)):
cv2.line(img, (x * hashDistance, 0), (x * hashDistance, hashLength), (0,0,255), 1)
for y in range(0, int(width / hashDistance)):
cv2.line(img, (0, y * hashDistance), (hashLength, y * hashDistance), (0,0,255), 1)
return img
[docs]def polygon_intersection_area(polygons):
""" Compute the area of intersection of an array of polygons
:param polygons: a list of polygons
:type polygons: list
:return: the area of intersection of the polygons
:rtype: int
"""
if len(polygons) == 0:
return 0
dx = 0
dy = 0
maxx = np.amax(np.array(polygons)[...,0])
minx = np.amin(np.array(polygons)[...,0])
maxy = np.amax(np.array(polygons)[...,1])
miny = np.amin(np.array(polygons)[...,1])
if minx < 0:
dx = -int(minx)
maxx = maxx + dx
if miny < 0:
dy = -int(miny)
maxy = maxy + dy
# (dx, dy) is used as an offset in fillPoly
for i, polypoints in enumerate(polygons):
newImage = createImage(maxx, maxy, 1)
polypoints = np.array(polypoints, np.int32)
polypoints = polypoints.reshape(-1, 1, 2)
cv2.fillPoly(newImage, [polypoints], (255, 255, 255), cv2.LINE_8, 0, (dx, dy))
if(i == 0):
compositeImage = newImage
else:
compositeImage = cv2.bitwise_and(compositeImage, newImage)
area = cv2.countNonZero(compositeImage)
return area
[docs]def get_max_score_index(scores, threshold=0, top_k=0, descending=True):
""" Get the max scores with corresponding indicies
Adapted from the OpenCV c++ source in `nms.inl.hpp <https://github.com/opencv/opencv/blob/ee1e1ce377aa61ddea47a6c2114f99951153bb4f/modules/dnn/src/nms.inl.hpp#L33>`__
:param scores: a list of scores
:type scores: list
:param threshold: consider scores higher than this threshold
:type threshold: float
:param top_k: return at most top_k scores; if 0, keep all
:type top_k: int
:param descending: if True, list is returened in descending order, else ascending
:returns: a sorted by score list of [score, index]
"""
score_index = []
# Generate index score pairs
for i, score in enumerate(scores):
if (threshold > 0) and (score > threshold):
score_index.append([score, i])
else:
score_index.append([score, i])
# Sort the score pair according to the scores in descending order
npscores = np.array(score_index)
if descending:
npscores = npscores[npscores[:,0].argsort()[::-1]] #descending order
else:
npscores = npscores[npscores[:,0].argsort()] # ascending order
if top_k > 0:
npscores = npscores[0:top_k]
return npscores.tolist()