pse_postprocess.py 4.0 KB
Newer Older
W
WenmuZhou 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13
# 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.
W
WenmuZhou 已提交
14 15 16 17
"""
This code is refer from:
https://github.com/whai362/PSENet/blob/python3/models/head/psenet_head.py
"""
W
WenmuZhou 已提交
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39

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 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,
文幕地方's avatar
文幕地方 已提交
40
                 box_type='quad',
W
WenmuZhou 已提交
41 42
                 scale=4,
                 **kwargs):
文幕地方's avatar
文幕地方 已提交
43
        assert box_type in ['quad', 'poly'], 'Only quad and poly is supported'
W
WenmuZhou 已提交
44 45 46 47 48 49 50 51 52 53
        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)
W
WenmuZhou 已提交
54 55
        pred = F.interpolate(
            pred, scale_factor=4 // self.scale, mode='bilinear')
W
WenmuZhou 已提交
56 57 58 59 60

        score = F.sigmoid(pred[:, 0, :, :])

        kernels = (pred > self.thresh).astype('float32')
        text_mask = kernels[:, 0, :, :]
文幕地方's avatar
文幕地方 已提交
61 62
        text_mask = paddle.unsqueeze(text_mask, axis=1)

W
WenmuZhou 已提交
63 64 65 66 67 68 69
        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]):
W
WenmuZhou 已提交
70 71 72
            boxes, scores = self.boxes_from_bitmap(score[batch_index],
                                                   kernels[batch_index],
                                                   shape_list[batch_index])
W
WenmuZhou 已提交
73 74 75 76

            boxes_batch.append({'points': boxes, 'scores': scores})
        return boxes_batch

W
WenmuZhou 已提交
77
    def boxes_from_bitmap(self, score, kernels, shape):
W
WenmuZhou 已提交
78
        label = pse(kernels, self.min_area)
W
WenmuZhou 已提交
79
        return self.generate_box(score, label, shape)
W
WenmuZhou 已提交
80

W
WenmuZhou 已提交
81 82
    def generate_box(self, score, label, shape):
        src_h, src_w, ratio_h, ratio_w = shape
W
WenmuZhou 已提交
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
        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

文幕地方's avatar
文幕地方 已提交
100
            if self.box_type == 'quad':
W
WenmuZhou 已提交
101 102 103 104 105 106 107 108 109
                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

W
WenmuZhou 已提交
110 111
                contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL,
                                               cv2.CHAIN_APPROX_SIMPLE)
W
WenmuZhou 已提交
112 113 114 115
                bbox = np.squeeze(contours[0], 1)
            else:
                raise NotImplementedError

W
WenmuZhou 已提交
116 117
            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)
W
WenmuZhou 已提交
118 119 120
            boxes.append(bbox)
            scores.append(score_i)
        return boxes, scores