Skip to content

Commit 1042848

Browse files
committed
feat: add cpp demo for wechatqrcode
1 parent 807f45b commit 1042848

File tree

3 files changed

+204
-0
lines changed

3 files changed

+204
-0
lines changed
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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})

models/qrcode_wechatqrcode/README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ Notes:
99

1010
## Demo
1111

12+
### Python
13+
1214
Run the following command to try the demo:
1315

1416
```shell
@@ -21,6 +23,23 @@ python demo.py --input /path/to/image -v
2123
python demo.py --help
2224
```
2325

26+
### C++
27+
28+
Install latest OpenCV 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+
2443
### Example outputs
2544

2645
![webcam demo](./example_outputs/wechat_qrcode_demo.gif)

models/qrcode_wechatqrcode/demo.cpp

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
#include <iostream>
2+
#include <opencv2/opencv.hpp>
3+
#include <opencv2/wechat_qrcode.hpp>
4+
#include <string>
5+
#include <vector>
6+
7+
// function to visualize QR code detection results
8+
cv::Mat visualize(cv::Mat image, const std::vector<std::string>& results,
9+
const std::vector<cv::Mat>& points,
10+
cv::Scalar points_color = cv::Scalar(0, 255, 0),
11+
cv::Scalar text_color = cv::Scalar(0, 255, 0),
12+
double fps = -1) {
13+
cv::Mat output = image.clone();
14+
15+
if (fps >= 0) {
16+
cv::putText(output, "FPS: " + std::to_string(fps), cv::Point(0, 15),
17+
cv::FONT_HERSHEY_SIMPLEX, 0.5, text_color);
18+
}
19+
20+
double fontScale = 0.5;
21+
int fontSize = 1;
22+
23+
for (size_t i = 0; i < results.size(); ++i) {
24+
const auto& p = points[i];
25+
26+
// iterate through the mat to access points
27+
for (int r = 0; r < p.rows; ++r) {
28+
cv::Point point(p.at<float>(r, 0), p.at<float>(r, 1));
29+
cv::circle(output, point, 10, points_color, -1);
30+
}
31+
32+
// calculate QR code center
33+
int qrcode_center_x = (p.at<float>(0, 0) + p.at<float>(2, 0)) / 2;
34+
int qrcode_center_y = (p.at<float>(0, 1) + p.at<float>(2, 1)) / 2;
35+
36+
// get text size
37+
int baseline = 0;
38+
cv::Size text_size =
39+
cv::getTextSize(results[i], cv::FONT_HERSHEY_DUPLEX, fontScale,
40+
fontSize, &baseline);
41+
42+
// position text at the center of QR code
43+
cv::Point text_pos(qrcode_center_x - text_size.width / 2,
44+
qrcode_center_y + text_size.height / 2);
45+
46+
// draw text
47+
cv::putText(output, results[i], text_pos, cv::FONT_HERSHEY_DUPLEX,
48+
fontScale, text_color, fontSize);
49+
}
50+
51+
return output;
52+
}
53+
54+
int main(int argc, char** argv) {
55+
// argument parsing
56+
cv::CommandLineParser parser(
57+
argc, argv,
58+
"{help h | | Show this help message.}"
59+
"{input i | | Set path to the input image. Omit for using default camera.}"
60+
"{detect_prototxt_path | detect_2021nov.prototxt | Set path to detect.prototxt.}"
61+
"{detect_model_path | detect_2021nov.caffemodel | Set path to detect.caffemodel.}"
62+
"{sr_model_path | sr_2021nov.caffemodel | Set path to sr.caffemodel.}"
63+
"{backend_target bt | 0 | Choose one of the backend-target pairs to run this demo.}"
64+
"{save s | false | Specify to save file with results (i.e. bounding box, confidence level). Invalid in case of camera input.}"
65+
"{vis v | false | Specify to open a new window to show results. Invalid in case of camera input.}");
66+
67+
if (parser.has("help")) {
68+
parser.printMessage();
69+
return 0;
70+
}
71+
72+
// backend-target pairs
73+
const std::vector<std::pair<int, int>> backend_target_pairs = {
74+
{cv::dnn::DNN_BACKEND_OPENCV, cv::dnn::DNN_TARGET_CPU},
75+
{cv::dnn::DNN_BACKEND_CUDA, cv::dnn::DNN_TARGET_CUDA},
76+
{cv::dnn::DNN_BACKEND_CUDA, cv::dnn::DNN_TARGET_CUDA_FP16},
77+
{cv::dnn::DNN_BACKEND_TIMVX, cv::dnn::DNN_TARGET_NPU},
78+
{cv::dnn::DNN_BACKEND_CANN, cv::dnn::DNN_TARGET_NPU}};
79+
80+
// get backend-target from arguments
81+
int backend_target_index = parser.get<int>("backend_target");
82+
if (backend_target_index < 0 ||
83+
backend_target_index >= backend_target_pairs.size()) {
84+
std::cerr << "Invalid backend-target index" << std::endl;
85+
return -1;
86+
}
87+
88+
// get paths
89+
std::string detect_prototxt = parser.get<std::string>("detect_prototxt_path");
90+
std::string detect_model = parser.get<std::string>("detect_model_path");
91+
std::string sr_prototxt = parser.get<std::string>("sr_prototxt_path");
92+
std::string sr_model = parser.get<std::string>("sr_model_path");
93+
94+
// initialize wechatqrcode detector
95+
cv::Ptr<cv::wechat_qrcode::WeChatQRCode> detector =
96+
cv::makePtr<cv::wechat_qrcode::WeChatQRCode>(
97+
detect_prototxt, detect_model, sr_prototxt, sr_model);
98+
99+
// check if input is specified
100+
std::string input_path = parser.get<std::string>("input");
101+
bool save_result = parser.get<bool>("save");
102+
bool visualize_result = parser.get<bool>("vis");
103+
104+
if (!input_path.empty()) {
105+
// image processing
106+
cv::Mat image = cv::imread(input_path);
107+
if (image.empty()) {
108+
std::cerr << "Could not read the image" << std::endl;
109+
return -1;
110+
}
111+
112+
std::vector<std::string> results;
113+
std::vector<cv::Mat> points;
114+
results = detector->detectAndDecode(image, points);
115+
116+
for (const auto& result : results) {
117+
std::cout << result << std::endl;
118+
}
119+
120+
// visualize results
121+
cv::Mat result_image = visualize(image, results, points);
122+
123+
// save results if requested
124+
if (save_result) {
125+
cv::imwrite("result.jpg", result_image);
126+
std::cout << "Results saved to result.jpg" << std::endl;
127+
}
128+
129+
// show visualization if requested
130+
if (visualize_result) {
131+
cv::imshow(input_path, result_image);
132+
cv::waitKey(0);
133+
}
134+
} else {
135+
// camera processing
136+
cv::VideoCapture cap(0);
137+
if (!cap.isOpened()) {
138+
std::cerr << "Error opening camera" << std::endl;
139+
return -1;
140+
}
141+
142+
cv::Mat frame;
143+
cv::TickMeter tm;
144+
145+
while (true) {
146+
cap >> frame;
147+
if (frame.empty()) {
148+
std::cout << "No frames grabbed" << std::endl;
149+
break;
150+
}
151+
152+
std::vector<std::string> results;
153+
std::vector<cv::Mat> points;
154+
155+
tm.start();
156+
results = detector->detectAndDecode(frame, points);
157+
tm.stop();
158+
159+
double fps = tm.getFPS();
160+
161+
// visualize results
162+
cv::Mat result_frame =
163+
visualize(frame, results, points, cv::Scalar(0, 255, 0),
164+
cv::Scalar(0, 255, 0), fps);
165+
cv::imshow("WeChatQRCode Demo", result_frame);
166+
167+
tm.reset();
168+
169+
if (cv::waitKey(1) >= 0) break;
170+
}
171+
}
172+
173+
return 0;
174+
}

0 commit comments

Comments
 (0)