Repository: PaddlePaddle/PaddleOCR

Issue:
Shrink map generation at training for DB is wrong for some polygon
Hi. Thanks for the great works.

After trying the DB training code, I've found out that the current shrink map generation at training for DB is wrong for some polygon.

For example, this polygon:
```
[[370, 111], [360, 111], [354, 113], [337, 113], [336, 109], [281, 109], [278, 111], [269, 111], [260, 108], [243, 108], [241, 108], [181, 108], [177, 111], [169, 111], [162, 112], [145, 112], [144, 108], [84, 108], [83, 108], [9, 108], [9, 117], [83, 117], [84, 117], [144, 117], [145, 119], [162, 119], [169, 117], [177, 117], [181, 118], [241, 118], [243, 114], [260, 114], [269, 118], [278, 118], [281, 118], [336, 118], [337, 119], [354, 119], [360, 118], [370, 118]]
```
![lol2](https://user-images.githubusercontent.com/26834698/108241717-b582d380-717e-11eb-9d7a-d6bf3fc0cf55.png)

Will result in this mask after shrinking
![lol](https://user-images.githubusercontent.com/26834698/108241733-bb78b480-717e-11eb-9bfd-da67fc275607.png)

Why? We can take a look at this block of code

https://github.com/PaddlePaddle/PaddleOCR/blob/d91c3e7c6b851f1c3d3af95c8f9c3e7276200ee7/ppocr/data/imaug/make_shrink_map.py#L47-L60

Since vatti clipping algorithm invoked by pyclipper can return multiple polygon (5 in this case, with the default shrink ratio 0.4) like this:
```
[[[240, 112], [239, 115], [181, 115], [177, 114], [179, 114], [183, 111], [243, 111]], [[367, 115], [360, 115], [356, 116], [361, 114], [367, 114]], [[334, 114], [334, 115], [270, 115], [268, 114], [280, 114], [283, 112], [333, 112]], [[142, 113], [142, 114], [12, 114], [12, 111], [141, 111]], [[147, 116], [147, 115], [162, 115], [169, 114], [162, 116]]]
```
![lol](https://user-images.githubusercontent.com/26834698/108242184-3510a280-717f-11eb-8cc9-90e14e1f351b.png)

But the current implementation only uses the first polygon and assumes there is only one polygon, leading to the wrong shrink map. 
https://github.com/PaddlePaddle/PaddleOCR/blob/d91c3e7c6b851f1c3d3af95c8f9c3e7276200ee7/ppocr/data/imaug/make_shrink_map.py#L59

This will greatly affect the accuracy of the trained model. Ideally, we would want a shrink map of a text region to not be spliced up like above but rather a shrink map like this (not using the original polygon of course, if it can):

![lol](https://user-images.githubusercontent.com/26834698/108242699-cbdd5f00-717f-11eb-8f05-4d81f53ae649.png)

I already sent a PR to fix this issue (#2014).
Shrink map generation at training for DB is wrong for some polygon
Hi. Thanks for the great works.

After trying the DB training code, I've found out that the current shrink map generation at training for DB is wrong for some polygon.

For example, this polygon:
```
[[370, 111], [360, 111], [354, 113], [337, 113], [336, 109], [281, 109], [278, 111], [269, 111], [260, 108], [243, 108], [241, 108], [181, 108], [177, 111], [169, 111], [162, 112], [145, 112], [144, 108], [84, 108], [83, 108], [9, 108], [9, 117], [83, 117], [84, 117], [144, 117], [145, 119], [162, 119], [169, 117], [177, 117], [181, 118], [241, 118], [243, 114], [260, 114], [269, 118], [278, 118], [281, 118], [336, 118], [337, 119], [354, 119], [360, 118], [370, 118]]
```
![lol2](https://user-images.githubusercontent.com/26834698/108241717-b582d380-717e-11eb-9d7a-d6bf3fc0cf55.png)

Will result in this mask after shrinking
![lol](https://user-images.githubusercontent.com/26834698/108241733-bb78b480-717e-11eb-9bfd-da67fc275607.png)

Why? We can take a look at this block of code

https://github.com/PaddlePaddle/PaddleOCR/blob/d91c3e7c6b851f1c3d3af95c8f9c3e7276200ee7/ppocr/data/imaug/make_shrink_map.py#L47-L60

Since vatti clipping algorithm invoked by pyclipper can return multiple polygon (5 in this case, with the default shrink ratio 0.4) like this:
```
[[[240, 112], [239, 115], [181, 115], [177, 114], [179, 114], [183, 111], [243, 111]], [[367, 115], [360, 115], [356, 116], [361, 114], [367, 114]], [[334, 114], [334, 115], [270, 115], [268, 114], [280, 114], [283, 112], [333, 112]], [[142, 113], [142, 114], [12, 114], [12, 111], [141, 111]], [[147, 116], [147, 115], [162, 115], [169, 114], [162, 116]]]
```
![lol](https://user-images.githubusercontent.com/26834698/108242184-3510a280-717f-11eb-8cc9-90e14e1f351b.png)

But the current implementation only uses the first polygon and assumes there is only one polygon, leading to the wrong shrink map. 
https://github.com/PaddlePaddle/PaddleOCR/blob/d91c3e7c6b851f1c3d3af95c8f9c3e7276200ee7/ppocr/data/imaug/make_shrink_map.py#L59

This will greatly affect the accuracy of the trained model. Ideally, we would want a shrink map of a text region to not be spliced up like above but rather a shrink map like this (not using the original polygon of course, if it can):

![lol](https://user-images.githubusercontent.com/26834698/108242699-cbdd5f00-717f-11eb-8f05-4d81f53ae649.png)

I already sent a PR to fix this issue (#2014).


Discussion:

Resolving patch:
diff --git a/ppocr/data/imaug/make_shrink_map.py b/ppocr/data/imaug/make_shrink_map.py
--- a/ppocr/data/imaug/make_shrink_map.py
+++ b/ppocr/data/imaug/make_shrink_map.py
@@ -44,20 +44,33 @@ def __call__(self, data):
                 ignore_tags[i] = True
             else:
                 polygon_shape = Polygon(polygon)
-                distance = polygon_shape.area * (
-                    1 - np.power(self.shrink_ratio, 2)) / polygon_shape.length
-                subject = [tuple(l) for l in text_polys[i]]
+                subject = [tuple(l) for l in polygon]
                 padding = pyclipper.PyclipperOffset()
                 padding.AddPath(subject, pyclipper.JT_ROUND,
                                 pyclipper.ET_CLOSEDPOLYGON)
-                shrinked = padding.Execute(-distance)
+                shrinked = []
+
+                # Increase the shrink ratio every time we get multiple polygon returned back 
+                possible_ratios = np.arange(self.shrink_ratio, 1, self.shrink_ratio)
+                np.append(possible_ratios, 1)
+                # print(possible_ratios)
+                for ratio in possible_ratios:
+                    # print(f"Change shrink ratio to {ratio}")
+                    distance = polygon_shape.area * (
+                        1 - np.power(ratio, 2)) / polygon_shape.length
+                    shrinked = padding.Execute(-distance)
+                    if len(shrinked) == 1:
+                        break
+
                 if shrinked == []:
                     cv2.fillPoly(mask,
                                  polygon.astype(np.int32)[np.newaxis, :, :], 0)
                     ignore_tags[i] = True
                     continue
-                shrinked = np.array(shrinked[0]).reshape(-1, 2)
-                cv2.fillPoly(gt, [shrinked.astype(np.int32)], 1)
+
+                for each_shirnk in shrinked:
+                    shirnk = np.array(each_shirnk).reshape(-1, 2)
+                    cv2.fillPoly(gt, [shirnk.astype(np.int32)], 1)
                 # cv2.fillPoly(gt[0], [shrinked.astype(np.int32)], 1)
 
         data['shrink_map'] = gt
@@ -91,4 +104,4 @@ def polygon_area(self, polygon):
             edge += (polygon[next_index, 0] - polygon[i, 0]) * (
                 polygon[next_index, 1] - polygon[i, 1])
 
-        return edge / 2.
+        return edge / 2.
\ No newline at end of file


Test patch: