二维码解码库
在 C++ 生态中,常见的二维码解码库有:
- libdecodeqr 多年未更新
- ZBar 多年未更新,
- zxing-cpp 官方 ZXing(Java)的高质量 C++ 移植,由专业团队维护;
- opencv4 QRCodeDetector (对opencv 有版本要求)
测试
基于opencv
c
import cv2
import numpy as np
import argparse
import os
def enhance_image(img):
if len(img.shape) == 3:
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
else:
gray = img.copy()
clahe = cv2.createCLAHE(clipLimit=3.0, tileGridSize=(8, 8))
enhanced = clahe.apply(gray)
kernel = np.array([[0, -1, 0], [-1, 5, -1], [0, -1, 0]])
return cv2.filter2D(enhanced, -1, kernel)
def try_decode_opencv(img, scale=1.0):
if scale != 1.0:
h, w = img.shape[:2]
img = cv2.resize(img, (int(w * scale), int(h * scale)))
detector = cv2.QRCodeDetector()
data, points, _ = detector.detectAndDecode(img)
if data:
if scale != 1.0 and points is not None:
points = points / scale
return data, points
return None, None
def decode_qr_robust(img):
strategies = [
("original", lambda: try_decode_opencv(img, 1.0)),
("enhanced", lambda: try_decode_opencv(enhance_image(img), 1.0)),
("scale_1.5x", lambda: try_decode_opencv(img, 1.5)),
("scale_2x", lambda: try_decode_opencv(img, 2.0)),
]
for name, func in strategies:
try:
data, points = func()
if data:
print(f"✅ 成功 ({name}): {data}")
return data, points
except Exception as e:
continue
print("❌ 解码失败")
return None, None
def draw_result(img, points, text):
out = img.copy()
if points is not None:
pts = points.reshape((-1, 1, 2)).astype(np.int32)
cv2.polylines(out, [pts], True, (0, 255, 0), 2)
txt = text[:50] + "..." if len(text) > 50 else text
# txt = text
# print(pts.shape)
x = int(pts[0][0][0])
y = int(pts[0][0][1]) - 20
cv2.putText(out, txt, (20, y), cv2.FONT_HERSHEY_COMPLEX, 1, (0, 0, 255), 2, cv2.LINE_AA)
return out
def test_image(path):
img = cv2.imread(path)
if img is None:
print("❌ 图像读取失败")
return
data, points = decode_qr_robust(img)
if data:
out = draw_result(img, points, data)
out_path = path.replace(".", "_decoded.")
cv2.imwrite(out_path, out)
print(f"🖼️ 保存结果: {out_path}")
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("--image", required=True)
args = parser.parse_args()
test_image(args.image)

基于zxing-cpp
c
git clone https://github.com/zxing-cpp/zxing-cpp.git
cd zxing-cpp
mkdir build
cd build
cmake ..
make
官方自带测试用例:zxing-cpp/example
为了快速测试,直接基于zxing-cpp/example/ZXingOpenCV.cpp 修改下,增加支持读图片:
c
int main(int argc, char* argv[])
{
Mat image;
// 读取图片
std::string imagePath = argv[1];
image = imread(imagePath);
if (image.empty()) {
std::cerr << "❌ 无法读取图像: " << imagePath << std::endl;
return -1;
}
std::cout << "🖼️ 正在解码图像: " << imagePath << std::endl;
int64 t0 = cv::getTickCount();
auto barcodes = ReadBarcodes(image);
// ⏱️ 结束计时
double t_ms = (cv::getTickCount() - t0) / cv::getTickFrequency() * 1000;
std::cout << "⏱️ 解码耗时: " << t_ms << " ms" << std::endl;
// 绘制结果
bool found = false;
for (auto& barcode : barcodes) {
if (barcode.isValid()) {
std::cout << "✅ 解码成功: " << barcode.text() << std::endl;
DrawBarcode(image, barcode);
found = true;
}
}
if (found)
{
// 可选:保存结果
imwrite("decoded_output.jpg", image);
std::cout << "💾 结果已保存为 decoded_output.jpg" << std::endl;
}else
{
std::cout << "❌ 未检测到有效二维码" << std::endl;
}
return 0;
}
