Soham Kalburgi commited on
Commit
41b75c4
·
1 Parent(s): 9b5a5a4

feat: add cpp demo for wechatqrcode (#279)

Browse files

* feat: add cpp demo for wechatqrcode

* refactor: change to class based

* fix: make cpp11 compatible

* fix: add opencv_contrib in readme

Files changed (3) hide show
  1. CMakeLists.txt +11 -0
  2. README.md +19 -0
  3. demo.cpp +192 -0
CMakeLists.txt ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ cmake_minimum_required(VERSION 3.24.0)
2
+ project(opencv_zoo_qrcode_wechatqrcode)
3
+
4
+ set(OPENCV_VERSION "4.10.0")
5
+ set(OPENCV_INSTALLATION_PATH "" CACHE PATH "Where to look for OpenCV installation")
6
+
7
+ # Find OpenCV
8
+ find_package(OpenCV ${OPENCV_VERSION} REQUIRED HINTS ${OPENCV_INSTALLATION_PATH})
9
+
10
+ add_executable(demo demo.cpp)
11
+ target_link_libraries(demo ${OpenCV_LIBS})
README.md CHANGED
@@ -9,6 +9,8 @@ Notes:
9
 
10
  ## Demo
11
 
 
 
12
  Run the following command to try the demo:
13
 
14
  ```shell
@@ -21,6 +23,23 @@ python demo.py --input /path/to/image -v
21
  python demo.py --help
22
  ```
23
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
  ### Example outputs
25
 
26
  ![webcam demo](./example_outputs/wechat_qrcode_demo.gif)
 
9
 
10
  ## Demo
11
 
12
+ ### Python
13
+
14
  Run the following command to try the demo:
15
 
16
  ```shell
 
23
  python demo.py --help
24
  ```
25
 
26
+ ### C++
27
+
28
+ Install latest OpenCV (with opencv_contrib) and CMake >= 3.24.0 to get started with:
29
+
30
+ ```shell
31
+ # A typical and default installation path of OpenCV is /usr/local
32
+ cmake -B build -D OPENCV_INSTALLATION_PATH=/path/to/opencv/installation .
33
+ cmake --build build
34
+
35
+ # detect on camera input
36
+ ./build/demo
37
+ # detect on an image
38
+ ./build/demo -i=/path/to/image -v
39
+ # get help messages
40
+ ./build/demo -h
41
+ ```
42
+
43
  ### Example outputs
44
 
45
  ![webcam demo](./example_outputs/wechat_qrcode_demo.gif)
demo.cpp ADDED
@@ -0,0 +1,192 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #include <iostream>
2
+ #include <opencv2/opencv.hpp>
3
+ #include <opencv2/wechat_qrcode.hpp>
4
+ #include <string>
5
+ #include <vector>
6
+
7
+ class WeChatQRCode {
8
+ public:
9
+ WeChatQRCode(const std::string& detect_prototxt,
10
+ const std::string& detect_model,
11
+ const std::string& sr_prototxt, const std::string& sr_model,
12
+ int backend_target_index)
13
+ : backend_target_index_(backend_target_index) {
14
+
15
+ const std::vector<std::pair<int, int>> backend_target_pairs = {
16
+ {cv::dnn::DNN_BACKEND_OPENCV, cv::dnn::DNN_TARGET_CPU},
17
+ {cv::dnn::DNN_BACKEND_CUDA, cv::dnn::DNN_TARGET_CUDA},
18
+ {cv::dnn::DNN_BACKEND_CUDA, cv::dnn::DNN_TARGET_CUDA_FP16},
19
+ {cv::dnn::DNN_BACKEND_TIMVX, cv::dnn::DNN_TARGET_NPU},
20
+ {cv::dnn::DNN_BACKEND_CANN, cv::dnn::DNN_TARGET_NPU}};
21
+
22
+ if (backend_target_index_ < 0 ||
23
+ backend_target_index_ >= backend_target_pairs.size()) {
24
+ throw std::invalid_argument("Invalid backend-target index");
25
+ }
26
+
27
+ // initialize detector
28
+ detector_ = cv::makePtr<cv::wechat_qrcode::WeChatQRCode>(
29
+ detect_prototxt, detect_model, sr_prototxt, sr_model);
30
+ }
31
+
32
+ std::pair<std::vector<std::string>, std::vector<cv::Mat>> detect(
33
+ const cv::Mat& image) {
34
+ std::vector<std::string> results;
35
+ std::vector<cv::Mat> points;
36
+ results = detector_->detectAndDecode(image, points);
37
+ return {results, points};
38
+ }
39
+
40
+ cv::Mat visualize(const cv::Mat& image,
41
+ const std::vector<std::string>& results,
42
+ const std::vector<cv::Mat>& points,
43
+ cv::Scalar points_color = cv::Scalar(0, 255, 0),
44
+ cv::Scalar text_color = cv::Scalar(0, 255, 0),
45
+ double fps = -1) const {
46
+ cv::Mat output = image.clone();
47
+
48
+ if (fps >= 0) {
49
+ cv::putText(output, "FPS: " + std::to_string(fps), cv::Point(0, 15),
50
+ cv::FONT_HERSHEY_SIMPLEX, 0.5, text_color);
51
+ }
52
+
53
+ double fontScale = 0.5;
54
+ int fontSize = 1;
55
+
56
+ for (size_t i = 0; i < results.size(); ++i) {
57
+ const auto& p = points[i];
58
+
59
+ for (int r = 0; r < p.rows; ++r) {
60
+ cv::Point point(p.at<float>(r, 0), p.at<float>(r, 1));
61
+ cv::circle(output, point, 10, points_color, -1);
62
+ }
63
+
64
+ int qrcode_center_x = (p.at<float>(0, 0) + p.at<float>(2, 0)) / 2;
65
+ int qrcode_center_y = (p.at<float>(0, 1) + p.at<float>(2, 1)) / 2;
66
+
67
+ int baseline = 0;
68
+ cv::Size text_size =
69
+ cv::getTextSize(results[i], cv::FONT_HERSHEY_DUPLEX, fontScale,
70
+ fontSize, &baseline);
71
+
72
+ cv::Point text_pos(qrcode_center_x - text_size.width / 2,
73
+ qrcode_center_y + text_size.height / 2);
74
+
75
+ cv::putText(output, results[i], text_pos, cv::FONT_HERSHEY_DUPLEX,
76
+ fontScale, text_color, fontSize);
77
+ }
78
+
79
+ return output;
80
+ }
81
+
82
+ private:
83
+ int backend_target_index_;
84
+ cv::Ptr<cv::wechat_qrcode::WeChatQRCode> detector_;
85
+ };
86
+
87
+ int main(int argc, char** argv) {
88
+
89
+ cv::CommandLineParser parser(
90
+ argc, argv,
91
+ "{help h | | Show this help message.}"
92
+ "{input i | | Set path to the input image. Omit for using default camera.}"
93
+ "{detect_prototxt_path | detect_2021nov.prototxt | Set path to detect.prototxt.}"
94
+ "{detect_model_path | detect_2021nov.caffemodel | Set path to detect.caffemodel.}"
95
+ "{sr_prototxt_path | sr_2021nov.prototxt | Set path to sr.prototxt.}"
96
+ "{sr_model_path | sr_2021nov.caffemodel | Set path to sr.caffemodel.}"
97
+ "{backend_target bt | 0 | Choose one of the backend-target pairs to run this demo.}"
98
+ "{save s | false | Specify to save file with results.}"
99
+ "{vis v | false | Specify to open a new window to show results.}");
100
+
101
+ if (parser.has("help")) {
102
+ parser.printMessage();
103
+ return 0;
104
+ }
105
+
106
+ // get paths
107
+ std::string detect_prototxt = parser.get<std::string>("detect_prototxt_path");
108
+ std::string detect_model = parser.get<std::string>("detect_model_path");
109
+ std::string sr_prototxt = parser.get<std::string>("sr_prototxt_path");
110
+ std::string sr_model = parser.get<std::string>("sr_model_path");
111
+ int backend_target_index = parser.get<int>("backend_target");
112
+
113
+ // input check
114
+ std::string input_path = parser.get<std::string>("input");
115
+ bool save_result = parser.get<bool>("save");
116
+ bool visualize_result = parser.get<bool>("vis");
117
+
118
+ try {
119
+ WeChatQRCode qrDetector(detect_prototxt, detect_model, sr_prototxt,
120
+ sr_model, backend_target_index);
121
+
122
+ if (!input_path.empty()) {
123
+ // process image
124
+ cv::Mat image = cv::imread(input_path);
125
+ if (image.empty()) {
126
+ std::cerr << "Could not read the image" << std::endl;
127
+ return -1;
128
+ }
129
+
130
+ std::pair<std::vector<std::string>, std::vector<cv::Mat>> detectionResult = qrDetector.detect(image);
131
+ auto& results = detectionResult.first;
132
+ auto& points = detectionResult.second;
133
+
134
+ for (const auto& result : results) {
135
+ std::cout << result << std::endl;
136
+ }
137
+
138
+ cv::Mat result_image = qrDetector.visualize(image, results, points);
139
+
140
+ if (save_result) {
141
+ cv::imwrite("result.jpg", result_image);
142
+ std::cout << "Results saved to result.jpg" << std::endl;
143
+ }
144
+
145
+ if (visualize_result) {
146
+ cv::imshow(input_path, result_image);
147
+ cv::waitKey(0);
148
+ }
149
+ } else {
150
+ // process camera
151
+ cv::VideoCapture cap(0);
152
+ if (!cap.isOpened()) {
153
+ std::cerr << "Error opening camera" << std::endl;
154
+ return -1;
155
+ }
156
+
157
+ cv::Mat frame;
158
+ cv::TickMeter tm;
159
+
160
+ while (true) {
161
+ cap >> frame;
162
+ if (frame.empty()) {
163
+ std::cout << "No frames grabbed" << std::endl;
164
+ break;
165
+ }
166
+
167
+ std::pair<std::vector<std::string>, std::vector<cv::Mat>> detectionResult = qrDetector.detect(frame);
168
+ auto& results = detectionResult.first;
169
+ auto& points = detectionResult.second;
170
+
171
+ tm.start();
172
+ double fps = tm.getFPS();
173
+ tm.stop();
174
+
175
+ cv::Mat result_frame = qrDetector.visualize(
176
+ frame, results, points, cv::Scalar(0, 255, 0),
177
+ cv::Scalar(0, 255, 0), fps);
178
+ cv::imshow("WeChatQRCode Demo", result_frame);
179
+
180
+ tm.reset();
181
+
182
+ if (cv::waitKey(1) >= 0) break;
183
+ }
184
+ }
185
+
186
+ } catch (const std::exception& ex) {
187
+ std::cerr << "Error: " << ex.what() << std::endl;
188
+ return -1;
189
+ }
190
+
191
+ return 0;
192
+ }