Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
wangsen
paddle_dbnet
Commits
4a182a89
Commit
4a182a89
authored
Aug 10, 2021
by
MissPenguin
Browse files
split cpp inference
parent
0bf4fc37
Changes
31
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
5769 additions
and
4 deletions
+5769
-4
deploy/cpp_infer/src_rec/preprocess_op.cpp
deploy/cpp_infer/src_rec/preprocess_op.cpp
+133
-0
deploy/cpp_infer/src_rec/utility.cpp
deploy/cpp_infer/src_rec/utility.cpp
+95
-0
deploy/cpp_infer/src_system/clipper.cpp
deploy/cpp_infer/src_system/clipper.cpp
+4380
-0
deploy/cpp_infer/src_system/main.cpp
deploy/cpp_infer/src_system/main.cpp
+215
-0
deploy/cpp_infer/src_system/ocr_cls.cpp
deploy/cpp_infer/src_system/ocr_cls.cpp
+0
-0
deploy/cpp_infer/src_system/ocr_det.cpp
deploy/cpp_infer/src_system/ocr_det.cpp
+161
-0
deploy/cpp_infer/src_system/ocr_rec.cpp
deploy/cpp_infer/src_system/ocr_rec.cpp
+184
-0
deploy/cpp_infer/src_system/postprocess_op.cpp
deploy/cpp_infer/src_system/postprocess_op.cpp
+355
-0
deploy/cpp_infer/src_system/preprocess_op.cpp
deploy/cpp_infer/src_system/preprocess_op.cpp
+133
-0
deploy/cpp_infer/src_system/utility.cpp
deploy/cpp_infer/src_system/utility.cpp
+95
-0
deploy/cpp_infer/tools/build.sh
deploy/cpp_infer/tools/build.sh
+18
-4
No files found.
deploy/cpp_infer/src_rec/preprocess_op.cpp
0 → 100644
View file @
4a182a89
// 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.
#include "opencv2/core.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/imgproc.hpp"
#include "paddle_api.h"
#include "paddle_inference_api.h"
#include <chrono>
#include <iomanip>
#include <iostream>
#include <ostream>
#include <vector>
#include <cstring>
#include <fstream>
#include <numeric>
#include <include/preprocess_op.h>
namespace
PaddleOCR
{
void
Permute
::
Run
(
const
cv
::
Mat
*
im
,
float
*
data
)
{
int
rh
=
im
->
rows
;
int
rw
=
im
->
cols
;
int
rc
=
im
->
channels
();
for
(
int
i
=
0
;
i
<
rc
;
++
i
)
{
cv
::
extractChannel
(
*
im
,
cv
::
Mat
(
rh
,
rw
,
CV_32FC1
,
data
+
i
*
rh
*
rw
),
i
);
}
}
void
Normalize
::
Run
(
cv
::
Mat
*
im
,
const
std
::
vector
<
float
>
&
mean
,
const
std
::
vector
<
float
>
&
scale
,
const
bool
is_scale
)
{
double
e
=
1.0
;
if
(
is_scale
)
{
e
/=
255.0
;
}
(
*
im
).
convertTo
(
*
im
,
CV_32FC3
,
e
);
std
::
vector
<
cv
::
Mat
>
bgr_channels
(
3
);
cv
::
split
(
*
im
,
bgr_channels
);
for
(
auto
i
=
0
;
i
<
bgr_channels
.
size
();
i
++
)
{
bgr_channels
[
i
].
convertTo
(
bgr_channels
[
i
],
CV_32FC1
,
1.0
*
scale
[
i
],
(
0.0
-
mean
[
i
])
*
scale
[
i
]);
}
cv
::
merge
(
bgr_channels
,
*
im
);
}
void
ResizeImgType0
::
Run
(
const
cv
::
Mat
&
img
,
cv
::
Mat
&
resize_img
,
int
max_size_len
,
float
&
ratio_h
,
float
&
ratio_w
,
bool
use_tensorrt
)
{
int
w
=
img
.
cols
;
int
h
=
img
.
rows
;
float
ratio
=
1.
f
;
int
max_wh
=
w
>=
h
?
w
:
h
;
if
(
max_wh
>
max_size_len
)
{
if
(
h
>
w
)
{
ratio
=
float
(
max_size_len
)
/
float
(
h
);
}
else
{
ratio
=
float
(
max_size_len
)
/
float
(
w
);
}
}
int
resize_h
=
int
(
float
(
h
)
*
ratio
);
int
resize_w
=
int
(
float
(
w
)
*
ratio
);
resize_h
=
max
(
int
(
round
(
float
(
resize_h
)
/
32
)
*
32
),
32
);
resize_w
=
max
(
int
(
round
(
float
(
resize_w
)
/
32
)
*
32
),
32
);
cv
::
resize
(
img
,
resize_img
,
cv
::
Size
(
resize_w
,
resize_h
));
ratio_h
=
float
(
resize_h
)
/
float
(
h
);
ratio_w
=
float
(
resize_w
)
/
float
(
w
);
}
void
CrnnResizeImg
::
Run
(
const
cv
::
Mat
&
img
,
cv
::
Mat
&
resize_img
,
float
wh_ratio
,
bool
use_tensorrt
,
const
std
::
vector
<
int
>
&
rec_image_shape
)
{
int
imgC
,
imgH
,
imgW
;
imgC
=
rec_image_shape
[
0
];
imgH
=
rec_image_shape
[
1
];
imgW
=
rec_image_shape
[
2
];
imgW
=
int
(
32
*
wh_ratio
);
float
ratio
=
float
(
img
.
cols
)
/
float
(
img
.
rows
);
int
resize_w
,
resize_h
;
if
(
ceilf
(
imgH
*
ratio
)
>
imgW
)
resize_w
=
imgW
;
else
resize_w
=
int
(
ceilf
(
imgH
*
ratio
));
cv
::
resize
(
img
,
resize_img
,
cv
::
Size
(
resize_w
,
imgH
),
0.
f
,
0.
f
,
cv
::
INTER_LINEAR
);
cv
::
copyMakeBorder
(
resize_img
,
resize_img
,
0
,
0
,
0
,
int
(
imgW
-
resize_img
.
cols
),
cv
::
BORDER_CONSTANT
,
{
127
,
127
,
127
});
}
void
ClsResizeImg
::
Run
(
const
cv
::
Mat
&
img
,
cv
::
Mat
&
resize_img
,
bool
use_tensorrt
,
const
std
::
vector
<
int
>
&
rec_image_shape
)
{
int
imgC
,
imgH
,
imgW
;
imgC
=
rec_image_shape
[
0
];
imgH
=
rec_image_shape
[
1
];
imgW
=
rec_image_shape
[
2
];
float
ratio
=
float
(
img
.
cols
)
/
float
(
img
.
rows
);
int
resize_w
,
resize_h
;
if
(
ceilf
(
imgH
*
ratio
)
>
imgW
)
resize_w
=
imgW
;
else
resize_w
=
int
(
ceilf
(
imgH
*
ratio
));
cv
::
resize
(
img
,
resize_img
,
cv
::
Size
(
resize_w
,
imgH
),
0.
f
,
0.
f
,
cv
::
INTER_LINEAR
);
if
(
resize_w
<
imgW
)
{
cv
::
copyMakeBorder
(
resize_img
,
resize_img
,
0
,
0
,
0
,
imgW
-
resize_w
,
cv
::
BORDER_CONSTANT
,
cv
::
Scalar
(
0
,
0
,
0
));
}
}
}
// namespace PaddleOCR
deploy/cpp_infer/src_rec/utility.cpp
0 → 100644
View file @
4a182a89
// 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.
#include <dirent.h>
#include <include/utility.h>
#include <iostream>
#include <ostream>
#include <sys/stat.h>
#include <sys/types.h>
#include <vector>
namespace
PaddleOCR
{
std
::
vector
<
std
::
string
>
Utility
::
ReadDict
(
const
std
::
string
&
path
)
{
std
::
ifstream
in
(
path
);
std
::
string
line
;
std
::
vector
<
std
::
string
>
m_vec
;
if
(
in
)
{
while
(
getline
(
in
,
line
))
{
m_vec
.
push_back
(
line
);
}
}
else
{
std
::
cout
<<
"no such label file: "
<<
path
<<
", exit the program..."
<<
std
::
endl
;
exit
(
1
);
}
return
m_vec
;
}
void
Utility
::
VisualizeBboxes
(
const
cv
::
Mat
&
srcimg
,
const
std
::
vector
<
std
::
vector
<
std
::
vector
<
int
>>>
&
boxes
)
{
cv
::
Mat
img_vis
;
srcimg
.
copyTo
(
img_vis
);
for
(
int
n
=
0
;
n
<
boxes
.
size
();
n
++
)
{
cv
::
Point
rook_points
[
4
];
for
(
int
m
=
0
;
m
<
boxes
[
n
].
size
();
m
++
)
{
rook_points
[
m
]
=
cv
::
Point
(
int
(
boxes
[
n
][
m
][
0
]),
int
(
boxes
[
n
][
m
][
1
]));
}
const
cv
::
Point
*
ppt
[
1
]
=
{
rook_points
};
int
npt
[]
=
{
4
};
cv
::
polylines
(
img_vis
,
ppt
,
npt
,
1
,
1
,
CV_RGB
(
0
,
255
,
0
),
2
,
8
,
0
);
}
cv
::
imwrite
(
"./ocr_vis.png"
,
img_vis
);
std
::
cout
<<
"The detection visualized image saved in ./ocr_vis.png"
<<
std
::
endl
;
}
// list all files under a directory
void
Utility
::
GetAllFiles
(
const
char
*
dir_name
,
std
::
vector
<
std
::
string
>
&
all_inputs
)
{
if
(
NULL
==
dir_name
)
{
std
::
cout
<<
" dir_name is null ! "
<<
std
::
endl
;
return
;
}
struct
stat
s
;
lstat
(
dir_name
,
&
s
);
if
(
!
S_ISDIR
(
s
.
st_mode
))
{
std
::
cout
<<
"dir_name is not a valid directory !"
<<
std
::
endl
;
all_inputs
.
push_back
(
dir_name
);
return
;
}
else
{
struct
dirent
*
filename
;
// return value for readdir()
DIR
*
dir
;
// return value for opendir()
dir
=
opendir
(
dir_name
);
if
(
NULL
==
dir
)
{
std
::
cout
<<
"Can not open dir "
<<
dir_name
<<
std
::
endl
;
return
;
}
std
::
cout
<<
"Successfully opened the dir !"
<<
std
::
endl
;
while
((
filename
=
readdir
(
dir
))
!=
NULL
)
{
if
(
strcmp
(
filename
->
d_name
,
"."
)
==
0
||
strcmp
(
filename
->
d_name
,
".."
)
==
0
)
continue
;
// img_dir + std::string("/") + all_inputs[0];
all_inputs
.
push_back
(
dir_name
+
std
::
string
(
"/"
)
+
std
::
string
(
filename
->
d_name
));
}
}
}
}
// namespace PaddleOCR
\ No newline at end of file
deploy/cpp_infer/src_system/clipper.cpp
0 → 100644
View file @
4a182a89
This diff is collapsed.
Click to expand it.
deploy/cpp_infer/src_system/main.cpp
0 → 100644
View file @
4a182a89
// 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.
#include "glog/logging.h"
#include "omp.h"
#include "opencv2/core.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/imgproc.hpp"
#include <chrono>
#include <iomanip>
#include <iostream>
#include <ostream>
#include <vector>
#include <cstring>
#include <fstream>
#include <numeric>
#include <glog/logging.h>
// #include <include/config.h>
#include <include/ocr_det.h>
#include <include/ocr_rec.h>
// #include <include/utility.h>
#include <sys/stat.h>
#include <gflags/gflags.h>
DEFINE_bool
(
use_gpu
,
false
,
"Infering with GPU or CPU."
);
DEFINE_int32
(
gpu_id
,
0
,
"Device id of GPU to execute."
);
DEFINE_int32
(
gpu_mem
,
4000
,
"GPU id when infering with GPU."
);
DEFINE_int32
(
cpu_math_library_num_threads
,
10
,
"Num of threads with CPU."
);
DEFINE_bool
(
use_mkldnn
,
false
,
"Whether use mkldnn with CPU."
);
DEFINE_string
(
image_dir
,
""
,
"Dir of input image."
);
DEFINE_string
(
det_model_dir
,
""
,
"Path of det inference model."
);
DEFINE_int32
(
max_side_len
,
960
,
"max_side_len of input image."
);
DEFINE_double
(
det_db_thresh
,
0.3
,
"Threshold of det_db_thresh."
);
DEFINE_double
(
det_db_box_thresh
,
0.5
,
"Threshold of det_db_box_thresh."
);
DEFINE_double
(
det_db_unclip_ratio
,
1.6
,
"Threshold of det_db_unclip_ratio."
);
DEFINE_bool
(
use_polygon_score
,
false
,
"Whether use polygon score."
);
DEFINE_bool
(
visualize
,
true
,
"Whether show the detection results."
);
DEFINE_bool
(
use_angle_cls
,
false
,
"Whether use use_angle_cls."
);
DEFINE_string
(
cls_model_dir
,
""
,
"Path of cls inference model."
);
DEFINE_double
(
cls_thresh
,
0.9
,
"Threshold of cls_thresh."
);
DEFINE_string
(
rec_model_dir
,
""
,
"Path of rec inference model."
);
DEFINE_string
(
char_list_file
,
"../../ppocr/utils/ppocr_keys_v1.txt"
,
"Path of dictionary."
);
DEFINE_bool
(
use_tensorrt
,
false
,
"Whether use tensorrt."
);
DEFINE_bool
(
use_fp16
,
false
,
"Whether use fp16 when use tensorrt."
);
using
namespace
std
;
using
namespace
cv
;
using
namespace
PaddleOCR
;
static
bool
PathExists
(
const
std
::
string
&
path
){
#ifdef _WIN32
struct
_stat
buffer
;
return
(
_stat
(
path
.
c_str
(),
&
buffer
)
==
0
);
#else
struct
stat
buffer
;
return
(
stat
(
path
.
c_str
(),
&
buffer
)
==
0
);
#endif // !_WIN32
}
cv
::
Mat
GetRotateCropImage
(
const
cv
::
Mat
&
srcimage
,
std
::
vector
<
std
::
vector
<
int
>>
box
)
{
cv
::
Mat
image
;
srcimage
.
copyTo
(
image
);
std
::
vector
<
std
::
vector
<
int
>>
points
=
box
;
int
x_collect
[
4
]
=
{
box
[
0
][
0
],
box
[
1
][
0
],
box
[
2
][
0
],
box
[
3
][
0
]};
int
y_collect
[
4
]
=
{
box
[
0
][
1
],
box
[
1
][
1
],
box
[
2
][
1
],
box
[
3
][
1
]};
int
left
=
int
(
*
std
::
min_element
(
x_collect
,
x_collect
+
4
));
int
right
=
int
(
*
std
::
max_element
(
x_collect
,
x_collect
+
4
));
int
top
=
int
(
*
std
::
min_element
(
y_collect
,
y_collect
+
4
));
int
bottom
=
int
(
*
std
::
max_element
(
y_collect
,
y_collect
+
4
));
cv
::
Mat
img_crop
;
image
(
cv
::
Rect
(
left
,
top
,
right
-
left
,
bottom
-
top
)).
copyTo
(
img_crop
);
for
(
int
i
=
0
;
i
<
points
.
size
();
i
++
)
{
points
[
i
][
0
]
-=
left
;
points
[
i
][
1
]
-=
top
;
}
int
img_crop_width
=
int
(
sqrt
(
pow
(
points
[
0
][
0
]
-
points
[
1
][
0
],
2
)
+
pow
(
points
[
0
][
1
]
-
points
[
1
][
1
],
2
)));
int
img_crop_height
=
int
(
sqrt
(
pow
(
points
[
0
][
0
]
-
points
[
3
][
0
],
2
)
+
pow
(
points
[
0
][
1
]
-
points
[
3
][
1
],
2
)));
cv
::
Point2f
pts_std
[
4
];
pts_std
[
0
]
=
cv
::
Point2f
(
0.
,
0.
);
pts_std
[
1
]
=
cv
::
Point2f
(
img_crop_width
,
0.
);
pts_std
[
2
]
=
cv
::
Point2f
(
img_crop_width
,
img_crop_height
);
pts_std
[
3
]
=
cv
::
Point2f
(
0.
f
,
img_crop_height
);
cv
::
Point2f
pointsf
[
4
];
pointsf
[
0
]
=
cv
::
Point2f
(
points
[
0
][
0
],
points
[
0
][
1
]);
pointsf
[
1
]
=
cv
::
Point2f
(
points
[
1
][
0
],
points
[
1
][
1
]);
pointsf
[
2
]
=
cv
::
Point2f
(
points
[
2
][
0
],
points
[
2
][
1
]);
pointsf
[
3
]
=
cv
::
Point2f
(
points
[
3
][
0
],
points
[
3
][
1
]);
cv
::
Mat
M
=
cv
::
getPerspectiveTransform
(
pointsf
,
pts_std
);
cv
::
Mat
dst_img
;
cv
::
warpPerspective
(
img_crop
,
dst_img
,
M
,
cv
::
Size
(
img_crop_width
,
img_crop_height
),
cv
::
BORDER_REPLICATE
);
if
(
float
(
dst_img
.
rows
)
>=
float
(
dst_img
.
cols
)
*
1.5
)
{
cv
::
Mat
srcCopy
=
cv
::
Mat
(
dst_img
.
rows
,
dst_img
.
cols
,
dst_img
.
depth
());
cv
::
transpose
(
dst_img
,
srcCopy
);
cv
::
flip
(
srcCopy
,
srcCopy
,
0
);
return
srcCopy
;
}
else
{
return
dst_img
;
}
}
int
main
(
int
argc
,
char
**
argv
)
{
// Parsing command-line
google
::
ParseCommandLineFlags
(
&
argc
,
&
argv
,
true
);
if
((
FLAGS_det_model_dir
.
empty
()
||
FLAGS_rec_model_dir
.
empty
()
||
FLAGS_image_dir
.
empty
())
||
(
FLAGS_use_angle_cls
&&
FLAGS_cls_model_dir
.
empty
()))
{
std
::
cout
<<
"Usage[default]: ./ocr_system --det_model_dir=/PATH/TO/DET_INFERENCE_MODEL/ "
<<
"--rec_model_dir=/PATH/TO/REC_INFERENCE_MODEL/ "
<<
"--image_dir=/PATH/TO/INPUT/IMAGE/"
<<
std
::
endl
;
std
::
cout
<<
"Usage[use angle cls]: ./ocr_system --det_model_dir=/PATH/TO/DET_INFERENCE_MODEL/ "
<<
"--use_angle_cls=true "
<<
"--cls_model_dir=/PATH/TO/CLS_INFERENCE_MODEL/ "
<<
"--rec_model_dir=/PATH/TO/REC_INFERENCE_MODEL/ "
<<
"--image_dir=/PATH/TO/INPUT/IMAGE/"
<<
std
::
endl
;
return
-
1
;
}
if
(
!
PathExists
(
FLAGS_image_dir
))
{
std
::
cerr
<<
"[ERROR] image path not exist! image_dir: "
<<
FLAGS_image_dir
<<
endl
;
exit
(
1
);
}
std
::
vector
<
cv
::
String
>
cv_all_img_names
;
cv
::
glob
(
FLAGS_image_dir
,
cv_all_img_names
);
std
::
cout
<<
"total images num: "
<<
cv_all_img_names
.
size
()
<<
endl
;
DBDetector
det
(
FLAGS_det_model_dir
,
FLAGS_use_gpu
,
FLAGS_gpu_id
,
FLAGS_gpu_mem
,
FLAGS_cpu_math_library_num_threads
,
FLAGS_use_mkldnn
,
FLAGS_max_side_len
,
FLAGS_det_db_thresh
,
FLAGS_det_db_box_thresh
,
FLAGS_det_db_unclip_ratio
,
FLAGS_use_polygon_score
,
FLAGS_visualize
,
FLAGS_use_tensorrt
,
FLAGS_use_fp16
);
Classifier
*
cls
=
nullptr
;
if
(
FLAGS_use_angle_cls
)
{
cls
=
new
Classifier
(
FLAGS_cls_model_dir
,
FLAGS_use_gpu
,
FLAGS_gpu_id
,
FLAGS_gpu_mem
,
FLAGS_cpu_math_library_num_threads
,
FLAGS_use_mkldnn
,
FLAGS_cls_thresh
,
FLAGS_use_tensorrt
,
FLAGS_use_fp16
);
}
CRNNRecognizer
rec
(
FLAGS_rec_model_dir
,
FLAGS_use_gpu
,
FLAGS_gpu_id
,
FLAGS_gpu_mem
,
FLAGS_cpu_math_library_num_threads
,
FLAGS_use_mkldnn
,
FLAGS_char_list_file
,
FLAGS_use_tensorrt
,
FLAGS_use_fp16
);
auto
start
=
std
::
chrono
::
system_clock
::
now
();
for
(
int
i
=
0
;
i
<
cv_all_img_names
.
size
();
++
i
)
{
LOG
(
INFO
)
<<
"The predict img: "
<<
cv_all_img_names
[
i
];
cv
::
Mat
srcimg
=
cv
::
imread
(
FLAGS_image_dir
,
cv
::
IMREAD_COLOR
);
if
(
!
srcimg
.
data
)
{
std
::
cerr
<<
"[ERROR] image read failed! image path: "
<<
cv_all_img_names
[
i
]
<<
endl
;
exit
(
1
);
}
std
::
vector
<
std
::
vector
<
std
::
vector
<
int
>>>
boxes
;
det
.
Run
(
srcimg
,
boxes
);
cv
::
Mat
crop_img
;
for
(
int
j
=
0
;
j
<
boxes
.
size
();
j
++
)
{
crop_img
=
GetRotateCropImage
(
srcimg
,
boxes
[
j
]);
if
(
cls
!=
nullptr
)
{
crop_img
=
cls
->
Run
(
crop_img
);
}
rec
.
Run
(
crop_img
);
}
auto
end
=
std
::
chrono
::
system_clock
::
now
();
auto
duration
=
std
::
chrono
::
duration_cast
<
std
::
chrono
::
microseconds
>
(
end
-
start
);
std
::
cout
<<
"Cost "
<<
double
(
duration
.
count
())
*
std
::
chrono
::
microseconds
::
period
::
num
/
std
::
chrono
::
microseconds
::
period
::
den
<<
"s"
<<
std
::
endl
;
}
return
0
;
}
deploy/cpp_infer/src/ocr_cls.cpp
→
deploy/cpp_infer/src
_system
/ocr_cls.cpp
View file @
4a182a89
File moved
deploy/cpp_infer/src_system/ocr_det.cpp
0 → 100644
View file @
4a182a89
// 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.
#include <include/ocr_det.h>
namespace
PaddleOCR
{
void
DBDetector
::
LoadModel
(
const
std
::
string
&
model_dir
)
{
// AnalysisConfig config;
paddle_infer
::
Config
config
;
config
.
SetModel
(
model_dir
+
"/inference.pdmodel"
,
model_dir
+
"/inference.pdiparams"
);
if
(
this
->
use_gpu_
)
{
config
.
EnableUseGpu
(
this
->
gpu_mem_
,
this
->
gpu_id_
);
if
(
this
->
use_tensorrt_
)
{
config
.
EnableTensorRtEngine
(
1
<<
20
,
10
,
3
,
this
->
use_fp16_
?
paddle_infer
::
Config
::
Precision
::
kHalf
:
paddle_infer
::
Config
::
Precision
::
kFloat32
,
false
,
false
);
std
::
map
<
std
::
string
,
std
::
vector
<
int
>>
min_input_shape
=
{
{
"x"
,
{
1
,
3
,
50
,
50
}},
{
"conv2d_92.tmp_0"
,
{
1
,
96
,
20
,
20
}},
{
"conv2d_91.tmp_0"
,
{
1
,
96
,
10
,
10
}},
{
"nearest_interp_v2_1.tmp_0"
,
{
1
,
96
,
10
,
10
}},
{
"nearest_interp_v2_2.tmp_0"
,
{
1
,
96
,
20
,
20
}},
{
"nearest_interp_v2_3.tmp_0"
,
{
1
,
24
,
20
,
20
}},
{
"nearest_interp_v2_4.tmp_0"
,
{
1
,
24
,
20
,
20
}},
{
"nearest_interp_v2_5.tmp_0"
,
{
1
,
24
,
20
,
20
}},
{
"elementwise_add_7"
,
{
1
,
56
,
2
,
2
}},
{
"nearest_interp_v2_0.tmp_0"
,
{
1
,
96
,
2
,
2
}}};
std
::
map
<
std
::
string
,
std
::
vector
<
int
>>
max_input_shape
=
{
{
"x"
,
{
1
,
3
,
this
->
max_side_len_
,
this
->
max_side_len_
}},
{
"conv2d_92.tmp_0"
,
{
1
,
96
,
400
,
400
}},
{
"conv2d_91.tmp_0"
,
{
1
,
96
,
200
,
200
}},
{
"nearest_interp_v2_1.tmp_0"
,
{
1
,
96
,
200
,
200
}},
{
"nearest_interp_v2_2.tmp_0"
,
{
1
,
96
,
400
,
400
}},
{
"nearest_interp_v2_3.tmp_0"
,
{
1
,
24
,
400
,
400
}},
{
"nearest_interp_v2_4.tmp_0"
,
{
1
,
24
,
400
,
400
}},
{
"nearest_interp_v2_5.tmp_0"
,
{
1
,
24
,
400
,
400
}},
{
"elementwise_add_7"
,
{
1
,
56
,
400
,
400
}},
{
"nearest_interp_v2_0.tmp_0"
,
{
1
,
96
,
400
,
400
}}};
std
::
map
<
std
::
string
,
std
::
vector
<
int
>>
opt_input_shape
=
{
{
"x"
,
{
1
,
3
,
640
,
640
}},
{
"conv2d_92.tmp_0"
,
{
1
,
96
,
160
,
160
}},
{
"conv2d_91.tmp_0"
,
{
1
,
96
,
80
,
80
}},
{
"nearest_interp_v2_1.tmp_0"
,
{
1
,
96
,
80
,
80
}},
{
"nearest_interp_v2_2.tmp_0"
,
{
1
,
96
,
160
,
160
}},
{
"nearest_interp_v2_3.tmp_0"
,
{
1
,
24
,
160
,
160
}},
{
"nearest_interp_v2_4.tmp_0"
,
{
1
,
24
,
160
,
160
}},
{
"nearest_interp_v2_5.tmp_0"
,
{
1
,
24
,
160
,
160
}},
{
"elementwise_add_7"
,
{
1
,
56
,
40
,
40
}},
{
"nearest_interp_v2_0.tmp_0"
,
{
1
,
96
,
40
,
40
}}};
config
.
SetTRTDynamicShapeInfo
(
min_input_shape
,
max_input_shape
,
opt_input_shape
);
}
}
else
{
config
.
DisableGpu
();
if
(
this
->
use_mkldnn_
)
{
config
.
EnableMKLDNN
();
// cache 10 different shapes for mkldnn to avoid memory leak
config
.
SetMkldnnCacheCapacity
(
10
);
}
config
.
SetCpuMathLibraryNumThreads
(
this
->
cpu_math_library_num_threads_
);
}
// use zero_copy_run as default
config
.
SwitchUseFeedFetchOps
(
false
);
// true for multiple input
config
.
SwitchSpecifyInputNames
(
true
);
config
.
SwitchIrOptim
(
true
);
config
.
EnableMemoryOptim
();
// config.DisableGlogInfo();
this
->
predictor_
=
CreatePredictor
(
config
);
}
void
DBDetector
::
Run
(
cv
::
Mat
&
img
,
std
::
vector
<
std
::
vector
<
std
::
vector
<
int
>>>
&
boxes
)
{
float
ratio_h
{};
float
ratio_w
{};
cv
::
Mat
srcimg
;
cv
::
Mat
resize_img
;
img
.
copyTo
(
srcimg
);
this
->
resize_op_
.
Run
(
img
,
resize_img
,
this
->
max_side_len_
,
ratio_h
,
ratio_w
,
this
->
use_tensorrt_
);
this
->
normalize_op_
.
Run
(
&
resize_img
,
this
->
mean_
,
this
->
scale_
,
this
->
is_scale_
);
std
::
vector
<
float
>
input
(
1
*
3
*
resize_img
.
rows
*
resize_img
.
cols
,
0.0
f
);
this
->
permute_op_
.
Run
(
&
resize_img
,
input
.
data
());
// Inference.
auto
input_names
=
this
->
predictor_
->
GetInputNames
();
auto
input_t
=
this
->
predictor_
->
GetInputHandle
(
input_names
[
0
]);
input_t
->
Reshape
({
1
,
3
,
resize_img
.
rows
,
resize_img
.
cols
});
input_t
->
CopyFromCpu
(
input
.
data
());
this
->
predictor_
->
Run
();
std
::
vector
<
float
>
out_data
;
auto
output_names
=
this
->
predictor_
->
GetOutputNames
();
auto
output_t
=
this
->
predictor_
->
GetOutputHandle
(
output_names
[
0
]);
std
::
vector
<
int
>
output_shape
=
output_t
->
shape
();
int
out_num
=
std
::
accumulate
(
output_shape
.
begin
(),
output_shape
.
end
(),
1
,
std
::
multiplies
<
int
>
());
out_data
.
resize
(
out_num
);
output_t
->
CopyToCpu
(
out_data
.
data
());
int
n2
=
output_shape
[
2
];
int
n3
=
output_shape
[
3
];
int
n
=
n2
*
n3
;
std
::
vector
<
float
>
pred
(
n
,
0.0
);
std
::
vector
<
unsigned
char
>
cbuf
(
n
,
' '
);
for
(
int
i
=
0
;
i
<
n
;
i
++
)
{
pred
[
i
]
=
float
(
out_data
[
i
]);
cbuf
[
i
]
=
(
unsigned
char
)((
out_data
[
i
])
*
255
);
}
cv
::
Mat
cbuf_map
(
n2
,
n3
,
CV_8UC1
,
(
unsigned
char
*
)
cbuf
.
data
());
cv
::
Mat
pred_map
(
n2
,
n3
,
CV_32F
,
(
float
*
)
pred
.
data
());
const
double
threshold
=
this
->
det_db_thresh_
*
255
;
const
double
maxvalue
=
255
;
cv
::
Mat
bit_map
;
cv
::
threshold
(
cbuf_map
,
bit_map
,
threshold
,
maxvalue
,
cv
::
THRESH_BINARY
);
cv
::
Mat
dilation_map
;
cv
::
Mat
dila_ele
=
cv
::
getStructuringElement
(
cv
::
MORPH_RECT
,
cv
::
Size
(
2
,
2
));
cv
::
dilate
(
bit_map
,
dilation_map
,
dila_ele
);
boxes
=
post_processor_
.
BoxesFromBitmap
(
pred_map
,
dilation_map
,
this
->
det_db_box_thresh_
,
this
->
det_db_unclip_ratio_
,
this
->
use_polygon_score_
);
boxes
=
post_processor_
.
FilterTagDetRes
(
boxes
,
ratio_h
,
ratio_w
,
srcimg
);
std
::
cout
<<
"Detected boxes num: "
<<
boxes
.
size
()
<<
endl
;
//// visualization
if
(
this
->
visualize_
)
{
Utility
::
VisualizeBboxes
(
srcimg
,
boxes
);
}
}
}
// namespace PaddleOCR
deploy/cpp_infer/src_system/ocr_rec.cpp
0 → 100644
View file @
4a182a89
// 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.
#include <include/ocr_rec.h>
namespace
PaddleOCR
{
void
CRNNRecognizer
::
Run
(
cv
::
Mat
&
img
)
{
cv
::
Mat
srcimg
;
img
.
copyTo
(
srcimg
);
cv
::
Mat
resize_img
;
float
wh_ratio
=
float
(
srcimg
.
cols
)
/
float
(
srcimg
.
rows
);
this
->
resize_op_
.
Run
(
srcimg
,
resize_img
,
wh_ratio
,
this
->
use_tensorrt_
);
this
->
normalize_op_
.
Run
(
&
resize_img
,
this
->
mean_
,
this
->
scale_
,
this
->
is_scale_
);
std
::
vector
<
float
>
input
(
1
*
3
*
resize_img
.
rows
*
resize_img
.
cols
,
0.0
f
);
this
->
permute_op_
.
Run
(
&
resize_img
,
input
.
data
());
// Inference.
auto
input_names
=
this
->
predictor_
->
GetInputNames
();
auto
input_t
=
this
->
predictor_
->
GetInputHandle
(
input_names
[
0
]);
input_t
->
Reshape
({
1
,
3
,
resize_img
.
rows
,
resize_img
.
cols
});
input_t
->
CopyFromCpu
(
input
.
data
());
this
->
predictor_
->
Run
();
std
::
vector
<
float
>
predict_batch
;
auto
output_names
=
this
->
predictor_
->
GetOutputNames
();
auto
output_t
=
this
->
predictor_
->
GetOutputHandle
(
output_names
[
0
]);
auto
predict_shape
=
output_t
->
shape
();
int
out_num
=
std
::
accumulate
(
predict_shape
.
begin
(),
predict_shape
.
end
(),
1
,
std
::
multiplies
<
int
>
());
predict_batch
.
resize
(
out_num
);
output_t
->
CopyToCpu
(
predict_batch
.
data
());
// ctc decode
std
::
vector
<
std
::
string
>
str_res
;
int
argmax_idx
;
int
last_index
=
0
;
float
score
=
0.
f
;
int
count
=
0
;
float
max_value
=
0.0
f
;
for
(
int
n
=
0
;
n
<
predict_shape
[
1
];
n
++
)
{
argmax_idx
=
int
(
Utility
::
argmax
(
&
predict_batch
[
n
*
predict_shape
[
2
]],
&
predict_batch
[(
n
+
1
)
*
predict_shape
[
2
]]));
max_value
=
float
(
*
std
::
max_element
(
&
predict_batch
[
n
*
predict_shape
[
2
]],
&
predict_batch
[(
n
+
1
)
*
predict_shape
[
2
]]));
if
(
argmax_idx
>
0
&&
(
!
(
n
>
0
&&
argmax_idx
==
last_index
)))
{
score
+=
max_value
;
count
+=
1
;
str_res
.
push_back
(
label_list_
[
argmax_idx
]);
}
last_index
=
argmax_idx
;
}
score
/=
count
;
for
(
int
i
=
0
;
i
<
str_res
.
size
();
i
++
)
{
std
::
cout
<<
str_res
[
i
];
}
std
::
cout
<<
"
\t
score: "
<<
score
<<
std
::
endl
;
}
void
CRNNRecognizer
::
LoadModel
(
const
std
::
string
&
model_dir
)
{
// AnalysisConfig config;
paddle_infer
::
Config
config
;
config
.
SetModel
(
model_dir
+
"/inference.pdmodel"
,
model_dir
+
"/inference.pdiparams"
);
if
(
this
->
use_gpu_
)
{
config
.
EnableUseGpu
(
this
->
gpu_mem_
,
this
->
gpu_id_
);
if
(
this
->
use_tensorrt_
)
{
config
.
EnableTensorRtEngine
(
1
<<
20
,
10
,
3
,
this
->
use_fp16_
?
paddle_infer
::
Config
::
Precision
::
kHalf
:
paddle_infer
::
Config
::
Precision
::
kFloat32
,
false
,
false
);
std
::
map
<
std
::
string
,
std
::
vector
<
int
>>
min_input_shape
=
{
{
"x"
,
{
1
,
3
,
32
,
10
}}};
std
::
map
<
std
::
string
,
std
::
vector
<
int
>>
max_input_shape
=
{
{
"x"
,
{
1
,
3
,
32
,
2000
}}};
std
::
map
<
std
::
string
,
std
::
vector
<
int
>>
opt_input_shape
=
{
{
"x"
,
{
1
,
3
,
32
,
320
}}};
config
.
SetTRTDynamicShapeInfo
(
min_input_shape
,
max_input_shape
,
opt_input_shape
);
}
}
else
{
config
.
DisableGpu
();
if
(
this
->
use_mkldnn_
)
{
config
.
EnableMKLDNN
();
// cache 10 different shapes for mkldnn to avoid memory leak
config
.
SetMkldnnCacheCapacity
(
10
);
}
config
.
SetCpuMathLibraryNumThreads
(
this
->
cpu_math_library_num_threads_
);
}
config
.
SwitchUseFeedFetchOps
(
false
);
// true for multiple input
config
.
SwitchSpecifyInputNames
(
true
);
config
.
SwitchIrOptim
(
true
);
config
.
EnableMemoryOptim
();
config
.
DisableGlogInfo
();
this
->
predictor_
=
CreatePredictor
(
config
);
}
cv
::
Mat
CRNNRecognizer
::
GetRotateCropImage
(
const
cv
::
Mat
&
srcimage
,
std
::
vector
<
std
::
vector
<
int
>>
box
)
{
cv
::
Mat
image
;
srcimage
.
copyTo
(
image
);
std
::
vector
<
std
::
vector
<
int
>>
points
=
box
;
int
x_collect
[
4
]
=
{
box
[
0
][
0
],
box
[
1
][
0
],
box
[
2
][
0
],
box
[
3
][
0
]};
int
y_collect
[
4
]
=
{
box
[
0
][
1
],
box
[
1
][
1
],
box
[
2
][
1
],
box
[
3
][
1
]};
int
left
=
int
(
*
std
::
min_element
(
x_collect
,
x_collect
+
4
));
int
right
=
int
(
*
std
::
max_element
(
x_collect
,
x_collect
+
4
));
int
top
=
int
(
*
std
::
min_element
(
y_collect
,
y_collect
+
4
));
int
bottom
=
int
(
*
std
::
max_element
(
y_collect
,
y_collect
+
4
));
cv
::
Mat
img_crop
;
image
(
cv
::
Rect
(
left
,
top
,
right
-
left
,
bottom
-
top
)).
copyTo
(
img_crop
);
for
(
int
i
=
0
;
i
<
points
.
size
();
i
++
)
{
points
[
i
][
0
]
-=
left
;
points
[
i
][
1
]
-=
top
;
}
int
img_crop_width
=
int
(
sqrt
(
pow
(
points
[
0
][
0
]
-
points
[
1
][
0
],
2
)
+
pow
(
points
[
0
][
1
]
-
points
[
1
][
1
],
2
)));
int
img_crop_height
=
int
(
sqrt
(
pow
(
points
[
0
][
0
]
-
points
[
3
][
0
],
2
)
+
pow
(
points
[
0
][
1
]
-
points
[
3
][
1
],
2
)));
cv
::
Point2f
pts_std
[
4
];
pts_std
[
0
]
=
cv
::
Point2f
(
0.
,
0.
);
pts_std
[
1
]
=
cv
::
Point2f
(
img_crop_width
,
0.
);
pts_std
[
2
]
=
cv
::
Point2f
(
img_crop_width
,
img_crop_height
);
pts_std
[
3
]
=
cv
::
Point2f
(
0.
f
,
img_crop_height
);
cv
::
Point2f
pointsf
[
4
];
pointsf
[
0
]
=
cv
::
Point2f
(
points
[
0
][
0
],
points
[
0
][
1
]);
pointsf
[
1
]
=
cv
::
Point2f
(
points
[
1
][
0
],
points
[
1
][
1
]);
pointsf
[
2
]
=
cv
::
Point2f
(
points
[
2
][
0
],
points
[
2
][
1
]);
pointsf
[
3
]
=
cv
::
Point2f
(
points
[
3
][
0
],
points
[
3
][
1
]);
cv
::
Mat
M
=
cv
::
getPerspectiveTransform
(
pointsf
,
pts_std
);
cv
::
Mat
dst_img
;
cv
::
warpPerspective
(
img_crop
,
dst_img
,
M
,
cv
::
Size
(
img_crop_width
,
img_crop_height
),
cv
::
BORDER_REPLICATE
);
if
(
float
(
dst_img
.
rows
)
>=
float
(
dst_img
.
cols
)
*
1.5
)
{
cv
::
Mat
srcCopy
=
cv
::
Mat
(
dst_img
.
rows
,
dst_img
.
cols
,
dst_img
.
depth
());
cv
::
transpose
(
dst_img
,
srcCopy
);
cv
::
flip
(
srcCopy
,
srcCopy
,
0
);
return
srcCopy
;
}
else
{
return
dst_img
;
}
}
}
// namespace PaddleOCR
deploy/cpp_infer/src_system/postprocess_op.cpp
0 → 100644
View file @
4a182a89
// 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.
#include <include/postprocess_op.h>
namespace
PaddleOCR
{
void
PostProcessor
::
GetContourArea
(
const
std
::
vector
<
std
::
vector
<
float
>>
&
box
,
float
unclip_ratio
,
float
&
distance
)
{
int
pts_num
=
4
;
float
area
=
0.0
f
;
float
dist
=
0.0
f
;
for
(
int
i
=
0
;
i
<
pts_num
;
i
++
)
{
area
+=
box
[
i
][
0
]
*
box
[(
i
+
1
)
%
pts_num
][
1
]
-
box
[
i
][
1
]
*
box
[(
i
+
1
)
%
pts_num
][
0
];
dist
+=
sqrtf
((
box
[
i
][
0
]
-
box
[(
i
+
1
)
%
pts_num
][
0
])
*
(
box
[
i
][
0
]
-
box
[(
i
+
1
)
%
pts_num
][
0
])
+
(
box
[
i
][
1
]
-
box
[(
i
+
1
)
%
pts_num
][
1
])
*
(
box
[
i
][
1
]
-
box
[(
i
+
1
)
%
pts_num
][
1
]));
}
area
=
fabs
(
float
(
area
/
2.0
));
distance
=
area
*
unclip_ratio
/
dist
;
}
cv
::
RotatedRect
PostProcessor
::
UnClip
(
std
::
vector
<
std
::
vector
<
float
>>
box
,
const
float
&
unclip_ratio
)
{
float
distance
=
1.0
;
GetContourArea
(
box
,
unclip_ratio
,
distance
);
ClipperLib
::
ClipperOffset
offset
;
ClipperLib
::
Path
p
;
p
<<
ClipperLib
::
IntPoint
(
int
(
box
[
0
][
0
]),
int
(
box
[
0
][
1
]))
<<
ClipperLib
::
IntPoint
(
int
(
box
[
1
][
0
]),
int
(
box
[
1
][
1
]))
<<
ClipperLib
::
IntPoint
(
int
(
box
[
2
][
0
]),
int
(
box
[
2
][
1
]))
<<
ClipperLib
::
IntPoint
(
int
(
box
[
3
][
0
]),
int
(
box
[
3
][
1
]));
offset
.
AddPath
(
p
,
ClipperLib
::
jtRound
,
ClipperLib
::
etClosedPolygon
);
ClipperLib
::
Paths
soln
;
offset
.
Execute
(
soln
,
distance
);
std
::
vector
<
cv
::
Point2f
>
points
;
for
(
int
j
=
0
;
j
<
soln
.
size
();
j
++
)
{
for
(
int
i
=
0
;
i
<
soln
[
soln
.
size
()
-
1
].
size
();
i
++
)
{
points
.
emplace_back
(
soln
[
j
][
i
].
X
,
soln
[
j
][
i
].
Y
);
}
}
cv
::
RotatedRect
res
;
if
(
points
.
size
()
<=
0
)
{
res
=
cv
::
RotatedRect
(
cv
::
Point2f
(
0
,
0
),
cv
::
Size2f
(
1
,
1
),
0
);
}
else
{
res
=
cv
::
minAreaRect
(
points
);
}
return
res
;
}
float
**
PostProcessor
::
Mat2Vec
(
cv
::
Mat
mat
)
{
auto
**
array
=
new
float
*
[
mat
.
rows
];
for
(
int
i
=
0
;
i
<
mat
.
rows
;
++
i
)
array
[
i
]
=
new
float
[
mat
.
cols
];
for
(
int
i
=
0
;
i
<
mat
.
rows
;
++
i
)
{
for
(
int
j
=
0
;
j
<
mat
.
cols
;
++
j
)
{
array
[
i
][
j
]
=
mat
.
at
<
float
>
(
i
,
j
);
}
}
return
array
;
}
std
::
vector
<
std
::
vector
<
int
>>
PostProcessor
::
OrderPointsClockwise
(
std
::
vector
<
std
::
vector
<
int
>>
pts
)
{
std
::
vector
<
std
::
vector
<
int
>>
box
=
pts
;
std
::
sort
(
box
.
begin
(),
box
.
end
(),
XsortInt
);
std
::
vector
<
std
::
vector
<
int
>>
leftmost
=
{
box
[
0
],
box
[
1
]};
std
::
vector
<
std
::
vector
<
int
>>
rightmost
=
{
box
[
2
],
box
[
3
]};
if
(
leftmost
[
0
][
1
]
>
leftmost
[
1
][
1
])
std
::
swap
(
leftmost
[
0
],
leftmost
[
1
]);
if
(
rightmost
[
0
][
1
]
>
rightmost
[
1
][
1
])
std
::
swap
(
rightmost
[
0
],
rightmost
[
1
]);
std
::
vector
<
std
::
vector
<
int
>>
rect
=
{
leftmost
[
0
],
rightmost
[
0
],
rightmost
[
1
],
leftmost
[
1
]};
return
rect
;
}
std
::
vector
<
std
::
vector
<
float
>>
PostProcessor
::
Mat2Vector
(
cv
::
Mat
mat
)
{
std
::
vector
<
std
::
vector
<
float
>>
img_vec
;
std
::
vector
<
float
>
tmp
;
for
(
int
i
=
0
;
i
<
mat
.
rows
;
++
i
)
{
tmp
.
clear
();
for
(
int
j
=
0
;
j
<
mat
.
cols
;
++
j
)
{
tmp
.
push_back
(
mat
.
at
<
float
>
(
i
,
j
));
}
img_vec
.
push_back
(
tmp
);
}
return
img_vec
;
}
bool
PostProcessor
::
XsortFp32
(
std
::
vector
<
float
>
a
,
std
::
vector
<
float
>
b
)
{
if
(
a
[
0
]
!=
b
[
0
])
return
a
[
0
]
<
b
[
0
];
return
false
;
}
bool
PostProcessor
::
XsortInt
(
std
::
vector
<
int
>
a
,
std
::
vector
<
int
>
b
)
{
if
(
a
[
0
]
!=
b
[
0
])
return
a
[
0
]
<
b
[
0
];
return
false
;
}
std
::
vector
<
std
::
vector
<
float
>>
PostProcessor
::
GetMiniBoxes
(
cv
::
RotatedRect
box
,
float
&
ssid
)
{
ssid
=
std
::
max
(
box
.
size
.
width
,
box
.
size
.
height
);
cv
::
Mat
points
;
cv
::
boxPoints
(
box
,
points
);
auto
array
=
Mat2Vector
(
points
);
std
::
sort
(
array
.
begin
(),
array
.
end
(),
XsortFp32
);
std
::
vector
<
float
>
idx1
=
array
[
0
],
idx2
=
array
[
1
],
idx3
=
array
[
2
],
idx4
=
array
[
3
];
if
(
array
[
3
][
1
]
<=
array
[
2
][
1
])
{
idx2
=
array
[
3
];
idx3
=
array
[
2
];
}
else
{
idx2
=
array
[
2
];
idx3
=
array
[
3
];
}
if
(
array
[
1
][
1
]
<=
array
[
0
][
1
])
{
idx1
=
array
[
1
];
idx4
=
array
[
0
];
}
else
{
idx1
=
array
[
0
];
idx4
=
array
[
1
];
}
array
[
0
]
=
idx1
;
array
[
1
]
=
idx2
;
array
[
2
]
=
idx3
;
array
[
3
]
=
idx4
;
return
array
;
}
float
PostProcessor
::
PolygonScoreAcc
(
std
::
vector
<
cv
::
Point
>
contour
,
cv
::
Mat
pred
)
{
int
width
=
pred
.
cols
;
int
height
=
pred
.
rows
;
std
::
vector
<
float
>
box_x
;
std
::
vector
<
float
>
box_y
;
for
(
int
i
=
0
;
i
<
contour
.
size
();
++
i
)
{
box_x
.
push_back
(
contour
[
i
].
x
);
box_y
.
push_back
(
contour
[
i
].
y
);
}
int
xmin
=
clamp
(
int
(
std
::
floor
(
*
(
std
::
min_element
(
box_x
.
begin
(),
box_x
.
end
())))),
0
,
width
-
1
);
int
xmax
=
clamp
(
int
(
std
::
ceil
(
*
(
std
::
max_element
(
box_x
.
begin
(),
box_x
.
end
())))),
0
,
width
-
1
);
int
ymin
=
clamp
(
int
(
std
::
floor
(
*
(
std
::
min_element
(
box_y
.
begin
(),
box_y
.
end
())))),
0
,
height
-
1
);
int
ymax
=
clamp
(
int
(
std
::
ceil
(
*
(
std
::
max_element
(
box_y
.
begin
(),
box_y
.
end
())))),
0
,
height
-
1
);
cv
::
Mat
mask
;
mask
=
cv
::
Mat
::
zeros
(
ymax
-
ymin
+
1
,
xmax
-
xmin
+
1
,
CV_8UC1
);
cv
::
Point
*
rook_point
=
new
cv
::
Point
[
contour
.
size
()];
for
(
int
i
=
0
;
i
<
contour
.
size
();
++
i
)
{
rook_point
[
i
]
=
cv
::
Point
(
int
(
box_x
[
i
])
-
xmin
,
int
(
box_y
[
i
])
-
ymin
);
}
const
cv
::
Point
*
ppt
[
1
]
=
{
rook_point
};
int
npt
[]
=
{
int
(
contour
.
size
())};
cv
::
fillPoly
(
mask
,
ppt
,
npt
,
1
,
cv
::
Scalar
(
1
));
cv
::
Mat
croppedImg
;
pred
(
cv
::
Rect
(
xmin
,
ymin
,
xmax
-
xmin
+
1
,
ymax
-
ymin
+
1
)).
copyTo
(
croppedImg
);
float
score
=
cv
::
mean
(
croppedImg
,
mask
)[
0
];
delete
[]
rook_point
;
return
score
;
}
float
PostProcessor
::
BoxScoreFast
(
std
::
vector
<
std
::
vector
<
float
>>
box_array
,
cv
::
Mat
pred
)
{
auto
array
=
box_array
;
int
width
=
pred
.
cols
;
int
height
=
pred
.
rows
;
float
box_x
[
4
]
=
{
array
[
0
][
0
],
array
[
1
][
0
],
array
[
2
][
0
],
array
[
3
][
0
]};
float
box_y
[
4
]
=
{
array
[
0
][
1
],
array
[
1
][
1
],
array
[
2
][
1
],
array
[
3
][
1
]};
int
xmin
=
clamp
(
int
(
std
::
floor
(
*
(
std
::
min_element
(
box_x
,
box_x
+
4
)))),
0
,
width
-
1
);
int
xmax
=
clamp
(
int
(
std
::
ceil
(
*
(
std
::
max_element
(
box_x
,
box_x
+
4
)))),
0
,
width
-
1
);
int
ymin
=
clamp
(
int
(
std
::
floor
(
*
(
std
::
min_element
(
box_y
,
box_y
+
4
)))),
0
,
height
-
1
);
int
ymax
=
clamp
(
int
(
std
::
ceil
(
*
(
std
::
max_element
(
box_y
,
box_y
+
4
)))),
0
,
height
-
1
);
cv
::
Mat
mask
;
mask
=
cv
::
Mat
::
zeros
(
ymax
-
ymin
+
1
,
xmax
-
xmin
+
1
,
CV_8UC1
);
cv
::
Point
root_point
[
4
];
root_point
[
0
]
=
cv
::
Point
(
int
(
array
[
0
][
0
])
-
xmin
,
int
(
array
[
0
][
1
])
-
ymin
);
root_point
[
1
]
=
cv
::
Point
(
int
(
array
[
1
][
0
])
-
xmin
,
int
(
array
[
1
][
1
])
-
ymin
);
root_point
[
2
]
=
cv
::
Point
(
int
(
array
[
2
][
0
])
-
xmin
,
int
(
array
[
2
][
1
])
-
ymin
);
root_point
[
3
]
=
cv
::
Point
(
int
(
array
[
3
][
0
])
-
xmin
,
int
(
array
[
3
][
1
])
-
ymin
);
const
cv
::
Point
*
ppt
[
1
]
=
{
root_point
};
int
npt
[]
=
{
4
};
cv
::
fillPoly
(
mask
,
ppt
,
npt
,
1
,
cv
::
Scalar
(
1
));
cv
::
Mat
croppedImg
;
pred
(
cv
::
Rect
(
xmin
,
ymin
,
xmax
-
xmin
+
1
,
ymax
-
ymin
+
1
))
.
copyTo
(
croppedImg
);
auto
score
=
cv
::
mean
(
croppedImg
,
mask
)[
0
];
return
score
;
}
std
::
vector
<
std
::
vector
<
std
::
vector
<
int
>>>
PostProcessor
::
BoxesFromBitmap
(
const
cv
::
Mat
pred
,
const
cv
::
Mat
bitmap
,
const
float
&
box_thresh
,
const
float
&
det_db_unclip_ratio
,
const
bool
&
use_polygon_score
)
{
const
int
min_size
=
3
;
const
int
max_candidates
=
1000
;
int
width
=
bitmap
.
cols
;
int
height
=
bitmap
.
rows
;
std
::
vector
<
std
::
vector
<
cv
::
Point
>>
contours
;
std
::
vector
<
cv
::
Vec4i
>
hierarchy
;
cv
::
findContours
(
bitmap
,
contours
,
hierarchy
,
cv
::
RETR_LIST
,
cv
::
CHAIN_APPROX_SIMPLE
);
int
num_contours
=
contours
.
size
()
>=
max_candidates
?
max_candidates
:
contours
.
size
();
std
::
vector
<
std
::
vector
<
std
::
vector
<
int
>>>
boxes
;
for
(
int
_i
=
0
;
_i
<
num_contours
;
_i
++
)
{
if
(
contours
[
_i
].
size
()
<=
2
)
{
continue
;
}
float
ssid
;
cv
::
RotatedRect
box
=
cv
::
minAreaRect
(
contours
[
_i
]);
auto
array
=
GetMiniBoxes
(
box
,
ssid
);
auto
box_for_unclip
=
array
;
// end get_mini_box
if
(
ssid
<
min_size
)
{
continue
;
}
float
score
;
if
(
use_polygon_score
)
/* compute using polygon*/
score
=
PolygonScoreAcc
(
contours
[
_i
],
pred
);
else
score
=
BoxScoreFast
(
array
,
pred
);
if
(
score
<
box_thresh
)
continue
;
// start for unclip
cv
::
RotatedRect
points
=
UnClip
(
box_for_unclip
,
det_db_unclip_ratio
);
if
(
points
.
size
.
height
<
1.001
&&
points
.
size
.
width
<
1.001
)
{
continue
;
}
// end for unclip
cv
::
RotatedRect
clipbox
=
points
;
auto
cliparray
=
GetMiniBoxes
(
clipbox
,
ssid
);
if
(
ssid
<
min_size
+
2
)
continue
;
int
dest_width
=
pred
.
cols
;
int
dest_height
=
pred
.
rows
;
std
::
vector
<
std
::
vector
<
int
>>
intcliparray
;
for
(
int
num_pt
=
0
;
num_pt
<
4
;
num_pt
++
)
{
std
::
vector
<
int
>
a
{
int
(
clampf
(
roundf
(
cliparray
[
num_pt
][
0
]
/
float
(
width
)
*
float
(
dest_width
)),
0
,
float
(
dest_width
))),
int
(
clampf
(
roundf
(
cliparray
[
num_pt
][
1
]
/
float
(
height
)
*
float
(
dest_height
)),
0
,
float
(
dest_height
)))};
intcliparray
.
push_back
(
a
);
}
boxes
.
push_back
(
intcliparray
);
}
// end for
return
boxes
;
}
std
::
vector
<
std
::
vector
<
std
::
vector
<
int
>>>
PostProcessor
::
FilterTagDetRes
(
std
::
vector
<
std
::
vector
<
std
::
vector
<
int
>>>
boxes
,
float
ratio_h
,
float
ratio_w
,
cv
::
Mat
srcimg
)
{
int
oriimg_h
=
srcimg
.
rows
;
int
oriimg_w
=
srcimg
.
cols
;
std
::
vector
<
std
::
vector
<
std
::
vector
<
int
>>>
root_points
;
for
(
int
n
=
0
;
n
<
boxes
.
size
();
n
++
)
{
boxes
[
n
]
=
OrderPointsClockwise
(
boxes
[
n
]);
for
(
int
m
=
0
;
m
<
boxes
[
0
].
size
();
m
++
)
{
boxes
[
n
][
m
][
0
]
/=
ratio_w
;
boxes
[
n
][
m
][
1
]
/=
ratio_h
;
boxes
[
n
][
m
][
0
]
=
int
(
_min
(
_max
(
boxes
[
n
][
m
][
0
],
0
),
oriimg_w
-
1
));
boxes
[
n
][
m
][
1
]
=
int
(
_min
(
_max
(
boxes
[
n
][
m
][
1
],
0
),
oriimg_h
-
1
));
}
}
for
(
int
n
=
0
;
n
<
boxes
.
size
();
n
++
)
{
int
rect_width
,
rect_height
;
rect_width
=
int
(
sqrt
(
pow
(
boxes
[
n
][
0
][
0
]
-
boxes
[
n
][
1
][
0
],
2
)
+
pow
(
boxes
[
n
][
0
][
1
]
-
boxes
[
n
][
1
][
1
],
2
)));
rect_height
=
int
(
sqrt
(
pow
(
boxes
[
n
][
0
][
0
]
-
boxes
[
n
][
3
][
0
],
2
)
+
pow
(
boxes
[
n
][
0
][
1
]
-
boxes
[
n
][
3
][
1
],
2
)));
if
(
rect_width
<=
4
||
rect_height
<=
4
)
continue
;
root_points
.
push_back
(
boxes
[
n
]);
}
return
root_points
;
}
}
// namespace PaddleOCR
deploy/cpp_infer/src_system/preprocess_op.cpp
0 → 100644
View file @
4a182a89
// 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.
#include "opencv2/core.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/imgproc.hpp"
#include "paddle_api.h"
#include "paddle_inference_api.h"
#include <chrono>
#include <iomanip>
#include <iostream>
#include <ostream>
#include <vector>
#include <cstring>
#include <fstream>
#include <numeric>
#include <include/preprocess_op.h>
namespace
PaddleOCR
{
void
Permute
::
Run
(
const
cv
::
Mat
*
im
,
float
*
data
)
{
int
rh
=
im
->
rows
;
int
rw
=
im
->
cols
;
int
rc
=
im
->
channels
();
for
(
int
i
=
0
;
i
<
rc
;
++
i
)
{
cv
::
extractChannel
(
*
im
,
cv
::
Mat
(
rh
,
rw
,
CV_32FC1
,
data
+
i
*
rh
*
rw
),
i
);
}
}
void
Normalize
::
Run
(
cv
::
Mat
*
im
,
const
std
::
vector
<
float
>
&
mean
,
const
std
::
vector
<
float
>
&
scale
,
const
bool
is_scale
)
{
double
e
=
1.0
;
if
(
is_scale
)
{
e
/=
255.0
;
}
(
*
im
).
convertTo
(
*
im
,
CV_32FC3
,
e
);
std
::
vector
<
cv
::
Mat
>
bgr_channels
(
3
);
cv
::
split
(
*
im
,
bgr_channels
);
for
(
auto
i
=
0
;
i
<
bgr_channels
.
size
();
i
++
)
{
bgr_channels
[
i
].
convertTo
(
bgr_channels
[
i
],
CV_32FC1
,
1.0
*
scale
[
i
],
(
0.0
-
mean
[
i
])
*
scale
[
i
]);
}
cv
::
merge
(
bgr_channels
,
*
im
);
}
void
ResizeImgType0
::
Run
(
const
cv
::
Mat
&
img
,
cv
::
Mat
&
resize_img
,
int
max_size_len
,
float
&
ratio_h
,
float
&
ratio_w
,
bool
use_tensorrt
)
{
int
w
=
img
.
cols
;
int
h
=
img
.
rows
;
float
ratio
=
1.
f
;
int
max_wh
=
w
>=
h
?
w
:
h
;
if
(
max_wh
>
max_size_len
)
{
if
(
h
>
w
)
{
ratio
=
float
(
max_size_len
)
/
float
(
h
);
}
else
{
ratio
=
float
(
max_size_len
)
/
float
(
w
);
}
}
int
resize_h
=
int
(
float
(
h
)
*
ratio
);
int
resize_w
=
int
(
float
(
w
)
*
ratio
);
resize_h
=
max
(
int
(
round
(
float
(
resize_h
)
/
32
)
*
32
),
32
);
resize_w
=
max
(
int
(
round
(
float
(
resize_w
)
/
32
)
*
32
),
32
);
cv
::
resize
(
img
,
resize_img
,
cv
::
Size
(
resize_w
,
resize_h
));
ratio_h
=
float
(
resize_h
)
/
float
(
h
);
ratio_w
=
float
(
resize_w
)
/
float
(
w
);
}
void
CrnnResizeImg
::
Run
(
const
cv
::
Mat
&
img
,
cv
::
Mat
&
resize_img
,
float
wh_ratio
,
bool
use_tensorrt
,
const
std
::
vector
<
int
>
&
rec_image_shape
)
{
int
imgC
,
imgH
,
imgW
;
imgC
=
rec_image_shape
[
0
];
imgH
=
rec_image_shape
[
1
];
imgW
=
rec_image_shape
[
2
];
imgW
=
int
(
32
*
wh_ratio
);
float
ratio
=
float
(
img
.
cols
)
/
float
(
img
.
rows
);
int
resize_w
,
resize_h
;
if
(
ceilf
(
imgH
*
ratio
)
>
imgW
)
resize_w
=
imgW
;
else
resize_w
=
int
(
ceilf
(
imgH
*
ratio
));
cv
::
resize
(
img
,
resize_img
,
cv
::
Size
(
resize_w
,
imgH
),
0.
f
,
0.
f
,
cv
::
INTER_LINEAR
);
cv
::
copyMakeBorder
(
resize_img
,
resize_img
,
0
,
0
,
0
,
int
(
imgW
-
resize_img
.
cols
),
cv
::
BORDER_CONSTANT
,
{
127
,
127
,
127
});
}
void
ClsResizeImg
::
Run
(
const
cv
::
Mat
&
img
,
cv
::
Mat
&
resize_img
,
bool
use_tensorrt
,
const
std
::
vector
<
int
>
&
rec_image_shape
)
{
int
imgC
,
imgH
,
imgW
;
imgC
=
rec_image_shape
[
0
];
imgH
=
rec_image_shape
[
1
];
imgW
=
rec_image_shape
[
2
];
float
ratio
=
float
(
img
.
cols
)
/
float
(
img
.
rows
);
int
resize_w
,
resize_h
;
if
(
ceilf
(
imgH
*
ratio
)
>
imgW
)
resize_w
=
imgW
;
else
resize_w
=
int
(
ceilf
(
imgH
*
ratio
));
cv
::
resize
(
img
,
resize_img
,
cv
::
Size
(
resize_w
,
imgH
),
0.
f
,
0.
f
,
cv
::
INTER_LINEAR
);
if
(
resize_w
<
imgW
)
{
cv
::
copyMakeBorder
(
resize_img
,
resize_img
,
0
,
0
,
0
,
imgW
-
resize_w
,
cv
::
BORDER_CONSTANT
,
cv
::
Scalar
(
0
,
0
,
0
));
}
}
}
// namespace PaddleOCR
deploy/cpp_infer/src_system/utility.cpp
0 → 100644
View file @
4a182a89
// 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.
#include <dirent.h>
#include <include/utility.h>
#include <iostream>
#include <ostream>
#include <sys/stat.h>
#include <sys/types.h>
#include <vector>
namespace
PaddleOCR
{
std
::
vector
<
std
::
string
>
Utility
::
ReadDict
(
const
std
::
string
&
path
)
{
std
::
ifstream
in
(
path
);
std
::
string
line
;
std
::
vector
<
std
::
string
>
m_vec
;
if
(
in
)
{
while
(
getline
(
in
,
line
))
{
m_vec
.
push_back
(
line
);
}
}
else
{
std
::
cout
<<
"no such label file: "
<<
path
<<
", exit the program..."
<<
std
::
endl
;
exit
(
1
);
}
return
m_vec
;
}
void
Utility
::
VisualizeBboxes
(
const
cv
::
Mat
&
srcimg
,
const
std
::
vector
<
std
::
vector
<
std
::
vector
<
int
>>>
&
boxes
)
{
cv
::
Mat
img_vis
;
srcimg
.
copyTo
(
img_vis
);
for
(
int
n
=
0
;
n
<
boxes
.
size
();
n
++
)
{
cv
::
Point
rook_points
[
4
];
for
(
int
m
=
0
;
m
<
boxes
[
n
].
size
();
m
++
)
{
rook_points
[
m
]
=
cv
::
Point
(
int
(
boxes
[
n
][
m
][
0
]),
int
(
boxes
[
n
][
m
][
1
]));
}
const
cv
::
Point
*
ppt
[
1
]
=
{
rook_points
};
int
npt
[]
=
{
4
};
cv
::
polylines
(
img_vis
,
ppt
,
npt
,
1
,
1
,
CV_RGB
(
0
,
255
,
0
),
2
,
8
,
0
);
}
cv
::
imwrite
(
"./ocr_vis.png"
,
img_vis
);
std
::
cout
<<
"The detection visualized image saved in ./ocr_vis.png"
<<
std
::
endl
;
}
// list all files under a directory
void
Utility
::
GetAllFiles
(
const
char
*
dir_name
,
std
::
vector
<
std
::
string
>
&
all_inputs
)
{
if
(
NULL
==
dir_name
)
{
std
::
cout
<<
" dir_name is null ! "
<<
std
::
endl
;
return
;
}
struct
stat
s
;
lstat
(
dir_name
,
&
s
);
if
(
!
S_ISDIR
(
s
.
st_mode
))
{
std
::
cout
<<
"dir_name is not a valid directory !"
<<
std
::
endl
;
all_inputs
.
push_back
(
dir_name
);
return
;
}
else
{
struct
dirent
*
filename
;
// return value for readdir()
DIR
*
dir
;
// return value for opendir()
dir
=
opendir
(
dir_name
);
if
(
NULL
==
dir
)
{
std
::
cout
<<
"Can not open dir "
<<
dir_name
<<
std
::
endl
;
return
;
}
std
::
cout
<<
"Successfully opened the dir !"
<<
std
::
endl
;
while
((
filename
=
readdir
(
dir
))
!=
NULL
)
{
if
(
strcmp
(
filename
->
d_name
,
"."
)
==
0
||
strcmp
(
filename
->
d_name
,
".."
)
==
0
)
continue
;
// img_dir + std::string("/") + all_inputs[0];
all_inputs
.
push_back
(
dir_name
+
std
::
string
(
"/"
)
+
std
::
string
(
filename
->
d_name
));
}
}
}
}
// namespace PaddleOCR
\ No newline at end of file
deploy/cpp_infer/tools/build.sh
View file @
4a182a89
OPENCV_DIR
=
your_opencv_dir
set
-o
errexit
LIB_DIR
=
your_paddle_inference_dir
CUDA_LIB_DIR
=
your_cuda_lib_dir
if
[
$#
!=
1
]
;
then
CUDNN_LIB_DIR
=
your_cudnn_lib_dir
echo
"USAGE:
$0
MODE (one of ['det', 'rec', 'system'])"
echo
" e.g.:
$0
system"
exit
1
;
fi
# MODE be one of ['det', 'rec', 'system']
MODE
=
$1
cp
CMakeLists_
$MODE
.txt CMakeLists.txt
OPENCV_DIR
=
/paddle/git/new/PaddleOCR/deploy/cpp_infer/opencv-3.4.7/opencv3/
LIB_DIR
=
/paddle/git/new/PaddleOCR/deploy/cpp_infer/paddle_inference/
CUDA_LIB_DIR
=
/usr/local/cuda/lib64/
CUDNN_LIB_DIR
=
/usr/lib/x86_64-linux-gnu/
BUILD_DIR
=
build
BUILD_DIR
=
build
rm
-rf
${
BUILD_DIR
}
rm
-rf
${
BUILD_DIR
}
...
...
Prev
1
2
Next
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment