code: # copyright (c) 2021 PaddlePaddle Authors. All Rights Reserve.
  #
  # Licensed under the Apache License, Version 2.0 (the "License");
  # you may not use this file except in compliance with the License.
  # You may obtain a copy of the License at
  #
  #    http://www.apache.org/licenses/LICENSE-2.0
  #
  # Unless required by applicable law or agreed to in writing, software
  # distributed under the License is distributed on an "AS IS" BASIS,
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  # See the License for the specific language governing permissions and
  # limitations under the License.
  """
  This code is refer from:
  https://github.com/whai362/PSENet/blob/python3/models/head/psenet_head.py
  """
  
  from __future__ import absolute_import
  from __future__ import division
  from __future__ import print_function
  
  import numpy as np
  import cv2
  import paddle
  from paddle.nn import functional as F
  
  from pyxlpr.ppocr.postprocess.pse_postprocess.pse import pse
  
  
  class PSEPostProcess(object):
      """
      The post process for PSE.
      """
  
      def __init__(self,
                   thresh=0.5,
                   box_thresh=0.85,
                   min_area=16,
                   box_type='box',
                   scale=4,
                   **kwargs):
          assert box_type in ['box', 'poly'], 'Only box and poly is supported'
          self.thresh = thresh
          self.box_thresh = box_thresh
          self.min_area = min_area
          self.box_type = box_type
          self.scale = scale
  
      def __call__(self, outs_dict, shape_list):
          pred = outs_dict['maps']
          if not isinstance(pred, paddle.Tensor):
              pred = paddle.to_tensor(pred)
          pred = F.interpolate(
              pred, scale_factor=4 // self.scale, mode='bilinear')
  
          score = F.sigmoid(pred[:, 0, :, :])
  
          kernels = (pred > self.thresh).astype('float32')
          text_mask = kernels[:, 0, :, :]
          kernels[:, 0:, :, :] = kernels[:, 0:, :, :] * text_mask
  
          score = score.numpy()
          kernels = kernels.numpy().astype(np.uint8)
  
          boxes_batch = []
          for batch_index in range(pred.shape[0]):
              boxes, scores = self.boxes_from_bitmap(score[batch_index],
                                                     kernels[batch_index],
                                                     shape_list[batch_index])
  
              boxes_batch.append({'points': boxes, 'scores': scores})
          return boxes_batch
  
      def boxes_from_bitmap(self, score, kernels, shape):
          label = pse(kernels, self.min_area)
          return self.generate_box(score, label, shape)
  
      def generate_box(self, score, label, shape):
          src_h, src_w, ratio_h, ratio_w = shape
          label_num = np.max(label) + 1
  
          boxes = []
          scores = []
          for i in range(1, label_num):
              ind = label == i
              points = np.array(np.where(ind)).transpose((1, 0))[:, ::-1]
  
              if points.shape[0] < self.min_area:
                  label[ind] = 0
                  continue
  
              score_i = np.mean(score[ind])
              if score_i < self.box_thresh:
                  label[ind] = 0
                  continue
  
              if self.box_type == 'box':
                  rect = cv2.minAreaRect(points)
                  bbox = cv2.boxPoints(rect)
              elif self.box_type == 'poly':
                  box_height = np.max(points[:, 1]) + 10
                  box_width = np.max(points[:, 0]) + 10
  
                  mask = np.zeros((box_height, box_width), np.uint8)
                  mask[points[:, 1], points[:, 0]] = 255
  
                  contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL,
                                                 cv2.CHAIN_APPROX_SIMPLE)
                  bbox = np.squeeze(contours[0], 1)
              else:
                  raise NotImplementedError
  
              bbox[:, 0] = np.clip(np.round(bbox[:, 0] / ratio_w), 0, src_w)
              bbox[:, 1] = np.clip(np.round(bbox[:, 1] / ratio_h), 0, src_h)
              boxes.append(bbox)
              scores.append(score_i)
          return boxes, scores
  
apis: numpy.zeros numpy.squeeze numpy.max numpy.round numpy.where numpy.mean