Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Tetragramm
GitHub Repository: Tetragramm/opencv
Path: blob/master/samples/dnn/text_detection.cpp
16337 views
1
#include <opencv2/imgproc.hpp>
2
#include <opencv2/highgui.hpp>
3
#include <opencv2/dnn.hpp>
4
5
using namespace cv;
6
using namespace cv::dnn;
7
8
const char* keys =
9
"{ help h | | Print help message. }"
10
"{ input i | | Path to input image or video file. Skip this argument to capture frames from a camera.}"
11
"{ model m | | Path to a binary .pb file contains trained network.}"
12
"{ width | 320 | Preprocess input image by resizing to a specific width. It should be multiple by 32. }"
13
"{ height | 320 | Preprocess input image by resizing to a specific height. It should be multiple by 32. }"
14
"{ thr | 0.5 | Confidence threshold. }"
15
"{ nms | 0.4 | Non-maximum suppression threshold. }";
16
17
void decode(const Mat& scores, const Mat& geometry, float scoreThresh,
18
std::vector<RotatedRect>& detections, std::vector<float>& confidences);
19
20
int main(int argc, char** argv)
21
{
22
// Parse command line arguments.
23
CommandLineParser parser(argc, argv, keys);
24
parser.about("Use this script to run TensorFlow implementation (https://github.com/argman/EAST) of "
25
"EAST: An Efficient and Accurate Scene Text Detector (https://arxiv.org/abs/1704.03155v2)");
26
if (argc == 1 || parser.has("help"))
27
{
28
parser.printMessage();
29
return 0;
30
}
31
32
float confThreshold = parser.get<float>("thr");
33
float nmsThreshold = parser.get<float>("nms");
34
int inpWidth = parser.get<int>("width");
35
int inpHeight = parser.get<int>("height");
36
String model = parser.get<String>("model");
37
38
if (!parser.check())
39
{
40
parser.printErrors();
41
return 1;
42
}
43
44
CV_Assert(!model.empty());
45
46
// Load network.
47
Net net = readNet(model);
48
49
// Open a video file or an image file or a camera stream.
50
VideoCapture cap;
51
if (parser.has("input"))
52
cap.open(parser.get<String>("input"));
53
else
54
cap.open(0);
55
56
static const std::string kWinName = "EAST: An Efficient and Accurate Scene Text Detector";
57
namedWindow(kWinName, WINDOW_NORMAL);
58
59
std::vector<Mat> outs;
60
std::vector<String> outNames(2);
61
outNames[0] = "feature_fusion/Conv_7/Sigmoid";
62
outNames[1] = "feature_fusion/concat_3";
63
64
Mat frame, blob;
65
while (waitKey(1) < 0)
66
{
67
cap >> frame;
68
if (frame.empty())
69
{
70
waitKey();
71
break;
72
}
73
74
blobFromImage(frame, blob, 1.0, Size(inpWidth, inpHeight), Scalar(123.68, 116.78, 103.94), true, false);
75
net.setInput(blob);
76
net.forward(outs, outNames);
77
78
Mat scores = outs[0];
79
Mat geometry = outs[1];
80
81
// Decode predicted bounding boxes.
82
std::vector<RotatedRect> boxes;
83
std::vector<float> confidences;
84
decode(scores, geometry, confThreshold, boxes, confidences);
85
86
// Apply non-maximum suppression procedure.
87
std::vector<int> indices;
88
NMSBoxes(boxes, confidences, confThreshold, nmsThreshold, indices);
89
90
// Render detections.
91
Point2f ratio((float)frame.cols / inpWidth, (float)frame.rows / inpHeight);
92
for (size_t i = 0; i < indices.size(); ++i)
93
{
94
RotatedRect& box = boxes[indices[i]];
95
96
Point2f vertices[4];
97
box.points(vertices);
98
for (int j = 0; j < 4; ++j)
99
{
100
vertices[j].x *= ratio.x;
101
vertices[j].y *= ratio.y;
102
}
103
for (int j = 0; j < 4; ++j)
104
line(frame, vertices[j], vertices[(j + 1) % 4], Scalar(0, 255, 0), 1);
105
}
106
107
// Put efficiency information.
108
std::vector<double> layersTimes;
109
double freq = getTickFrequency() / 1000;
110
double t = net.getPerfProfile(layersTimes) / freq;
111
std::string label = format("Inference time: %.2f ms", t);
112
putText(frame, label, Point(0, 15), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 255, 0));
113
114
imshow(kWinName, frame);
115
}
116
return 0;
117
}
118
119
void decode(const Mat& scores, const Mat& geometry, float scoreThresh,
120
std::vector<RotatedRect>& detections, std::vector<float>& confidences)
121
{
122
detections.clear();
123
CV_Assert(scores.dims == 4); CV_Assert(geometry.dims == 4); CV_Assert(scores.size[0] == 1);
124
CV_Assert(geometry.size[0] == 1); CV_Assert(scores.size[1] == 1); CV_Assert(geometry.size[1] == 5);
125
CV_Assert(scores.size[2] == geometry.size[2]); CV_Assert(scores.size[3] == geometry.size[3]);
126
127
const int height = scores.size[2];
128
const int width = scores.size[3];
129
for (int y = 0; y < height; ++y)
130
{
131
const float* scoresData = scores.ptr<float>(0, 0, y);
132
const float* x0_data = geometry.ptr<float>(0, 0, y);
133
const float* x1_data = geometry.ptr<float>(0, 1, y);
134
const float* x2_data = geometry.ptr<float>(0, 2, y);
135
const float* x3_data = geometry.ptr<float>(0, 3, y);
136
const float* anglesData = geometry.ptr<float>(0, 4, y);
137
for (int x = 0; x < width; ++x)
138
{
139
float score = scoresData[x];
140
if (score < scoreThresh)
141
continue;
142
143
// Decode a prediction.
144
// Multiple by 4 because feature maps are 4 time less than input image.
145
float offsetX = x * 4.0f, offsetY = y * 4.0f;
146
float angle = anglesData[x];
147
float cosA = std::cos(angle);
148
float sinA = std::sin(angle);
149
float h = x0_data[x] + x2_data[x];
150
float w = x1_data[x] + x3_data[x];
151
152
Point2f offset(offsetX + cosA * x1_data[x] + sinA * x2_data[x],
153
offsetY - sinA * x1_data[x] + cosA * x2_data[x]);
154
Point2f p1 = Point2f(-sinA * h, -cosA * h) + offset;
155
Point2f p3 = Point2f(-cosA * w, sinA * w) + offset;
156
RotatedRect r(0.5f * (p1 + p3), Size2f(w, h), -angle * 180.0f / (float)CV_PI);
157
detections.push_back(r);
158
confidences.push_back(score);
159
}
160
}
161
}
162
163