| |
| import cv2 |
| import numpy as np |
|
|
| from mmocr.models.builder import POSTPROCESSOR |
| from .base_postprocessor import BasePostprocessor |
| from .utils import fill_hole, fourier2poly, poly_nms |
|
|
|
|
| @POSTPROCESSOR.register_module() |
| class FCEPostprocessor(BasePostprocessor): |
| """Decoding predictions of FCENet to instances. |
| |
| Args: |
| fourier_degree (int): The maximum Fourier transform degree k. |
| num_reconstr_points (int): The points number of the polygon |
| reconstructed from predicted Fourier coefficients. |
| text_repr_type (str): Boundary encoding type 'poly' or 'quad'. |
| scale (int): The down-sample scale of the prediction. |
| alpha (float): The parameter to calculate final scores. Score_{final} |
| = (Score_{text region} ^ alpha) |
| * (Score_{text center region}^ beta) |
| beta (float): The parameter to calculate final score. |
| score_thr (float): The threshold used to filter out the final |
| candidates. |
| nms_thr (float): The threshold of nms. |
| """ |
|
|
| def __init__(self, |
| fourier_degree, |
| num_reconstr_points, |
| text_repr_type='poly', |
| alpha=1.0, |
| beta=2.0, |
| score_thr=0.3, |
| nms_thr=0.1, |
| **kwargs): |
| super().__init__(text_repr_type) |
| self.fourier_degree = fourier_degree |
| self.num_reconstr_points = num_reconstr_points |
| self.alpha = alpha |
| self.beta = beta |
| self.score_thr = score_thr |
| self.nms_thr = nms_thr |
|
|
| def __call__(self, preds, scale): |
| """ |
| Args: |
| preds (list[Tensor]): Classification prediction and regression |
| prediction. |
| scale (float): Scale of current layer. |
| |
| Returns: |
| list[list[float]]: The instance boundary and confidence. |
| """ |
| assert isinstance(preds, list) |
| assert len(preds) == 2 |
|
|
| cls_pred = preds[0][0] |
| tr_pred = cls_pred[0:2].softmax(dim=0).data.cpu().numpy() |
| tcl_pred = cls_pred[2:].softmax(dim=0).data.cpu().numpy() |
|
|
| reg_pred = preds[1][0].permute(1, 2, 0).data.cpu().numpy() |
| x_pred = reg_pred[:, :, :2 * self.fourier_degree + 1] |
| y_pred = reg_pred[:, :, 2 * self.fourier_degree + 1:] |
|
|
| score_pred = (tr_pred[1]**self.alpha) * (tcl_pred[1]**self.beta) |
| tr_pred_mask = (score_pred) > self.score_thr |
| tr_mask = fill_hole(tr_pred_mask) |
|
|
| tr_contours, _ = cv2.findContours( |
| tr_mask.astype(np.uint8), cv2.RETR_TREE, |
| cv2.CHAIN_APPROX_SIMPLE) |
|
|
| mask = np.zeros_like(tr_mask) |
| boundaries = [] |
| for cont in tr_contours: |
| deal_map = mask.copy().astype(np.int8) |
| cv2.drawContours(deal_map, [cont], -1, 1, -1) |
|
|
| score_map = score_pred * deal_map |
| score_mask = score_map > 0 |
| xy_text = np.argwhere(score_mask) |
| dxy = xy_text[:, 1] + xy_text[:, 0] * 1j |
|
|
| x, y = x_pred[score_mask], y_pred[score_mask] |
| c = x + y * 1j |
| c[:, self.fourier_degree] = c[:, self.fourier_degree] + dxy |
| c *= scale |
|
|
| polygons = fourier2poly(c, self.num_reconstr_points) |
| score = score_map[score_mask].reshape(-1, 1) |
| polygons = poly_nms( |
| np.hstack((polygons, score)).tolist(), self.nms_thr) |
|
|
| boundaries = boundaries + polygons |
|
|
| boundaries = poly_nms(boundaries, self.nms_thr) |
|
|
| if self.text_repr_type == 'quad': |
| new_boundaries = [] |
| for boundary in boundaries: |
| poly = np.array(boundary[:-1]).reshape(-1, |
| 2).astype(np.float32) |
| score = boundary[-1] |
| points = cv2.boxPoints(cv2.minAreaRect(poly)) |
| points = np.int0(points) |
| new_boundaries.append(points.reshape(-1).tolist() + [score]) |
|
|
| return boundaries |
|
|