Spaces:
Runtime error
Runtime error
| # Copyright (c) OpenMMLab. All rights reserved. | |
| import sys | |
| import cv2 | |
| import numpy as np | |
| import pyclipper | |
| from mmcv.utils import print_log | |
| from shapely.geometry import Polygon as plg | |
| import mmocr.utils.check_argument as check_argument | |
| class BaseTextDetTargets: | |
| """Generate text detector ground truths.""" | |
| def __init__(self): | |
| pass | |
| def point2line(self, xs, ys, point_1, point_2): | |
| """Compute the distance from point to a line. This is adapted from | |
| https://github.com/MhLiao/DB. | |
| Args: | |
| xs (ndarray): The x coordinates of size hxw. | |
| ys (ndarray): The y coordinates of size hxw. | |
| point_1 (ndarray): The first point with shape 1x2. | |
| point_2 (ndarray): The second point with shape 1x2. | |
| Returns: | |
| result (ndarray): The distance matrix of size hxw. | |
| """ | |
| # suppose a triangle with three edge abc with c=point_1 point_2 | |
| # a^2 | |
| a_square = np.square(xs - point_1[0]) + np.square(ys - point_1[1]) | |
| # b^2 | |
| b_square = np.square(xs - point_2[0]) + np.square(ys - point_2[1]) | |
| # c^2 | |
| c_square = np.square(point_1[0] - point_2[0]) + np.square(point_1[1] - | |
| point_2[1]) | |
| # -cosC=(c^2-a^2-b^2)/2(ab) | |
| neg_cos_c = ( | |
| (c_square - a_square - b_square) / | |
| (np.finfo(np.float32).eps + 2 * np.sqrt(a_square * b_square))) | |
| # sinC^2=1-cosC^2 | |
| square_sin = 1 - np.square(neg_cos_c) | |
| square_sin = np.nan_to_num(square_sin) | |
| # distance=a*b*sinC/c=a*h/c=2*area/c | |
| result = np.sqrt(a_square * b_square * square_sin / | |
| (np.finfo(np.float32).eps + c_square)) | |
| # set result to minimum edge if C<pi/2 | |
| result[neg_cos_c < 0] = np.sqrt(np.fmin(a_square, | |
| b_square))[neg_cos_c < 0] | |
| return result | |
| def polygon_area(self, polygon): | |
| """Compute the polygon area. Please refer to Green's theorem. | |
| https://en.wikipedia.org/wiki/Green%27s_theorem. This is adapted from | |
| https://github.com/MhLiao/DB. | |
| Args: | |
| polygon (ndarray): The polygon boundary points. | |
| """ | |
| polygon = polygon.reshape(-1, 2) | |
| edge = 0 | |
| for i in range(polygon.shape[0]): | |
| next_index = (i + 1) % polygon.shape[0] | |
| edge += (polygon[next_index, 0] - polygon[i, 0]) * ( | |
| polygon[next_index, 1] + polygon[i, 1]) | |
| return edge / 2. | |
| def polygon_size(self, polygon): | |
| """Estimate the height and width of the minimum bounding box of the | |
| polygon. | |
| Args: | |
| polygon (ndarray): The polygon point sequence. | |
| Returns: | |
| size (tuple): The height and width of the minimum bounding box. | |
| """ | |
| poly = polygon.reshape(-1, 2) | |
| rect = cv2.minAreaRect(poly.astype(np.int32)) | |
| size = rect[1] | |
| return size | |
| def generate_kernels(self, | |
| img_size, | |
| text_polys, | |
| shrink_ratio, | |
| max_shrink=sys.maxsize, | |
| ignore_tags=None): | |
| """Generate text instance kernels for one shrink ratio. | |
| Args: | |
| img_size (tuple(int, int)): The image size of (height, width). | |
| text_polys (list[list[ndarray]]: The list of text polygons. | |
| shrink_ratio (float): The shrink ratio of kernel. | |
| Returns: | |
| text_kernel (ndarray): The text kernel mask of (height, width). | |
| """ | |
| assert isinstance(img_size, tuple) | |
| assert check_argument.is_2dlist(text_polys) | |
| assert isinstance(shrink_ratio, float) | |
| h, w = img_size | |
| text_kernel = np.zeros((h, w), dtype=np.float32) | |
| for text_ind, poly in enumerate(text_polys): | |
| instance = poly[0].reshape(-1, 2).astype(np.int32) | |
| area = plg(instance).area | |
| peri = cv2.arcLength(instance, True) | |
| distance = min( | |
| int(area * (1 - shrink_ratio * shrink_ratio) / (peri + 0.001) + | |
| 0.5), max_shrink) | |
| pco = pyclipper.PyclipperOffset() | |
| pco.AddPath(instance, pyclipper.JT_ROUND, | |
| pyclipper.ET_CLOSEDPOLYGON) | |
| shrunk = np.array(pco.Execute(-distance)) | |
| # check shrunk == [] or empty ndarray | |
| if len(shrunk) == 0 or shrunk.size == 0: | |
| if ignore_tags is not None: | |
| ignore_tags[text_ind] = True | |
| continue | |
| try: | |
| shrunk = np.array(shrunk[0]).reshape(-1, 2) | |
| except Exception as e: | |
| print_log(f'{shrunk} with error {e}') | |
| if ignore_tags is not None: | |
| ignore_tags[text_ind] = True | |
| continue | |
| cv2.fillPoly(text_kernel, [shrunk.astype(np.int32)], text_ind + 1) | |
| return text_kernel, ignore_tags | |
| def generate_effective_mask(self, mask_size: tuple, polygons_ignore): | |
| """Generate effective mask by setting the ineffective regions to 0 and | |
| effective regions to 1. | |
| Args: | |
| mask_size (tuple): The mask size. | |
| polygons_ignore (list[[ndarray]]: The list of ignored text | |
| polygons. | |
| Returns: | |
| mask (ndarray): The effective mask of (height, width). | |
| """ | |
| assert check_argument.is_2dlist(polygons_ignore) | |
| mask = np.ones(mask_size, dtype=np.uint8) | |
| for poly in polygons_ignore: | |
| instance = poly[0].reshape(-1, | |
| 2).astype(np.int32).reshape(1, -1, 2) | |
| cv2.fillPoly(mask, instance, 0) | |
| return mask | |
| def generate_targets(self, results): | |
| raise NotImplementedError | |
| def __call__(self, results): | |
| results = self.generate_targets(results) | |
| return results | |