当前位置: 首页 > news >正文

C++ + OpenCV + Tesseract 实现英文数字验证码识别

本文展示如何用 C++ 结合 OpenCV 做图像预处理,再调用 Tesseract OCR 识别验证码。适用于希望在高性能后端或本地服务里集成 OCR 的场景。方案包含:

环境与依赖安装

图像预处理(灰度、二值化、形态学去噪、放大)

使用 Tesseract API 调用(设定白名单、PSM)

完整 C++ 示例与 CMake 构建

批量识别、并发与部署建议

评估方法与常见问题排查

1 环境准备
1.1 安装系统依赖(Ubuntu 示例)
sudo apt update
sudo apt install -y build-essential cmake pkg-config git
sudo apt install -y libopencv-dev
sudo apt install -y tesseract-ocr libtesseract-dev libleptonica-dev

macOS(Homebrew):

brew install opencv tesseract

确保 pkg-config --modversion opencv4、tesseract --version 可用。

1.2 创建工程目录
captcha_cpp_ocr/
├── CMakeLists.txt
├── src/
│ └── main.cpp
└── samples/
└── captcha.png

2 图像预处理思路(为什么要预处理)

Tesseract 对清晰、对比高、字符分离的图像效果最好。典型预处理步骤:

放缩(resize)——放大小字体提高识别率

灰度化(cv::cvtColor)

高斯模糊(可选,用于去噪)

自适应/固定阈值二值化(cv::adaptiveThreshold 或 cv::threshold)

形态学操作(开/闭运算)去除噪点或断连字符

倾斜校正(如果需要)

3 完整 C++ 示例代码(main.cpp)

把以下文件保存为 src/main.cpp。

// main.cpp
// 依赖: OpenCV, Tesseract (libtesseract)
// 编译: 使用 CMake(见项目 CMakeLists.txt)

include

include

include

include

include <opencv2/opencv.hpp>

include <tesseract/baseapi.h>

include <leptonica/allheaders.h>

namespace fs = std::filesystem;

// ---------- 图像预处理函数 ----------
cv::Mat preprocess(const cv::Mat &src) {
cv::Mat gray;
if (src.channels() == 3) {
cv::cvtColor(src, gray, cv::COLOR_BGR2GRAY);
} else {
gray = src.clone();
}

// 放大 - 提高小字体识别率
const double scale = 2.0;
cv::Mat resized;
cv::resize(gray, resized, cv::Size(), scale, scale, cv::INTER_CUBIC);// 可选: 高斯去噪
cv::Mat blurred;
cv::GaussianBlur(resized, blurred, cv::Size(3, 3), 0);// 自适应阈值(二值化)
cv::Mat bw;
cv::adaptiveThreshold(blurred, bw, 255,cv::ADAPTIVE_THRESH_GAUSSIAN_C,cv::THRESH_BINARY_INV, 11, 2);// 形态学处理:先开运算去小噪点,再闭运算连接字符可能断裂边缘
cv::Mat morph;
cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(2,2));
cv::morphologyEx(bw, morph, cv::MORPH_OPEN, kernel);
cv::morphologyEx(morph, morph, cv::MORPH_CLOSE, kernel);// 可选: 再次去小区域噪点
std::vector<std::vector<cv::Point>> contours;
cv::findContours(morph.clone(), contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
for (auto &c : contours) {double area = cv::contourArea(c);if (area < 20) {cv::drawContours(morph, std::vector<std::vector<cv::Point>>{c}, -1, cv::Scalar(0), cv::FILLED);}
}// 最终返回二值图 - 转回白底黑字(Tesseract 对白底黑字通常表现更稳)
cv::Mat final;
cv::bitwise_not(morph, final); // invert to white background, black text
return final;

}

// ---------- 使用 Tesseract 识别单图 ----------
std::string recognizeWithTesseract(const cv::Mat &img, tesseract::TessBaseAPI &api) {
// 将 OpenCV Mat 转为 Pix*(Leptonica)
Pix *pix = pixCreate(img.cols, img.rows, 8);
for (int y = 0; y < img.rows; ++y) {
memcpy(pixGetData(pix) + y * pixGetWpl(pix) * 4, img.ptr(y), img.cols);
}
// 也可使用 pixReadMem or pixCreateHeader + pixSetData,以上为简化示例

api.SetImage(pix);
api.Recognize(0);
char *out = api.GetUTF8Text();
std::string result;
if (out) {result = std::string(out);delete[] out;
}
pixDestroy(&pix);
// 清理并返回
// 去掉换行与非字母数字字符
std::string cleaned;
for (char c : result) {if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'))cleaned.push_back(c);
}
return cleaned;

}

int main(int argc, char** argv) {
if (argc < 2) {
std::cout << "Usage: " << argv[0] << " <image_or_folder>\n";
return 1;
}

std::string path = argv[1];
tesseract::TessBaseAPI api;
// 初始化 tesseract:NULL 表示使用默认 TESSDATA_PREFIX 环境变量或安装路径
if (api.Init(NULL, "eng", tesseract::OEM_LSTM_ONLY)) {std::cerr << "Could not initialize tesseract.\n";return -1;
}
// 白名单:只识别大写字母和数字(根据需求调整)
api.SetVariable("tessedit_char_whitelist", "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789");
// 可设置页面分割模式:单行/单词等,常用 PSM_SINGLE_LINE 或 PSM_SINGLE_BLOCK
api.SetPageSegMode(tesseract::PSM_SINGLE_LINE);// 如果是文件夹,批量识别
fs::path p(path);
std::vector<fs::path> images;
if (fs::is_directory(p)) {for (auto &entry : fs::directory_iterator(p)) {if (!entry.is_regular_file()) continue;std::string ext = entry.path().extension().string();std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower);if (ext == ".png" || ext == ".jpg" || ext == ".jpeg" || ext == ".bmp") {images.push_back(entry.path());}}
} else {images.push_back(p);
}for (auto &imgPath : images) {cv::Mat src = cv::imread(imgPath.string());if (src.empty()) {std::cerr << "Failed to open " << imgPath << "\n";continue;}cv::Mat proc = preprocess(src);// 调试可视化:// cv::imshow("proc", proc); cv::waitKey(0);std::string text = recognizeWithTesseract(proc, api);std::cout << imgPath.filename().string() << " -> " << text << std::endl;
}api.End();
return 0;

}

说明:上面把 Pix 创建做了示意(简化),在实际工程中建议使用 pixCreateHeader + pixSetData 或将 Mat 保存为临时 PNG 再 pixRead。若要避免内存复制,参考 Leptonica 文档使用 pixCreateHeader 并设置数据指针,注意行对齐(wpl)和内存生命周期。

4 CMakeLists.txt(构建脚本)

创建项目根目录 CMakeLists.txt:

cmake_minimum_required(VERSION 3.10)
project(captcha_ocr)

set(CMAKE_CXX_STANDARD 17)
find_package(PkgConfig REQUIRED)
pkg_check_modules(OPENCV4 REQUIRED opencv4)
find_package(Tesseract REQUIRED)

include_directories(${OPENCV4_INCLUDE_DIRS})
link_directories(${OPENCV4_LIBRARY_DIRS})
add_definitions(${OPENCV4_CFLAGS_OTHER})

add_executable(captcha_ocr src/main.cpp)

target_link_libraries(captcha_ocr ${OPENCV4_LIBRARIES} tesseract lept)

5 构建与运行
mkdir build && cd build
cmake ..
make -j4

单张测试

./captcha_ocr ../samples/captcha.png

批量测试

./captcha_ocr ../samples/

http://www.wxhsa.cn/company.asp?id=5940

相关文章:

  • Hadoop伪分布式hbase学习
  • Redis源码学习 -- 基本数据结构 -- Quicklist - -蓝蜗牛
  • 动态修改线程池参数
  • 力扣70题 爬楼梯
  • PHP(Laravel)+ ImageMagick + Tesseract 实现验证码识别
  • Windows下使用python + opencv读取含中文路径的图片 和 把图片数据保存到含中文路径下
  • 黑白世界
  • 在 PHP 中,$_GET
  • 在 ThinkPHP DB
  • 什么是网络+HTTP详解
  • 快速管理win系统上的用户
  • redis实现全局唯一id
  • 表格识别技术:“唤醒”沉睡在纸质文档中的海量结构化数据
  • 【大三下】资料,仅内部学习使用
  • fastboot工具的常见命令
  • 《软件需求最佳实践》阅读笔记一
  • 挖掘PDF生成器中的SSRF漏洞:从发现到利用
  • 做题记录 2
  • 计数原理与排列组合
  • 9.16动态用例设计方法 笔记
  • 深入解析:ESP32三种主流的开发环境
  • js
  • 9.16电商状态迁移图
  • c# ConcurrentDictionary
  • 核桃OJ【S组 第二轮】信息学竞赛10w选手模拟考
  • 第一次个人编程作业
  • 【初赛】软件系统 - Slayer
  • 漏洞详解--XXE 从入门到精通!
  • 数学分析习题课 note
  • 总结-CDQ 分治