mirror of
https://github.com/YaoFANGUK/video-subtitle-remover.git
synced 2026-03-17 18:57:35 +08:00
vsr v1.0.0
This commit is contained in:
13
backend/ppocr/utils/__init__.py
Executable file
13
backend/ppocr/utils/__init__.py
Executable file
@@ -0,0 +1,13 @@
|
||||
# Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# 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.
|
||||
117
backend/ppocr/utils/dict/ar_dict.txt
Normal file
117
backend/ppocr/utils/dict/ar_dict.txt
Normal file
@@ -0,0 +1,117 @@
|
||||
a
|
||||
r
|
||||
b
|
||||
i
|
||||
c
|
||||
_
|
||||
m
|
||||
g
|
||||
/
|
||||
1
|
||||
0
|
||||
I
|
||||
L
|
||||
S
|
||||
V
|
||||
R
|
||||
C
|
||||
2
|
||||
v
|
||||
l
|
||||
6
|
||||
3
|
||||
9
|
||||
.
|
||||
j
|
||||
p
|
||||
ا
|
||||
ل
|
||||
م
|
||||
ر
|
||||
ج
|
||||
و
|
||||
ح
|
||||
ي
|
||||
ة
|
||||
5
|
||||
8
|
||||
7
|
||||
أ
|
||||
ب
|
||||
ض
|
||||
4
|
||||
ك
|
||||
س
|
||||
ه
|
||||
ث
|
||||
ن
|
||||
ط
|
||||
ع
|
||||
ت
|
||||
غ
|
||||
خ
|
||||
ف
|
||||
ئ
|
||||
ز
|
||||
إ
|
||||
د
|
||||
ص
|
||||
ظ
|
||||
ذ
|
||||
ش
|
||||
ى
|
||||
ق
|
||||
ؤ
|
||||
آ
|
||||
ء
|
||||
s
|
||||
e
|
||||
n
|
||||
w
|
||||
t
|
||||
u
|
||||
z
|
||||
d
|
||||
A
|
||||
N
|
||||
G
|
||||
h
|
||||
o
|
||||
E
|
||||
T
|
||||
H
|
||||
O
|
||||
B
|
||||
y
|
||||
F
|
||||
U
|
||||
J
|
||||
X
|
||||
W
|
||||
P
|
||||
Z
|
||||
M
|
||||
k
|
||||
q
|
||||
Y
|
||||
Q
|
||||
D
|
||||
f
|
||||
K
|
||||
x
|
||||
'
|
||||
%
|
||||
-
|
||||
#
|
||||
@
|
||||
!
|
||||
&
|
||||
$
|
||||
,
|
||||
:
|
||||
é
|
||||
?
|
||||
+
|
||||
É
|
||||
(
|
||||
|
||||
161
backend/ppocr/utils/dict/arabic_dict.txt
Normal file
161
backend/ppocr/utils/dict/arabic_dict.txt
Normal file
@@ -0,0 +1,161 @@
|
||||
!
|
||||
#
|
||||
$
|
||||
%
|
||||
&
|
||||
'
|
||||
(
|
||||
+
|
||||
,
|
||||
-
|
||||
.
|
||||
/
|
||||
0
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
6
|
||||
7
|
||||
8
|
||||
9
|
||||
:
|
||||
?
|
||||
@
|
||||
A
|
||||
B
|
||||
C
|
||||
D
|
||||
E
|
||||
F
|
||||
G
|
||||
H
|
||||
I
|
||||
J
|
||||
K
|
||||
L
|
||||
M
|
||||
N
|
||||
O
|
||||
P
|
||||
Q
|
||||
R
|
||||
S
|
||||
T
|
||||
U
|
||||
V
|
||||
W
|
||||
X
|
||||
Y
|
||||
Z
|
||||
_
|
||||
a
|
||||
b
|
||||
c
|
||||
d
|
||||
e
|
||||
f
|
||||
g
|
||||
h
|
||||
i
|
||||
j
|
||||
k
|
||||
l
|
||||
m
|
||||
n
|
||||
o
|
||||
p
|
||||
q
|
||||
r
|
||||
s
|
||||
t
|
||||
u
|
||||
v
|
||||
w
|
||||
x
|
||||
y
|
||||
z
|
||||
É
|
||||
é
|
||||
ء
|
||||
آ
|
||||
أ
|
||||
ؤ
|
||||
إ
|
||||
ئ
|
||||
ا
|
||||
ب
|
||||
ة
|
||||
ت
|
||||
ث
|
||||
ج
|
||||
ح
|
||||
خ
|
||||
د
|
||||
ذ
|
||||
ر
|
||||
ز
|
||||
س
|
||||
ش
|
||||
ص
|
||||
ض
|
||||
ط
|
||||
ظ
|
||||
ع
|
||||
غ
|
||||
ف
|
||||
ق
|
||||
ك
|
||||
ل
|
||||
م
|
||||
ن
|
||||
ه
|
||||
و
|
||||
ى
|
||||
ي
|
||||
ً
|
||||
ٌ
|
||||
ٍ
|
||||
َ
|
||||
ُ
|
||||
ِ
|
||||
ّ
|
||||
ْ
|
||||
ٓ
|
||||
ٔ
|
||||
ٰ
|
||||
ٱ
|
||||
ٹ
|
||||
پ
|
||||
چ
|
||||
ڈ
|
||||
ڑ
|
||||
ژ
|
||||
ک
|
||||
ڭ
|
||||
گ
|
||||
ں
|
||||
ھ
|
||||
ۀ
|
||||
ہ
|
||||
ۂ
|
||||
ۃ
|
||||
ۆ
|
||||
ۇ
|
||||
ۈ
|
||||
ۋ
|
||||
ی
|
||||
ې
|
||||
ے
|
||||
ۓ
|
||||
ە
|
||||
١
|
||||
٢
|
||||
٣
|
||||
٤
|
||||
٥
|
||||
٦
|
||||
٧
|
||||
٨
|
||||
٩
|
||||
145
backend/ppocr/utils/dict/be_dict.txt
Normal file
145
backend/ppocr/utils/dict/be_dict.txt
Normal file
@@ -0,0 +1,145 @@
|
||||
b
|
||||
e
|
||||
_
|
||||
i
|
||||
m
|
||||
g
|
||||
/
|
||||
2
|
||||
0
|
||||
I
|
||||
L
|
||||
S
|
||||
V
|
||||
R
|
||||
C
|
||||
1
|
||||
v
|
||||
a
|
||||
l
|
||||
6
|
||||
9
|
||||
4
|
||||
3
|
||||
.
|
||||
j
|
||||
p
|
||||
п
|
||||
а
|
||||
з
|
||||
б
|
||||
у
|
||||
г
|
||||
н
|
||||
ц
|
||||
ь
|
||||
8
|
||||
м
|
||||
л
|
||||
і
|
||||
о
|
||||
ў
|
||||
ы
|
||||
7
|
||||
5
|
||||
М
|
||||
х
|
||||
с
|
||||
р
|
||||
ф
|
||||
я
|
||||
е
|
||||
д
|
||||
ж
|
||||
ю
|
||||
ч
|
||||
й
|
||||
к
|
||||
Д
|
||||
в
|
||||
Б
|
||||
т
|
||||
І
|
||||
ш
|
||||
ё
|
||||
э
|
||||
К
|
||||
Л
|
||||
Н
|
||||
А
|
||||
Ж
|
||||
Г
|
||||
В
|
||||
П
|
||||
З
|
||||
Е
|
||||
О
|
||||
Р
|
||||
С
|
||||
У
|
||||
Ё
|
||||
Й
|
||||
Т
|
||||
Ч
|
||||
Э
|
||||
Ц
|
||||
Ю
|
||||
Ш
|
||||
Ф
|
||||
Х
|
||||
Я
|
||||
Ь
|
||||
Ы
|
||||
Ў
|
||||
s
|
||||
c
|
||||
n
|
||||
w
|
||||
M
|
||||
o
|
||||
t
|
||||
T
|
||||
E
|
||||
A
|
||||
B
|
||||
u
|
||||
h
|
||||
y
|
||||
k
|
||||
r
|
||||
H
|
||||
d
|
||||
Y
|
||||
O
|
||||
U
|
||||
F
|
||||
f
|
||||
x
|
||||
D
|
||||
G
|
||||
N
|
||||
K
|
||||
P
|
||||
z
|
||||
J
|
||||
X
|
||||
W
|
||||
Z
|
||||
Q
|
||||
%
|
||||
-
|
||||
q
|
||||
@
|
||||
'
|
||||
!
|
||||
#
|
||||
&
|
||||
,
|
||||
:
|
||||
$
|
||||
(
|
||||
?
|
||||
é
|
||||
+
|
||||
É
|
||||
|
||||
140
backend/ppocr/utils/dict/bg_dict.txt
Normal file
140
backend/ppocr/utils/dict/bg_dict.txt
Normal file
@@ -0,0 +1,140 @@
|
||||
!
|
||||
#
|
||||
$
|
||||
%
|
||||
&
|
||||
'
|
||||
(
|
||||
+
|
||||
,
|
||||
-
|
||||
.
|
||||
/
|
||||
0
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
6
|
||||
7
|
||||
8
|
||||
9
|
||||
:
|
||||
?
|
||||
@
|
||||
A
|
||||
B
|
||||
C
|
||||
D
|
||||
E
|
||||
F
|
||||
G
|
||||
H
|
||||
I
|
||||
J
|
||||
K
|
||||
L
|
||||
M
|
||||
N
|
||||
O
|
||||
P
|
||||
Q
|
||||
R
|
||||
S
|
||||
T
|
||||
U
|
||||
V
|
||||
W
|
||||
X
|
||||
Y
|
||||
Z
|
||||
_
|
||||
a
|
||||
b
|
||||
c
|
||||
d
|
||||
e
|
||||
f
|
||||
g
|
||||
h
|
||||
i
|
||||
j
|
||||
k
|
||||
l
|
||||
m
|
||||
n
|
||||
o
|
||||
p
|
||||
q
|
||||
r
|
||||
s
|
||||
t
|
||||
u
|
||||
v
|
||||
w
|
||||
x
|
||||
y
|
||||
z
|
||||
É
|
||||
é
|
||||
А
|
||||
Б
|
||||
В
|
||||
Г
|
||||
Д
|
||||
Е
|
||||
Ж
|
||||
З
|
||||
И
|
||||
Й
|
||||
К
|
||||
Л
|
||||
М
|
||||
Н
|
||||
О
|
||||
П
|
||||
Р
|
||||
С
|
||||
Т
|
||||
У
|
||||
Ф
|
||||
Х
|
||||
Ц
|
||||
Ч
|
||||
Ш
|
||||
Щ
|
||||
Ъ
|
||||
Ю
|
||||
Я
|
||||
а
|
||||
б
|
||||
в
|
||||
г
|
||||
д
|
||||
е
|
||||
ж
|
||||
з
|
||||
и
|
||||
й
|
||||
к
|
||||
л
|
||||
м
|
||||
н
|
||||
о
|
||||
п
|
||||
р
|
||||
с
|
||||
т
|
||||
у
|
||||
ф
|
||||
х
|
||||
ц
|
||||
ч
|
||||
ш
|
||||
щ
|
||||
ъ
|
||||
ь
|
||||
ю
|
||||
я
|
||||
|
||||
6623
backend/ppocr/utils/dict/ch_dict.txt
Normal file
6623
backend/ppocr/utils/dict/ch_dict.txt
Normal file
File diff suppressed because it is too large
Load Diff
8421
backend/ppocr/utils/dict/chinese_cht_dict.txt
Normal file
8421
backend/ppocr/utils/dict/chinese_cht_dict.txt
Normal file
File diff suppressed because it is too large
Load Diff
163
backend/ppocr/utils/dict/cyrillic_dict.txt
Normal file
163
backend/ppocr/utils/dict/cyrillic_dict.txt
Normal file
@@ -0,0 +1,163 @@
|
||||
|
||||
!
|
||||
#
|
||||
$
|
||||
%
|
||||
&
|
||||
'
|
||||
(
|
||||
+
|
||||
,
|
||||
-
|
||||
.
|
||||
/
|
||||
0
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
6
|
||||
7
|
||||
8
|
||||
9
|
||||
:
|
||||
?
|
||||
@
|
||||
A
|
||||
B
|
||||
C
|
||||
D
|
||||
E
|
||||
F
|
||||
G
|
||||
H
|
||||
I
|
||||
J
|
||||
K
|
||||
L
|
||||
M
|
||||
N
|
||||
O
|
||||
P
|
||||
Q
|
||||
R
|
||||
S
|
||||
T
|
||||
U
|
||||
V
|
||||
W
|
||||
X
|
||||
Y
|
||||
Z
|
||||
_
|
||||
a
|
||||
b
|
||||
c
|
||||
d
|
||||
e
|
||||
f
|
||||
g
|
||||
h
|
||||
i
|
||||
j
|
||||
k
|
||||
l
|
||||
m
|
||||
n
|
||||
o
|
||||
p
|
||||
q
|
||||
r
|
||||
s
|
||||
t
|
||||
u
|
||||
v
|
||||
w
|
||||
x
|
||||
y
|
||||
z
|
||||
É
|
||||
é
|
||||
Ё
|
||||
Є
|
||||
І
|
||||
Ј
|
||||
Љ
|
||||
Ў
|
||||
А
|
||||
Б
|
||||
В
|
||||
Г
|
||||
Д
|
||||
Е
|
||||
Ж
|
||||
З
|
||||
И
|
||||
Й
|
||||
К
|
||||
Л
|
||||
М
|
||||
Н
|
||||
О
|
||||
П
|
||||
Р
|
||||
С
|
||||
Т
|
||||
У
|
||||
Ф
|
||||
Х
|
||||
Ц
|
||||
Ч
|
||||
Ш
|
||||
Щ
|
||||
Ъ
|
||||
Ы
|
||||
Ь
|
||||
Э
|
||||
Ю
|
||||
Я
|
||||
а
|
||||
б
|
||||
в
|
||||
г
|
||||
д
|
||||
е
|
||||
ж
|
||||
з
|
||||
и
|
||||
й
|
||||
к
|
||||
л
|
||||
м
|
||||
н
|
||||
о
|
||||
п
|
||||
р
|
||||
с
|
||||
т
|
||||
у
|
||||
ф
|
||||
х
|
||||
ц
|
||||
ч
|
||||
ш
|
||||
щ
|
||||
ъ
|
||||
ы
|
||||
ь
|
||||
э
|
||||
ю
|
||||
я
|
||||
ё
|
||||
ђ
|
||||
є
|
||||
і
|
||||
ј
|
||||
љ
|
||||
њ
|
||||
ћ
|
||||
ў
|
||||
џ
|
||||
Ґ
|
||||
ґ
|
||||
167
backend/ppocr/utils/dict/devanagari_dict.txt
Normal file
167
backend/ppocr/utils/dict/devanagari_dict.txt
Normal file
@@ -0,0 +1,167 @@
|
||||
|
||||
!
|
||||
#
|
||||
$
|
||||
%
|
||||
&
|
||||
'
|
||||
(
|
||||
+
|
||||
,
|
||||
-
|
||||
.
|
||||
/
|
||||
0
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
6
|
||||
7
|
||||
8
|
||||
9
|
||||
:
|
||||
?
|
||||
@
|
||||
A
|
||||
B
|
||||
C
|
||||
D
|
||||
E
|
||||
F
|
||||
G
|
||||
H
|
||||
I
|
||||
J
|
||||
K
|
||||
L
|
||||
M
|
||||
N
|
||||
O
|
||||
P
|
||||
Q
|
||||
R
|
||||
S
|
||||
T
|
||||
U
|
||||
V
|
||||
W
|
||||
X
|
||||
Y
|
||||
Z
|
||||
_
|
||||
a
|
||||
b
|
||||
c
|
||||
d
|
||||
e
|
||||
f
|
||||
g
|
||||
h
|
||||
i
|
||||
j
|
||||
k
|
||||
l
|
||||
m
|
||||
n
|
||||
o
|
||||
p
|
||||
q
|
||||
r
|
||||
s
|
||||
t
|
||||
u
|
||||
v
|
||||
w
|
||||
x
|
||||
y
|
||||
z
|
||||
É
|
||||
é
|
||||
ँ
|
||||
ं
|
||||
ः
|
||||
अ
|
||||
आ
|
||||
इ
|
||||
ई
|
||||
उ
|
||||
ऊ
|
||||
ऋ
|
||||
ए
|
||||
ऐ
|
||||
ऑ
|
||||
ओ
|
||||
औ
|
||||
क
|
||||
ख
|
||||
ग
|
||||
घ
|
||||
ङ
|
||||
च
|
||||
छ
|
||||
ज
|
||||
झ
|
||||
ञ
|
||||
ट
|
||||
ठ
|
||||
ड
|
||||
ढ
|
||||
ण
|
||||
त
|
||||
थ
|
||||
द
|
||||
ध
|
||||
न
|
||||
ऩ
|
||||
प
|
||||
फ
|
||||
ब
|
||||
भ
|
||||
म
|
||||
य
|
||||
र
|
||||
ऱ
|
||||
ल
|
||||
ळ
|
||||
व
|
||||
श
|
||||
ष
|
||||
स
|
||||
ह
|
||||
़
|
||||
ा
|
||||
ि
|
||||
ी
|
||||
ु
|
||||
ू
|
||||
ृ
|
||||
ॅ
|
||||
े
|
||||
ै
|
||||
ॉ
|
||||
ो
|
||||
ौ
|
||||
्
|
||||
॒
|
||||
क़
|
||||
ख़
|
||||
ग़
|
||||
ज़
|
||||
ड़
|
||||
ढ़
|
||||
फ़
|
||||
ॠ
|
||||
।
|
||||
०
|
||||
१
|
||||
२
|
||||
३
|
||||
४
|
||||
५
|
||||
६
|
||||
७
|
||||
८
|
||||
९
|
||||
॰
|
||||
95
backend/ppocr/utils/dict/en_dict.txt
Normal file
95
backend/ppocr/utils/dict/en_dict.txt
Normal file
@@ -0,0 +1,95 @@
|
||||
0
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
6
|
||||
7
|
||||
8
|
||||
9
|
||||
:
|
||||
;
|
||||
<
|
||||
=
|
||||
>
|
||||
?
|
||||
@
|
||||
A
|
||||
B
|
||||
C
|
||||
D
|
||||
E
|
||||
F
|
||||
G
|
||||
H
|
||||
I
|
||||
J
|
||||
K
|
||||
L
|
||||
M
|
||||
N
|
||||
O
|
||||
P
|
||||
Q
|
||||
R
|
||||
S
|
||||
T
|
||||
U
|
||||
V
|
||||
W
|
||||
X
|
||||
Y
|
||||
Z
|
||||
[
|
||||
\
|
||||
]
|
||||
^
|
||||
_
|
||||
`
|
||||
a
|
||||
b
|
||||
c
|
||||
d
|
||||
e
|
||||
f
|
||||
g
|
||||
h
|
||||
i
|
||||
j
|
||||
k
|
||||
l
|
||||
m
|
||||
n
|
||||
o
|
||||
p
|
||||
q
|
||||
r
|
||||
s
|
||||
t
|
||||
u
|
||||
v
|
||||
w
|
||||
x
|
||||
y
|
||||
z
|
||||
{
|
||||
|
|
||||
}
|
||||
~
|
||||
!
|
||||
"
|
||||
#
|
||||
$
|
||||
%
|
||||
&
|
||||
'
|
||||
(
|
||||
)
|
||||
*
|
||||
+
|
||||
,
|
||||
-
|
||||
.
|
||||
/
|
||||
|
||||
110
backend/ppocr/utils/dict/es_dict.txt
Normal file
110
backend/ppocr/utils/dict/es_dict.txt
Normal file
@@ -0,0 +1,110 @@
|
||||
x
|
||||
i
|
||||
_
|
||||
m
|
||||
g
|
||||
/
|
||||
1
|
||||
0
|
||||
I
|
||||
L
|
||||
S
|
||||
V
|
||||
R
|
||||
C
|
||||
2
|
||||
v
|
||||
a
|
||||
l
|
||||
3
|
||||
6
|
||||
4
|
||||
5
|
||||
.
|
||||
j
|
||||
p
|
||||
|
||||
Q
|
||||
u
|
||||
e
|
||||
r
|
||||
o
|
||||
8
|
||||
7
|
||||
n
|
||||
c
|
||||
9
|
||||
t
|
||||
b
|
||||
é
|
||||
q
|
||||
d
|
||||
ó
|
||||
y
|
||||
F
|
||||
s
|
||||
,
|
||||
O
|
||||
í
|
||||
T
|
||||
f
|
||||
"
|
||||
U
|
||||
M
|
||||
h
|
||||
:
|
||||
P
|
||||
H
|
||||
A
|
||||
E
|
||||
D
|
||||
z
|
||||
N
|
||||
á
|
||||
ñ
|
||||
ú
|
||||
%
|
||||
;
|
||||
è
|
||||
+
|
||||
Y
|
||||
-
|
||||
B
|
||||
G
|
||||
(
|
||||
)
|
||||
¿
|
||||
?
|
||||
w
|
||||
¡
|
||||
!
|
||||
X
|
||||
É
|
||||
K
|
||||
k
|
||||
Á
|
||||
ü
|
||||
Ú
|
||||
«
|
||||
»
|
||||
J
|
||||
'
|
||||
ö
|
||||
W
|
||||
Z
|
||||
º
|
||||
Ö
|
||||
|
||||
[
|
||||
]
|
||||
Ç
|
||||
ç
|
||||
à
|
||||
ä
|
||||
û
|
||||
ò
|
||||
Í
|
||||
ê
|
||||
ô
|
||||
ø
|
||||
ª
|
||||
136
backend/ppocr/utils/dict/fa_dict.txt
Normal file
136
backend/ppocr/utils/dict/fa_dict.txt
Normal file
@@ -0,0 +1,136 @@
|
||||
f
|
||||
a
|
||||
_
|
||||
i
|
||||
m
|
||||
g
|
||||
/
|
||||
1
|
||||
3
|
||||
I
|
||||
L
|
||||
S
|
||||
V
|
||||
R
|
||||
C
|
||||
2
|
||||
0
|
||||
v
|
||||
l
|
||||
6
|
||||
8
|
||||
5
|
||||
.
|
||||
j
|
||||
p
|
||||
و
|
||||
د
|
||||
ر
|
||||
ك
|
||||
ن
|
||||
ش
|
||||
ه
|
||||
ا
|
||||
4
|
||||
9
|
||||
ی
|
||||
ج
|
||||
ِ
|
||||
7
|
||||
غ
|
||||
ل
|
||||
س
|
||||
ز
|
||||
ّ
|
||||
ت
|
||||
ک
|
||||
گ
|
||||
ي
|
||||
م
|
||||
ب
|
||||
ف
|
||||
چ
|
||||
خ
|
||||
ق
|
||||
ژ
|
||||
آ
|
||||
ص
|
||||
پ
|
||||
َ
|
||||
ع
|
||||
ئ
|
||||
ح
|
||||
ٔ
|
||||
ض
|
||||
ُ
|
||||
ذ
|
||||
أ
|
||||
ى
|
||||
ط
|
||||
ظ
|
||||
ث
|
||||
ة
|
||||
ً
|
||||
ء
|
||||
ؤ
|
||||
ْ
|
||||
ۀ
|
||||
إ
|
||||
ٍ
|
||||
ٌ
|
||||
ٰ
|
||||
ٓ
|
||||
ٱ
|
||||
s
|
||||
c
|
||||
e
|
||||
n
|
||||
w
|
||||
N
|
||||
E
|
||||
W
|
||||
Y
|
||||
D
|
||||
O
|
||||
H
|
||||
A
|
||||
d
|
||||
z
|
||||
r
|
||||
T
|
||||
G
|
||||
o
|
||||
t
|
||||
x
|
||||
h
|
||||
b
|
||||
B
|
||||
M
|
||||
Z
|
||||
u
|
||||
P
|
||||
F
|
||||
y
|
||||
q
|
||||
U
|
||||
K
|
||||
k
|
||||
J
|
||||
Q
|
||||
'
|
||||
X
|
||||
#
|
||||
?
|
||||
%
|
||||
$
|
||||
,
|
||||
:
|
||||
&
|
||||
!
|
||||
-
|
||||
(
|
||||
É
|
||||
@
|
||||
é
|
||||
+
|
||||
|
||||
136
backend/ppocr/utils/dict/french_dict.txt
Normal file
136
backend/ppocr/utils/dict/french_dict.txt
Normal file
@@ -0,0 +1,136 @@
|
||||
f
|
||||
e
|
||||
n
|
||||
c
|
||||
h
|
||||
_
|
||||
i
|
||||
m
|
||||
g
|
||||
/
|
||||
r
|
||||
v
|
||||
a
|
||||
l
|
||||
t
|
||||
w
|
||||
o
|
||||
d
|
||||
6
|
||||
1
|
||||
.
|
||||
p
|
||||
B
|
||||
u
|
||||
2
|
||||
à
|
||||
3
|
||||
R
|
||||
y
|
||||
4
|
||||
U
|
||||
E
|
||||
A
|
||||
5
|
||||
P
|
||||
O
|
||||
S
|
||||
T
|
||||
D
|
||||
7
|
||||
Z
|
||||
8
|
||||
I
|
||||
N
|
||||
L
|
||||
G
|
||||
M
|
||||
H
|
||||
0
|
||||
J
|
||||
K
|
||||
-
|
||||
9
|
||||
F
|
||||
C
|
||||
V
|
||||
é
|
||||
X
|
||||
'
|
||||
s
|
||||
Q
|
||||
:
|
||||
è
|
||||
x
|
||||
b
|
||||
Y
|
||||
Œ
|
||||
É
|
||||
z
|
||||
W
|
||||
Ç
|
||||
È
|
||||
k
|
||||
Ô
|
||||
ô
|
||||
€
|
||||
À
|
||||
Ê
|
||||
q
|
||||
ù
|
||||
°
|
||||
ê
|
||||
î
|
||||
*
|
||||
Â
|
||||
j
|
||||
"
|
||||
,
|
||||
â
|
||||
%
|
||||
û
|
||||
ç
|
||||
ü
|
||||
?
|
||||
!
|
||||
;
|
||||
ö
|
||||
(
|
||||
)
|
||||
ï
|
||||
º
|
||||
ó
|
||||
ø
|
||||
å
|
||||
+
|
||||
™
|
||||
á
|
||||
Ë
|
||||
<
|
||||
²
|
||||
Á
|
||||
Î
|
||||
&
|
||||
@
|
||||
œ
|
||||
ε
|
||||
Ü
|
||||
ë
|
||||
[
|
||||
]
|
||||
í
|
||||
ò
|
||||
Ö
|
||||
ä
|
||||
ß
|
||||
«
|
||||
»
|
||||
ú
|
||||
ñ
|
||||
æ
|
||||
µ
|
||||
³
|
||||
Å
|
||||
$
|
||||
#
|
||||
|
||||
143
backend/ppocr/utils/dict/german_dict.txt
Normal file
143
backend/ppocr/utils/dict/german_dict.txt
Normal file
@@ -0,0 +1,143 @@
|
||||
|
||||
!
|
||||
"
|
||||
#
|
||||
$
|
||||
%
|
||||
&
|
||||
'
|
||||
(
|
||||
)
|
||||
*
|
||||
+
|
||||
,
|
||||
-
|
||||
.
|
||||
/
|
||||
0
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
6
|
||||
7
|
||||
8
|
||||
9
|
||||
:
|
||||
;
|
||||
=
|
||||
>
|
||||
?
|
||||
@
|
||||
A
|
||||
B
|
||||
C
|
||||
D
|
||||
E
|
||||
F
|
||||
G
|
||||
H
|
||||
I
|
||||
J
|
||||
K
|
||||
L
|
||||
M
|
||||
N
|
||||
O
|
||||
P
|
||||
Q
|
||||
R
|
||||
S
|
||||
T
|
||||
U
|
||||
V
|
||||
W
|
||||
X
|
||||
Y
|
||||
Z
|
||||
[
|
||||
]
|
||||
_
|
||||
a
|
||||
b
|
||||
c
|
||||
d
|
||||
e
|
||||
f
|
||||
g
|
||||
h
|
||||
i
|
||||
j
|
||||
k
|
||||
l
|
||||
m
|
||||
n
|
||||
o
|
||||
p
|
||||
q
|
||||
r
|
||||
s
|
||||
t
|
||||
u
|
||||
v
|
||||
w
|
||||
x
|
||||
y
|
||||
z
|
||||
£
|
||||
§
|
||||
|
||||
°
|
||||
´
|
||||
µ
|
||||
·
|
||||
º
|
||||
¿
|
||||
Á
|
||||
Ä
|
||||
Å
|
||||
É
|
||||
Ï
|
||||
Ô
|
||||
Ö
|
||||
Ü
|
||||
ß
|
||||
à
|
||||
á
|
||||
â
|
||||
ã
|
||||
ä
|
||||
å
|
||||
æ
|
||||
ç
|
||||
è
|
||||
é
|
||||
ê
|
||||
ë
|
||||
í
|
||||
ï
|
||||
ñ
|
||||
ò
|
||||
ó
|
||||
ô
|
||||
ö
|
||||
ø
|
||||
ù
|
||||
ú
|
||||
û
|
||||
ü
|
||||
ō
|
||||
Š
|
||||
Ÿ
|
||||
ʒ
|
||||
β
|
||||
δ
|
||||
з
|
||||
Ṡ
|
||||
‘
|
||||
€
|
||||
©
|
||||
ª
|
||||
«
|
||||
¬
|
||||
162
backend/ppocr/utils/dict/hi_dict.txt
Normal file
162
backend/ppocr/utils/dict/hi_dict.txt
Normal file
@@ -0,0 +1,162 @@
|
||||
|
||||
!
|
||||
#
|
||||
$
|
||||
%
|
||||
&
|
||||
'
|
||||
(
|
||||
+
|
||||
,
|
||||
-
|
||||
.
|
||||
/
|
||||
0
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
6
|
||||
7
|
||||
8
|
||||
9
|
||||
:
|
||||
?
|
||||
@
|
||||
A
|
||||
B
|
||||
C
|
||||
D
|
||||
E
|
||||
F
|
||||
G
|
||||
H
|
||||
I
|
||||
J
|
||||
K
|
||||
L
|
||||
M
|
||||
N
|
||||
O
|
||||
P
|
||||
Q
|
||||
R
|
||||
S
|
||||
T
|
||||
U
|
||||
V
|
||||
W
|
||||
X
|
||||
Y
|
||||
Z
|
||||
_
|
||||
a
|
||||
b
|
||||
c
|
||||
d
|
||||
e
|
||||
f
|
||||
g
|
||||
h
|
||||
i
|
||||
j
|
||||
k
|
||||
l
|
||||
m
|
||||
n
|
||||
o
|
||||
p
|
||||
q
|
||||
r
|
||||
s
|
||||
t
|
||||
u
|
||||
v
|
||||
w
|
||||
x
|
||||
y
|
||||
z
|
||||
É
|
||||
é
|
||||
ँ
|
||||
ं
|
||||
ः
|
||||
अ
|
||||
आ
|
||||
इ
|
||||
ई
|
||||
उ
|
||||
ऊ
|
||||
ऋ
|
||||
ए
|
||||
ऐ
|
||||
ऑ
|
||||
ओ
|
||||
औ
|
||||
क
|
||||
ख
|
||||
ग
|
||||
घ
|
||||
ङ
|
||||
च
|
||||
छ
|
||||
ज
|
||||
झ
|
||||
ञ
|
||||
ट
|
||||
ठ
|
||||
ड
|
||||
ढ
|
||||
ण
|
||||
त
|
||||
थ
|
||||
द
|
||||
ध
|
||||
न
|
||||
प
|
||||
फ
|
||||
ब
|
||||
भ
|
||||
म
|
||||
य
|
||||
र
|
||||
ल
|
||||
ळ
|
||||
व
|
||||
श
|
||||
ष
|
||||
स
|
||||
ह
|
||||
़
|
||||
ा
|
||||
ि
|
||||
ी
|
||||
ु
|
||||
ू
|
||||
ृ
|
||||
ॅ
|
||||
े
|
||||
ै
|
||||
ॉ
|
||||
ो
|
||||
ौ
|
||||
्
|
||||
क़
|
||||
ख़
|
||||
ग़
|
||||
ज़
|
||||
ड़
|
||||
ढ़
|
||||
फ़
|
||||
०
|
||||
१
|
||||
२
|
||||
३
|
||||
४
|
||||
५
|
||||
६
|
||||
७
|
||||
८
|
||||
९
|
||||
॰
|
||||
118
backend/ppocr/utils/dict/it_dict.txt
Normal file
118
backend/ppocr/utils/dict/it_dict.txt
Normal file
@@ -0,0 +1,118 @@
|
||||
i
|
||||
t
|
||||
_
|
||||
m
|
||||
g
|
||||
/
|
||||
5
|
||||
I
|
||||
L
|
||||
S
|
||||
V
|
||||
R
|
||||
C
|
||||
2
|
||||
0
|
||||
1
|
||||
v
|
||||
a
|
||||
l
|
||||
7
|
||||
8
|
||||
9
|
||||
6
|
||||
.
|
||||
j
|
||||
p
|
||||
|
||||
e
|
||||
r
|
||||
o
|
||||
d
|
||||
s
|
||||
n
|
||||
3
|
||||
4
|
||||
P
|
||||
u
|
||||
c
|
||||
A
|
||||
-
|
||||
,
|
||||
"
|
||||
z
|
||||
h
|
||||
f
|
||||
b
|
||||
q
|
||||
ì
|
||||
'
|
||||
à
|
||||
O
|
||||
è
|
||||
G
|
||||
ù
|
||||
é
|
||||
ò
|
||||
;
|
||||
F
|
||||
E
|
||||
B
|
||||
N
|
||||
H
|
||||
k
|
||||
:
|
||||
U
|
||||
T
|
||||
X
|
||||
D
|
||||
K
|
||||
?
|
||||
[
|
||||
M
|
||||
|
||||
x
|
||||
y
|
||||
(
|
||||
)
|
||||
W
|
||||
ö
|
||||
º
|
||||
w
|
||||
]
|
||||
Q
|
||||
J
|
||||
+
|
||||
ü
|
||||
!
|
||||
È
|
||||
á
|
||||
%
|
||||
=
|
||||
»
|
||||
ñ
|
||||
Ö
|
||||
Y
|
||||
ä
|
||||
í
|
||||
Z
|
||||
«
|
||||
@
|
||||
ó
|
||||
ø
|
||||
ï
|
||||
ú
|
||||
ê
|
||||
ç
|
||||
Á
|
||||
É
|
||||
Å
|
||||
ß
|
||||
{
|
||||
}
|
||||
&
|
||||
`
|
||||
û
|
||||
î
|
||||
#
|
||||
$
|
||||
4399
backend/ppocr/utils/dict/japan_dict.txt
Normal file
4399
backend/ppocr/utils/dict/japan_dict.txt
Normal file
File diff suppressed because it is too large
Load Diff
153
backend/ppocr/utils/dict/ka_dict.txt
Normal file
153
backend/ppocr/utils/dict/ka_dict.txt
Normal file
@@ -0,0 +1,153 @@
|
||||
k
|
||||
a
|
||||
_
|
||||
i
|
||||
m
|
||||
g
|
||||
/
|
||||
1
|
||||
2
|
||||
I
|
||||
L
|
||||
S
|
||||
V
|
||||
R
|
||||
C
|
||||
0
|
||||
v
|
||||
l
|
||||
6
|
||||
4
|
||||
8
|
||||
.
|
||||
j
|
||||
p
|
||||
ಗ
|
||||
ು
|
||||
ಣ
|
||||
ಪ
|
||||
ಡ
|
||||
ಿ
|
||||
ಸ
|
||||
ಲ
|
||||
ಾ
|
||||
ದ
|
||||
್
|
||||
7
|
||||
5
|
||||
3
|
||||
ವ
|
||||
ಷ
|
||||
ಬ
|
||||
ಹ
|
||||
ೆ
|
||||
9
|
||||
ಅ
|
||||
ಳ
|
||||
ನ
|
||||
ರ
|
||||
ಉ
|
||||
ಕ
|
||||
ಎ
|
||||
ೇ
|
||||
ಂ
|
||||
ೈ
|
||||
ೊ
|
||||
ೀ
|
||||
ಯ
|
||||
ೋ
|
||||
ತ
|
||||
ಶ
|
||||
ಭ
|
||||
ಧ
|
||||
ಚ
|
||||
ಜ
|
||||
ೂ
|
||||
ಮ
|
||||
ಒ
|
||||
ೃ
|
||||
ಥ
|
||||
ಇ
|
||||
ಟ
|
||||
ಖ
|
||||
ಆ
|
||||
ಞ
|
||||
ಫ
|
||||
-
|
||||
ಢ
|
||||
ಊ
|
||||
ಓ
|
||||
ಐ
|
||||
ಃ
|
||||
ಘ
|
||||
ಝ
|
||||
ೌ
|
||||
ಠ
|
||||
ಛ
|
||||
ಔ
|
||||
ಏ
|
||||
ಈ
|
||||
ಋ
|
||||
೨
|
||||
೦
|
||||
೧
|
||||
೮
|
||||
೯
|
||||
೪
|
||||
,
|
||||
೫
|
||||
೭
|
||||
೩
|
||||
೬
|
||||
ಙ
|
||||
s
|
||||
c
|
||||
e
|
||||
n
|
||||
w
|
||||
o
|
||||
u
|
||||
t
|
||||
d
|
||||
E
|
||||
A
|
||||
T
|
||||
B
|
||||
Z
|
||||
N
|
||||
G
|
||||
O
|
||||
q
|
||||
z
|
||||
r
|
||||
x
|
||||
P
|
||||
K
|
||||
M
|
||||
J
|
||||
U
|
||||
D
|
||||
f
|
||||
F
|
||||
h
|
||||
b
|
||||
W
|
||||
Y
|
||||
y
|
||||
H
|
||||
X
|
||||
Q
|
||||
'
|
||||
#
|
||||
&
|
||||
!
|
||||
@
|
||||
$
|
||||
:
|
||||
%
|
||||
é
|
||||
É
|
||||
(
|
||||
?
|
||||
+
|
||||
|
||||
4
backend/ppocr/utils/dict/kie_dict/xfund_class_list.txt
Normal file
4
backend/ppocr/utils/dict/kie_dict/xfund_class_list.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
OTHER
|
||||
QUESTION
|
||||
ANSWER
|
||||
HEADER
|
||||
153
backend/ppocr/utils/dict/kn_dict.txt
Normal file
153
backend/ppocr/utils/dict/kn_dict.txt
Normal file
@@ -0,0 +1,153 @@
|
||||
k
|
||||
a
|
||||
_
|
||||
i
|
||||
m
|
||||
g
|
||||
/
|
||||
1
|
||||
2
|
||||
I
|
||||
L
|
||||
S
|
||||
V
|
||||
R
|
||||
C
|
||||
0
|
||||
v
|
||||
l
|
||||
6
|
||||
4
|
||||
8
|
||||
.
|
||||
j
|
||||
p
|
||||
ಗ
|
||||
ು
|
||||
ಣ
|
||||
ಪ
|
||||
ಡ
|
||||
ಿ
|
||||
ಸ
|
||||
ಲ
|
||||
ಾ
|
||||
ದ
|
||||
್
|
||||
7
|
||||
5
|
||||
3
|
||||
ವ
|
||||
ಷ
|
||||
ಬ
|
||||
ಹ
|
||||
ೆ
|
||||
9
|
||||
ಅ
|
||||
ಳ
|
||||
ನ
|
||||
ರ
|
||||
ಉ
|
||||
ಕ
|
||||
ಎ
|
||||
ೇ
|
||||
ಂ
|
||||
ೈ
|
||||
ೊ
|
||||
ೀ
|
||||
ಯ
|
||||
ೋ
|
||||
ತ
|
||||
ಶ
|
||||
ಭ
|
||||
ಧ
|
||||
ಚ
|
||||
ಜ
|
||||
ೂ
|
||||
ಮ
|
||||
ಒ
|
||||
ೃ
|
||||
ಥ
|
||||
ಇ
|
||||
ಟ
|
||||
ಖ
|
||||
ಆ
|
||||
ಞ
|
||||
ಫ
|
||||
-
|
||||
ಢ
|
||||
ಊ
|
||||
ಓ
|
||||
ಐ
|
||||
ಃ
|
||||
ಘ
|
||||
ಝ
|
||||
ೌ
|
||||
ಠ
|
||||
ಛ
|
||||
ಔ
|
||||
ಏ
|
||||
ಈ
|
||||
ಋ
|
||||
೨
|
||||
೦
|
||||
೧
|
||||
೮
|
||||
೯
|
||||
೪
|
||||
,
|
||||
೫
|
||||
೭
|
||||
೩
|
||||
೬
|
||||
ಙ
|
||||
s
|
||||
c
|
||||
e
|
||||
n
|
||||
w
|
||||
o
|
||||
u
|
||||
t
|
||||
d
|
||||
E
|
||||
A
|
||||
T
|
||||
B
|
||||
Z
|
||||
N
|
||||
G
|
||||
O
|
||||
q
|
||||
z
|
||||
r
|
||||
x
|
||||
P
|
||||
K
|
||||
M
|
||||
J
|
||||
U
|
||||
D
|
||||
f
|
||||
F
|
||||
h
|
||||
b
|
||||
W
|
||||
Y
|
||||
y
|
||||
H
|
||||
X
|
||||
Q
|
||||
'
|
||||
#
|
||||
&
|
||||
!
|
||||
@
|
||||
$
|
||||
:
|
||||
%
|
||||
é
|
||||
É
|
||||
(
|
||||
?
|
||||
+
|
||||
|
||||
3688
backend/ppocr/utils/dict/korean_dict.txt
Normal file
3688
backend/ppocr/utils/dict/korean_dict.txt
Normal file
File diff suppressed because it is too large
Load Diff
185
backend/ppocr/utils/dict/latin_dict.txt
Normal file
185
backend/ppocr/utils/dict/latin_dict.txt
Normal file
@@ -0,0 +1,185 @@
|
||||
|
||||
!
|
||||
"
|
||||
#
|
||||
$
|
||||
%
|
||||
&
|
||||
'
|
||||
(
|
||||
)
|
||||
*
|
||||
+
|
||||
,
|
||||
-
|
||||
.
|
||||
/
|
||||
0
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
6
|
||||
7
|
||||
8
|
||||
9
|
||||
:
|
||||
;
|
||||
<
|
||||
=
|
||||
>
|
||||
?
|
||||
@
|
||||
A
|
||||
B
|
||||
C
|
||||
D
|
||||
E
|
||||
F
|
||||
G
|
||||
H
|
||||
I
|
||||
J
|
||||
K
|
||||
L
|
||||
M
|
||||
N
|
||||
O
|
||||
P
|
||||
Q
|
||||
R
|
||||
S
|
||||
T
|
||||
U
|
||||
V
|
||||
W
|
||||
X
|
||||
Y
|
||||
Z
|
||||
[
|
||||
]
|
||||
_
|
||||
`
|
||||
a
|
||||
b
|
||||
c
|
||||
d
|
||||
e
|
||||
f
|
||||
g
|
||||
h
|
||||
i
|
||||
j
|
||||
k
|
||||
l
|
||||
m
|
||||
n
|
||||
o
|
||||
p
|
||||
q
|
||||
r
|
||||
s
|
||||
t
|
||||
u
|
||||
v
|
||||
w
|
||||
x
|
||||
y
|
||||
z
|
||||
{
|
||||
}
|
||||
¡
|
||||
£
|
||||
§
|
||||
ª
|
||||
«
|
||||
|
||||
°
|
||||
²
|
||||
³
|
||||
´
|
||||
µ
|
||||
·
|
||||
º
|
||||
»
|
||||
¿
|
||||
À
|
||||
Á
|
||||
Â
|
||||
Ä
|
||||
Å
|
||||
Ç
|
||||
È
|
||||
É
|
||||
Ê
|
||||
Ë
|
||||
Ì
|
||||
Í
|
||||
Î
|
||||
Ï
|
||||
Ò
|
||||
Ó
|
||||
Ô
|
||||
Õ
|
||||
Ö
|
||||
Ú
|
||||
Ü
|
||||
Ý
|
||||
ß
|
||||
à
|
||||
á
|
||||
â
|
||||
ã
|
||||
ä
|
||||
å
|
||||
æ
|
||||
ç
|
||||
è
|
||||
é
|
||||
ê
|
||||
ë
|
||||
ì
|
||||
í
|
||||
î
|
||||
ï
|
||||
ñ
|
||||
ò
|
||||
ó
|
||||
ô
|
||||
õ
|
||||
ö
|
||||
ø
|
||||
ù
|
||||
ú
|
||||
û
|
||||
ü
|
||||
ý
|
||||
ą
|
||||
Ć
|
||||
ć
|
||||
Č
|
||||
č
|
||||
Đ
|
||||
đ
|
||||
ę
|
||||
ı
|
||||
Ł
|
||||
ł
|
||||
ō
|
||||
Œ
|
||||
œ
|
||||
Š
|
||||
š
|
||||
Ÿ
|
||||
Ž
|
||||
ž
|
||||
ʒ
|
||||
β
|
||||
δ
|
||||
ε
|
||||
з
|
||||
Ṡ
|
||||
‘
|
||||
€
|
||||
™
|
||||
10
backend/ppocr/utils/dict/layout_dict/layout_cdla_dict.txt
Normal file
10
backend/ppocr/utils/dict/layout_dict/layout_cdla_dict.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
text
|
||||
title
|
||||
figure
|
||||
figure_caption
|
||||
table
|
||||
table_caption
|
||||
header
|
||||
footer
|
||||
reference
|
||||
equation
|
||||
@@ -0,0 +1,5 @@
|
||||
text
|
||||
title
|
||||
list
|
||||
table
|
||||
figure
|
||||
@@ -0,0 +1 @@
|
||||
table
|
||||
153
backend/ppocr/utils/dict/mr_dict.txt
Normal file
153
backend/ppocr/utils/dict/mr_dict.txt
Normal file
@@ -0,0 +1,153 @@
|
||||
|
||||
!
|
||||
#
|
||||
$
|
||||
%
|
||||
&
|
||||
'
|
||||
(
|
||||
+
|
||||
,
|
||||
-
|
||||
.
|
||||
/
|
||||
0
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
6
|
||||
7
|
||||
8
|
||||
9
|
||||
:
|
||||
?
|
||||
@
|
||||
A
|
||||
B
|
||||
C
|
||||
D
|
||||
E
|
||||
F
|
||||
G
|
||||
H
|
||||
I
|
||||
J
|
||||
K
|
||||
L
|
||||
M
|
||||
N
|
||||
O
|
||||
P
|
||||
Q
|
||||
R
|
||||
S
|
||||
T
|
||||
U
|
||||
V
|
||||
W
|
||||
X
|
||||
Y
|
||||
Z
|
||||
_
|
||||
a
|
||||
b
|
||||
c
|
||||
d
|
||||
e
|
||||
f
|
||||
g
|
||||
h
|
||||
i
|
||||
j
|
||||
k
|
||||
l
|
||||
m
|
||||
n
|
||||
o
|
||||
p
|
||||
q
|
||||
r
|
||||
s
|
||||
t
|
||||
u
|
||||
v
|
||||
w
|
||||
x
|
||||
y
|
||||
z
|
||||
É
|
||||
é
|
||||
ँ
|
||||
ं
|
||||
ः
|
||||
अ
|
||||
आ
|
||||
इ
|
||||
ई
|
||||
उ
|
||||
ऊ
|
||||
ए
|
||||
ऐ
|
||||
ऑ
|
||||
ओ
|
||||
औ
|
||||
क
|
||||
ख
|
||||
ग
|
||||
घ
|
||||
च
|
||||
छ
|
||||
ज
|
||||
झ
|
||||
ञ
|
||||
ट
|
||||
ठ
|
||||
ड
|
||||
ढ
|
||||
ण
|
||||
त
|
||||
थ
|
||||
द
|
||||
ध
|
||||
न
|
||||
प
|
||||
फ
|
||||
ब
|
||||
भ
|
||||
म
|
||||
य
|
||||
र
|
||||
ऱ
|
||||
ल
|
||||
ळ
|
||||
व
|
||||
श
|
||||
ष
|
||||
स
|
||||
ह
|
||||
़
|
||||
ा
|
||||
ि
|
||||
ी
|
||||
ु
|
||||
ू
|
||||
ृ
|
||||
ॅ
|
||||
े
|
||||
ै
|
||||
ॉ
|
||||
ो
|
||||
ौ
|
||||
्
|
||||
०
|
||||
१
|
||||
२
|
||||
३
|
||||
४
|
||||
५
|
||||
६
|
||||
७
|
||||
८
|
||||
९
|
||||
153
backend/ppocr/utils/dict/ne_dict.txt
Normal file
153
backend/ppocr/utils/dict/ne_dict.txt
Normal file
@@ -0,0 +1,153 @@
|
||||
|
||||
!
|
||||
#
|
||||
$
|
||||
%
|
||||
&
|
||||
'
|
||||
(
|
||||
+
|
||||
,
|
||||
-
|
||||
.
|
||||
/
|
||||
0
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
6
|
||||
7
|
||||
8
|
||||
9
|
||||
:
|
||||
?
|
||||
@
|
||||
A
|
||||
B
|
||||
C
|
||||
D
|
||||
E
|
||||
F
|
||||
G
|
||||
H
|
||||
I
|
||||
J
|
||||
K
|
||||
L
|
||||
M
|
||||
N
|
||||
O
|
||||
P
|
||||
Q
|
||||
R
|
||||
S
|
||||
T
|
||||
U
|
||||
V
|
||||
W
|
||||
X
|
||||
Y
|
||||
Z
|
||||
_
|
||||
a
|
||||
b
|
||||
c
|
||||
d
|
||||
e
|
||||
f
|
||||
g
|
||||
h
|
||||
i
|
||||
j
|
||||
k
|
||||
l
|
||||
m
|
||||
n
|
||||
o
|
||||
p
|
||||
q
|
||||
r
|
||||
s
|
||||
t
|
||||
u
|
||||
v
|
||||
w
|
||||
x
|
||||
y
|
||||
z
|
||||
É
|
||||
é
|
||||
ः
|
||||
अ
|
||||
आ
|
||||
इ
|
||||
ई
|
||||
उ
|
||||
ऊ
|
||||
ऋ
|
||||
ए
|
||||
ऐ
|
||||
ओ
|
||||
औ
|
||||
क
|
||||
ख
|
||||
ग
|
||||
घ
|
||||
ङ
|
||||
च
|
||||
छ
|
||||
ज
|
||||
झ
|
||||
ञ
|
||||
ट
|
||||
ठ
|
||||
ड
|
||||
ढ
|
||||
ण
|
||||
त
|
||||
थ
|
||||
द
|
||||
ध
|
||||
न
|
||||
ऩ
|
||||
प
|
||||
फ
|
||||
ब
|
||||
भ
|
||||
म
|
||||
य
|
||||
र
|
||||
ऱ
|
||||
ल
|
||||
व
|
||||
श
|
||||
ष
|
||||
स
|
||||
ह
|
||||
़
|
||||
ा
|
||||
ि
|
||||
ी
|
||||
ु
|
||||
ू
|
||||
ृ
|
||||
े
|
||||
ै
|
||||
ो
|
||||
ौ
|
||||
्
|
||||
॒
|
||||
ॠ
|
||||
।
|
||||
०
|
||||
१
|
||||
२
|
||||
३
|
||||
४
|
||||
५
|
||||
६
|
||||
७
|
||||
८
|
||||
९
|
||||
96
backend/ppocr/utils/dict/oc_dict.txt
Normal file
96
backend/ppocr/utils/dict/oc_dict.txt
Normal file
@@ -0,0 +1,96 @@
|
||||
o
|
||||
c
|
||||
_
|
||||
i
|
||||
m
|
||||
g
|
||||
/
|
||||
2
|
||||
0
|
||||
I
|
||||
L
|
||||
S
|
||||
V
|
||||
R
|
||||
C
|
||||
1
|
||||
v
|
||||
a
|
||||
l
|
||||
4
|
||||
3
|
||||
.
|
||||
j
|
||||
p
|
||||
r
|
||||
e
|
||||
è
|
||||
t
|
||||
9
|
||||
7
|
||||
5
|
||||
8
|
||||
n
|
||||
'
|
||||
b
|
||||
s
|
||||
6
|
||||
q
|
||||
u
|
||||
á
|
||||
d
|
||||
ò
|
||||
à
|
||||
h
|
||||
z
|
||||
f
|
||||
ï
|
||||
í
|
||||
A
|
||||
ç
|
||||
x
|
||||
ó
|
||||
é
|
||||
P
|
||||
O
|
||||
Ò
|
||||
ü
|
||||
k
|
||||
À
|
||||
F
|
||||
-
|
||||
ú
|
||||
|
||||
æ
|
||||
Á
|
||||
D
|
||||
E
|
||||
w
|
||||
K
|
||||
T
|
||||
N
|
||||
y
|
||||
U
|
||||
Z
|
||||
G
|
||||
B
|
||||
J
|
||||
H
|
||||
M
|
||||
W
|
||||
Y
|
||||
X
|
||||
Q
|
||||
%
|
||||
$
|
||||
,
|
||||
@
|
||||
&
|
||||
!
|
||||
:
|
||||
(
|
||||
#
|
||||
?
|
||||
+
|
||||
É
|
||||
|
||||
130
backend/ppocr/utils/dict/pt_dict.txt
Normal file
130
backend/ppocr/utils/dict/pt_dict.txt
Normal file
@@ -0,0 +1,130 @@
|
||||
p
|
||||
u
|
||||
_
|
||||
i
|
||||
m
|
||||
g
|
||||
/
|
||||
8
|
||||
I
|
||||
L
|
||||
S
|
||||
V
|
||||
R
|
||||
C
|
||||
2
|
||||
0
|
||||
1
|
||||
v
|
||||
a
|
||||
l
|
||||
6
|
||||
7
|
||||
4
|
||||
5
|
||||
.
|
||||
j
|
||||
|
||||
q
|
||||
e
|
||||
s
|
||||
t
|
||||
ã
|
||||
o
|
||||
x
|
||||
9
|
||||
c
|
||||
n
|
||||
r
|
||||
z
|
||||
ç
|
||||
õ
|
||||
3
|
||||
A
|
||||
U
|
||||
d
|
||||
º
|
||||
ô
|
||||
|
||||
,
|
||||
E
|
||||
;
|
||||
ó
|
||||
á
|
||||
b
|
||||
D
|
||||
?
|
||||
ú
|
||||
ê
|
||||
-
|
||||
h
|
||||
P
|
||||
f
|
||||
à
|
||||
N
|
||||
í
|
||||
O
|
||||
M
|
||||
G
|
||||
É
|
||||
é
|
||||
â
|
||||
F
|
||||
:
|
||||
T
|
||||
Á
|
||||
"
|
||||
Q
|
||||
)
|
||||
W
|
||||
J
|
||||
B
|
||||
H
|
||||
(
|
||||
ö
|
||||
%
|
||||
Ö
|
||||
«
|
||||
w
|
||||
K
|
||||
y
|
||||
!
|
||||
k
|
||||
]
|
||||
'
|
||||
Z
|
||||
+
|
||||
Ç
|
||||
Õ
|
||||
Y
|
||||
À
|
||||
X
|
||||
µ
|
||||
»
|
||||
ª
|
||||
Í
|
||||
ü
|
||||
ä
|
||||
´
|
||||
è
|
||||
ñ
|
||||
ß
|
||||
ï
|
||||
Ú
|
||||
ë
|
||||
Ô
|
||||
Ï
|
||||
Ó
|
||||
[
|
||||
Ì
|
||||
<
|
||||
Â
|
||||
ò
|
||||
§
|
||||
³
|
||||
ø
|
||||
å
|
||||
#
|
||||
$
|
||||
&
|
||||
@
|
||||
130
backend/ppocr/utils/dict/pu_dict.txt
Normal file
130
backend/ppocr/utils/dict/pu_dict.txt
Normal file
@@ -0,0 +1,130 @@
|
||||
p
|
||||
u
|
||||
_
|
||||
i
|
||||
m
|
||||
g
|
||||
/
|
||||
8
|
||||
I
|
||||
L
|
||||
S
|
||||
V
|
||||
R
|
||||
C
|
||||
2
|
||||
0
|
||||
1
|
||||
v
|
||||
a
|
||||
l
|
||||
6
|
||||
7
|
||||
4
|
||||
5
|
||||
.
|
||||
j
|
||||
|
||||
q
|
||||
e
|
||||
s
|
||||
t
|
||||
ã
|
||||
o
|
||||
x
|
||||
9
|
||||
c
|
||||
n
|
||||
r
|
||||
z
|
||||
ç
|
||||
õ
|
||||
3
|
||||
A
|
||||
U
|
||||
d
|
||||
º
|
||||
ô
|
||||
|
||||
,
|
||||
E
|
||||
;
|
||||
ó
|
||||
á
|
||||
b
|
||||
D
|
||||
?
|
||||
ú
|
||||
ê
|
||||
-
|
||||
h
|
||||
P
|
||||
f
|
||||
à
|
||||
N
|
||||
í
|
||||
O
|
||||
M
|
||||
G
|
||||
É
|
||||
é
|
||||
â
|
||||
F
|
||||
:
|
||||
T
|
||||
Á
|
||||
"
|
||||
Q
|
||||
)
|
||||
W
|
||||
J
|
||||
B
|
||||
H
|
||||
(
|
||||
ö
|
||||
%
|
||||
Ö
|
||||
«
|
||||
w
|
||||
K
|
||||
y
|
||||
!
|
||||
k
|
||||
]
|
||||
'
|
||||
Z
|
||||
+
|
||||
Ç
|
||||
Õ
|
||||
Y
|
||||
À
|
||||
X
|
||||
µ
|
||||
»
|
||||
ª
|
||||
Í
|
||||
ü
|
||||
ä
|
||||
´
|
||||
è
|
||||
ñ
|
||||
ß
|
||||
ï
|
||||
Ú
|
||||
ë
|
||||
Ô
|
||||
Ï
|
||||
Ó
|
||||
[
|
||||
Ì
|
||||
<
|
||||
Â
|
||||
ò
|
||||
§
|
||||
³
|
||||
ø
|
||||
å
|
||||
#
|
||||
$
|
||||
&
|
||||
@
|
||||
134
backend/ppocr/utils/dict/rs_cyrillic_dict.txt
Normal file
134
backend/ppocr/utils/dict/rs_cyrillic_dict.txt
Normal file
@@ -0,0 +1,134 @@
|
||||
r
|
||||
s
|
||||
c
|
||||
_
|
||||
i
|
||||
m
|
||||
g
|
||||
/
|
||||
5
|
||||
I
|
||||
L
|
||||
S
|
||||
V
|
||||
R
|
||||
C
|
||||
2
|
||||
0
|
||||
1
|
||||
v
|
||||
a
|
||||
l
|
||||
9
|
||||
7
|
||||
8
|
||||
.
|
||||
j
|
||||
p
|
||||
м
|
||||
а
|
||||
с
|
||||
и
|
||||
р
|
||||
ћ
|
||||
е
|
||||
ш
|
||||
3
|
||||
4
|
||||
о
|
||||
г
|
||||
н
|
||||
з
|
||||
в
|
||||
л
|
||||
6
|
||||
т
|
||||
ж
|
||||
у
|
||||
к
|
||||
п
|
||||
њ
|
||||
д
|
||||
ч
|
||||
С
|
||||
ј
|
||||
ф
|
||||
ц
|
||||
љ
|
||||
х
|
||||
О
|
||||
И
|
||||
А
|
||||
б
|
||||
Ш
|
||||
К
|
||||
ђ
|
||||
џ
|
||||
М
|
||||
В
|
||||
З
|
||||
Д
|
||||
Р
|
||||
У
|
||||
Н
|
||||
Т
|
||||
Б
|
||||
?
|
||||
П
|
||||
Х
|
||||
Ј
|
||||
Ц
|
||||
Г
|
||||
Љ
|
||||
Л
|
||||
Ф
|
||||
e
|
||||
n
|
||||
w
|
||||
E
|
||||
F
|
||||
A
|
||||
N
|
||||
f
|
||||
o
|
||||
b
|
||||
M
|
||||
G
|
||||
t
|
||||
y
|
||||
W
|
||||
k
|
||||
P
|
||||
u
|
||||
H
|
||||
B
|
||||
T
|
||||
z
|
||||
h
|
||||
O
|
||||
Y
|
||||
d
|
||||
U
|
||||
K
|
||||
D
|
||||
x
|
||||
X
|
||||
J
|
||||
Z
|
||||
Q
|
||||
q
|
||||
'
|
||||
-
|
||||
@
|
||||
é
|
||||
#
|
||||
!
|
||||
,
|
||||
%
|
||||
$
|
||||
:
|
||||
&
|
||||
+
|
||||
(
|
||||
É
|
||||
|
||||
91
backend/ppocr/utils/dict/rs_dict.txt
Normal file
91
backend/ppocr/utils/dict/rs_dict.txt
Normal file
@@ -0,0 +1,91 @@
|
||||
r
|
||||
s
|
||||
_
|
||||
i
|
||||
m
|
||||
g
|
||||
/
|
||||
1
|
||||
I
|
||||
L
|
||||
S
|
||||
V
|
||||
R
|
||||
C
|
||||
2
|
||||
0
|
||||
v
|
||||
a
|
||||
l
|
||||
7
|
||||
5
|
||||
8
|
||||
6
|
||||
.
|
||||
j
|
||||
p
|
||||
|
||||
t
|
||||
d
|
||||
9
|
||||
3
|
||||
e
|
||||
š
|
||||
4
|
||||
k
|
||||
u
|
||||
ć
|
||||
c
|
||||
n
|
||||
đ
|
||||
o
|
||||
z
|
||||
č
|
||||
b
|
||||
ž
|
||||
f
|
||||
Z
|
||||
T
|
||||
h
|
||||
M
|
||||
F
|
||||
O
|
||||
Š
|
||||
B
|
||||
H
|
||||
A
|
||||
E
|
||||
Đ
|
||||
Ž
|
||||
D
|
||||
P
|
||||
G
|
||||
Č
|
||||
K
|
||||
U
|
||||
N
|
||||
J
|
||||
Ć
|
||||
w
|
||||
y
|
||||
W
|
||||
x
|
||||
Y
|
||||
X
|
||||
q
|
||||
Q
|
||||
#
|
||||
&
|
||||
$
|
||||
,
|
||||
-
|
||||
%
|
||||
'
|
||||
@
|
||||
!
|
||||
:
|
||||
?
|
||||
(
|
||||
É
|
||||
é
|
||||
+
|
||||
91
backend/ppocr/utils/dict/rs_latin_dict.txt
Normal file
91
backend/ppocr/utils/dict/rs_latin_dict.txt
Normal file
@@ -0,0 +1,91 @@
|
||||
r
|
||||
s
|
||||
_
|
||||
i
|
||||
m
|
||||
g
|
||||
/
|
||||
1
|
||||
I
|
||||
L
|
||||
S
|
||||
V
|
||||
R
|
||||
C
|
||||
2
|
||||
0
|
||||
v
|
||||
a
|
||||
l
|
||||
7
|
||||
5
|
||||
8
|
||||
6
|
||||
.
|
||||
j
|
||||
p
|
||||
|
||||
t
|
||||
d
|
||||
9
|
||||
3
|
||||
e
|
||||
š
|
||||
4
|
||||
k
|
||||
u
|
||||
ć
|
||||
c
|
||||
n
|
||||
đ
|
||||
o
|
||||
z
|
||||
č
|
||||
b
|
||||
ž
|
||||
f
|
||||
Z
|
||||
T
|
||||
h
|
||||
M
|
||||
F
|
||||
O
|
||||
Š
|
||||
B
|
||||
H
|
||||
A
|
||||
E
|
||||
Đ
|
||||
Ž
|
||||
D
|
||||
P
|
||||
G
|
||||
Č
|
||||
K
|
||||
U
|
||||
N
|
||||
J
|
||||
Ć
|
||||
w
|
||||
y
|
||||
W
|
||||
x
|
||||
Y
|
||||
X
|
||||
q
|
||||
Q
|
||||
#
|
||||
&
|
||||
$
|
||||
,
|
||||
-
|
||||
%
|
||||
'
|
||||
@
|
||||
!
|
||||
:
|
||||
?
|
||||
(
|
||||
É
|
||||
é
|
||||
+
|
||||
134
backend/ppocr/utils/dict/rsc_dict.txt
Normal file
134
backend/ppocr/utils/dict/rsc_dict.txt
Normal file
@@ -0,0 +1,134 @@
|
||||
r
|
||||
s
|
||||
c
|
||||
_
|
||||
i
|
||||
m
|
||||
g
|
||||
/
|
||||
5
|
||||
I
|
||||
L
|
||||
S
|
||||
V
|
||||
R
|
||||
C
|
||||
2
|
||||
0
|
||||
1
|
||||
v
|
||||
a
|
||||
l
|
||||
9
|
||||
7
|
||||
8
|
||||
.
|
||||
j
|
||||
p
|
||||
м
|
||||
а
|
||||
с
|
||||
и
|
||||
р
|
||||
ћ
|
||||
е
|
||||
ш
|
||||
3
|
||||
4
|
||||
о
|
||||
г
|
||||
н
|
||||
з
|
||||
в
|
||||
л
|
||||
6
|
||||
т
|
||||
ж
|
||||
у
|
||||
к
|
||||
п
|
||||
њ
|
||||
д
|
||||
ч
|
||||
С
|
||||
ј
|
||||
ф
|
||||
ц
|
||||
љ
|
||||
х
|
||||
О
|
||||
И
|
||||
А
|
||||
б
|
||||
Ш
|
||||
К
|
||||
ђ
|
||||
џ
|
||||
М
|
||||
В
|
||||
З
|
||||
Д
|
||||
Р
|
||||
У
|
||||
Н
|
||||
Т
|
||||
Б
|
||||
?
|
||||
П
|
||||
Х
|
||||
Ј
|
||||
Ц
|
||||
Г
|
||||
Љ
|
||||
Л
|
||||
Ф
|
||||
e
|
||||
n
|
||||
w
|
||||
E
|
||||
F
|
||||
A
|
||||
N
|
||||
f
|
||||
o
|
||||
b
|
||||
M
|
||||
G
|
||||
t
|
||||
y
|
||||
W
|
||||
k
|
||||
P
|
||||
u
|
||||
H
|
||||
B
|
||||
T
|
||||
z
|
||||
h
|
||||
O
|
||||
Y
|
||||
d
|
||||
U
|
||||
K
|
||||
D
|
||||
x
|
||||
X
|
||||
J
|
||||
Z
|
||||
Q
|
||||
q
|
||||
'
|
||||
-
|
||||
@
|
||||
é
|
||||
#
|
||||
!
|
||||
,
|
||||
%
|
||||
$
|
||||
:
|
||||
&
|
||||
+
|
||||
(
|
||||
É
|
||||
|
||||
163
backend/ppocr/utils/dict/ru_dict.txt
Normal file
163
backend/ppocr/utils/dict/ru_dict.txt
Normal file
@@ -0,0 +1,163 @@
|
||||
|
||||
!
|
||||
#
|
||||
$
|
||||
%
|
||||
&
|
||||
'
|
||||
(
|
||||
+
|
||||
,
|
||||
-
|
||||
.
|
||||
/
|
||||
0
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
6
|
||||
7
|
||||
8
|
||||
9
|
||||
:
|
||||
?
|
||||
@
|
||||
A
|
||||
B
|
||||
C
|
||||
D
|
||||
E
|
||||
F
|
||||
G
|
||||
H
|
||||
I
|
||||
J
|
||||
K
|
||||
L
|
||||
M
|
||||
N
|
||||
O
|
||||
P
|
||||
Q
|
||||
R
|
||||
S
|
||||
T
|
||||
U
|
||||
V
|
||||
W
|
||||
X
|
||||
Y
|
||||
Z
|
||||
_
|
||||
a
|
||||
b
|
||||
c
|
||||
d
|
||||
e
|
||||
f
|
||||
g
|
||||
h
|
||||
i
|
||||
j
|
||||
k
|
||||
l
|
||||
m
|
||||
n
|
||||
o
|
||||
p
|
||||
q
|
||||
r
|
||||
s
|
||||
t
|
||||
u
|
||||
v
|
||||
w
|
||||
x
|
||||
y
|
||||
z
|
||||
É
|
||||
é
|
||||
Ё
|
||||
Є
|
||||
І
|
||||
Ј
|
||||
Љ
|
||||
Ў
|
||||
А
|
||||
Б
|
||||
В
|
||||
Г
|
||||
Д
|
||||
Е
|
||||
Ж
|
||||
З
|
||||
И
|
||||
Й
|
||||
К
|
||||
Л
|
||||
М
|
||||
Н
|
||||
О
|
||||
П
|
||||
Р
|
||||
С
|
||||
Т
|
||||
У
|
||||
Ф
|
||||
Х
|
||||
Ц
|
||||
Ч
|
||||
Ш
|
||||
Щ
|
||||
Ъ
|
||||
Ы
|
||||
Ь
|
||||
Э
|
||||
Ю
|
||||
Я
|
||||
а
|
||||
б
|
||||
в
|
||||
г
|
||||
д
|
||||
е
|
||||
ж
|
||||
з
|
||||
и
|
||||
й
|
||||
к
|
||||
л
|
||||
м
|
||||
н
|
||||
о
|
||||
п
|
||||
р
|
||||
с
|
||||
т
|
||||
у
|
||||
ф
|
||||
х
|
||||
ц
|
||||
ч
|
||||
ш
|
||||
щ
|
||||
ъ
|
||||
ы
|
||||
ь
|
||||
э
|
||||
ю
|
||||
я
|
||||
ё
|
||||
ђ
|
||||
є
|
||||
і
|
||||
ј
|
||||
љ
|
||||
њ
|
||||
ћ
|
||||
ў
|
||||
џ
|
||||
Ґ
|
||||
ґ
|
||||
68
backend/ppocr/utils/dict/spin_dict.txt
Normal file
68
backend/ppocr/utils/dict/spin_dict.txt
Normal file
@@ -0,0 +1,68 @@
|
||||
0
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
6
|
||||
7
|
||||
8
|
||||
9
|
||||
a
|
||||
b
|
||||
c
|
||||
d
|
||||
e
|
||||
f
|
||||
g
|
||||
h
|
||||
i
|
||||
j
|
||||
k
|
||||
l
|
||||
m
|
||||
n
|
||||
o
|
||||
p
|
||||
q
|
||||
r
|
||||
s
|
||||
t
|
||||
u
|
||||
v
|
||||
w
|
||||
x
|
||||
y
|
||||
z
|
||||
:
|
||||
(
|
||||
'
|
||||
-
|
||||
,
|
||||
%
|
||||
>
|
||||
.
|
||||
[
|
||||
?
|
||||
)
|
||||
"
|
||||
=
|
||||
_
|
||||
*
|
||||
]
|
||||
;
|
||||
&
|
||||
+
|
||||
$
|
||||
@
|
||||
/
|
||||
|
|
||||
!
|
||||
<
|
||||
#
|
||||
`
|
||||
{
|
||||
~
|
||||
\
|
||||
}
|
||||
^
|
||||
128
backend/ppocr/utils/dict/ta_dict.txt
Normal file
128
backend/ppocr/utils/dict/ta_dict.txt
Normal file
@@ -0,0 +1,128 @@
|
||||
t
|
||||
a
|
||||
_
|
||||
i
|
||||
m
|
||||
g
|
||||
/
|
||||
3
|
||||
I
|
||||
L
|
||||
S
|
||||
V
|
||||
R
|
||||
C
|
||||
2
|
||||
0
|
||||
1
|
||||
v
|
||||
l
|
||||
9
|
||||
7
|
||||
8
|
||||
.
|
||||
j
|
||||
p
|
||||
ப
|
||||
ூ
|
||||
த
|
||||
ம
|
||||
ி
|
||||
வ
|
||||
ர
|
||||
்
|
||||
ந
|
||||
ோ
|
||||
ன
|
||||
6
|
||||
ஆ
|
||||
ற
|
||||
ல
|
||||
5
|
||||
ள
|
||||
ா
|
||||
ொ
|
||||
ழ
|
||||
ு
|
||||
4
|
||||
ெ
|
||||
ண
|
||||
க
|
||||
ட
|
||||
ை
|
||||
ே
|
||||
ச
|
||||
ய
|
||||
ஒ
|
||||
இ
|
||||
அ
|
||||
ங
|
||||
உ
|
||||
ீ
|
||||
ஞ
|
||||
எ
|
||||
ஓ
|
||||
ஃ
|
||||
ஜ
|
||||
ஷ
|
||||
ஸ
|
||||
ஏ
|
||||
ஊ
|
||||
ஹ
|
||||
ஈ
|
||||
ஐ
|
||||
ௌ
|
||||
ஔ
|
||||
s
|
||||
c
|
||||
e
|
||||
n
|
||||
w
|
||||
F
|
||||
T
|
||||
O
|
||||
P
|
||||
K
|
||||
A
|
||||
N
|
||||
G
|
||||
Y
|
||||
E
|
||||
M
|
||||
H
|
||||
U
|
||||
B
|
||||
o
|
||||
b
|
||||
D
|
||||
d
|
||||
r
|
||||
W
|
||||
u
|
||||
y
|
||||
f
|
||||
X
|
||||
k
|
||||
q
|
||||
h
|
||||
J
|
||||
z
|
||||
Z
|
||||
Q
|
||||
x
|
||||
-
|
||||
'
|
||||
$
|
||||
,
|
||||
%
|
||||
@
|
||||
é
|
||||
!
|
||||
#
|
||||
+
|
||||
É
|
||||
&
|
||||
:
|
||||
(
|
||||
?
|
||||
|
||||
277
backend/ppocr/utils/dict/table_dict.txt
Normal file
277
backend/ppocr/utils/dict/table_dict.txt
Normal file
@@ -0,0 +1,277 @@
|
||||
←
|
||||
</overline>
|
||||
☆
|
||||
─
|
||||
α
|
||||
|
||||
|
||||
⋅
|
||||
$
|
||||
ω
|
||||
ψ
|
||||
χ
|
||||
(
|
||||
υ
|
||||
≥
|
||||
σ
|
||||
,
|
||||
ρ
|
||||
ε
|
||||
0
|
||||
■
|
||||
4
|
||||
8
|
||||
✗
|
||||
b
|
||||
<
|
||||
✓
|
||||
Ψ
|
||||
Ω
|
||||
€
|
||||
D
|
||||
3
|
||||
Π
|
||||
H
|
||||
║
|
||||
</strike>
|
||||
L
|
||||
Φ
|
||||
Χ
|
||||
θ
|
||||
P
|
||||
κ
|
||||
λ
|
||||
μ
|
||||
T
|
||||
ξ
|
||||
X
|
||||
β
|
||||
γ
|
||||
δ
|
||||
\
|
||||
ζ
|
||||
η
|
||||
`
|
||||
d
|
||||
<strike>
|
||||
h
|
||||
f
|
||||
l
|
||||
Θ
|
||||
p
|
||||
√
|
||||
t
|
||||
</sub>
|
||||
x
|
||||
Β
|
||||
Γ
|
||||
Δ
|
||||
|
|
||||
ǂ
|
||||
ɛ
|
||||
j
|
||||
̧
|
||||
➢
|
||||
|
||||
̌
|
||||
′
|
||||
«
|
||||
△
|
||||
▲
|
||||
#
|
||||
</b>
|
||||
'
|
||||
Ι
|
||||
+
|
||||
¶
|
||||
/
|
||||
▼
|
||||
⇑
|
||||
□
|
||||
·
|
||||
7
|
||||
▪
|
||||
;
|
||||
?
|
||||
➔
|
||||
∩
|
||||
C
|
||||
÷
|
||||
G
|
||||
⇒
|
||||
K
|
||||
<sup>
|
||||
O
|
||||
S
|
||||
С
|
||||
W
|
||||
Α
|
||||
[
|
||||
○
|
||||
_
|
||||
●
|
||||
‡
|
||||
c
|
||||
z
|
||||
g
|
||||
<i>
|
||||
o
|
||||
<sub>
|
||||
〈
|
||||
〉
|
||||
s
|
||||
⩽
|
||||
w
|
||||
φ
|
||||
ʹ
|
||||
{
|
||||
»
|
||||
∣
|
||||
̆
|
||||
e
|
||||
ˆ
|
||||
∈
|
||||
τ
|
||||
◆
|
||||
ι
|
||||
∅
|
||||
∆
|
||||
∙
|
||||
∘
|
||||
Ø
|
||||
ß
|
||||
✔
|
||||
∞
|
||||
∑
|
||||
−
|
||||
×
|
||||
◊
|
||||
∗
|
||||
∖
|
||||
˃
|
||||
˂
|
||||
∫
|
||||
"
|
||||
i
|
||||
&
|
||||
π
|
||||
↔
|
||||
*
|
||||
∥
|
||||
æ
|
||||
∧
|
||||
.
|
||||
⁄
|
||||
ø
|
||||
Q
|
||||
∼
|
||||
6
|
||||
⁎
|
||||
:
|
||||
★
|
||||
>
|
||||
a
|
||||
B
|
||||
≈
|
||||
F
|
||||
J
|
||||
̄
|
||||
N
|
||||
♯
|
||||
R
|
||||
V
|
||||
<overline>
|
||||
―
|
||||
Z
|
||||
♣
|
||||
^
|
||||
¤
|
||||
¥
|
||||
§
|
||||
<underline>
|
||||
¢
|
||||
£
|
||||
≦
|
||||
|
||||
≤
|
||||
‖
|
||||
Λ
|
||||
©
|
||||
n
|
||||
↓
|
||||
→
|
||||
↑
|
||||
r
|
||||
°
|
||||
±
|
||||
v
|
||||
<b>
|
||||
♂
|
||||
k
|
||||
♀
|
||||
~
|
||||
ᅟ
|
||||
̇
|
||||
@
|
||||
”
|
||||
♦
|
||||
ł
|
||||
®
|
||||
⊕
|
||||
„
|
||||
!
|
||||
</sup>
|
||||
%
|
||||
⇓
|
||||
)
|
||||
-
|
||||
1
|
||||
5
|
||||
9
|
||||
=
|
||||
А
|
||||
A
|
||||
‰
|
||||
⋆
|
||||
Σ
|
||||
E
|
||||
◦
|
||||
I
|
||||
※
|
||||
M
|
||||
m
|
||||
̨
|
||||
⩾
|
||||
†
|
||||
</i>
|
||||
•
|
||||
U
|
||||
Y
|
||||
|
||||
]
|
||||
̸
|
||||
2
|
||||
‐
|
||||
–
|
||||
‒
|
||||
̂
|
||||
—
|
||||
̀
|
||||
́
|
||||
’
|
||||
‘
|
||||
⋮
|
||||
⋯
|
||||
̊
|
||||
“
|
||||
̈
|
||||
≧
|
||||
q
|
||||
u
|
||||
ı
|
||||
y
|
||||
</underline>
|
||||
|
||||
̃
|
||||
}
|
||||
ν
|
||||
39
backend/ppocr/utils/dict/table_master_structure_dict.txt
Normal file
39
backend/ppocr/utils/dict/table_master_structure_dict.txt
Normal file
@@ -0,0 +1,39 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<td></td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<eb></eb>
|
||||
</tbody>
|
||||
<td
|
||||
colspan="5"
|
||||
>
|
||||
</td>
|
||||
colspan="2"
|
||||
colspan="3"
|
||||
<eb2></eb2>
|
||||
<eb1></eb1>
|
||||
rowspan="2"
|
||||
colspan="4"
|
||||
colspan="6"
|
||||
rowspan="3"
|
||||
colspan="9"
|
||||
colspan="10"
|
||||
colspan="7"
|
||||
rowspan="4"
|
||||
rowspan="5"
|
||||
rowspan="9"
|
||||
colspan="8"
|
||||
rowspan="8"
|
||||
rowspan="6"
|
||||
rowspan="7"
|
||||
rowspan="10"
|
||||
<eb3></eb3>
|
||||
<eb4></eb4>
|
||||
<eb5></eb5>
|
||||
<eb6></eb6>
|
||||
<eb7></eb7>
|
||||
<eb8></eb8>
|
||||
<eb9></eb9>
|
||||
<eb10></eb10>
|
||||
28
backend/ppocr/utils/dict/table_structure_dict.txt
Normal file
28
backend/ppocr/utils/dict/table_structure_dict.txt
Normal file
@@ -0,0 +1,28 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<td>
|
||||
</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
<td
|
||||
colspan="5"
|
||||
>
|
||||
colspan="2"
|
||||
colspan="3"
|
||||
rowspan="2"
|
||||
colspan="4"
|
||||
colspan="6"
|
||||
rowspan="3"
|
||||
colspan="9"
|
||||
colspan="10"
|
||||
colspan="7"
|
||||
rowspan="4"
|
||||
rowspan="5"
|
||||
rowspan="9"
|
||||
colspan="8"
|
||||
rowspan="8"
|
||||
rowspan="6"
|
||||
rowspan="7"
|
||||
rowspan="10"
|
||||
48
backend/ppocr/utils/dict/table_structure_dict_ch.txt
Normal file
48
backend/ppocr/utils/dict/table_structure_dict_ch.txt
Normal file
@@ -0,0 +1,48 @@
|
||||
<thead>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
<tr>
|
||||
</tr>
|
||||
<td>
|
||||
<td
|
||||
>
|
||||
</td>
|
||||
colspan="2"
|
||||
colspan="3"
|
||||
colspan="4"
|
||||
colspan="5"
|
||||
colspan="6"
|
||||
colspan="7"
|
||||
colspan="8"
|
||||
colspan="9"
|
||||
colspan="10"
|
||||
colspan="11"
|
||||
colspan="12"
|
||||
colspan="13"
|
||||
colspan="14"
|
||||
colspan="15"
|
||||
colspan="16"
|
||||
colspan="17"
|
||||
colspan="18"
|
||||
colspan="19"
|
||||
colspan="20"
|
||||
rowspan="2"
|
||||
rowspan="3"
|
||||
rowspan="4"
|
||||
rowspan="5"
|
||||
rowspan="6"
|
||||
rowspan="7"
|
||||
rowspan="8"
|
||||
rowspan="9"
|
||||
rowspan="10"
|
||||
rowspan="11"
|
||||
rowspan="12"
|
||||
rowspan="13"
|
||||
rowspan="14"
|
||||
rowspan="15"
|
||||
rowspan="16"
|
||||
rowspan="17"
|
||||
rowspan="18"
|
||||
rowspan="19"
|
||||
rowspan="20"
|
||||
151
backend/ppocr/utils/dict/te_dict.txt
Normal file
151
backend/ppocr/utils/dict/te_dict.txt
Normal file
@@ -0,0 +1,151 @@
|
||||
t
|
||||
e
|
||||
_
|
||||
i
|
||||
m
|
||||
g
|
||||
/
|
||||
5
|
||||
I
|
||||
L
|
||||
S
|
||||
V
|
||||
R
|
||||
C
|
||||
2
|
||||
0
|
||||
1
|
||||
v
|
||||
a
|
||||
l
|
||||
3
|
||||
4
|
||||
8
|
||||
9
|
||||
.
|
||||
j
|
||||
p
|
||||
త
|
||||
ె
|
||||
ర
|
||||
క
|
||||
్
|
||||
ి
|
||||
ం
|
||||
చ
|
||||
ే
|
||||
ద
|
||||
ు
|
||||
7
|
||||
6
|
||||
ఉ
|
||||
ా
|
||||
మ
|
||||
ట
|
||||
ో
|
||||
వ
|
||||
ప
|
||||
ల
|
||||
శ
|
||||
ఆ
|
||||
య
|
||||
ై
|
||||
భ
|
||||
'
|
||||
ీ
|
||||
గ
|
||||
ూ
|
||||
డ
|
||||
ధ
|
||||
హ
|
||||
న
|
||||
జ
|
||||
స
|
||||
[
|
||||
|
||||
ష
|
||||
అ
|
||||
ణ
|
||||
ఫ
|
||||
బ
|
||||
ఎ
|
||||
;
|
||||
ళ
|
||||
థ
|
||||
ొ
|
||||
ఠ
|
||||
ృ
|
||||
ఒ
|
||||
ఇ
|
||||
ః
|
||||
ఊ
|
||||
ఖ
|
||||
-
|
||||
ఐ
|
||||
ఘ
|
||||
ౌ
|
||||
ఏ
|
||||
ఈ
|
||||
ఛ
|
||||
,
|
||||
ఓ
|
||||
ఞ
|
||||
|
|
||||
?
|
||||
:
|
||||
ఢ
|
||||
"
|
||||
(
|
||||
”
|
||||
!
|
||||
+
|
||||
)
|
||||
*
|
||||
=
|
||||
&
|
||||
“
|
||||
€
|
||||
]
|
||||
£
|
||||
$
|
||||
s
|
||||
c
|
||||
n
|
||||
w
|
||||
k
|
||||
J
|
||||
G
|
||||
u
|
||||
d
|
||||
r
|
||||
E
|
||||
o
|
||||
h
|
||||
y
|
||||
b
|
||||
f
|
||||
B
|
||||
M
|
||||
O
|
||||
T
|
||||
N
|
||||
D
|
||||
P
|
||||
A
|
||||
F
|
||||
x
|
||||
W
|
||||
Y
|
||||
U
|
||||
H
|
||||
K
|
||||
X
|
||||
z
|
||||
Z
|
||||
Q
|
||||
q
|
||||
É
|
||||
%
|
||||
#
|
||||
@
|
||||
é
|
||||
114
backend/ppocr/utils/dict/ug_dict.txt
Normal file
114
backend/ppocr/utils/dict/ug_dict.txt
Normal file
@@ -0,0 +1,114 @@
|
||||
u
|
||||
g
|
||||
_
|
||||
i
|
||||
m
|
||||
/
|
||||
1
|
||||
I
|
||||
L
|
||||
S
|
||||
V
|
||||
R
|
||||
C
|
||||
2
|
||||
0
|
||||
v
|
||||
a
|
||||
l
|
||||
8
|
||||
5
|
||||
3
|
||||
6
|
||||
9
|
||||
.
|
||||
j
|
||||
p
|
||||
|
||||
ق
|
||||
ا
|
||||
پ
|
||||
ل
|
||||
4
|
||||
7
|
||||
ئ
|
||||
ى
|
||||
ش
|
||||
ت
|
||||
ي
|
||||
ك
|
||||
د
|
||||
ف
|
||||
ر
|
||||
و
|
||||
ن
|
||||
ب
|
||||
ە
|
||||
خ
|
||||
ې
|
||||
چ
|
||||
ۇ
|
||||
ز
|
||||
س
|
||||
م
|
||||
ۋ
|
||||
گ
|
||||
ڭ
|
||||
ۆ
|
||||
ۈ
|
||||
ج
|
||||
غ
|
||||
ھ
|
||||
ژ
|
||||
s
|
||||
c
|
||||
e
|
||||
n
|
||||
w
|
||||
P
|
||||
E
|
||||
D
|
||||
U
|
||||
d
|
||||
r
|
||||
b
|
||||
y
|
||||
B
|
||||
o
|
||||
O
|
||||
Y
|
||||
N
|
||||
T
|
||||
k
|
||||
t
|
||||
h
|
||||
A
|
||||
H
|
||||
F
|
||||
z
|
||||
W
|
||||
K
|
||||
G
|
||||
M
|
||||
f
|
||||
Z
|
||||
X
|
||||
Q
|
||||
J
|
||||
x
|
||||
q
|
||||
-
|
||||
!
|
||||
%
|
||||
#
|
||||
?
|
||||
:
|
||||
$
|
||||
,
|
||||
&
|
||||
'
|
||||
É
|
||||
@
|
||||
é
|
||||
(
|
||||
+
|
||||
142
backend/ppocr/utils/dict/uk_dict.txt
Normal file
142
backend/ppocr/utils/dict/uk_dict.txt
Normal file
@@ -0,0 +1,142 @@
|
||||
u
|
||||
k
|
||||
_
|
||||
i
|
||||
m
|
||||
g
|
||||
/
|
||||
1
|
||||
6
|
||||
I
|
||||
L
|
||||
S
|
||||
V
|
||||
R
|
||||
C
|
||||
2
|
||||
0
|
||||
v
|
||||
a
|
||||
l
|
||||
7
|
||||
9
|
||||
.
|
||||
j
|
||||
p
|
||||
в
|
||||
і
|
||||
д
|
||||
п
|
||||
о
|
||||
н
|
||||
с
|
||||
т
|
||||
ю
|
||||
4
|
||||
5
|
||||
3
|
||||
а
|
||||
и
|
||||
м
|
||||
е
|
||||
р
|
||||
ч
|
||||
у
|
||||
Б
|
||||
з
|
||||
л
|
||||
к
|
||||
8
|
||||
А
|
||||
В
|
||||
г
|
||||
є
|
||||
б
|
||||
ь
|
||||
х
|
||||
ґ
|
||||
ш
|
||||
ц
|
||||
ф
|
||||
я
|
||||
щ
|
||||
ж
|
||||
Г
|
||||
Х
|
||||
У
|
||||
Т
|
||||
Е
|
||||
І
|
||||
Н
|
||||
П
|
||||
З
|
||||
Л
|
||||
Ю
|
||||
С
|
||||
Д
|
||||
М
|
||||
К
|
||||
Р
|
||||
Ф
|
||||
О
|
||||
Ц
|
||||
И
|
||||
Я
|
||||
Ч
|
||||
Ш
|
||||
Ж
|
||||
Є
|
||||
Ґ
|
||||
Ь
|
||||
s
|
||||
c
|
||||
e
|
||||
n
|
||||
w
|
||||
A
|
||||
P
|
||||
r
|
||||
E
|
||||
t
|
||||
o
|
||||
h
|
||||
d
|
||||
y
|
||||
M
|
||||
G
|
||||
N
|
||||
F
|
||||
B
|
||||
T
|
||||
D
|
||||
U
|
||||
O
|
||||
W
|
||||
Z
|
||||
f
|
||||
H
|
||||
Y
|
||||
b
|
||||
K
|
||||
z
|
||||
x
|
||||
Q
|
||||
X
|
||||
q
|
||||
J
|
||||
$
|
||||
-
|
||||
'
|
||||
#
|
||||
&
|
||||
%
|
||||
?
|
||||
:
|
||||
!
|
||||
,
|
||||
+
|
||||
@
|
||||
(
|
||||
é
|
||||
É
|
||||
|
||||
137
backend/ppocr/utils/dict/ur_dict.txt
Normal file
137
backend/ppocr/utils/dict/ur_dict.txt
Normal file
@@ -0,0 +1,137 @@
|
||||
u
|
||||
r
|
||||
_
|
||||
i
|
||||
m
|
||||
g
|
||||
/
|
||||
3
|
||||
I
|
||||
L
|
||||
S
|
||||
V
|
||||
R
|
||||
C
|
||||
2
|
||||
0
|
||||
1
|
||||
v
|
||||
a
|
||||
l
|
||||
9
|
||||
7
|
||||
8
|
||||
.
|
||||
j
|
||||
p
|
||||
|
||||
چ
|
||||
ٹ
|
||||
پ
|
||||
ا
|
||||
ئ
|
||||
ی
|
||||
ے
|
||||
4
|
||||
6
|
||||
و
|
||||
ل
|
||||
ن
|
||||
ڈ
|
||||
ھ
|
||||
ک
|
||||
ت
|
||||
ش
|
||||
ف
|
||||
ق
|
||||
ر
|
||||
د
|
||||
5
|
||||
ب
|
||||
ج
|
||||
خ
|
||||
ہ
|
||||
س
|
||||
ز
|
||||
غ
|
||||
ڑ
|
||||
ں
|
||||
آ
|
||||
م
|
||||
ؤ
|
||||
ط
|
||||
ص
|
||||
ح
|
||||
ع
|
||||
گ
|
||||
ث
|
||||
ض
|
||||
ذ
|
||||
ۓ
|
||||
ِ
|
||||
ء
|
||||
ظ
|
||||
ً
|
||||
ي
|
||||
ُ
|
||||
ۃ
|
||||
أ
|
||||
ٰ
|
||||
ە
|
||||
ژ
|
||||
ۂ
|
||||
ة
|
||||
ّ
|
||||
ك
|
||||
ه
|
||||
s
|
||||
c
|
||||
e
|
||||
n
|
||||
w
|
||||
o
|
||||
d
|
||||
t
|
||||
D
|
||||
M
|
||||
T
|
||||
U
|
||||
E
|
||||
b
|
||||
P
|
||||
h
|
||||
y
|
||||
W
|
||||
H
|
||||
A
|
||||
x
|
||||
B
|
||||
O
|
||||
N
|
||||
G
|
||||
Y
|
||||
Q
|
||||
F
|
||||
k
|
||||
K
|
||||
q
|
||||
J
|
||||
Z
|
||||
f
|
||||
z
|
||||
X
|
||||
'
|
||||
@
|
||||
&
|
||||
!
|
||||
,
|
||||
:
|
||||
$
|
||||
-
|
||||
#
|
||||
?
|
||||
%
|
||||
é
|
||||
+
|
||||
(
|
||||
É
|
||||
110
backend/ppocr/utils/dict/xi_dict.txt
Normal file
110
backend/ppocr/utils/dict/xi_dict.txt
Normal file
@@ -0,0 +1,110 @@
|
||||
x
|
||||
i
|
||||
_
|
||||
m
|
||||
g
|
||||
/
|
||||
1
|
||||
0
|
||||
I
|
||||
L
|
||||
S
|
||||
V
|
||||
R
|
||||
C
|
||||
2
|
||||
v
|
||||
a
|
||||
l
|
||||
3
|
||||
6
|
||||
4
|
||||
5
|
||||
.
|
||||
j
|
||||
p
|
||||
|
||||
Q
|
||||
u
|
||||
e
|
||||
r
|
||||
o
|
||||
8
|
||||
7
|
||||
n
|
||||
c
|
||||
9
|
||||
t
|
||||
b
|
||||
é
|
||||
q
|
||||
d
|
||||
ó
|
||||
y
|
||||
F
|
||||
s
|
||||
,
|
||||
O
|
||||
í
|
||||
T
|
||||
f
|
||||
"
|
||||
U
|
||||
M
|
||||
h
|
||||
:
|
||||
P
|
||||
H
|
||||
A
|
||||
E
|
||||
D
|
||||
z
|
||||
N
|
||||
á
|
||||
ñ
|
||||
ú
|
||||
%
|
||||
;
|
||||
è
|
||||
+
|
||||
Y
|
||||
-
|
||||
B
|
||||
G
|
||||
(
|
||||
)
|
||||
¿
|
||||
?
|
||||
w
|
||||
¡
|
||||
!
|
||||
X
|
||||
É
|
||||
K
|
||||
k
|
||||
Á
|
||||
ü
|
||||
Ú
|
||||
«
|
||||
»
|
||||
J
|
||||
'
|
||||
ö
|
||||
W
|
||||
Z
|
||||
º
|
||||
Ö
|
||||
|
||||
[
|
||||
]
|
||||
Ç
|
||||
ç
|
||||
à
|
||||
ä
|
||||
û
|
||||
ò
|
||||
Í
|
||||
ê
|
||||
ô
|
||||
ø
|
||||
ª
|
||||
574
backend/ppocr/utils/e2e_metric/Deteval.py
Executable file
574
backend/ppocr/utils/e2e_metric/Deteval.py
Executable file
@@ -0,0 +1,574 @@
|
||||
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
import numpy as np
|
||||
import scipy.io as io
|
||||
from ppocr.utils.e2e_metric.polygon_fast import iod, area_of_intersection, area
|
||||
|
||||
|
||||
def get_socre_A(gt_dir, pred_dict):
|
||||
allInputs = 1
|
||||
|
||||
def input_reading_mod(pred_dict):
|
||||
"""This helper reads input from txt files"""
|
||||
det = []
|
||||
n = len(pred_dict)
|
||||
for i in range(n):
|
||||
points = pred_dict[i]['points']
|
||||
text = pred_dict[i]['texts']
|
||||
point = ",".join(map(str, points.reshape(-1, )))
|
||||
det.append([point, text])
|
||||
return det
|
||||
|
||||
def gt_reading_mod(gt_dict):
|
||||
"""This helper reads groundtruths from mat files"""
|
||||
gt = []
|
||||
n = len(gt_dict)
|
||||
for i in range(n):
|
||||
points = gt_dict[i]['points'].tolist()
|
||||
h = len(points)
|
||||
text = gt_dict[i]['text']
|
||||
xx = [
|
||||
np.array(
|
||||
['x:'], dtype='<U2'), 0, np.array(
|
||||
['y:'], dtype='<U2'), 0, np.array(
|
||||
['#'], dtype='<U1'), np.array(
|
||||
['#'], dtype='<U1')
|
||||
]
|
||||
t_x, t_y = [], []
|
||||
for j in range(h):
|
||||
t_x.append(points[j][0])
|
||||
t_y.append(points[j][1])
|
||||
xx[1] = np.array([t_x], dtype='int16')
|
||||
xx[3] = np.array([t_y], dtype='int16')
|
||||
if text != "":
|
||||
xx[4] = np.array([text], dtype='U{}'.format(len(text)))
|
||||
xx[5] = np.array(['c'], dtype='<U1')
|
||||
gt.append(xx)
|
||||
return gt
|
||||
|
||||
def detection_filtering(detections, groundtruths, threshold=0.5):
|
||||
for gt_id, gt in enumerate(groundtruths):
|
||||
if (gt[5] == '#') and (gt[1].shape[1] > 1):
|
||||
gt_x = list(map(int, np.squeeze(gt[1])))
|
||||
gt_y = list(map(int, np.squeeze(gt[3])))
|
||||
for det_id, detection in enumerate(detections):
|
||||
detection_orig = detection
|
||||
detection = [float(x) for x in detection[0].split(',')]
|
||||
detection = list(map(int, detection))
|
||||
det_x = detection[0::2]
|
||||
det_y = detection[1::2]
|
||||
det_gt_iou = iod(det_x, det_y, gt_x, gt_y)
|
||||
if det_gt_iou > threshold:
|
||||
detections[det_id] = []
|
||||
|
||||
detections[:] = [item for item in detections if item != []]
|
||||
return detections
|
||||
|
||||
def sigma_calculation(det_x, det_y, gt_x, gt_y):
|
||||
"""
|
||||
sigma = inter_area / gt_area
|
||||
"""
|
||||
return np.round((area_of_intersection(det_x, det_y, gt_x, gt_y) /
|
||||
area(gt_x, gt_y)), 2)
|
||||
|
||||
def tau_calculation(det_x, det_y, gt_x, gt_y):
|
||||
if area(det_x, det_y) == 0.0:
|
||||
return 0
|
||||
return np.round((area_of_intersection(det_x, det_y, gt_x, gt_y) /
|
||||
area(det_x, det_y)), 2)
|
||||
|
||||
##############################Initialization###################################
|
||||
# global_sigma = []
|
||||
# global_tau = []
|
||||
# global_pred_str = []
|
||||
# global_gt_str = []
|
||||
###############################################################################
|
||||
|
||||
for input_id in range(allInputs):
|
||||
if (input_id != '.DS_Store') and (input_id != 'Pascal_result.txt') and (
|
||||
input_id != 'Pascal_result_curved.txt') and (input_id != 'Pascal_result_non_curved.txt') and (
|
||||
input_id != 'Deteval_result.txt') and (input_id != 'Deteval_result_curved.txt') \
|
||||
and (input_id != 'Deteval_result_non_curved.txt'):
|
||||
detections = input_reading_mod(pred_dict)
|
||||
groundtruths = gt_reading_mod(gt_dir)
|
||||
detections = detection_filtering(
|
||||
detections,
|
||||
groundtruths) # filters detections overlapping with DC area
|
||||
dc_id = []
|
||||
for i in range(len(groundtruths)):
|
||||
if groundtruths[i][5] == '#':
|
||||
dc_id.append(i)
|
||||
cnt = 0
|
||||
for a in dc_id:
|
||||
num = a - cnt
|
||||
del groundtruths[num]
|
||||
cnt += 1
|
||||
|
||||
local_sigma_table = np.zeros((len(groundtruths), len(detections)))
|
||||
local_tau_table = np.zeros((len(groundtruths), len(detections)))
|
||||
local_pred_str = {}
|
||||
local_gt_str = {}
|
||||
|
||||
for gt_id, gt in enumerate(groundtruths):
|
||||
if len(detections) > 0:
|
||||
for det_id, detection in enumerate(detections):
|
||||
detection_orig = detection
|
||||
detection = [float(x) for x in detection[0].split(',')]
|
||||
detection = list(map(int, detection))
|
||||
pred_seq_str = detection_orig[1].strip()
|
||||
det_x = detection[0::2]
|
||||
det_y = detection[1::2]
|
||||
gt_x = list(map(int, np.squeeze(gt[1])))
|
||||
gt_y = list(map(int, np.squeeze(gt[3])))
|
||||
gt_seq_str = str(gt[4].tolist()[0])
|
||||
|
||||
local_sigma_table[gt_id, det_id] = sigma_calculation(
|
||||
det_x, det_y, gt_x, gt_y)
|
||||
local_tau_table[gt_id, det_id] = tau_calculation(
|
||||
det_x, det_y, gt_x, gt_y)
|
||||
local_pred_str[det_id] = pred_seq_str
|
||||
local_gt_str[gt_id] = gt_seq_str
|
||||
|
||||
global_sigma = local_sigma_table
|
||||
global_tau = local_tau_table
|
||||
global_pred_str = local_pred_str
|
||||
global_gt_str = local_gt_str
|
||||
|
||||
single_data = {}
|
||||
single_data['sigma'] = global_sigma
|
||||
single_data['global_tau'] = global_tau
|
||||
single_data['global_pred_str'] = global_pred_str
|
||||
single_data['global_gt_str'] = global_gt_str
|
||||
return single_data
|
||||
|
||||
|
||||
def get_socre_B(gt_dir, img_id, pred_dict):
|
||||
allInputs = 1
|
||||
|
||||
def input_reading_mod(pred_dict):
|
||||
"""This helper reads input from txt files"""
|
||||
det = []
|
||||
n = len(pred_dict)
|
||||
for i in range(n):
|
||||
points = pred_dict[i]['points']
|
||||
text = pred_dict[i]['texts']
|
||||
point = ",".join(map(str, points.reshape(-1, )))
|
||||
det.append([point, text])
|
||||
return det
|
||||
|
||||
def gt_reading_mod(gt_dir, gt_id):
|
||||
gt = io.loadmat('%s/poly_gt_img%s.mat' % (gt_dir, gt_id))
|
||||
gt = gt['polygt']
|
||||
return gt
|
||||
|
||||
def detection_filtering(detections, groundtruths, threshold=0.5):
|
||||
for gt_id, gt in enumerate(groundtruths):
|
||||
if (gt[5] == '#') and (gt[1].shape[1] > 1):
|
||||
gt_x = list(map(int, np.squeeze(gt[1])))
|
||||
gt_y = list(map(int, np.squeeze(gt[3])))
|
||||
for det_id, detection in enumerate(detections):
|
||||
detection_orig = detection
|
||||
detection = [float(x) for x in detection[0].split(',')]
|
||||
detection = list(map(int, detection))
|
||||
det_x = detection[0::2]
|
||||
det_y = detection[1::2]
|
||||
det_gt_iou = iod(det_x, det_y, gt_x, gt_y)
|
||||
if det_gt_iou > threshold:
|
||||
detections[det_id] = []
|
||||
|
||||
detections[:] = [item for item in detections if item != []]
|
||||
return detections
|
||||
|
||||
def sigma_calculation(det_x, det_y, gt_x, gt_y):
|
||||
"""
|
||||
sigma = inter_area / gt_area
|
||||
"""
|
||||
return np.round((area_of_intersection(det_x, det_y, gt_x, gt_y) /
|
||||
area(gt_x, gt_y)), 2)
|
||||
|
||||
def tau_calculation(det_x, det_y, gt_x, gt_y):
|
||||
if area(det_x, det_y) == 0.0:
|
||||
return 0
|
||||
return np.round((area_of_intersection(det_x, det_y, gt_x, gt_y) /
|
||||
area(det_x, det_y)), 2)
|
||||
|
||||
##############################Initialization###################################
|
||||
# global_sigma = []
|
||||
# global_tau = []
|
||||
# global_pred_str = []
|
||||
# global_gt_str = []
|
||||
###############################################################################
|
||||
|
||||
for input_id in range(allInputs):
|
||||
if (input_id != '.DS_Store') and (input_id != 'Pascal_result.txt') and (
|
||||
input_id != 'Pascal_result_curved.txt') and (input_id != 'Pascal_result_non_curved.txt') and (
|
||||
input_id != 'Deteval_result.txt') and (input_id != 'Deteval_result_curved.txt') \
|
||||
and (input_id != 'Deteval_result_non_curved.txt'):
|
||||
detections = input_reading_mod(pred_dict)
|
||||
groundtruths = gt_reading_mod(gt_dir, img_id).tolist()
|
||||
detections = detection_filtering(
|
||||
detections,
|
||||
groundtruths) # filters detections overlapping with DC area
|
||||
dc_id = []
|
||||
for i in range(len(groundtruths)):
|
||||
if groundtruths[i][5] == '#':
|
||||
dc_id.append(i)
|
||||
cnt = 0
|
||||
for a in dc_id:
|
||||
num = a - cnt
|
||||
del groundtruths[num]
|
||||
cnt += 1
|
||||
|
||||
local_sigma_table = np.zeros((len(groundtruths), len(detections)))
|
||||
local_tau_table = np.zeros((len(groundtruths), len(detections)))
|
||||
local_pred_str = {}
|
||||
local_gt_str = {}
|
||||
|
||||
for gt_id, gt in enumerate(groundtruths):
|
||||
if len(detections) > 0:
|
||||
for det_id, detection in enumerate(detections):
|
||||
detection_orig = detection
|
||||
detection = [float(x) for x in detection[0].split(',')]
|
||||
detection = list(map(int, detection))
|
||||
pred_seq_str = detection_orig[1].strip()
|
||||
det_x = detection[0::2]
|
||||
det_y = detection[1::2]
|
||||
gt_x = list(map(int, np.squeeze(gt[1])))
|
||||
gt_y = list(map(int, np.squeeze(gt[3])))
|
||||
gt_seq_str = str(gt[4].tolist()[0])
|
||||
|
||||
local_sigma_table[gt_id, det_id] = sigma_calculation(
|
||||
det_x, det_y, gt_x, gt_y)
|
||||
local_tau_table[gt_id, det_id] = tau_calculation(
|
||||
det_x, det_y, gt_x, gt_y)
|
||||
local_pred_str[det_id] = pred_seq_str
|
||||
local_gt_str[gt_id] = gt_seq_str
|
||||
|
||||
global_sigma = local_sigma_table
|
||||
global_tau = local_tau_table
|
||||
global_pred_str = local_pred_str
|
||||
global_gt_str = local_gt_str
|
||||
|
||||
single_data = {}
|
||||
single_data['sigma'] = global_sigma
|
||||
single_data['global_tau'] = global_tau
|
||||
single_data['global_pred_str'] = global_pred_str
|
||||
single_data['global_gt_str'] = global_gt_str
|
||||
return single_data
|
||||
|
||||
|
||||
def combine_results(all_data):
|
||||
tr = 0.7
|
||||
tp = 0.6
|
||||
fsc_k = 0.8
|
||||
k = 2
|
||||
global_sigma = []
|
||||
global_tau = []
|
||||
global_pred_str = []
|
||||
global_gt_str = []
|
||||
for data in all_data:
|
||||
global_sigma.append(data['sigma'])
|
||||
global_tau.append(data['global_tau'])
|
||||
global_pred_str.append(data['global_pred_str'])
|
||||
global_gt_str.append(data['global_gt_str'])
|
||||
|
||||
global_accumulative_recall = 0
|
||||
global_accumulative_precision = 0
|
||||
total_num_gt = 0
|
||||
total_num_det = 0
|
||||
hit_str_count = 0
|
||||
hit_count = 0
|
||||
|
||||
def one_to_one(local_sigma_table, local_tau_table,
|
||||
local_accumulative_recall, local_accumulative_precision,
|
||||
global_accumulative_recall, global_accumulative_precision,
|
||||
gt_flag, det_flag, idy):
|
||||
hit_str_num = 0
|
||||
for gt_id in range(num_gt):
|
||||
gt_matching_qualified_sigma_candidates = np.where(
|
||||
local_sigma_table[gt_id, :] > tr)
|
||||
gt_matching_num_qualified_sigma_candidates = gt_matching_qualified_sigma_candidates[
|
||||
0].shape[0]
|
||||
gt_matching_qualified_tau_candidates = np.where(
|
||||
local_tau_table[gt_id, :] > tp)
|
||||
gt_matching_num_qualified_tau_candidates = gt_matching_qualified_tau_candidates[
|
||||
0].shape[0]
|
||||
|
||||
det_matching_qualified_sigma_candidates = np.where(
|
||||
local_sigma_table[:, gt_matching_qualified_sigma_candidates[0]]
|
||||
> tr)
|
||||
det_matching_num_qualified_sigma_candidates = det_matching_qualified_sigma_candidates[
|
||||
0].shape[0]
|
||||
det_matching_qualified_tau_candidates = np.where(
|
||||
local_tau_table[:, gt_matching_qualified_tau_candidates[0]] >
|
||||
tp)
|
||||
det_matching_num_qualified_tau_candidates = det_matching_qualified_tau_candidates[
|
||||
0].shape[0]
|
||||
|
||||
if (gt_matching_num_qualified_sigma_candidates == 1) and (gt_matching_num_qualified_tau_candidates == 1) and \
|
||||
(det_matching_num_qualified_sigma_candidates == 1) and (
|
||||
det_matching_num_qualified_tau_candidates == 1):
|
||||
global_accumulative_recall = global_accumulative_recall + 1.0
|
||||
global_accumulative_precision = global_accumulative_precision + 1.0
|
||||
local_accumulative_recall = local_accumulative_recall + 1.0
|
||||
local_accumulative_precision = local_accumulative_precision + 1.0
|
||||
|
||||
gt_flag[0, gt_id] = 1
|
||||
matched_det_id = np.where(local_sigma_table[gt_id, :] > tr)
|
||||
# recg start
|
||||
gt_str_cur = global_gt_str[idy][gt_id]
|
||||
pred_str_cur = global_pred_str[idy][matched_det_id[0].tolist()[
|
||||
0]]
|
||||
if pred_str_cur == gt_str_cur:
|
||||
hit_str_num += 1
|
||||
else:
|
||||
if pred_str_cur.lower() == gt_str_cur.lower():
|
||||
hit_str_num += 1
|
||||
# recg end
|
||||
det_flag[0, matched_det_id] = 1
|
||||
return local_accumulative_recall, local_accumulative_precision, global_accumulative_recall, global_accumulative_precision, gt_flag, det_flag, hit_str_num
|
||||
|
||||
def one_to_many(local_sigma_table, local_tau_table,
|
||||
local_accumulative_recall, local_accumulative_precision,
|
||||
global_accumulative_recall, global_accumulative_precision,
|
||||
gt_flag, det_flag, idy):
|
||||
hit_str_num = 0
|
||||
for gt_id in range(num_gt):
|
||||
# skip the following if the groundtruth was matched
|
||||
if gt_flag[0, gt_id] > 0:
|
||||
continue
|
||||
|
||||
non_zero_in_sigma = np.where(local_sigma_table[gt_id, :] > 0)
|
||||
num_non_zero_in_sigma = non_zero_in_sigma[0].shape[0]
|
||||
|
||||
if num_non_zero_in_sigma >= k:
|
||||
####search for all detections that overlaps with this groundtruth
|
||||
qualified_tau_candidates = np.where((local_tau_table[
|
||||
gt_id, :] >= tp) & (det_flag[0, :] == 0))
|
||||
num_qualified_tau_candidates = qualified_tau_candidates[
|
||||
0].shape[0]
|
||||
|
||||
if num_qualified_tau_candidates == 1:
|
||||
if ((local_tau_table[gt_id, qualified_tau_candidates] >= tp)
|
||||
and
|
||||
(local_sigma_table[gt_id, qualified_tau_candidates] >=
|
||||
tr)):
|
||||
# became an one-to-one case
|
||||
global_accumulative_recall = global_accumulative_recall + 1.0
|
||||
global_accumulative_precision = global_accumulative_precision + 1.0
|
||||
local_accumulative_recall = local_accumulative_recall + 1.0
|
||||
local_accumulative_precision = local_accumulative_precision + 1.0
|
||||
|
||||
gt_flag[0, gt_id] = 1
|
||||
det_flag[0, qualified_tau_candidates] = 1
|
||||
# recg start
|
||||
gt_str_cur = global_gt_str[idy][gt_id]
|
||||
pred_str_cur = global_pred_str[idy][
|
||||
qualified_tau_candidates[0].tolist()[0]]
|
||||
if pred_str_cur == gt_str_cur:
|
||||
hit_str_num += 1
|
||||
else:
|
||||
if pred_str_cur.lower() == gt_str_cur.lower():
|
||||
hit_str_num += 1
|
||||
# recg end
|
||||
elif (np.sum(local_sigma_table[gt_id, qualified_tau_candidates])
|
||||
>= tr):
|
||||
gt_flag[0, gt_id] = 1
|
||||
det_flag[0, qualified_tau_candidates] = 1
|
||||
# recg start
|
||||
gt_str_cur = global_gt_str[idy][gt_id]
|
||||
pred_str_cur = global_pred_str[idy][
|
||||
qualified_tau_candidates[0].tolist()[0]]
|
||||
if pred_str_cur == gt_str_cur:
|
||||
hit_str_num += 1
|
||||
else:
|
||||
if pred_str_cur.lower() == gt_str_cur.lower():
|
||||
hit_str_num += 1
|
||||
# recg end
|
||||
|
||||
global_accumulative_recall = global_accumulative_recall + fsc_k
|
||||
global_accumulative_precision = global_accumulative_precision + num_qualified_tau_candidates * fsc_k
|
||||
|
||||
local_accumulative_recall = local_accumulative_recall + fsc_k
|
||||
local_accumulative_precision = local_accumulative_precision + num_qualified_tau_candidates * fsc_k
|
||||
|
||||
return local_accumulative_recall, local_accumulative_precision, global_accumulative_recall, global_accumulative_precision, gt_flag, det_flag, hit_str_num
|
||||
|
||||
def many_to_one(local_sigma_table, local_tau_table,
|
||||
local_accumulative_recall, local_accumulative_precision,
|
||||
global_accumulative_recall, global_accumulative_precision,
|
||||
gt_flag, det_flag, idy):
|
||||
hit_str_num = 0
|
||||
for det_id in range(num_det):
|
||||
# skip the following if the detection was matched
|
||||
if det_flag[0, det_id] > 0:
|
||||
continue
|
||||
|
||||
non_zero_in_tau = np.where(local_tau_table[:, det_id] > 0)
|
||||
num_non_zero_in_tau = non_zero_in_tau[0].shape[0]
|
||||
|
||||
if num_non_zero_in_tau >= k:
|
||||
####search for all detections that overlaps with this groundtruth
|
||||
qualified_sigma_candidates = np.where((
|
||||
local_sigma_table[:, det_id] >= tp) & (gt_flag[0, :] == 0))
|
||||
num_qualified_sigma_candidates = qualified_sigma_candidates[
|
||||
0].shape[0]
|
||||
|
||||
if num_qualified_sigma_candidates == 1:
|
||||
if ((local_tau_table[qualified_sigma_candidates, det_id] >=
|
||||
tp) and
|
||||
(local_sigma_table[qualified_sigma_candidates, det_id]
|
||||
>= tr)):
|
||||
# became an one-to-one case
|
||||
global_accumulative_recall = global_accumulative_recall + 1.0
|
||||
global_accumulative_precision = global_accumulative_precision + 1.0
|
||||
local_accumulative_recall = local_accumulative_recall + 1.0
|
||||
local_accumulative_precision = local_accumulative_precision + 1.0
|
||||
|
||||
gt_flag[0, qualified_sigma_candidates] = 1
|
||||
det_flag[0, det_id] = 1
|
||||
# recg start
|
||||
pred_str_cur = global_pred_str[idy][det_id]
|
||||
gt_len = len(qualified_sigma_candidates[0])
|
||||
for idx in range(gt_len):
|
||||
ele_gt_id = qualified_sigma_candidates[0].tolist()[
|
||||
idx]
|
||||
if ele_gt_id not in global_gt_str[idy]:
|
||||
continue
|
||||
gt_str_cur = global_gt_str[idy][ele_gt_id]
|
||||
if pred_str_cur == gt_str_cur:
|
||||
hit_str_num += 1
|
||||
break
|
||||
else:
|
||||
if pred_str_cur.lower() == gt_str_cur.lower():
|
||||
hit_str_num += 1
|
||||
break
|
||||
# recg end
|
||||
elif (np.sum(local_tau_table[qualified_sigma_candidates,
|
||||
det_id]) >= tp):
|
||||
det_flag[0, det_id] = 1
|
||||
gt_flag[0, qualified_sigma_candidates] = 1
|
||||
# recg start
|
||||
pred_str_cur = global_pred_str[idy][det_id]
|
||||
gt_len = len(qualified_sigma_candidates[0])
|
||||
for idx in range(gt_len):
|
||||
ele_gt_id = qualified_sigma_candidates[0].tolist()[idx]
|
||||
if ele_gt_id not in global_gt_str[idy]:
|
||||
continue
|
||||
gt_str_cur = global_gt_str[idy][ele_gt_id]
|
||||
if pred_str_cur == gt_str_cur:
|
||||
hit_str_num += 1
|
||||
break
|
||||
else:
|
||||
if pred_str_cur.lower() == gt_str_cur.lower():
|
||||
hit_str_num += 1
|
||||
break
|
||||
# recg end
|
||||
|
||||
global_accumulative_recall = global_accumulative_recall + num_qualified_sigma_candidates * fsc_k
|
||||
global_accumulative_precision = global_accumulative_precision + fsc_k
|
||||
|
||||
local_accumulative_recall = local_accumulative_recall + num_qualified_sigma_candidates * fsc_k
|
||||
local_accumulative_precision = local_accumulative_precision + fsc_k
|
||||
return local_accumulative_recall, local_accumulative_precision, global_accumulative_recall, global_accumulative_precision, gt_flag, det_flag, hit_str_num
|
||||
|
||||
for idx in range(len(global_sigma)):
|
||||
local_sigma_table = np.array(global_sigma[idx])
|
||||
local_tau_table = global_tau[idx]
|
||||
|
||||
num_gt = local_sigma_table.shape[0]
|
||||
num_det = local_sigma_table.shape[1]
|
||||
|
||||
total_num_gt = total_num_gt + num_gt
|
||||
total_num_det = total_num_det + num_det
|
||||
|
||||
local_accumulative_recall = 0
|
||||
local_accumulative_precision = 0
|
||||
gt_flag = np.zeros((1, num_gt))
|
||||
det_flag = np.zeros((1, num_det))
|
||||
|
||||
#######first check for one-to-one case##########
|
||||
local_accumulative_recall, local_accumulative_precision, global_accumulative_recall, global_accumulative_precision, \
|
||||
gt_flag, det_flag, hit_str_num = one_to_one(local_sigma_table, local_tau_table,
|
||||
local_accumulative_recall, local_accumulative_precision,
|
||||
global_accumulative_recall, global_accumulative_precision,
|
||||
gt_flag, det_flag, idx)
|
||||
|
||||
hit_str_count += hit_str_num
|
||||
#######then check for one-to-many case##########
|
||||
local_accumulative_recall, local_accumulative_precision, global_accumulative_recall, global_accumulative_precision, \
|
||||
gt_flag, det_flag, hit_str_num = one_to_many(local_sigma_table, local_tau_table,
|
||||
local_accumulative_recall, local_accumulative_precision,
|
||||
global_accumulative_recall, global_accumulative_precision,
|
||||
gt_flag, det_flag, idx)
|
||||
hit_str_count += hit_str_num
|
||||
#######then check for many-to-one case##########
|
||||
local_accumulative_recall, local_accumulative_precision, global_accumulative_recall, global_accumulative_precision, \
|
||||
gt_flag, det_flag, hit_str_num = many_to_one(local_sigma_table, local_tau_table,
|
||||
local_accumulative_recall, local_accumulative_precision,
|
||||
global_accumulative_recall, global_accumulative_precision,
|
||||
gt_flag, det_flag, idx)
|
||||
hit_str_count += hit_str_num
|
||||
|
||||
try:
|
||||
recall = global_accumulative_recall / total_num_gt
|
||||
except ZeroDivisionError:
|
||||
recall = 0
|
||||
|
||||
try:
|
||||
precision = global_accumulative_precision / total_num_det
|
||||
except ZeroDivisionError:
|
||||
precision = 0
|
||||
|
||||
try:
|
||||
f_score = 2 * precision * recall / (precision + recall)
|
||||
except ZeroDivisionError:
|
||||
f_score = 0
|
||||
|
||||
try:
|
||||
seqerr = 1 - float(hit_str_count) / global_accumulative_recall
|
||||
except ZeroDivisionError:
|
||||
seqerr = 1
|
||||
|
||||
try:
|
||||
recall_e2e = float(hit_str_count) / total_num_gt
|
||||
except ZeroDivisionError:
|
||||
recall_e2e = 0
|
||||
|
||||
try:
|
||||
precision_e2e = float(hit_str_count) / total_num_det
|
||||
except ZeroDivisionError:
|
||||
precision_e2e = 0
|
||||
|
||||
try:
|
||||
f_score_e2e = 2 * precision_e2e * recall_e2e / (
|
||||
precision_e2e + recall_e2e)
|
||||
except ZeroDivisionError:
|
||||
f_score_e2e = 0
|
||||
|
||||
final = {
|
||||
'total_num_gt': total_num_gt,
|
||||
'total_num_det': total_num_det,
|
||||
'global_accumulative_recall': global_accumulative_recall,
|
||||
'hit_str_count': hit_str_count,
|
||||
'recall': recall,
|
||||
'precision': precision,
|
||||
'f_score': f_score,
|
||||
'seqerr': seqerr,
|
||||
'recall_e2e': recall_e2e,
|
||||
'precision_e2e': precision_e2e,
|
||||
'f_score_e2e': f_score_e2e
|
||||
}
|
||||
return final
|
||||
83
backend/ppocr/utils/e2e_metric/polygon_fast.py
Executable file
83
backend/ppocr/utils/e2e_metric/polygon_fast.py
Executable file
@@ -0,0 +1,83 @@
|
||||
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# 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.
|
||||
import numpy as np
|
||||
from shapely.geometry import Polygon
|
||||
"""
|
||||
:param det_x: [1, N] Xs of detection's vertices
|
||||
:param det_y: [1, N] Ys of detection's vertices
|
||||
:param gt_x: [1, N] Xs of groundtruth's vertices
|
||||
:param gt_y: [1, N] Ys of groundtruth's vertices
|
||||
|
||||
##############
|
||||
All the calculation of 'AREA' in this script is handled by:
|
||||
1) First generating a binary mask with the polygon area filled up with 1's
|
||||
2) Summing up all the 1's
|
||||
"""
|
||||
|
||||
|
||||
def area(x, y):
|
||||
polygon = Polygon(np.stack([x, y], axis=1))
|
||||
return float(polygon.area)
|
||||
|
||||
|
||||
def approx_area_of_intersection(det_x, det_y, gt_x, gt_y):
|
||||
"""
|
||||
This helper determine if both polygons are intersecting with each others with an approximation method.
|
||||
Area of intersection represented by the minimum bounding rectangular [xmin, ymin, xmax, ymax]
|
||||
"""
|
||||
det_ymax = np.max(det_y)
|
||||
det_xmax = np.max(det_x)
|
||||
det_ymin = np.min(det_y)
|
||||
det_xmin = np.min(det_x)
|
||||
|
||||
gt_ymax = np.max(gt_y)
|
||||
gt_xmax = np.max(gt_x)
|
||||
gt_ymin = np.min(gt_y)
|
||||
gt_xmin = np.min(gt_x)
|
||||
|
||||
all_min_ymax = np.minimum(det_ymax, gt_ymax)
|
||||
all_max_ymin = np.maximum(det_ymin, gt_ymin)
|
||||
|
||||
intersect_heights = np.maximum(0.0, (all_min_ymax - all_max_ymin))
|
||||
|
||||
all_min_xmax = np.minimum(det_xmax, gt_xmax)
|
||||
all_max_xmin = np.maximum(det_xmin, gt_xmin)
|
||||
intersect_widths = np.maximum(0.0, (all_min_xmax - all_max_xmin))
|
||||
|
||||
return intersect_heights * intersect_widths
|
||||
|
||||
|
||||
def area_of_intersection(det_x, det_y, gt_x, gt_y):
|
||||
p1 = Polygon(np.stack([det_x, det_y], axis=1)).buffer(0)
|
||||
p2 = Polygon(np.stack([gt_x, gt_y], axis=1)).buffer(0)
|
||||
return float(p1.intersection(p2).area)
|
||||
|
||||
|
||||
def area_of_union(det_x, det_y, gt_x, gt_y):
|
||||
p1 = Polygon(np.stack([det_x, det_y], axis=1)).buffer(0)
|
||||
p2 = Polygon(np.stack([gt_x, gt_y], axis=1)).buffer(0)
|
||||
return float(p1.union(p2).area)
|
||||
|
||||
|
||||
def iou(det_x, det_y, gt_x, gt_y):
|
||||
return area_of_intersection(det_x, det_y, gt_x, gt_y) / (
|
||||
area_of_union(det_x, det_y, gt_x, gt_y) + 1.0)
|
||||
|
||||
|
||||
def iod(det_x, det_y, gt_x, gt_y):
|
||||
"""
|
||||
This helper determine the fraction of intersection area over detection area
|
||||
"""
|
||||
return area_of_intersection(det_x, det_y, gt_x, gt_y) / (
|
||||
area(det_x, det_y) + 1.0)
|
||||
87
backend/ppocr/utils/e2e_utils/extract_batchsize.py
Normal file
87
backend/ppocr/utils/e2e_utils/extract_batchsize.py
Normal file
@@ -0,0 +1,87 @@
|
||||
import paddle
|
||||
import numpy as np
|
||||
import copy
|
||||
|
||||
|
||||
def org_tcl_rois(batch_size, pos_lists, pos_masks, label_lists, tcl_bs):
|
||||
"""
|
||||
"""
|
||||
pos_lists_, pos_masks_, label_lists_ = [], [], []
|
||||
img_bs = batch_size
|
||||
ngpu = int(batch_size / img_bs)
|
||||
img_ids = np.array(pos_lists, dtype=np.int32)[:, 0, 0].copy()
|
||||
pos_lists_split, pos_masks_split, label_lists_split = [], [], []
|
||||
for i in range(ngpu):
|
||||
pos_lists_split.append([])
|
||||
pos_masks_split.append([])
|
||||
label_lists_split.append([])
|
||||
|
||||
for i in range(img_ids.shape[0]):
|
||||
img_id = img_ids[i]
|
||||
gpu_id = int(img_id / img_bs)
|
||||
img_id = img_id % img_bs
|
||||
pos_list = pos_lists[i].copy()
|
||||
pos_list[:, 0] = img_id
|
||||
pos_lists_split[gpu_id].append(pos_list)
|
||||
pos_masks_split[gpu_id].append(pos_masks[i].copy())
|
||||
label_lists_split[gpu_id].append(copy.deepcopy(label_lists[i]))
|
||||
# repeat or delete
|
||||
for i in range(ngpu):
|
||||
vp_len = len(pos_lists_split[i])
|
||||
if vp_len <= tcl_bs:
|
||||
for j in range(0, tcl_bs - vp_len):
|
||||
pos_list = pos_lists_split[i][j].copy()
|
||||
pos_lists_split[i].append(pos_list)
|
||||
pos_mask = pos_masks_split[i][j].copy()
|
||||
pos_masks_split[i].append(pos_mask)
|
||||
label_list = copy.deepcopy(label_lists_split[i][j])
|
||||
label_lists_split[i].append(label_list)
|
||||
else:
|
||||
for j in range(0, vp_len - tcl_bs):
|
||||
c_len = len(pos_lists_split[i])
|
||||
pop_id = np.random.permutation(c_len)[0]
|
||||
pos_lists_split[i].pop(pop_id)
|
||||
pos_masks_split[i].pop(pop_id)
|
||||
label_lists_split[i].pop(pop_id)
|
||||
# merge
|
||||
for i in range(ngpu):
|
||||
pos_lists_.extend(pos_lists_split[i])
|
||||
pos_masks_.extend(pos_masks_split[i])
|
||||
label_lists_.extend(label_lists_split[i])
|
||||
return pos_lists_, pos_masks_, label_lists_
|
||||
|
||||
|
||||
def pre_process(label_list, pos_list, pos_mask, max_text_length, max_text_nums,
|
||||
pad_num, tcl_bs):
|
||||
label_list = label_list.numpy()
|
||||
batch, _, _, _ = label_list.shape
|
||||
pos_list = pos_list.numpy()
|
||||
pos_mask = pos_mask.numpy()
|
||||
pos_list_t = []
|
||||
pos_mask_t = []
|
||||
label_list_t = []
|
||||
for i in range(batch):
|
||||
for j in range(max_text_nums):
|
||||
if pos_mask[i, j].any():
|
||||
pos_list_t.append(pos_list[i][j])
|
||||
pos_mask_t.append(pos_mask[i][j])
|
||||
label_list_t.append(label_list[i][j])
|
||||
pos_list, pos_mask, label_list = org_tcl_rois(batch, pos_list_t, pos_mask_t,
|
||||
label_list_t, tcl_bs)
|
||||
label = []
|
||||
tt = [l.tolist() for l in label_list]
|
||||
for i in range(tcl_bs):
|
||||
k = 0
|
||||
for j in range(max_text_length):
|
||||
if tt[i][j][0] != pad_num:
|
||||
k += 1
|
||||
else:
|
||||
break
|
||||
label.append(k)
|
||||
label = paddle.to_tensor(label)
|
||||
label = paddle.cast(label, dtype='int64')
|
||||
pos_list = paddle.to_tensor(pos_list)
|
||||
pos_mask = paddle.to_tensor(pos_mask)
|
||||
label_list = paddle.squeeze(paddle.to_tensor(label_list), axis=2)
|
||||
label_list = paddle.cast(label_list, dtype='int32')
|
||||
return pos_list, pos_mask, label_list, label
|
||||
457
backend/ppocr/utils/e2e_utils/extract_textpoint_fast.py
Normal file
457
backend/ppocr/utils/e2e_utils/extract_textpoint_fast.py
Normal file
@@ -0,0 +1,457 @@
|
||||
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# 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.
|
||||
"""Contains various CTC decoders."""
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
import cv2
|
||||
import math
|
||||
|
||||
import numpy as np
|
||||
from itertools import groupby
|
||||
from skimage.morphology._skeletonize import thin
|
||||
|
||||
|
||||
def get_dict(character_dict_path):
|
||||
character_str = ""
|
||||
with open(character_dict_path, "rb") as fin:
|
||||
lines = fin.readlines()
|
||||
for line in lines:
|
||||
line = line.decode('utf-8').strip("\n").strip("\r\n")
|
||||
character_str += line
|
||||
dict_character = list(character_str)
|
||||
return dict_character
|
||||
|
||||
|
||||
def softmax(logits):
|
||||
"""
|
||||
logits: N x d
|
||||
"""
|
||||
max_value = np.max(logits, axis=1, keepdims=True)
|
||||
exp = np.exp(logits - max_value)
|
||||
exp_sum = np.sum(exp, axis=1, keepdims=True)
|
||||
dist = exp / exp_sum
|
||||
return dist
|
||||
|
||||
|
||||
def get_keep_pos_idxs(labels, remove_blank=None):
|
||||
"""
|
||||
Remove duplicate and get pos idxs of keep items.
|
||||
The value of keep_blank should be [None, 95].
|
||||
"""
|
||||
duplicate_len_list = []
|
||||
keep_pos_idx_list = []
|
||||
keep_char_idx_list = []
|
||||
for k, v_ in groupby(labels):
|
||||
current_len = len(list(v_))
|
||||
if k != remove_blank:
|
||||
current_idx = int(sum(duplicate_len_list) + current_len // 2)
|
||||
keep_pos_idx_list.append(current_idx)
|
||||
keep_char_idx_list.append(k)
|
||||
duplicate_len_list.append(current_len)
|
||||
return keep_char_idx_list, keep_pos_idx_list
|
||||
|
||||
|
||||
def remove_blank(labels, blank=0):
|
||||
new_labels = [x for x in labels if x != blank]
|
||||
return new_labels
|
||||
|
||||
|
||||
def insert_blank(labels, blank=0):
|
||||
new_labels = [blank]
|
||||
for l in labels:
|
||||
new_labels += [l, blank]
|
||||
return new_labels
|
||||
|
||||
|
||||
def ctc_greedy_decoder(probs_seq, blank=95, keep_blank_in_idxs=True):
|
||||
"""
|
||||
CTC greedy (best path) decoder.
|
||||
"""
|
||||
raw_str = np.argmax(np.array(probs_seq), axis=1)
|
||||
remove_blank_in_pos = None if keep_blank_in_idxs else blank
|
||||
dedup_str, keep_idx_list = get_keep_pos_idxs(
|
||||
raw_str, remove_blank=remove_blank_in_pos)
|
||||
dst_str = remove_blank(dedup_str, blank=blank)
|
||||
return dst_str, keep_idx_list
|
||||
|
||||
|
||||
def instance_ctc_greedy_decoder(gather_info, logits_map, pts_num=4):
|
||||
_, _, C = logits_map.shape
|
||||
ys, xs = zip(*gather_info)
|
||||
logits_seq = logits_map[list(ys), list(xs)]
|
||||
probs_seq = logits_seq
|
||||
labels = np.argmax(probs_seq, axis=1)
|
||||
dst_str = [k for k, v_ in groupby(labels) if k != C - 1]
|
||||
detal = len(gather_info) // (pts_num - 1)
|
||||
keep_idx_list = [0] + [detal * (i + 1) for i in range(pts_num - 2)] + [-1]
|
||||
keep_gather_list = [gather_info[idx] for idx in keep_idx_list]
|
||||
return dst_str, keep_gather_list
|
||||
|
||||
|
||||
def ctc_decoder_for_image(gather_info_list,
|
||||
logits_map,
|
||||
Lexicon_Table,
|
||||
pts_num=6):
|
||||
"""
|
||||
CTC decoder using multiple processes.
|
||||
"""
|
||||
decoder_str = []
|
||||
decoder_xys = []
|
||||
for gather_info in gather_info_list:
|
||||
if len(gather_info) < pts_num:
|
||||
continue
|
||||
dst_str, xys_list = instance_ctc_greedy_decoder(
|
||||
gather_info, logits_map, pts_num=pts_num)
|
||||
dst_str_readable = ''.join([Lexicon_Table[idx] for idx in dst_str])
|
||||
if len(dst_str_readable) < 2:
|
||||
continue
|
||||
decoder_str.append(dst_str_readable)
|
||||
decoder_xys.append(xys_list)
|
||||
return decoder_str, decoder_xys
|
||||
|
||||
|
||||
def sort_with_direction(pos_list, f_direction):
|
||||
"""
|
||||
f_direction: h x w x 2
|
||||
pos_list: [[y, x], [y, x], [y, x] ...]
|
||||
"""
|
||||
|
||||
def sort_part_with_direction(pos_list, point_direction):
|
||||
pos_list = np.array(pos_list).reshape(-1, 2)
|
||||
point_direction = np.array(point_direction).reshape(-1, 2)
|
||||
average_direction = np.mean(point_direction, axis=0, keepdims=True)
|
||||
pos_proj_leng = np.sum(pos_list * average_direction, axis=1)
|
||||
sorted_list = pos_list[np.argsort(pos_proj_leng)].tolist()
|
||||
sorted_direction = point_direction[np.argsort(pos_proj_leng)].tolist()
|
||||
return sorted_list, sorted_direction
|
||||
|
||||
pos_list = np.array(pos_list).reshape(-1, 2)
|
||||
point_direction = f_direction[pos_list[:, 0], pos_list[:, 1]] # x, y
|
||||
point_direction = point_direction[:, ::-1] # x, y -> y, x
|
||||
sorted_point, sorted_direction = sort_part_with_direction(pos_list,
|
||||
point_direction)
|
||||
|
||||
point_num = len(sorted_point)
|
||||
if point_num >= 16:
|
||||
middle_num = point_num // 2
|
||||
first_part_point = sorted_point[:middle_num]
|
||||
first_point_direction = sorted_direction[:middle_num]
|
||||
sorted_fist_part_point, sorted_fist_part_direction = sort_part_with_direction(
|
||||
first_part_point, first_point_direction)
|
||||
|
||||
last_part_point = sorted_point[middle_num:]
|
||||
last_point_direction = sorted_direction[middle_num:]
|
||||
sorted_last_part_point, sorted_last_part_direction = sort_part_with_direction(
|
||||
last_part_point, last_point_direction)
|
||||
sorted_point = sorted_fist_part_point + sorted_last_part_point
|
||||
sorted_direction = sorted_fist_part_direction + sorted_last_part_direction
|
||||
|
||||
return sorted_point, np.array(sorted_direction)
|
||||
|
||||
|
||||
def add_id(pos_list, image_id=0):
|
||||
"""
|
||||
Add id for gather feature, for inference.
|
||||
"""
|
||||
new_list = []
|
||||
for item in pos_list:
|
||||
new_list.append((image_id, item[0], item[1]))
|
||||
return new_list
|
||||
|
||||
|
||||
def sort_and_expand_with_direction(pos_list, f_direction):
|
||||
"""
|
||||
f_direction: h x w x 2
|
||||
pos_list: [[y, x], [y, x], [y, x] ...]
|
||||
"""
|
||||
h, w, _ = f_direction.shape
|
||||
sorted_list, point_direction = sort_with_direction(pos_list, f_direction)
|
||||
|
||||
point_num = len(sorted_list)
|
||||
sub_direction_len = max(point_num // 3, 2)
|
||||
left_direction = point_direction[:sub_direction_len, :]
|
||||
right_dirction = point_direction[point_num - sub_direction_len:, :]
|
||||
|
||||
left_average_direction = -np.mean(left_direction, axis=0, keepdims=True)
|
||||
left_average_len = np.linalg.norm(left_average_direction)
|
||||
left_start = np.array(sorted_list[0])
|
||||
left_step = left_average_direction / (left_average_len + 1e-6)
|
||||
|
||||
right_average_direction = np.mean(right_dirction, axis=0, keepdims=True)
|
||||
right_average_len = np.linalg.norm(right_average_direction)
|
||||
right_step = right_average_direction / (right_average_len + 1e-6)
|
||||
right_start = np.array(sorted_list[-1])
|
||||
|
||||
append_num = max(
|
||||
int((left_average_len + right_average_len) / 2.0 * 0.15), 1)
|
||||
left_list = []
|
||||
right_list = []
|
||||
for i in range(append_num):
|
||||
ly, lx = np.round(left_start + left_step * (i + 1)).flatten().astype(
|
||||
'int32').tolist()
|
||||
if ly < h and lx < w and (ly, lx) not in left_list:
|
||||
left_list.append((ly, lx))
|
||||
ry, rx = np.round(right_start + right_step * (i + 1)).flatten().astype(
|
||||
'int32').tolist()
|
||||
if ry < h and rx < w and (ry, rx) not in right_list:
|
||||
right_list.append((ry, rx))
|
||||
|
||||
all_list = left_list[::-1] + sorted_list + right_list
|
||||
return all_list
|
||||
|
||||
|
||||
def sort_and_expand_with_direction_v2(pos_list, f_direction, binary_tcl_map):
|
||||
"""
|
||||
f_direction: h x w x 2
|
||||
pos_list: [[y, x], [y, x], [y, x] ...]
|
||||
binary_tcl_map: h x w
|
||||
"""
|
||||
h, w, _ = f_direction.shape
|
||||
sorted_list, point_direction = sort_with_direction(pos_list, f_direction)
|
||||
|
||||
point_num = len(sorted_list)
|
||||
sub_direction_len = max(point_num // 3, 2)
|
||||
left_direction = point_direction[:sub_direction_len, :]
|
||||
right_dirction = point_direction[point_num - sub_direction_len:, :]
|
||||
|
||||
left_average_direction = -np.mean(left_direction, axis=0, keepdims=True)
|
||||
left_average_len = np.linalg.norm(left_average_direction)
|
||||
left_start = np.array(sorted_list[0])
|
||||
left_step = left_average_direction / (left_average_len + 1e-6)
|
||||
|
||||
right_average_direction = np.mean(right_dirction, axis=0, keepdims=True)
|
||||
right_average_len = np.linalg.norm(right_average_direction)
|
||||
right_step = right_average_direction / (right_average_len + 1e-6)
|
||||
right_start = np.array(sorted_list[-1])
|
||||
|
||||
append_num = max(
|
||||
int((left_average_len + right_average_len) / 2.0 * 0.15), 1)
|
||||
max_append_num = 2 * append_num
|
||||
|
||||
left_list = []
|
||||
right_list = []
|
||||
for i in range(max_append_num):
|
||||
ly, lx = np.round(left_start + left_step * (i + 1)).flatten().astype(
|
||||
'int32').tolist()
|
||||
if ly < h and lx < w and (ly, lx) not in left_list:
|
||||
if binary_tcl_map[ly, lx] > 0.5:
|
||||
left_list.append((ly, lx))
|
||||
else:
|
||||
break
|
||||
|
||||
for i in range(max_append_num):
|
||||
ry, rx = np.round(right_start + right_step * (i + 1)).flatten().astype(
|
||||
'int32').tolist()
|
||||
if ry < h and rx < w and (ry, rx) not in right_list:
|
||||
if binary_tcl_map[ry, rx] > 0.5:
|
||||
right_list.append((ry, rx))
|
||||
else:
|
||||
break
|
||||
|
||||
all_list = left_list[::-1] + sorted_list + right_list
|
||||
return all_list
|
||||
|
||||
|
||||
def point_pair2poly(point_pair_list):
|
||||
"""
|
||||
Transfer vertical point_pairs into poly point in clockwise.
|
||||
"""
|
||||
point_num = len(point_pair_list) * 2
|
||||
point_list = [0] * point_num
|
||||
for idx, point_pair in enumerate(point_pair_list):
|
||||
point_list[idx] = point_pair[0]
|
||||
point_list[point_num - 1 - idx] = point_pair[1]
|
||||
return np.array(point_list).reshape(-1, 2)
|
||||
|
||||
|
||||
def shrink_quad_along_width(quad, begin_width_ratio=0., end_width_ratio=1.):
|
||||
ratio_pair = np.array(
|
||||
[[begin_width_ratio], [end_width_ratio]], dtype=np.float32)
|
||||
p0_1 = quad[0] + (quad[1] - quad[0]) * ratio_pair
|
||||
p3_2 = quad[3] + (quad[2] - quad[3]) * ratio_pair
|
||||
return np.array([p0_1[0], p0_1[1], p3_2[1], p3_2[0]])
|
||||
|
||||
|
||||
def expand_poly_along_width(poly, shrink_ratio_of_width=0.3):
|
||||
"""
|
||||
expand poly along width.
|
||||
"""
|
||||
point_num = poly.shape[0]
|
||||
left_quad = np.array(
|
||||
[poly[0], poly[1], poly[-2], poly[-1]], dtype=np.float32)
|
||||
left_ratio = -shrink_ratio_of_width * np.linalg.norm(left_quad[0] - left_quad[3]) / \
|
||||
(np.linalg.norm(left_quad[0] - left_quad[1]) + 1e-6)
|
||||
left_quad_expand = shrink_quad_along_width(left_quad, left_ratio, 1.0)
|
||||
right_quad = np.array(
|
||||
[
|
||||
poly[point_num // 2 - 2], poly[point_num // 2 - 1],
|
||||
poly[point_num // 2], poly[point_num // 2 + 1]
|
||||
],
|
||||
dtype=np.float32)
|
||||
right_ratio = 1.0 + shrink_ratio_of_width * np.linalg.norm(right_quad[0] - right_quad[3]) / \
|
||||
(np.linalg.norm(right_quad[0] - right_quad[1]) + 1e-6)
|
||||
right_quad_expand = shrink_quad_along_width(right_quad, 0.0, right_ratio)
|
||||
poly[0] = left_quad_expand[0]
|
||||
poly[-1] = left_quad_expand[-1]
|
||||
poly[point_num // 2 - 1] = right_quad_expand[1]
|
||||
poly[point_num // 2] = right_quad_expand[2]
|
||||
return poly
|
||||
|
||||
|
||||
def restore_poly(instance_yxs_list, seq_strs, p_border, ratio_w, ratio_h, src_w,
|
||||
src_h, valid_set):
|
||||
poly_list = []
|
||||
keep_str_list = []
|
||||
for yx_center_line, keep_str in zip(instance_yxs_list, seq_strs):
|
||||
if len(keep_str) < 2:
|
||||
print('--> too short, {}'.format(keep_str))
|
||||
continue
|
||||
|
||||
offset_expand = 1.0
|
||||
if valid_set == 'totaltext':
|
||||
offset_expand = 1.2
|
||||
|
||||
point_pair_list = []
|
||||
for y, x in yx_center_line:
|
||||
offset = p_border[:, y, x].reshape(2, 2) * offset_expand
|
||||
ori_yx = np.array([y, x], dtype=np.float32)
|
||||
point_pair = (ori_yx + offset)[:, ::-1] * 4.0 / np.array(
|
||||
[ratio_w, ratio_h]).reshape(-1, 2)
|
||||
point_pair_list.append(point_pair)
|
||||
|
||||
detected_poly = point_pair2poly(point_pair_list)
|
||||
detected_poly = expand_poly_along_width(
|
||||
detected_poly, shrink_ratio_of_width=0.2)
|
||||
detected_poly[:, 0] = np.clip(detected_poly[:, 0], a_min=0, a_max=src_w)
|
||||
detected_poly[:, 1] = np.clip(detected_poly[:, 1], a_min=0, a_max=src_h)
|
||||
|
||||
keep_str_list.append(keep_str)
|
||||
if valid_set == 'partvgg':
|
||||
middle_point = len(detected_poly) // 2
|
||||
detected_poly = detected_poly[
|
||||
[0, middle_point - 1, middle_point, -1], :]
|
||||
poly_list.append(detected_poly)
|
||||
elif valid_set == 'totaltext':
|
||||
poly_list.append(detected_poly)
|
||||
else:
|
||||
print('--> Not supported format.')
|
||||
exit(-1)
|
||||
return poly_list, keep_str_list
|
||||
|
||||
|
||||
def generate_pivot_list_fast(p_score,
|
||||
p_char_maps,
|
||||
f_direction,
|
||||
Lexicon_Table,
|
||||
score_thresh=0.5):
|
||||
"""
|
||||
return center point and end point of TCL instance; filter with the char maps;
|
||||
"""
|
||||
p_score = p_score[0]
|
||||
f_direction = f_direction.transpose(1, 2, 0)
|
||||
p_tcl_map = (p_score > score_thresh) * 1.0
|
||||
skeleton_map = thin(p_tcl_map.astype(np.uint8))
|
||||
instance_count, instance_label_map = cv2.connectedComponents(
|
||||
skeleton_map.astype(np.uint8), connectivity=8)
|
||||
|
||||
# get TCL Instance
|
||||
all_pos_yxs = []
|
||||
if instance_count > 0:
|
||||
for instance_id in range(1, instance_count):
|
||||
pos_list = []
|
||||
ys, xs = np.where(instance_label_map == instance_id)
|
||||
pos_list = list(zip(ys, xs))
|
||||
|
||||
if len(pos_list) < 3:
|
||||
continue
|
||||
|
||||
pos_list_sorted = sort_and_expand_with_direction_v2(
|
||||
pos_list, f_direction, p_tcl_map)
|
||||
all_pos_yxs.append(pos_list_sorted)
|
||||
|
||||
p_char_maps = p_char_maps.transpose([1, 2, 0])
|
||||
decoded_str, keep_yxs_list = ctc_decoder_for_image(
|
||||
all_pos_yxs, logits_map=p_char_maps, Lexicon_Table=Lexicon_Table)
|
||||
return keep_yxs_list, decoded_str
|
||||
|
||||
|
||||
def extract_main_direction(pos_list, f_direction):
|
||||
"""
|
||||
f_direction: h x w x 2
|
||||
pos_list: [[y, x], [y, x], [y, x] ...]
|
||||
"""
|
||||
pos_list = np.array(pos_list)
|
||||
point_direction = f_direction[pos_list[:, 0], pos_list[:, 1]]
|
||||
point_direction = point_direction[:, ::-1] # x, y -> y, x
|
||||
average_direction = np.mean(point_direction, axis=0, keepdims=True)
|
||||
average_direction = average_direction / (
|
||||
np.linalg.norm(average_direction) + 1e-6)
|
||||
return average_direction
|
||||
|
||||
|
||||
def sort_by_direction_with_image_id_deprecated(pos_list, f_direction):
|
||||
"""
|
||||
f_direction: h x w x 2
|
||||
pos_list: [[id, y, x], [id, y, x], [id, y, x] ...]
|
||||
"""
|
||||
pos_list_full = np.array(pos_list).reshape(-1, 3)
|
||||
pos_list = pos_list_full[:, 1:]
|
||||
point_direction = f_direction[pos_list[:, 0], pos_list[:, 1]] # x, y
|
||||
point_direction = point_direction[:, ::-1] # x, y -> y, x
|
||||
average_direction = np.mean(point_direction, axis=0, keepdims=True)
|
||||
pos_proj_leng = np.sum(pos_list * average_direction, axis=1)
|
||||
sorted_list = pos_list_full[np.argsort(pos_proj_leng)].tolist()
|
||||
return sorted_list
|
||||
|
||||
|
||||
def sort_by_direction_with_image_id(pos_list, f_direction):
|
||||
"""
|
||||
f_direction: h x w x 2
|
||||
pos_list: [[y, x], [y, x], [y, x] ...]
|
||||
"""
|
||||
|
||||
def sort_part_with_direction(pos_list_full, point_direction):
|
||||
pos_list_full = np.array(pos_list_full).reshape(-1, 3)
|
||||
pos_list = pos_list_full[:, 1:]
|
||||
point_direction = np.array(point_direction).reshape(-1, 2)
|
||||
average_direction = np.mean(point_direction, axis=0, keepdims=True)
|
||||
pos_proj_leng = np.sum(pos_list * average_direction, axis=1)
|
||||
sorted_list = pos_list_full[np.argsort(pos_proj_leng)].tolist()
|
||||
sorted_direction = point_direction[np.argsort(pos_proj_leng)].tolist()
|
||||
return sorted_list, sorted_direction
|
||||
|
||||
pos_list = np.array(pos_list).reshape(-1, 3)
|
||||
point_direction = f_direction[pos_list[:, 1], pos_list[:, 2]] # x, y
|
||||
point_direction = point_direction[:, ::-1] # x, y -> y, x
|
||||
sorted_point, sorted_direction = sort_part_with_direction(pos_list,
|
||||
point_direction)
|
||||
|
||||
point_num = len(sorted_point)
|
||||
if point_num >= 16:
|
||||
middle_num = point_num // 2
|
||||
first_part_point = sorted_point[:middle_num]
|
||||
first_point_direction = sorted_direction[:middle_num]
|
||||
sorted_fist_part_point, sorted_fist_part_direction = sort_part_with_direction(
|
||||
first_part_point, first_point_direction)
|
||||
|
||||
last_part_point = sorted_point[middle_num:]
|
||||
last_point_direction = sorted_direction[middle_num:]
|
||||
sorted_last_part_point, sorted_last_part_direction = sort_part_with_direction(
|
||||
last_part_point, last_point_direction)
|
||||
sorted_point = sorted_fist_part_point + sorted_last_part_point
|
||||
sorted_direction = sorted_fist_part_direction + sorted_last_part_direction
|
||||
|
||||
return sorted_point
|
||||
592
backend/ppocr/utils/e2e_utils/extract_textpoint_slow.py
Normal file
592
backend/ppocr/utils/e2e_utils/extract_textpoint_slow.py
Normal file
@@ -0,0 +1,592 @@
|
||||
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# 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.
|
||||
"""Contains various CTC decoders."""
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
import cv2
|
||||
import math
|
||||
|
||||
import numpy as np
|
||||
from itertools import groupby
|
||||
from skimage.morphology._skeletonize import thin
|
||||
|
||||
|
||||
def get_dict(character_dict_path):
|
||||
character_str = ""
|
||||
with open(character_dict_path, "rb") as fin:
|
||||
lines = fin.readlines()
|
||||
for line in lines:
|
||||
line = line.decode('utf-8').strip("\n").strip("\r\n")
|
||||
character_str += line
|
||||
dict_character = list(character_str)
|
||||
return dict_character
|
||||
|
||||
|
||||
def point_pair2poly(point_pair_list):
|
||||
"""
|
||||
Transfer vertical point_pairs into poly point in clockwise.
|
||||
"""
|
||||
pair_length_list = []
|
||||
for point_pair in point_pair_list:
|
||||
pair_length = np.linalg.norm(point_pair[0] - point_pair[1])
|
||||
pair_length_list.append(pair_length)
|
||||
pair_length_list = np.array(pair_length_list)
|
||||
pair_info = (pair_length_list.max(), pair_length_list.min(),
|
||||
pair_length_list.mean())
|
||||
|
||||
point_num = len(point_pair_list) * 2
|
||||
point_list = [0] * point_num
|
||||
for idx, point_pair in enumerate(point_pair_list):
|
||||
point_list[idx] = point_pair[0]
|
||||
point_list[point_num - 1 - idx] = point_pair[1]
|
||||
return np.array(point_list).reshape(-1, 2), pair_info
|
||||
|
||||
|
||||
def shrink_quad_along_width(quad, begin_width_ratio=0., end_width_ratio=1.):
|
||||
"""
|
||||
Generate shrink_quad_along_width.
|
||||
"""
|
||||
ratio_pair = np.array(
|
||||
[[begin_width_ratio], [end_width_ratio]], dtype=np.float32)
|
||||
p0_1 = quad[0] + (quad[1] - quad[0]) * ratio_pair
|
||||
p3_2 = quad[3] + (quad[2] - quad[3]) * ratio_pair
|
||||
return np.array([p0_1[0], p0_1[1], p3_2[1], p3_2[0]])
|
||||
|
||||
|
||||
def expand_poly_along_width(poly, shrink_ratio_of_width=0.3):
|
||||
"""
|
||||
expand poly along width.
|
||||
"""
|
||||
point_num = poly.shape[0]
|
||||
left_quad = np.array(
|
||||
[poly[0], poly[1], poly[-2], poly[-1]], dtype=np.float32)
|
||||
left_ratio = -shrink_ratio_of_width * np.linalg.norm(left_quad[0] - left_quad[3]) / \
|
||||
(np.linalg.norm(left_quad[0] - left_quad[1]) + 1e-6)
|
||||
left_quad_expand = shrink_quad_along_width(left_quad, left_ratio, 1.0)
|
||||
right_quad = np.array(
|
||||
[
|
||||
poly[point_num // 2 - 2], poly[point_num // 2 - 1],
|
||||
poly[point_num // 2], poly[point_num // 2 + 1]
|
||||
],
|
||||
dtype=np.float32)
|
||||
right_ratio = 1.0 + \
|
||||
shrink_ratio_of_width * np.linalg.norm(right_quad[0] - right_quad[3]) / \
|
||||
(np.linalg.norm(right_quad[0] - right_quad[1]) + 1e-6)
|
||||
right_quad_expand = shrink_quad_along_width(right_quad, 0.0, right_ratio)
|
||||
poly[0] = left_quad_expand[0]
|
||||
poly[-1] = left_quad_expand[-1]
|
||||
poly[point_num // 2 - 1] = right_quad_expand[1]
|
||||
poly[point_num // 2] = right_quad_expand[2]
|
||||
return poly
|
||||
|
||||
|
||||
def softmax(logits):
|
||||
"""
|
||||
logits: N x d
|
||||
"""
|
||||
max_value = np.max(logits, axis=1, keepdims=True)
|
||||
exp = np.exp(logits - max_value)
|
||||
exp_sum = np.sum(exp, axis=1, keepdims=True)
|
||||
dist = exp / exp_sum
|
||||
return dist
|
||||
|
||||
|
||||
def get_keep_pos_idxs(labels, remove_blank=None):
|
||||
"""
|
||||
Remove duplicate and get pos idxs of keep items.
|
||||
The value of keep_blank should be [None, 95].
|
||||
"""
|
||||
duplicate_len_list = []
|
||||
keep_pos_idx_list = []
|
||||
keep_char_idx_list = []
|
||||
for k, v_ in groupby(labels):
|
||||
current_len = len(list(v_))
|
||||
if k != remove_blank:
|
||||
current_idx = int(sum(duplicate_len_list) + current_len // 2)
|
||||
keep_pos_idx_list.append(current_idx)
|
||||
keep_char_idx_list.append(k)
|
||||
duplicate_len_list.append(current_len)
|
||||
return keep_char_idx_list, keep_pos_idx_list
|
||||
|
||||
|
||||
def remove_blank(labels, blank=0):
|
||||
new_labels = [x for x in labels if x != blank]
|
||||
return new_labels
|
||||
|
||||
|
||||
def insert_blank(labels, blank=0):
|
||||
new_labels = [blank]
|
||||
for l in labels:
|
||||
new_labels += [l, blank]
|
||||
return new_labels
|
||||
|
||||
|
||||
def ctc_greedy_decoder(probs_seq, blank=95, keep_blank_in_idxs=True):
|
||||
"""
|
||||
CTC greedy (best path) decoder.
|
||||
"""
|
||||
raw_str = np.argmax(np.array(probs_seq), axis=1)
|
||||
remove_blank_in_pos = None if keep_blank_in_idxs else blank
|
||||
dedup_str, keep_idx_list = get_keep_pos_idxs(
|
||||
raw_str, remove_blank=remove_blank_in_pos)
|
||||
dst_str = remove_blank(dedup_str, blank=blank)
|
||||
return dst_str, keep_idx_list
|
||||
|
||||
|
||||
def instance_ctc_greedy_decoder(gather_info,
|
||||
logits_map,
|
||||
keep_blank_in_idxs=True):
|
||||
"""
|
||||
gather_info: [[x, y], [x, y] ...]
|
||||
logits_map: H x W X (n_chars + 1)
|
||||
"""
|
||||
_, _, C = logits_map.shape
|
||||
ys, xs = zip(*gather_info)
|
||||
logits_seq = logits_map[list(ys), list(xs)] # n x 96
|
||||
probs_seq = softmax(logits_seq)
|
||||
dst_str, keep_idx_list = ctc_greedy_decoder(
|
||||
probs_seq, blank=C - 1, keep_blank_in_idxs=keep_blank_in_idxs)
|
||||
keep_gather_list = [gather_info[idx] for idx in keep_idx_list]
|
||||
return dst_str, keep_gather_list
|
||||
|
||||
|
||||
def ctc_decoder_for_image(gather_info_list, logits_map,
|
||||
keep_blank_in_idxs=True):
|
||||
"""
|
||||
CTC decoder using multiple processes.
|
||||
"""
|
||||
decoder_results = []
|
||||
for gather_info in gather_info_list:
|
||||
res = instance_ctc_greedy_decoder(
|
||||
gather_info, logits_map, keep_blank_in_idxs=keep_blank_in_idxs)
|
||||
decoder_results.append(res)
|
||||
return decoder_results
|
||||
|
||||
|
||||
def sort_with_direction(pos_list, f_direction):
|
||||
"""
|
||||
f_direction: h x w x 2
|
||||
pos_list: [[y, x], [y, x], [y, x] ...]
|
||||
"""
|
||||
|
||||
def sort_part_with_direction(pos_list, point_direction):
|
||||
pos_list = np.array(pos_list).reshape(-1, 2)
|
||||
point_direction = np.array(point_direction).reshape(-1, 2)
|
||||
average_direction = np.mean(point_direction, axis=0, keepdims=True)
|
||||
pos_proj_leng = np.sum(pos_list * average_direction, axis=1)
|
||||
sorted_list = pos_list[np.argsort(pos_proj_leng)].tolist()
|
||||
sorted_direction = point_direction[np.argsort(pos_proj_leng)].tolist()
|
||||
return sorted_list, sorted_direction
|
||||
|
||||
pos_list = np.array(pos_list).reshape(-1, 2)
|
||||
point_direction = f_direction[pos_list[:, 0], pos_list[:, 1]] # x, y
|
||||
point_direction = point_direction[:, ::-1] # x, y -> y, x
|
||||
sorted_point, sorted_direction = sort_part_with_direction(pos_list,
|
||||
point_direction)
|
||||
|
||||
point_num = len(sorted_point)
|
||||
if point_num >= 16:
|
||||
middle_num = point_num // 2
|
||||
first_part_point = sorted_point[:middle_num]
|
||||
first_point_direction = sorted_direction[:middle_num]
|
||||
sorted_fist_part_point, sorted_fist_part_direction = sort_part_with_direction(
|
||||
first_part_point, first_point_direction)
|
||||
|
||||
last_part_point = sorted_point[middle_num:]
|
||||
last_point_direction = sorted_direction[middle_num:]
|
||||
sorted_last_part_point, sorted_last_part_direction = sort_part_with_direction(
|
||||
last_part_point, last_point_direction)
|
||||
sorted_point = sorted_fist_part_point + sorted_last_part_point
|
||||
sorted_direction = sorted_fist_part_direction + sorted_last_part_direction
|
||||
|
||||
return sorted_point, np.array(sorted_direction)
|
||||
|
||||
|
||||
def add_id(pos_list, image_id=0):
|
||||
"""
|
||||
Add id for gather feature, for inference.
|
||||
"""
|
||||
new_list = []
|
||||
for item in pos_list:
|
||||
new_list.append((image_id, item[0], item[1]))
|
||||
return new_list
|
||||
|
||||
|
||||
def sort_and_expand_with_direction(pos_list, f_direction):
|
||||
"""
|
||||
f_direction: h x w x 2
|
||||
pos_list: [[y, x], [y, x], [y, x] ...]
|
||||
"""
|
||||
h, w, _ = f_direction.shape
|
||||
sorted_list, point_direction = sort_with_direction(pos_list, f_direction)
|
||||
|
||||
# expand along
|
||||
point_num = len(sorted_list)
|
||||
sub_direction_len = max(point_num // 3, 2)
|
||||
left_direction = point_direction[:sub_direction_len, :]
|
||||
right_dirction = point_direction[point_num - sub_direction_len:, :]
|
||||
|
||||
left_average_direction = -np.mean(left_direction, axis=0, keepdims=True)
|
||||
left_average_len = np.linalg.norm(left_average_direction)
|
||||
left_start = np.array(sorted_list[0])
|
||||
left_step = left_average_direction / (left_average_len + 1e-6)
|
||||
|
||||
right_average_direction = np.mean(right_dirction, axis=0, keepdims=True)
|
||||
right_average_len = np.linalg.norm(right_average_direction)
|
||||
right_step = right_average_direction / (right_average_len + 1e-6)
|
||||
right_start = np.array(sorted_list[-1])
|
||||
|
||||
append_num = max(
|
||||
int((left_average_len + right_average_len) / 2.0 * 0.15), 1)
|
||||
left_list = []
|
||||
right_list = []
|
||||
for i in range(append_num):
|
||||
ly, lx = np.round(left_start + left_step * (i + 1)).flatten().astype(
|
||||
'int32').tolist()
|
||||
if ly < h and lx < w and (ly, lx) not in left_list:
|
||||
left_list.append((ly, lx))
|
||||
ry, rx = np.round(right_start + right_step * (i + 1)).flatten().astype(
|
||||
'int32').tolist()
|
||||
if ry < h and rx < w and (ry, rx) not in right_list:
|
||||
right_list.append((ry, rx))
|
||||
|
||||
all_list = left_list[::-1] + sorted_list + right_list
|
||||
return all_list
|
||||
|
||||
|
||||
def sort_and_expand_with_direction_v2(pos_list, f_direction, binary_tcl_map):
|
||||
"""
|
||||
f_direction: h x w x 2
|
||||
pos_list: [[y, x], [y, x], [y, x] ...]
|
||||
binary_tcl_map: h x w
|
||||
"""
|
||||
h, w, _ = f_direction.shape
|
||||
sorted_list, point_direction = sort_with_direction(pos_list, f_direction)
|
||||
|
||||
# expand along
|
||||
point_num = len(sorted_list)
|
||||
sub_direction_len = max(point_num // 3, 2)
|
||||
left_direction = point_direction[:sub_direction_len, :]
|
||||
right_dirction = point_direction[point_num - sub_direction_len:, :]
|
||||
|
||||
left_average_direction = -np.mean(left_direction, axis=0, keepdims=True)
|
||||
left_average_len = np.linalg.norm(left_average_direction)
|
||||
left_start = np.array(sorted_list[0])
|
||||
left_step = left_average_direction / (left_average_len + 1e-6)
|
||||
|
||||
right_average_direction = np.mean(right_dirction, axis=0, keepdims=True)
|
||||
right_average_len = np.linalg.norm(right_average_direction)
|
||||
right_step = right_average_direction / (right_average_len + 1e-6)
|
||||
right_start = np.array(sorted_list[-1])
|
||||
|
||||
append_num = max(
|
||||
int((left_average_len + right_average_len) / 2.0 * 0.15), 1)
|
||||
max_append_num = 2 * append_num
|
||||
|
||||
left_list = []
|
||||
right_list = []
|
||||
for i in range(max_append_num):
|
||||
ly, lx = np.round(left_start + left_step * (i + 1)).flatten().astype(
|
||||
'int32').tolist()
|
||||
if ly < h and lx < w and (ly, lx) not in left_list:
|
||||
if binary_tcl_map[ly, lx] > 0.5:
|
||||
left_list.append((ly, lx))
|
||||
else:
|
||||
break
|
||||
|
||||
for i in range(max_append_num):
|
||||
ry, rx = np.round(right_start + right_step * (i + 1)).flatten().astype(
|
||||
'int32').tolist()
|
||||
if ry < h and rx < w and (ry, rx) not in right_list:
|
||||
if binary_tcl_map[ry, rx] > 0.5:
|
||||
right_list.append((ry, rx))
|
||||
else:
|
||||
break
|
||||
|
||||
all_list = left_list[::-1] + sorted_list + right_list
|
||||
return all_list
|
||||
|
||||
|
||||
def generate_pivot_list_curved(p_score,
|
||||
p_char_maps,
|
||||
f_direction,
|
||||
score_thresh=0.5,
|
||||
is_expand=True,
|
||||
is_backbone=False,
|
||||
image_id=0):
|
||||
"""
|
||||
return center point and end point of TCL instance; filter with the char maps;
|
||||
"""
|
||||
p_score = p_score[0]
|
||||
f_direction = f_direction.transpose(1, 2, 0)
|
||||
p_tcl_map = (p_score > score_thresh) * 1.0
|
||||
skeleton_map = thin(p_tcl_map)
|
||||
instance_count, instance_label_map = cv2.connectedComponents(
|
||||
skeleton_map.astype(np.uint8), connectivity=8)
|
||||
|
||||
# get TCL Instance
|
||||
all_pos_yxs = []
|
||||
center_pos_yxs = []
|
||||
end_points_yxs = []
|
||||
instance_center_pos_yxs = []
|
||||
pred_strs = []
|
||||
if instance_count > 0:
|
||||
for instance_id in range(1, instance_count):
|
||||
pos_list = []
|
||||
ys, xs = np.where(instance_label_map == instance_id)
|
||||
pos_list = list(zip(ys, xs))
|
||||
|
||||
### FIX-ME, eliminate outlier
|
||||
if len(pos_list) < 3:
|
||||
continue
|
||||
|
||||
if is_expand:
|
||||
pos_list_sorted = sort_and_expand_with_direction_v2(
|
||||
pos_list, f_direction, p_tcl_map)
|
||||
else:
|
||||
pos_list_sorted, _ = sort_with_direction(pos_list, f_direction)
|
||||
all_pos_yxs.append(pos_list_sorted)
|
||||
|
||||
# use decoder to filter backgroud points.
|
||||
p_char_maps = p_char_maps.transpose([1, 2, 0])
|
||||
decode_res = ctc_decoder_for_image(
|
||||
all_pos_yxs, logits_map=p_char_maps, keep_blank_in_idxs=True)
|
||||
for decoded_str, keep_yxs_list in decode_res:
|
||||
if is_backbone:
|
||||
keep_yxs_list_with_id = add_id(keep_yxs_list, image_id=image_id)
|
||||
instance_center_pos_yxs.append(keep_yxs_list_with_id)
|
||||
pred_strs.append(decoded_str)
|
||||
else:
|
||||
end_points_yxs.extend((keep_yxs_list[0], keep_yxs_list[-1]))
|
||||
center_pos_yxs.extend(keep_yxs_list)
|
||||
|
||||
if is_backbone:
|
||||
return pred_strs, instance_center_pos_yxs
|
||||
else:
|
||||
return center_pos_yxs, end_points_yxs
|
||||
|
||||
|
||||
def generate_pivot_list_horizontal(p_score,
|
||||
p_char_maps,
|
||||
f_direction,
|
||||
score_thresh=0.5,
|
||||
is_backbone=False,
|
||||
image_id=0):
|
||||
"""
|
||||
return center point and end point of TCL instance; filter with the char maps;
|
||||
"""
|
||||
p_score = p_score[0]
|
||||
f_direction = f_direction.transpose(1, 2, 0)
|
||||
p_tcl_map_bi = (p_score > score_thresh) * 1.0
|
||||
instance_count, instance_label_map = cv2.connectedComponents(
|
||||
p_tcl_map_bi.astype(np.uint8), connectivity=8)
|
||||
|
||||
# get TCL Instance
|
||||
all_pos_yxs = []
|
||||
center_pos_yxs = []
|
||||
end_points_yxs = []
|
||||
instance_center_pos_yxs = []
|
||||
|
||||
if instance_count > 0:
|
||||
for instance_id in range(1, instance_count):
|
||||
pos_list = []
|
||||
ys, xs = np.where(instance_label_map == instance_id)
|
||||
pos_list = list(zip(ys, xs))
|
||||
|
||||
### FIX-ME, eliminate outlier
|
||||
if len(pos_list) < 5:
|
||||
continue
|
||||
|
||||
# add rule here
|
||||
main_direction = extract_main_direction(pos_list,
|
||||
f_direction) # y x
|
||||
reference_directin = np.array([0, 1]).reshape([-1, 2]) # y x
|
||||
is_h_angle = abs(np.sum(
|
||||
main_direction * reference_directin)) < math.cos(math.pi / 180 *
|
||||
70)
|
||||
|
||||
point_yxs = np.array(pos_list)
|
||||
max_y, max_x = np.max(point_yxs, axis=0)
|
||||
min_y, min_x = np.min(point_yxs, axis=0)
|
||||
is_h_len = (max_y - min_y) < 1.5 * (max_x - min_x)
|
||||
|
||||
pos_list_final = []
|
||||
if is_h_len:
|
||||
xs = np.unique(xs)
|
||||
for x in xs:
|
||||
ys = instance_label_map[:, x].copy().reshape((-1, ))
|
||||
y = int(np.where(ys == instance_id)[0].mean())
|
||||
pos_list_final.append((y, x))
|
||||
else:
|
||||
ys = np.unique(ys)
|
||||
for y in ys:
|
||||
xs = instance_label_map[y, :].copy().reshape((-1, ))
|
||||
x = int(np.where(xs == instance_id)[0].mean())
|
||||
pos_list_final.append((y, x))
|
||||
|
||||
pos_list_sorted, _ = sort_with_direction(pos_list_final,
|
||||
f_direction)
|
||||
all_pos_yxs.append(pos_list_sorted)
|
||||
|
||||
# use decoder to filter backgroud points.
|
||||
p_char_maps = p_char_maps.transpose([1, 2, 0])
|
||||
decode_res = ctc_decoder_for_image(
|
||||
all_pos_yxs, logits_map=p_char_maps, keep_blank_in_idxs=True)
|
||||
for decoded_str, keep_yxs_list in decode_res:
|
||||
if is_backbone:
|
||||
keep_yxs_list_with_id = add_id(keep_yxs_list, image_id=image_id)
|
||||
instance_center_pos_yxs.append(keep_yxs_list_with_id)
|
||||
else:
|
||||
end_points_yxs.extend((keep_yxs_list[0], keep_yxs_list[-1]))
|
||||
center_pos_yxs.extend(keep_yxs_list)
|
||||
|
||||
if is_backbone:
|
||||
return instance_center_pos_yxs
|
||||
else:
|
||||
return center_pos_yxs, end_points_yxs
|
||||
|
||||
|
||||
def generate_pivot_list_slow(p_score,
|
||||
p_char_maps,
|
||||
f_direction,
|
||||
score_thresh=0.5,
|
||||
is_backbone=False,
|
||||
is_curved=True,
|
||||
image_id=0):
|
||||
"""
|
||||
Warp all the function together.
|
||||
"""
|
||||
if is_curved:
|
||||
return generate_pivot_list_curved(
|
||||
p_score,
|
||||
p_char_maps,
|
||||
f_direction,
|
||||
score_thresh=score_thresh,
|
||||
is_expand=True,
|
||||
is_backbone=is_backbone,
|
||||
image_id=image_id)
|
||||
else:
|
||||
return generate_pivot_list_horizontal(
|
||||
p_score,
|
||||
p_char_maps,
|
||||
f_direction,
|
||||
score_thresh=score_thresh,
|
||||
is_backbone=is_backbone,
|
||||
image_id=image_id)
|
||||
|
||||
|
||||
# for refine module
|
||||
def extract_main_direction(pos_list, f_direction):
|
||||
"""
|
||||
f_direction: h x w x 2
|
||||
pos_list: [[y, x], [y, x], [y, x] ...]
|
||||
"""
|
||||
pos_list = np.array(pos_list)
|
||||
point_direction = f_direction[pos_list[:, 0], pos_list[:, 1]]
|
||||
point_direction = point_direction[:, ::-1] # x, y -> y, x
|
||||
average_direction = np.mean(point_direction, axis=0, keepdims=True)
|
||||
average_direction = average_direction / (
|
||||
np.linalg.norm(average_direction) + 1e-6)
|
||||
return average_direction
|
||||
|
||||
|
||||
def sort_by_direction_with_image_id_deprecated(pos_list, f_direction):
|
||||
"""
|
||||
f_direction: h x w x 2
|
||||
pos_list: [[id, y, x], [id, y, x], [id, y, x] ...]
|
||||
"""
|
||||
pos_list_full = np.array(pos_list).reshape(-1, 3)
|
||||
pos_list = pos_list_full[:, 1:]
|
||||
point_direction = f_direction[pos_list[:, 0], pos_list[:, 1]] # x, y
|
||||
point_direction = point_direction[:, ::-1] # x, y -> y, x
|
||||
average_direction = np.mean(point_direction, axis=0, keepdims=True)
|
||||
pos_proj_leng = np.sum(pos_list * average_direction, axis=1)
|
||||
sorted_list = pos_list_full[np.argsort(pos_proj_leng)].tolist()
|
||||
return sorted_list
|
||||
|
||||
|
||||
def sort_by_direction_with_image_id(pos_list, f_direction):
|
||||
"""
|
||||
f_direction: h x w x 2
|
||||
pos_list: [[y, x], [y, x], [y, x] ...]
|
||||
"""
|
||||
|
||||
def sort_part_with_direction(pos_list_full, point_direction):
|
||||
pos_list_full = np.array(pos_list_full).reshape(-1, 3)
|
||||
pos_list = pos_list_full[:, 1:]
|
||||
point_direction = np.array(point_direction).reshape(-1, 2)
|
||||
average_direction = np.mean(point_direction, axis=0, keepdims=True)
|
||||
pos_proj_leng = np.sum(pos_list * average_direction, axis=1)
|
||||
sorted_list = pos_list_full[np.argsort(pos_proj_leng)].tolist()
|
||||
sorted_direction = point_direction[np.argsort(pos_proj_leng)].tolist()
|
||||
return sorted_list, sorted_direction
|
||||
|
||||
pos_list = np.array(pos_list).reshape(-1, 3)
|
||||
point_direction = f_direction[pos_list[:, 1], pos_list[:, 2]] # x, y
|
||||
point_direction = point_direction[:, ::-1] # x, y -> y, x
|
||||
sorted_point, sorted_direction = sort_part_with_direction(pos_list,
|
||||
point_direction)
|
||||
|
||||
point_num = len(sorted_point)
|
||||
if point_num >= 16:
|
||||
middle_num = point_num // 2
|
||||
first_part_point = sorted_point[:middle_num]
|
||||
first_point_direction = sorted_direction[:middle_num]
|
||||
sorted_fist_part_point, sorted_fist_part_direction = sort_part_with_direction(
|
||||
first_part_point, first_point_direction)
|
||||
|
||||
last_part_point = sorted_point[middle_num:]
|
||||
last_point_direction = sorted_direction[middle_num:]
|
||||
sorted_last_part_point, sorted_last_part_direction = sort_part_with_direction(
|
||||
last_part_point, last_point_direction)
|
||||
sorted_point = sorted_fist_part_point + sorted_last_part_point
|
||||
sorted_direction = sorted_fist_part_direction + sorted_last_part_direction
|
||||
|
||||
return sorted_point
|
||||
|
||||
|
||||
def generate_pivot_list_tt_inference(p_score,
|
||||
p_char_maps,
|
||||
f_direction,
|
||||
score_thresh=0.5,
|
||||
is_backbone=False,
|
||||
is_curved=True,
|
||||
image_id=0):
|
||||
"""
|
||||
return center point and end point of TCL instance; filter with the char maps;
|
||||
"""
|
||||
p_score = p_score[0]
|
||||
f_direction = f_direction.transpose(1, 2, 0)
|
||||
p_tcl_map = (p_score > score_thresh) * 1.0
|
||||
skeleton_map = thin(p_tcl_map)
|
||||
instance_count, instance_label_map = cv2.connectedComponents(
|
||||
skeleton_map.astype(np.uint8), connectivity=8)
|
||||
|
||||
# get TCL Instance
|
||||
all_pos_yxs = []
|
||||
if instance_count > 0:
|
||||
for instance_id in range(1, instance_count):
|
||||
pos_list = []
|
||||
ys, xs = np.where(instance_label_map == instance_id)
|
||||
pos_list = list(zip(ys, xs))
|
||||
### FIX-ME, eliminate outlier
|
||||
if len(pos_list) < 3:
|
||||
continue
|
||||
pos_list_sorted = sort_and_expand_with_direction_v2(
|
||||
pos_list, f_direction, p_tcl_map)
|
||||
pos_list_sorted_with_id = add_id(pos_list_sorted, image_id=image_id)
|
||||
all_pos_yxs.append(pos_list_sorted_with_id)
|
||||
return all_pos_yxs
|
||||
162
backend/ppocr/utils/e2e_utils/pgnet_pp_utils.py
Normal file
162
backend/ppocr/utils/e2e_utils/pgnet_pp_utils.py
Normal file
@@ -0,0 +1,162 @@
|
||||
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
import paddle
|
||||
import os
|
||||
import sys
|
||||
|
||||
__dir__ = os.path.dirname(__file__)
|
||||
sys.path.append(__dir__)
|
||||
sys.path.append(os.path.join(__dir__, '..'))
|
||||
from extract_textpoint_slow import *
|
||||
from extract_textpoint_fast import generate_pivot_list_fast, restore_poly
|
||||
|
||||
|
||||
class PGNet_PostProcess(object):
|
||||
# two different post-process
|
||||
def __init__(self, character_dict_path, valid_set, score_thresh, outs_dict,
|
||||
shape_list):
|
||||
self.Lexicon_Table = get_dict(character_dict_path)
|
||||
self.valid_set = valid_set
|
||||
self.score_thresh = score_thresh
|
||||
self.outs_dict = outs_dict
|
||||
self.shape_list = shape_list
|
||||
|
||||
def pg_postprocess_fast(self):
|
||||
p_score = self.outs_dict['f_score']
|
||||
p_border = self.outs_dict['f_border']
|
||||
p_char = self.outs_dict['f_char']
|
||||
p_direction = self.outs_dict['f_direction']
|
||||
if isinstance(p_score, paddle.Tensor):
|
||||
p_score = p_score[0].numpy()
|
||||
p_border = p_border[0].numpy()
|
||||
p_direction = p_direction[0].numpy()
|
||||
p_char = p_char[0].numpy()
|
||||
else:
|
||||
p_score = p_score[0]
|
||||
p_border = p_border[0]
|
||||
p_direction = p_direction[0]
|
||||
p_char = p_char[0]
|
||||
|
||||
src_h, src_w, ratio_h, ratio_w = self.shape_list[0]
|
||||
instance_yxs_list, seq_strs = generate_pivot_list_fast(
|
||||
p_score,
|
||||
p_char,
|
||||
p_direction,
|
||||
self.Lexicon_Table,
|
||||
score_thresh=self.score_thresh)
|
||||
poly_list, keep_str_list = restore_poly(instance_yxs_list, seq_strs,
|
||||
p_border, ratio_w, ratio_h,
|
||||
src_w, src_h, self.valid_set)
|
||||
data = {
|
||||
'points': poly_list,
|
||||
'texts': keep_str_list,
|
||||
}
|
||||
return data
|
||||
|
||||
def pg_postprocess_slow(self):
|
||||
p_score = self.outs_dict['f_score']
|
||||
p_border = self.outs_dict['f_border']
|
||||
p_char = self.outs_dict['f_char']
|
||||
p_direction = self.outs_dict['f_direction']
|
||||
if isinstance(p_score, paddle.Tensor):
|
||||
p_score = p_score[0].numpy()
|
||||
p_border = p_border[0].numpy()
|
||||
p_direction = p_direction[0].numpy()
|
||||
p_char = p_char[0].numpy()
|
||||
else:
|
||||
p_score = p_score[0]
|
||||
p_border = p_border[0]
|
||||
p_direction = p_direction[0]
|
||||
p_char = p_char[0]
|
||||
src_h, src_w, ratio_h, ratio_w = self.shape_list[0]
|
||||
is_curved = self.valid_set == "totaltext"
|
||||
char_seq_idx_set, instance_yxs_list = generate_pivot_list_slow(
|
||||
p_score,
|
||||
p_char,
|
||||
p_direction,
|
||||
score_thresh=self.score_thresh,
|
||||
is_backbone=True,
|
||||
is_curved=is_curved)
|
||||
seq_strs = []
|
||||
for char_idx_set in char_seq_idx_set:
|
||||
pr_str = ''.join([self.Lexicon_Table[pos] for pos in char_idx_set])
|
||||
seq_strs.append(pr_str)
|
||||
poly_list = []
|
||||
keep_str_list = []
|
||||
all_point_list = []
|
||||
all_point_pair_list = []
|
||||
for yx_center_line, keep_str in zip(instance_yxs_list, seq_strs):
|
||||
if len(yx_center_line) == 1:
|
||||
yx_center_line.append(yx_center_line[-1])
|
||||
|
||||
offset_expand = 1.0
|
||||
if self.valid_set == 'totaltext':
|
||||
offset_expand = 1.2
|
||||
|
||||
point_pair_list = []
|
||||
for batch_id, y, x in yx_center_line:
|
||||
offset = p_border[:, y, x].reshape(2, 2)
|
||||
if offset_expand != 1.0:
|
||||
offset_length = np.linalg.norm(
|
||||
offset, axis=1, keepdims=True)
|
||||
expand_length = np.clip(
|
||||
offset_length * (offset_expand - 1),
|
||||
a_min=0.5,
|
||||
a_max=3.0)
|
||||
offset_detal = offset / offset_length * expand_length
|
||||
offset = offset + offset_detal
|
||||
ori_yx = np.array([y, x], dtype=np.float32)
|
||||
point_pair = (ori_yx + offset)[:, ::-1] * 4.0 / np.array(
|
||||
[ratio_w, ratio_h]).reshape(-1, 2)
|
||||
point_pair_list.append(point_pair)
|
||||
|
||||
all_point_list.append([
|
||||
int(round(x * 4.0 / ratio_w)),
|
||||
int(round(y * 4.0 / ratio_h))
|
||||
])
|
||||
all_point_pair_list.append(point_pair.round().astype(np.int32)
|
||||
.tolist())
|
||||
|
||||
detected_poly, pair_length_info = point_pair2poly(point_pair_list)
|
||||
detected_poly = expand_poly_along_width(
|
||||
detected_poly, shrink_ratio_of_width=0.2)
|
||||
detected_poly[:, 0] = np.clip(
|
||||
detected_poly[:, 0], a_min=0, a_max=src_w)
|
||||
detected_poly[:, 1] = np.clip(
|
||||
detected_poly[:, 1], a_min=0, a_max=src_h)
|
||||
|
||||
if len(keep_str) < 2:
|
||||
continue
|
||||
|
||||
keep_str_list.append(keep_str)
|
||||
detected_poly = np.round(detected_poly).astype('int32')
|
||||
if self.valid_set == 'partvgg':
|
||||
middle_point = len(detected_poly) // 2
|
||||
detected_poly = detected_poly[
|
||||
[0, middle_point - 1, middle_point, -1], :]
|
||||
poly_list.append(detected_poly)
|
||||
elif self.valid_set == 'totaltext':
|
||||
poly_list.append(detected_poly)
|
||||
else:
|
||||
print('--> Not supported format.')
|
||||
exit(-1)
|
||||
data = {
|
||||
'points': poly_list,
|
||||
'texts': keep_str_list,
|
||||
}
|
||||
return data
|
||||
162
backend/ppocr/utils/e2e_utils/visual.py
Normal file
162
backend/ppocr/utils/e2e_utils/visual.py
Normal file
@@ -0,0 +1,162 @@
|
||||
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# 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.
|
||||
import numpy as np
|
||||
import cv2
|
||||
import time
|
||||
|
||||
|
||||
def resize_image(im, max_side_len=512):
|
||||
"""
|
||||
resize image to a size multiple of max_stride which is required by the network
|
||||
:param im: the resized image
|
||||
:param max_side_len: limit of max image size to avoid out of memory in gpu
|
||||
:return: the resized image and the resize ratio
|
||||
"""
|
||||
h, w, _ = im.shape
|
||||
|
||||
resize_w = w
|
||||
resize_h = h
|
||||
|
||||
if resize_h > resize_w:
|
||||
ratio = float(max_side_len) / resize_h
|
||||
else:
|
||||
ratio = float(max_side_len) / resize_w
|
||||
|
||||
resize_h = int(resize_h * ratio)
|
||||
resize_w = int(resize_w * ratio)
|
||||
|
||||
max_stride = 128
|
||||
resize_h = (resize_h + max_stride - 1) // max_stride * max_stride
|
||||
resize_w = (resize_w + max_stride - 1) // max_stride * max_stride
|
||||
im = cv2.resize(im, (int(resize_w), int(resize_h)))
|
||||
ratio_h = resize_h / float(h)
|
||||
ratio_w = resize_w / float(w)
|
||||
|
||||
return im, (ratio_h, ratio_w)
|
||||
|
||||
|
||||
def resize_image_min(im, max_side_len=512):
|
||||
"""
|
||||
"""
|
||||
h, w, _ = im.shape
|
||||
|
||||
resize_w = w
|
||||
resize_h = h
|
||||
|
||||
if resize_h < resize_w:
|
||||
ratio = float(max_side_len) / resize_h
|
||||
else:
|
||||
ratio = float(max_side_len) / resize_w
|
||||
|
||||
resize_h = int(resize_h * ratio)
|
||||
resize_w = int(resize_w * ratio)
|
||||
|
||||
max_stride = 128
|
||||
resize_h = (resize_h + max_stride - 1) // max_stride * max_stride
|
||||
resize_w = (resize_w + max_stride - 1) // max_stride * max_stride
|
||||
im = cv2.resize(im, (int(resize_w), int(resize_h)))
|
||||
ratio_h = resize_h / float(h)
|
||||
ratio_w = resize_w / float(w)
|
||||
return im, (ratio_h, ratio_w)
|
||||
|
||||
|
||||
def resize_image_for_totaltext(im, max_side_len=512):
|
||||
"""
|
||||
"""
|
||||
h, w, _ = im.shape
|
||||
|
||||
resize_w = w
|
||||
resize_h = h
|
||||
ratio = 1.25
|
||||
if h * ratio > max_side_len:
|
||||
ratio = float(max_side_len) / resize_h
|
||||
|
||||
resize_h = int(resize_h * ratio)
|
||||
resize_w = int(resize_w * ratio)
|
||||
|
||||
max_stride = 128
|
||||
resize_h = (resize_h + max_stride - 1) // max_stride * max_stride
|
||||
resize_w = (resize_w + max_stride - 1) // max_stride * max_stride
|
||||
im = cv2.resize(im, (int(resize_w), int(resize_h)))
|
||||
ratio_h = resize_h / float(h)
|
||||
ratio_w = resize_w / float(w)
|
||||
return im, (ratio_h, ratio_w)
|
||||
|
||||
|
||||
def point_pair2poly(point_pair_list):
|
||||
"""
|
||||
Transfer vertical point_pairs into poly point in clockwise.
|
||||
"""
|
||||
pair_length_list = []
|
||||
for point_pair in point_pair_list:
|
||||
pair_length = np.linalg.norm(point_pair[0] - point_pair[1])
|
||||
pair_length_list.append(pair_length)
|
||||
pair_length_list = np.array(pair_length_list)
|
||||
pair_info = (pair_length_list.max(), pair_length_list.min(),
|
||||
pair_length_list.mean())
|
||||
|
||||
point_num = len(point_pair_list) * 2
|
||||
point_list = [0] * point_num
|
||||
for idx, point_pair in enumerate(point_pair_list):
|
||||
point_list[idx] = point_pair[0]
|
||||
point_list[point_num - 1 - idx] = point_pair[1]
|
||||
return np.array(point_list).reshape(-1, 2), pair_info
|
||||
|
||||
|
||||
def shrink_quad_along_width(quad, begin_width_ratio=0., end_width_ratio=1.):
|
||||
"""
|
||||
Generate shrink_quad_along_width.
|
||||
"""
|
||||
ratio_pair = np.array(
|
||||
[[begin_width_ratio], [end_width_ratio]], dtype=np.float32)
|
||||
p0_1 = quad[0] + (quad[1] - quad[0]) * ratio_pair
|
||||
p3_2 = quad[3] + (quad[2] - quad[3]) * ratio_pair
|
||||
return np.array([p0_1[0], p0_1[1], p3_2[1], p3_2[0]])
|
||||
|
||||
|
||||
def expand_poly_along_width(poly, shrink_ratio_of_width=0.3):
|
||||
"""
|
||||
expand poly along width.
|
||||
"""
|
||||
point_num = poly.shape[0]
|
||||
left_quad = np.array(
|
||||
[poly[0], poly[1], poly[-2], poly[-1]], dtype=np.float32)
|
||||
left_ratio = -shrink_ratio_of_width * np.linalg.norm(left_quad[0] - left_quad[3]) / \
|
||||
(np.linalg.norm(left_quad[0] - left_quad[1]) + 1e-6)
|
||||
left_quad_expand = shrink_quad_along_width(left_quad, left_ratio, 1.0)
|
||||
right_quad = np.array(
|
||||
[
|
||||
poly[point_num // 2 - 2], poly[point_num // 2 - 1],
|
||||
poly[point_num // 2], poly[point_num // 2 + 1]
|
||||
],
|
||||
dtype=np.float32)
|
||||
right_ratio = 1.0 + \
|
||||
shrink_ratio_of_width * np.linalg.norm(right_quad[0] - right_quad[3]) / \
|
||||
(np.linalg.norm(right_quad[0] - right_quad[1]) + 1e-6)
|
||||
right_quad_expand = shrink_quad_along_width(right_quad, 0.0, right_ratio)
|
||||
poly[0] = left_quad_expand[0]
|
||||
poly[-1] = left_quad_expand[-1]
|
||||
poly[point_num // 2 - 1] = right_quad_expand[1]
|
||||
poly[point_num // 2] = right_quad_expand[2]
|
||||
return poly
|
||||
|
||||
|
||||
def norm2(x, axis=None):
|
||||
if axis:
|
||||
return np.sqrt(np.sum(x**2, axis=axis))
|
||||
return np.sqrt(np.sum(x**2))
|
||||
|
||||
|
||||
def cos(p1, p2):
|
||||
return (p1 * p2).sum() / (norm2(p1) * norm2(p2))
|
||||
54
backend/ppocr/utils/iou.py
Normal file
54
backend/ppocr/utils/iou.py
Normal file
@@ -0,0 +1,54 @@
|
||||
# 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/loss/iou.py
|
||||
"""
|
||||
|
||||
import paddle
|
||||
|
||||
EPS = 1e-6
|
||||
|
||||
|
||||
def iou_single(a, b, mask, n_class):
|
||||
valid = mask == 1
|
||||
a = a.masked_select(valid)
|
||||
b = b.masked_select(valid)
|
||||
miou = []
|
||||
for i in range(n_class):
|
||||
if a.shape == [0] and a.shape == b.shape:
|
||||
inter = paddle.to_tensor(0.0)
|
||||
union = paddle.to_tensor(0.0)
|
||||
else:
|
||||
inter = ((a == i).logical_and(b == i)).astype('float32')
|
||||
union = ((a == i).logical_or(b == i)).astype('float32')
|
||||
miou.append(paddle.sum(inter) / (paddle.sum(union) + EPS))
|
||||
miou = sum(miou) / len(miou)
|
||||
return miou
|
||||
|
||||
|
||||
def iou(a, b, mask, n_class=2, reduce=True):
|
||||
batch_size = a.shape[0]
|
||||
|
||||
a = a.reshape([batch_size, -1])
|
||||
b = b.reshape([batch_size, -1])
|
||||
mask = mask.reshape([batch_size, -1])
|
||||
|
||||
iou = paddle.zeros((batch_size, ), dtype='float32')
|
||||
for i in range(batch_size):
|
||||
iou[i] = iou_single(a[i], b[i], mask[i], n_class)
|
||||
|
||||
if reduce:
|
||||
iou = paddle.mean(iou)
|
||||
return iou
|
||||
3
backend/ppocr/utils/loggers/__init__.py
Normal file
3
backend/ppocr/utils/loggers/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from .vdl_logger import VDLLogger
|
||||
from .wandb_logger import WandbLogger
|
||||
from .loggers import Loggers
|
||||
15
backend/ppocr/utils/loggers/base_logger.py
Normal file
15
backend/ppocr/utils/loggers/base_logger.py
Normal file
@@ -0,0 +1,15 @@
|
||||
import os
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
class BaseLogger(ABC):
|
||||
def __init__(self, save_dir):
|
||||
self.save_dir = save_dir
|
||||
os.makedirs(self.save_dir, exist_ok=True)
|
||||
|
||||
@abstractmethod
|
||||
def log_metrics(self, metrics, prefix=None):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def close(self):
|
||||
pass
|
||||
18
backend/ppocr/utils/loggers/loggers.py
Normal file
18
backend/ppocr/utils/loggers/loggers.py
Normal file
@@ -0,0 +1,18 @@
|
||||
from .wandb_logger import WandbLogger
|
||||
|
||||
class Loggers(object):
|
||||
def __init__(self, loggers):
|
||||
super().__init__()
|
||||
self.loggers = loggers
|
||||
|
||||
def log_metrics(self, metrics, prefix=None, step=None):
|
||||
for logger in self.loggers:
|
||||
logger.log_metrics(metrics, prefix=prefix, step=step)
|
||||
|
||||
def log_model(self, is_best, prefix, metadata=None):
|
||||
for logger in self.loggers:
|
||||
logger.log_model(is_best=is_best, prefix=prefix, metadata=metadata)
|
||||
|
||||
def close(self):
|
||||
for logger in self.loggers:
|
||||
logger.close()
|
||||
21
backend/ppocr/utils/loggers/vdl_logger.py
Normal file
21
backend/ppocr/utils/loggers/vdl_logger.py
Normal file
@@ -0,0 +1,21 @@
|
||||
from .base_logger import BaseLogger
|
||||
from visualdl import LogWriter
|
||||
|
||||
class VDLLogger(BaseLogger):
|
||||
def __init__(self, save_dir):
|
||||
super().__init__(save_dir)
|
||||
self.vdl_writer = LogWriter(logdir=save_dir)
|
||||
|
||||
def log_metrics(self, metrics, prefix=None, step=None):
|
||||
if not prefix:
|
||||
prefix = ""
|
||||
updated_metrics = {prefix + "/" + k: v for k, v in metrics.items()}
|
||||
|
||||
for k, v in updated_metrics.items():
|
||||
self.vdl_writer.add_scalar(k, v, step)
|
||||
|
||||
def log_model(self, is_best, prefix, metadata=None):
|
||||
pass
|
||||
|
||||
def close(self):
|
||||
self.vdl_writer.close()
|
||||
78
backend/ppocr/utils/loggers/wandb_logger.py
Normal file
78
backend/ppocr/utils/loggers/wandb_logger.py
Normal file
@@ -0,0 +1,78 @@
|
||||
import os
|
||||
from .base_logger import BaseLogger
|
||||
|
||||
class WandbLogger(BaseLogger):
|
||||
def __init__(self,
|
||||
project=None,
|
||||
name=None,
|
||||
id=None,
|
||||
entity=None,
|
||||
save_dir=None,
|
||||
config=None,
|
||||
**kwargs):
|
||||
try:
|
||||
import wandb
|
||||
self.wandb = wandb
|
||||
except ModuleNotFoundError:
|
||||
raise ModuleNotFoundError(
|
||||
"Please install wandb using `pip install wandb`"
|
||||
)
|
||||
|
||||
self.project = project
|
||||
self.name = name
|
||||
self.id = id
|
||||
self.save_dir = save_dir
|
||||
self.config = config
|
||||
self.kwargs = kwargs
|
||||
self.entity = entity
|
||||
self._run = None
|
||||
self._wandb_init = dict(
|
||||
project=self.project,
|
||||
name=self.name,
|
||||
id=self.id,
|
||||
entity=self.entity,
|
||||
dir=self.save_dir,
|
||||
resume="allow"
|
||||
)
|
||||
self._wandb_init.update(**kwargs)
|
||||
|
||||
_ = self.run
|
||||
|
||||
if self.config:
|
||||
self.run.settings_config.update(self.config)
|
||||
|
||||
@property
|
||||
def run(self):
|
||||
if self._run is None:
|
||||
if self.wandb.run is not None:
|
||||
logger.info(
|
||||
"There is a wandb run already in progress "
|
||||
"and newly created instances of `WandbLogger` will reuse"
|
||||
" this run. If this is not desired, call `wandb.finish()`"
|
||||
"before instantiating `WandbLogger`."
|
||||
)
|
||||
self._run = self.wandb.run
|
||||
else:
|
||||
self._run = self.wandb.init(**self._wandb_init)
|
||||
return self._run
|
||||
|
||||
def log_metrics(self, metrics, prefix=None, step=None):
|
||||
if not prefix:
|
||||
prefix = ""
|
||||
updated_metrics = {prefix.lower() + "/" + k: v for k, v in metrics.items()}
|
||||
|
||||
self.run.log(updated_metrics, step=step)
|
||||
|
||||
def log_model(self, is_best, prefix, metadata=None):
|
||||
model_path = os.path.join(self.save_dir, prefix + '.pdparams')
|
||||
artifact = self.wandb.Artifact('model-{}'.format(self.run.id), type='model', metadata=metadata)
|
||||
artifact.add_file(model_path, name="model_ckpt.pdparams")
|
||||
|
||||
aliases = [prefix]
|
||||
if is_best:
|
||||
aliases.append("best")
|
||||
|
||||
self.run.log_artifact(artifact, aliases=aliases)
|
||||
|
||||
def close(self):
|
||||
self.run.finish()
|
||||
71
backend/ppocr/utils/logging.py
Normal file
71
backend/ppocr/utils/logging.py
Normal file
@@ -0,0 +1,71 @@
|
||||
# copyright (c) 2020 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/WenmuZhou/PytorchOCR/blob/master/torchocr/utils/logging.py
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import logging
|
||||
import functools
|
||||
import paddle.distributed as dist
|
||||
|
||||
logger_initialized = {}
|
||||
|
||||
|
||||
@functools.lru_cache()
|
||||
def get_logger(name='ppocr', log_file=None, log_level=logging.DEBUG):
|
||||
"""Initialize and get a logger by name.
|
||||
If the logger has not been initialized, this method will initialize the
|
||||
logger by adding one or two handlers, otherwise the initialized logger will
|
||||
be directly returned. During initialization, a StreamHandler will always be
|
||||
added. If `log_file` is specified a FileHandler will also be added.
|
||||
Args:
|
||||
name (str): Logger name.
|
||||
log_file (str | None): The log filename. If specified, a FileHandler
|
||||
will be added to the logger.
|
||||
log_level (int): The logger level. Note that only the process of
|
||||
rank 0 is affected, and other processes will set the level to
|
||||
"Error" thus be silent most of the time.
|
||||
Returns:
|
||||
logging.Logger: The expected logger.
|
||||
"""
|
||||
logger = logging.getLogger(name)
|
||||
if name in logger_initialized:
|
||||
return logger
|
||||
for logger_name in logger_initialized:
|
||||
if name.startswith(logger_name):
|
||||
return logger
|
||||
|
||||
formatter = logging.Formatter(
|
||||
'[%(asctime)s] %(name)s %(levelname)s: %(message)s',
|
||||
datefmt="%Y/%m/%d %H:%M:%S")
|
||||
|
||||
stream_handler = logging.StreamHandler(stream=sys.stdout)
|
||||
stream_handler.setFormatter(formatter)
|
||||
logger.addHandler(stream_handler)
|
||||
if log_file is not None and dist.get_rank() == 0:
|
||||
log_file_folder = os.path.split(log_file)[0]
|
||||
os.makedirs(log_file_folder, exist_ok=True)
|
||||
file_handler = logging.FileHandler(log_file, 'a')
|
||||
file_handler.setFormatter(formatter)
|
||||
logger.addHandler(file_handler)
|
||||
if dist.get_rank() == 0:
|
||||
logger.setLevel(log_level)
|
||||
else:
|
||||
logger.setLevel(logging.ERROR)
|
||||
logger_initialized[name] = True
|
||||
logger.propagate = False
|
||||
return logger
|
||||
84
backend/ppocr/utils/network.py
Normal file
84
backend/ppocr/utils/network.py
Normal file
@@ -0,0 +1,84 @@
|
||||
# copyright (c) 2020 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.
|
||||
|
||||
import os
|
||||
import sys
|
||||
import tarfile
|
||||
import requests
|
||||
from tqdm import tqdm
|
||||
|
||||
from ppocr.utils.logging import get_logger
|
||||
|
||||
|
||||
def download_with_progressbar(url, save_path):
|
||||
logger = get_logger()
|
||||
response = requests.get(url, stream=True)
|
||||
if response.status_code == 200:
|
||||
total_size_in_bytes = int(response.headers.get('content-length', 1))
|
||||
block_size = 1024 # 1 Kibibyte
|
||||
progress_bar = tqdm(
|
||||
total=total_size_in_bytes, unit='iB', unit_scale=True)
|
||||
with open(save_path, 'wb') as file:
|
||||
for data in response.iter_content(block_size):
|
||||
progress_bar.update(len(data))
|
||||
file.write(data)
|
||||
progress_bar.close()
|
||||
else:
|
||||
logger.error("Something went wrong while downloading models")
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
def maybe_download(model_storage_directory, url):
|
||||
# using custom model
|
||||
tar_file_name_list = [
|
||||
'inference.pdiparams', 'inference.pdiparams.info', 'inference.pdmodel'
|
||||
]
|
||||
if not os.path.exists(
|
||||
os.path.join(model_storage_directory, 'inference.pdiparams')
|
||||
) or not os.path.exists(
|
||||
os.path.join(model_storage_directory, 'inference.pdmodel')):
|
||||
assert url.endswith('.tar'), 'Only supports tar compressed package'
|
||||
tmp_path = os.path.join(model_storage_directory, url.split('/')[-1])
|
||||
print('download {} to {}'.format(url, tmp_path))
|
||||
os.makedirs(model_storage_directory, exist_ok=True)
|
||||
download_with_progressbar(url, tmp_path)
|
||||
with tarfile.open(tmp_path, 'r') as tarObj:
|
||||
for member in tarObj.getmembers():
|
||||
filename = None
|
||||
for tar_file_name in tar_file_name_list:
|
||||
if tar_file_name in member.name:
|
||||
filename = tar_file_name
|
||||
if filename is None:
|
||||
continue
|
||||
file = tarObj.extractfile(member)
|
||||
with open(
|
||||
os.path.join(model_storage_directory, filename),
|
||||
'wb') as f:
|
||||
f.write(file.read())
|
||||
os.remove(tmp_path)
|
||||
|
||||
|
||||
def is_link(s):
|
||||
return s is not None and s.startswith('http')
|
||||
|
||||
|
||||
def confirm_model_dir_url(model_dir, default_model_dir, default_url):
|
||||
url = default_url
|
||||
if model_dir is None or is_link(model_dir):
|
||||
if is_link(model_dir):
|
||||
url = model_dir
|
||||
file_name = url.split('/')[-1][:-4]
|
||||
model_dir = default_model_dir
|
||||
model_dir = os.path.join(model_dir, file_name)
|
||||
return model_dir, url
|
||||
146
backend/ppocr/utils/poly_nms.py
Normal file
146
backend/ppocr/utils/poly_nms.py
Normal file
@@ -0,0 +1,146 @@
|
||||
# copyright (c) 2022 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.
|
||||
|
||||
import numpy as np
|
||||
from shapely.geometry import Polygon
|
||||
|
||||
|
||||
def points2polygon(points):
|
||||
"""Convert k points to 1 polygon.
|
||||
|
||||
Args:
|
||||
points (ndarray or list): A ndarray or a list of shape (2k)
|
||||
that indicates k points.
|
||||
|
||||
Returns:
|
||||
polygon (Polygon): A polygon object.
|
||||
"""
|
||||
if isinstance(points, list):
|
||||
points = np.array(points)
|
||||
|
||||
assert isinstance(points, np.ndarray)
|
||||
assert (points.size % 2 == 0) and (points.size >= 8)
|
||||
|
||||
point_mat = points.reshape([-1, 2])
|
||||
return Polygon(point_mat)
|
||||
|
||||
|
||||
def poly_intersection(poly_det, poly_gt, buffer=0.0001):
|
||||
"""Calculate the intersection area between two polygon.
|
||||
|
||||
Args:
|
||||
poly_det (Polygon): A polygon predicted by detector.
|
||||
poly_gt (Polygon): A gt polygon.
|
||||
|
||||
Returns:
|
||||
intersection_area (float): The intersection area between two polygons.
|
||||
"""
|
||||
assert isinstance(poly_det, Polygon)
|
||||
assert isinstance(poly_gt, Polygon)
|
||||
|
||||
if buffer == 0:
|
||||
poly_inter = poly_det & poly_gt
|
||||
else:
|
||||
poly_inter = poly_det.buffer(buffer) & poly_gt.buffer(buffer)
|
||||
return poly_inter.area, poly_inter
|
||||
|
||||
|
||||
def poly_union(poly_det, poly_gt):
|
||||
"""Calculate the union area between two polygon.
|
||||
|
||||
Args:
|
||||
poly_det (Polygon): A polygon predicted by detector.
|
||||
poly_gt (Polygon): A gt polygon.
|
||||
|
||||
Returns:
|
||||
union_area (float): The union area between two polygons.
|
||||
"""
|
||||
assert isinstance(poly_det, Polygon)
|
||||
assert isinstance(poly_gt, Polygon)
|
||||
|
||||
area_det = poly_det.area
|
||||
area_gt = poly_gt.area
|
||||
area_inters, _ = poly_intersection(poly_det, poly_gt)
|
||||
return area_det + area_gt - area_inters
|
||||
|
||||
|
||||
def valid_boundary(x, with_score=True):
|
||||
num = len(x)
|
||||
if num < 8:
|
||||
return False
|
||||
if num % 2 == 0 and (not with_score):
|
||||
return True
|
||||
if num % 2 == 1 and with_score:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def boundary_iou(src, target):
|
||||
"""Calculate the IOU between two boundaries.
|
||||
|
||||
Args:
|
||||
src (list): Source boundary.
|
||||
target (list): Target boundary.
|
||||
|
||||
Returns:
|
||||
iou (float): The iou between two boundaries.
|
||||
"""
|
||||
assert valid_boundary(src, False)
|
||||
assert valid_boundary(target, False)
|
||||
src_poly = points2polygon(src)
|
||||
target_poly = points2polygon(target)
|
||||
|
||||
return poly_iou(src_poly, target_poly)
|
||||
|
||||
|
||||
def poly_iou(poly_det, poly_gt):
|
||||
"""Calculate the IOU between two polygons.
|
||||
|
||||
Args:
|
||||
poly_det (Polygon): A polygon predicted by detector.
|
||||
poly_gt (Polygon): A gt polygon.
|
||||
|
||||
Returns:
|
||||
iou (float): The IOU between two polygons.
|
||||
"""
|
||||
assert isinstance(poly_det, Polygon)
|
||||
assert isinstance(poly_gt, Polygon)
|
||||
area_inters, _ = poly_intersection(poly_det, poly_gt)
|
||||
area_union = poly_union(poly_det, poly_gt)
|
||||
if area_union == 0:
|
||||
return 0.0
|
||||
return area_inters / area_union
|
||||
|
||||
|
||||
def poly_nms(polygons, threshold):
|
||||
assert isinstance(polygons, list)
|
||||
|
||||
polygons = np.array(sorted(polygons, key=lambda x: x[-1]))
|
||||
|
||||
keep_poly = []
|
||||
index = [i for i in range(polygons.shape[0])]
|
||||
|
||||
while len(index) > 0:
|
||||
keep_poly.append(polygons[index[-1]].tolist())
|
||||
A = polygons[index[-1]][:-1]
|
||||
index = np.delete(index, -1)
|
||||
iou_list = np.zeros((len(index), ))
|
||||
for i in range(len(index)):
|
||||
B = polygons[index[i]][:-1]
|
||||
iou_list[i] = boundary_iou(A, B)
|
||||
remove_index = np.where(iou_list > threshold)
|
||||
index = np.delete(index, remove_index)
|
||||
|
||||
return keep_poly
|
||||
110
backend/ppocr/utils/profiler.py
Normal file
110
backend/ppocr/utils/profiler.py
Normal file
@@ -0,0 +1,110 @@
|
||||
# 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.
|
||||
|
||||
import sys
|
||||
import paddle
|
||||
|
||||
# A global variable to record the number of calling times for profiler
|
||||
# functions. It is used to specify the tracing range of training steps.
|
||||
_profiler_step_id = 0
|
||||
|
||||
# A global variable to avoid parsing from string every time.
|
||||
_profiler_options = None
|
||||
|
||||
|
||||
class ProfilerOptions(object):
|
||||
'''
|
||||
Use a string to initialize a ProfilerOptions.
|
||||
The string should be in the format: "key1=value1;key2=value;key3=value3".
|
||||
For example:
|
||||
"profile_path=model.profile"
|
||||
"batch_range=[50, 60]; profile_path=model.profile"
|
||||
"batch_range=[50, 60]; tracer_option=OpDetail; profile_path=model.profile"
|
||||
ProfilerOptions supports following key-value pair:
|
||||
batch_range - a integer list, e.g. [100, 110].
|
||||
state - a string, the optional values are 'CPU', 'GPU' or 'All'.
|
||||
sorted_key - a string, the optional values are 'calls', 'total',
|
||||
'max', 'min' or 'ave.
|
||||
tracer_option - a string, the optional values are 'Default', 'OpDetail',
|
||||
'AllOpDetail'.
|
||||
profile_path - a string, the path to save the serialized profile data,
|
||||
which can be used to generate a timeline.
|
||||
exit_on_finished - a boolean.
|
||||
'''
|
||||
|
||||
def __init__(self, options_str):
|
||||
assert isinstance(options_str, str)
|
||||
|
||||
self._options = {
|
||||
'batch_range': [10, 20],
|
||||
'state': 'All',
|
||||
'sorted_key': 'total',
|
||||
'tracer_option': 'Default',
|
||||
'profile_path': '/tmp/profile',
|
||||
'exit_on_finished': True
|
||||
}
|
||||
self._parse_from_string(options_str)
|
||||
|
||||
def _parse_from_string(self, options_str):
|
||||
for kv in options_str.replace(' ', '').split(';'):
|
||||
key, value = kv.split('=')
|
||||
if key == 'batch_range':
|
||||
value_list = value.replace('[', '').replace(']', '').split(',')
|
||||
value_list = list(map(int, value_list))
|
||||
if len(value_list) >= 2 and value_list[0] >= 0 and value_list[
|
||||
1] > value_list[0]:
|
||||
self._options[key] = value_list
|
||||
elif key == 'exit_on_finished':
|
||||
self._options[key] = value.lower() in ("yes", "true", "t", "1")
|
||||
elif key in [
|
||||
'state', 'sorted_key', 'tracer_option', 'profile_path'
|
||||
]:
|
||||
self._options[key] = value
|
||||
|
||||
def __getitem__(self, name):
|
||||
if self._options.get(name, None) is None:
|
||||
raise ValueError(
|
||||
"ProfilerOptions does not have an option named %s." % name)
|
||||
return self._options[name]
|
||||
|
||||
|
||||
def add_profiler_step(options_str=None):
|
||||
'''
|
||||
Enable the operator-level timing using PaddlePaddle's profiler.
|
||||
The profiler uses a independent variable to count the profiler steps.
|
||||
One call of this function is treated as a profiler step.
|
||||
|
||||
Args:
|
||||
profiler_options - a string to initialize the ProfilerOptions.
|
||||
Default is None, and the profiler is disabled.
|
||||
'''
|
||||
if options_str is None:
|
||||
return
|
||||
|
||||
global _profiler_step_id
|
||||
global _profiler_options
|
||||
|
||||
if _profiler_options is None:
|
||||
_profiler_options = ProfilerOptions(options_str)
|
||||
|
||||
if _profiler_step_id == _profiler_options['batch_range'][0]:
|
||||
paddle.utils.profiler.start_profiler(
|
||||
_profiler_options['state'], _profiler_options['tracer_option'])
|
||||
elif _profiler_step_id == _profiler_options['batch_range'][1]:
|
||||
paddle.utils.profiler.stop_profiler(_profiler_options['sorted_key'],
|
||||
_profiler_options['profile_path'])
|
||||
if _profiler_options['exit_on_finished']:
|
||||
sys.exit(0)
|
||||
|
||||
_profiler_step_id += 1
|
||||
185
backend/ppocr/utils/save_load.py
Normal file
185
backend/ppocr/utils/save_load.py
Normal file
@@ -0,0 +1,185 @@
|
||||
# Copyright (c) 2020 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.
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
import errno
|
||||
import os
|
||||
import pickle
|
||||
import six
|
||||
|
||||
import paddle
|
||||
|
||||
from ppocr.utils.logging import get_logger
|
||||
|
||||
__all__ = ['load_model']
|
||||
|
||||
|
||||
def _mkdir_if_not_exist(path, logger):
|
||||
"""
|
||||
mkdir if not exists, ignore the exception when multiprocess mkdir together
|
||||
"""
|
||||
if not os.path.exists(path):
|
||||
try:
|
||||
os.makedirs(path)
|
||||
except OSError as e:
|
||||
if e.errno == errno.EEXIST and os.path.isdir(path):
|
||||
logger.warning(
|
||||
'be happy if some process has already created {}'.format(
|
||||
path))
|
||||
else:
|
||||
raise OSError('Failed to mkdir {}'.format(path))
|
||||
|
||||
|
||||
def load_model(config, model, optimizer=None, model_type='det'):
|
||||
"""
|
||||
load model from checkpoint or pretrained_model
|
||||
"""
|
||||
logger = get_logger()
|
||||
global_config = config['Global']
|
||||
checkpoints = global_config.get('checkpoints')
|
||||
pretrained_model = global_config.get('pretrained_model')
|
||||
best_model_dict = {}
|
||||
|
||||
if model_type == 'vqa':
|
||||
checkpoints = config['Architecture']['Backbone']['checkpoints']
|
||||
# load vqa method metric
|
||||
if checkpoints:
|
||||
if os.path.exists(os.path.join(checkpoints, 'metric.states')):
|
||||
with open(os.path.join(checkpoints, 'metric.states'),
|
||||
'rb') as f:
|
||||
states_dict = pickle.load(f) if six.PY2 else pickle.load(
|
||||
f, encoding='latin1')
|
||||
best_model_dict = states_dict.get('best_model_dict', {})
|
||||
if 'epoch' in states_dict:
|
||||
best_model_dict['start_epoch'] = states_dict['epoch'] + 1
|
||||
logger.info("resume from {}".format(checkpoints))
|
||||
|
||||
if optimizer is not None:
|
||||
if checkpoints[-1] in ['/', '\\']:
|
||||
checkpoints = checkpoints[:-1]
|
||||
if os.path.exists(checkpoints + '.pdopt'):
|
||||
optim_dict = paddle.load(checkpoints + '.pdopt')
|
||||
optimizer.set_state_dict(optim_dict)
|
||||
else:
|
||||
logger.warning(
|
||||
"{}.pdopt is not exists, params of optimizer is not loaded".
|
||||
format(checkpoints))
|
||||
return best_model_dict
|
||||
|
||||
if checkpoints:
|
||||
if checkpoints.endswith('.pdparams'):
|
||||
checkpoints = checkpoints.replace('.pdparams', '')
|
||||
assert os.path.exists(checkpoints + ".pdparams"), \
|
||||
"The {}.pdparams does not exists!".format(checkpoints)
|
||||
|
||||
# load params from trained model
|
||||
params = paddle.load(checkpoints + '.pdparams')
|
||||
state_dict = model.state_dict()
|
||||
new_state_dict = {}
|
||||
for key, value in state_dict.items():
|
||||
if key not in params:
|
||||
logger.warning("{} not in loaded params {} !".format(
|
||||
key, params.keys()))
|
||||
continue
|
||||
pre_value = params[key]
|
||||
if list(value.shape) == list(pre_value.shape):
|
||||
new_state_dict[key] = pre_value
|
||||
else:
|
||||
logger.warning(
|
||||
"The shape of model params {} {} not matched with loaded params shape {} !".
|
||||
format(key, value.shape, pre_value.shape))
|
||||
model.set_state_dict(new_state_dict)
|
||||
|
||||
if optimizer is not None:
|
||||
if os.path.exists(checkpoints + '.pdopt'):
|
||||
optim_dict = paddle.load(checkpoints + '.pdopt')
|
||||
optimizer.set_state_dict(optim_dict)
|
||||
else:
|
||||
logger.warning(
|
||||
"{}.pdopt is not exists, params of optimizer is not loaded".
|
||||
format(checkpoints))
|
||||
|
||||
if os.path.exists(checkpoints + '.states'):
|
||||
with open(checkpoints + '.states', 'rb') as f:
|
||||
states_dict = pickle.load(f) if six.PY2 else pickle.load(
|
||||
f, encoding='latin1')
|
||||
best_model_dict = states_dict.get('best_model_dict', {})
|
||||
if 'epoch' in states_dict:
|
||||
best_model_dict['start_epoch'] = states_dict['epoch'] + 1
|
||||
logger.info("resume from {}".format(checkpoints))
|
||||
elif pretrained_model:
|
||||
load_pretrained_params(model, pretrained_model)
|
||||
else:
|
||||
logger.info('train from scratch')
|
||||
return best_model_dict
|
||||
|
||||
|
||||
def load_pretrained_params(model, path):
|
||||
logger = get_logger()
|
||||
if path.endswith('.pdparams'):
|
||||
path = path.replace('.pdparams', '')
|
||||
assert os.path.exists(path + ".pdparams"), \
|
||||
"The {}.pdparams does not exists!".format(path)
|
||||
|
||||
params = paddle.load(path + '.pdparams')
|
||||
state_dict = model.state_dict()
|
||||
new_state_dict = {}
|
||||
for k1 in params.keys():
|
||||
if k1 not in state_dict.keys():
|
||||
logger.warning("The pretrained params {} not in model".format(k1))
|
||||
else:
|
||||
if list(state_dict[k1].shape) == list(params[k1].shape):
|
||||
new_state_dict[k1] = params[k1]
|
||||
else:
|
||||
logger.warning(
|
||||
"The shape of model params {} {} not matched with loaded params {} {} !".
|
||||
format(k1, state_dict[k1].shape, k1, params[k1].shape))
|
||||
model.set_state_dict(new_state_dict)
|
||||
logger.info("load pretrain successful from {}".format(path))
|
||||
return model
|
||||
|
||||
|
||||
def save_model(model,
|
||||
optimizer,
|
||||
model_path,
|
||||
logger,
|
||||
config,
|
||||
is_best=False,
|
||||
prefix='ppocr',
|
||||
**kwargs):
|
||||
"""
|
||||
save model to the target path
|
||||
"""
|
||||
_mkdir_if_not_exist(model_path, logger)
|
||||
model_prefix = os.path.join(model_path, prefix)
|
||||
paddle.save(optimizer.state_dict(), model_prefix + '.pdopt')
|
||||
if config['Architecture']["model_type"] != 'vqa':
|
||||
paddle.save(model.state_dict(), model_prefix + '.pdparams')
|
||||
metric_prefix = model_prefix
|
||||
else:
|
||||
if config['Global']['distributed']:
|
||||
model._layers.backbone.model.save_pretrained(model_prefix)
|
||||
else:
|
||||
model.backbone.model.save_pretrained(model_prefix)
|
||||
metric_prefix = os.path.join(model_prefix, 'metric')
|
||||
# save metric and config
|
||||
if is_best:
|
||||
with open(metric_prefix + '.states', 'wb') as f:
|
||||
pickle.dump(kwargs, f, protocol=2)
|
||||
logger.info('save best model is to {}'.format(model_prefix))
|
||||
else:
|
||||
logger.info("save model in {}".format(model_prefix))
|
||||
72
backend/ppocr/utils/stats.py
Executable file
72
backend/ppocr/utils/stats.py
Executable file
@@ -0,0 +1,72 @@
|
||||
# Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
import collections
|
||||
import numpy as np
|
||||
import datetime
|
||||
|
||||
__all__ = ['TrainingStats', 'Time']
|
||||
|
||||
|
||||
class SmoothedValue(object):
|
||||
"""Track a series of values and provide access to smoothed values over a
|
||||
window or the global series average.
|
||||
"""
|
||||
|
||||
def __init__(self, window_size):
|
||||
self.deque = collections.deque(maxlen=window_size)
|
||||
|
||||
def add_value(self, value):
|
||||
self.deque.append(value)
|
||||
|
||||
def get_median_value(self):
|
||||
return np.median(self.deque)
|
||||
|
||||
|
||||
def Time():
|
||||
return datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')
|
||||
|
||||
|
||||
class TrainingStats(object):
|
||||
def __init__(self, window_size, stats_keys):
|
||||
self.window_size = window_size
|
||||
self.smoothed_losses_and_metrics = {
|
||||
key: SmoothedValue(window_size)
|
||||
for key in stats_keys
|
||||
}
|
||||
|
||||
def update(self, stats):
|
||||
for k, v in stats.items():
|
||||
if k not in self.smoothed_losses_and_metrics:
|
||||
self.smoothed_losses_and_metrics[k] = SmoothedValue(
|
||||
self.window_size)
|
||||
self.smoothed_losses_and_metrics[k].add_value(v)
|
||||
|
||||
def get(self, extras=None):
|
||||
stats = collections.OrderedDict()
|
||||
if extras:
|
||||
for k, v in extras.items():
|
||||
stats[k] = v
|
||||
for k, v in self.smoothed_losses_and_metrics.items():
|
||||
stats[k] = round(v.get_median_value(), 6)
|
||||
|
||||
return stats
|
||||
|
||||
def log(self, extras=None):
|
||||
d = self.get(extras)
|
||||
strs = []
|
||||
for k, v in d.items():
|
||||
strs.append('{}: {:x<6f}'.format(k, v))
|
||||
strs = ', '.join(strs)
|
||||
return strs
|
||||
131
backend/ppocr/utils/utility.py
Executable file
131
backend/ppocr/utils/utility.py
Executable file
@@ -0,0 +1,131 @@
|
||||
# Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
import logging
|
||||
import os
|
||||
import imghdr
|
||||
import cv2
|
||||
import random
|
||||
import numpy as np
|
||||
import paddle
|
||||
|
||||
|
||||
def print_dict(d, logger, delimiter=0):
|
||||
"""
|
||||
Recursively visualize a dict and
|
||||
indenting acrrording by the relationship of keys.
|
||||
"""
|
||||
for k, v in sorted(d.items()):
|
||||
if isinstance(v, dict):
|
||||
logger.info("{}{} : ".format(delimiter * " ", str(k)))
|
||||
print_dict(v, logger, delimiter + 4)
|
||||
elif isinstance(v, list) and len(v) >= 1 and isinstance(v[0], dict):
|
||||
logger.info("{}{} : ".format(delimiter * " ", str(k)))
|
||||
for value in v:
|
||||
print_dict(value, logger, delimiter + 4)
|
||||
else:
|
||||
logger.info("{}{} : {}".format(delimiter * " ", k, v))
|
||||
|
||||
|
||||
def get_check_global_params(mode):
|
||||
check_params = ['use_gpu', 'max_text_length', 'image_shape', \
|
||||
'image_shape', 'character_type', 'loss_type']
|
||||
if mode == "train_eval":
|
||||
check_params = check_params + [ \
|
||||
'train_batch_size_per_card', 'test_batch_size_per_card']
|
||||
elif mode == "test":
|
||||
check_params = check_params + ['test_batch_size_per_card']
|
||||
return check_params
|
||||
|
||||
|
||||
def _check_image_file(path):
|
||||
img_end = {'jpg', 'bmp', 'png', 'jpeg', 'rgb', 'tif', 'tiff', 'gif'}
|
||||
return any([path.lower().endswith(e) for e in img_end])
|
||||
|
||||
|
||||
def get_image_file_list(img_file):
|
||||
imgs_lists = []
|
||||
if img_file is None or not os.path.exists(img_file):
|
||||
raise Exception("not found any img file in {}".format(img_file))
|
||||
|
||||
img_end = {'jpg', 'bmp', 'png', 'jpeg', 'rgb', 'tif', 'tiff', 'gif'}
|
||||
if os.path.isfile(img_file) and _check_image_file(img_file):
|
||||
imgs_lists.append(img_file)
|
||||
elif os.path.isdir(img_file):
|
||||
for single_file in os.listdir(img_file):
|
||||
file_path = os.path.join(img_file, single_file)
|
||||
if os.path.isfile(file_path) and _check_image_file(file_path):
|
||||
imgs_lists.append(file_path)
|
||||
if len(imgs_lists) == 0:
|
||||
raise Exception("not found any img file in {}".format(img_file))
|
||||
imgs_lists = sorted(imgs_lists)
|
||||
return imgs_lists
|
||||
|
||||
|
||||
def check_and_read_gif(img_path):
|
||||
if os.path.basename(img_path)[-3:] in ['gif', 'GIF']:
|
||||
gif = cv2.VideoCapture(img_path)
|
||||
ret, frame = gif.read()
|
||||
if not ret:
|
||||
logger = logging.getLogger('ppocr')
|
||||
logger.info("Cannot read {}. This gif image maybe corrupted.")
|
||||
return None, False
|
||||
if len(frame.shape) == 2 or frame.shape[-1] == 1:
|
||||
frame = cv2.cvtColor(frame, cv2.COLOR_GRAY2RGB)
|
||||
imgvalue = frame[:, :, ::-1]
|
||||
return imgvalue, True
|
||||
return None, False
|
||||
|
||||
|
||||
def load_vqa_bio_label_maps(label_map_path):
|
||||
with open(label_map_path, "r", encoding='utf-8') as fin:
|
||||
lines = fin.readlines()
|
||||
lines = [line.strip() for line in lines]
|
||||
if "O" not in lines:
|
||||
lines.insert(0, "O")
|
||||
labels = []
|
||||
for line in lines:
|
||||
if line == "O":
|
||||
labels.append("O")
|
||||
else:
|
||||
labels.append("B-" + line)
|
||||
labels.append("I-" + line)
|
||||
label2id_map = {label: idx for idx, label in enumerate(labels)}
|
||||
id2label_map = {idx: label for idx, label in enumerate(labels)}
|
||||
return label2id_map, id2label_map
|
||||
|
||||
|
||||
def set_seed(seed=1024):
|
||||
random.seed(seed)
|
||||
np.random.seed(seed)
|
||||
paddle.seed(seed)
|
||||
|
||||
|
||||
class AverageMeter:
|
||||
def __init__(self):
|
||||
self.reset()
|
||||
|
||||
def reset(self):
|
||||
"""reset"""
|
||||
self.val = 0
|
||||
self.avg = 0
|
||||
self.sum = 0
|
||||
self.count = 0
|
||||
|
||||
def update(self, val, n=1):
|
||||
"""update"""
|
||||
self.val = val
|
||||
self.sum += val * n
|
||||
self.count += n
|
||||
self.avg = self.sum / self.count
|
||||
98
backend/ppocr/utils/visual.py
Normal file
98
backend/ppocr/utils/visual.py
Normal file
@@ -0,0 +1,98 @@
|
||||
# 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.
|
||||
import os
|
||||
import numpy as np
|
||||
from PIL import Image, ImageDraw, ImageFont
|
||||
|
||||
|
||||
def draw_ser_results(image,
|
||||
ocr_results,
|
||||
font_path="doc/fonts/simfang.ttf",
|
||||
font_size=18):
|
||||
np.random.seed(2021)
|
||||
color = (np.random.permutation(range(255)),
|
||||
np.random.permutation(range(255)),
|
||||
np.random.permutation(range(255)))
|
||||
color_map = {
|
||||
idx: (color[0][idx], color[1][idx], color[2][idx])
|
||||
for idx in range(1, 255)
|
||||
}
|
||||
if isinstance(image, np.ndarray):
|
||||
image = Image.fromarray(image)
|
||||
elif isinstance(image, str) and os.path.isfile(image):
|
||||
image = Image.open(image).convert('RGB')
|
||||
img_new = image.copy()
|
||||
draw = ImageDraw.Draw(img_new)
|
||||
|
||||
font = ImageFont.truetype(font_path, font_size, encoding="utf-8")
|
||||
for ocr_info in ocr_results:
|
||||
if ocr_info["pred_id"] not in color_map:
|
||||
continue
|
||||
color = color_map[ocr_info["pred_id"]]
|
||||
text = "{}: {}".format(ocr_info["pred"], ocr_info["text"])
|
||||
|
||||
draw_box_txt(ocr_info["bbox"], text, draw, font, font_size, color)
|
||||
|
||||
img_new = Image.blend(image, img_new, 0.5)
|
||||
return np.array(img_new)
|
||||
|
||||
|
||||
def draw_box_txt(bbox, text, draw, font, font_size, color):
|
||||
# draw ocr results outline
|
||||
bbox = ((bbox[0], bbox[1]), (bbox[2], bbox[3]))
|
||||
draw.rectangle(bbox, fill=color)
|
||||
|
||||
# draw ocr results
|
||||
start_y = max(0, bbox[0][1] - font_size)
|
||||
tw = font.getsize(text)[0]
|
||||
draw.rectangle(
|
||||
[(bbox[0][0] + 1, start_y), (bbox[0][0] + tw + 1, start_y + font_size)],
|
||||
fill=(0, 0, 255))
|
||||
draw.text((bbox[0][0] + 1, start_y), text, fill=(255, 255, 255), font=font)
|
||||
|
||||
|
||||
def draw_re_results(image,
|
||||
result,
|
||||
font_path="doc/fonts/simfang.ttf",
|
||||
font_size=18):
|
||||
np.random.seed(0)
|
||||
if isinstance(image, np.ndarray):
|
||||
image = Image.fromarray(image)
|
||||
elif isinstance(image, str) and os.path.isfile(image):
|
||||
image = Image.open(image).convert('RGB')
|
||||
img_new = image.copy()
|
||||
draw = ImageDraw.Draw(img_new)
|
||||
|
||||
font = ImageFont.truetype(font_path, font_size, encoding="utf-8")
|
||||
color_head = (0, 0, 255)
|
||||
color_tail = (255, 0, 0)
|
||||
color_line = (0, 255, 0)
|
||||
|
||||
for ocr_info_head, ocr_info_tail in result:
|
||||
draw_box_txt(ocr_info_head["bbox"], ocr_info_head["text"], draw, font,
|
||||
font_size, color_head)
|
||||
draw_box_txt(ocr_info_tail["bbox"], ocr_info_tail["text"], draw, font,
|
||||
font_size, color_tail)
|
||||
|
||||
center_head = (
|
||||
(ocr_info_head['bbox'][0] + ocr_info_head['bbox'][2]) // 2,
|
||||
(ocr_info_head['bbox'][1] + ocr_info_head['bbox'][3]) // 2)
|
||||
center_tail = (
|
||||
(ocr_info_tail['bbox'][0] + ocr_info_tail['bbox'][2]) // 2,
|
||||
(ocr_info_tail['bbox'][1] + ocr_info_tail['bbox'][3]) // 2)
|
||||
|
||||
draw.line([center_head, center_tail], fill=color_line, width=5)
|
||||
|
||||
img_new = Image.blend(image, img_new, 0.5)
|
||||
return np.array(img_new)
|
||||
Reference in New Issue
Block a user