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

从像素到数据库:手搓一个车牌识别系统

基于qt opencv c++使用传统阈值分割加机器学习方法进行车牌识别 可识别图片与视频 可加数据库mysql sqlite包

最近在折腾一个好玩的项目——用C++搭配Qt和OpenCV搞车牌识别。这东西看着玄乎,拆开来看其实就是几个关键步骤:定位车牌、切字符、识别字符、存数据库。咱们直接上代码边说边聊。

先搞车牌定位。传统玩法离不开阈值分割,这里用颜色空间转换加边缘检测:

// 转HSV空间更容易捕捉车牌颜色 cv::Mat hsv, mask; cv::cvtColor(src, hsv, cv::COLOR_BGR2HSV); cv::inRange(hsv, cv::Scalar(100, 80, 80), cv::Scalar(140, 255, 255), mask); // 形态学操作去噪点 cv::morphologyEx(mask, mask, cv::MORPH_CLOSE, cv::getStructuringElement(cv::MORPH_RECT, cv::Size(15,3))); // 找轮廓 std::vector<std::vector<cv::Point>> contours; cv::findContours(mask, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);

这里用了HSV颜色空间而不是RGB,因为车牌蓝底的色相更集中。闭运算(MORPH_CLOSE)用了个扁长的结构元素,专门对付车牌字符间的缝隙。

找到候选区域后,得用点机器学习的手段确认是不是真车牌。我直接偷懒用了OpenCV自带的SVM:

// 加载训练好的模型 cv::Ptr<cv::ml::SVM> svm = cv::ml::SVM::load("plate_svm.xml"); // 提取HOG特征 std::vector<float> descriptors; hog->compute(candidateROI, descriptors); // 预测 float result = svm->predict(descriptors); if(result > 0.5) { // 真·车牌区域 }

注意这里HOG特征的winSize要和训练时一致,不然分分钟翻车。当初训练模型时,我用了2000张正样本和5000张负样本,拿外卖的时间刚好够跑完训练。

字符切割是个精细活,垂直投影法效果不错:

// 二值化后做垂直投影 cv::reduce(binary, vertical, 0, cv::REDUCE_SUM, CV_32F); // 找波峰波谷 std::vector<int> splitPos; for(int i=1; i<vertical.cols; ++i){ if(vertical.at<float>(i-1)==0 && vertical.at<float>(i)>0){ splitPos.push_back(i); // 字符左边界 } }

遇到'川'这种中间有断的字符,得在投影后做连通域判断。实在切不开的时候,用宽度阈值兜底,超过平均宽度1.8倍的就强行劈开。

基于qt opencv c++使用传统阈值分割加机器学习方法进行车牌识别 可识别图片与视频 可加数据库mysql sqlite包

数据库部分用Qt自带的SQL模块:

QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE"); db.setDatabaseName("plates.db"); if(db.open()){ db.exec("CREATE TABLE IF NOT EXISTS plates(id INTEGER PRIMARY KEY, number TEXT, time DATETIME)"); } // 插入数据 QSqlQuery q; q.prepare("INSERT INTO plates(number, time) VALUES(?, datetime('now'))"); q.bindValue(0, plateNumber); q.exec();

想换MySQL就把QSQLITE改成QMYSQL,记得在pro文件里加QT += sql。遇到过个坑——同时开多个数据库连接时,得用不同connection name,不然数据乱窜。

视频流处理在Qt里可以挂到QMediaPlayer的信号上:

connect(player, &QMediaPlayer::videoFrameChanged, this, [=](const QVideoFrame &frame){ QImage img = frame.image(); if(!img.isNull()){ detectPlate(img.convertToFormat(QImage::Format_RGB888)); } });

这里要注意QImage和cv::Mat的格式转换,用错颜色空间的话,车牌能给你识别成彩虹糖。

整套系统跑起来后,发现最大的瓶颈在字符识别阶段。后来上了多线程,把图像处理和界面刷新分开,Qt的信号槽这时候是真香:

// 在子线程处理 void WorkerThread::processImage(const cv::Mat &frame) { auto result = plateRecognizer.detect(frame); emit detectionDone(result); // 通知主线程更新UI }

最后说个实战经验:千万别在代码里写死车牌颜色阈值!最好做个配置文件,遇到不同颜色的特种车牌,改个配置就能适配,省得重新编译。

(代码仓库地址假装这里有个GitHub链接)这个项目最爽的时刻,是看着监控视频里一辆辆车开过,数据库噌噌往上涨记录——虽然目前识别率大概就80%,停小区门口收停车费可能得挨揍,但自己玩是真够用了。

http://www.jsqmd.com/news/466409/

相关文章:

  • 功能型润滑油源头厂家
  • SQL注入实战避坑指南,解决渗透测试高频报错与失效问题
  • 告别格式内卷!PaperXie 格式排版板块实测:4000 + 高校模板重构毕业论文排版效率
  • 17届蓝桥杯嵌入式赛道开发板外设使用教程——按键、蜂鸣器、LCD屏幕
  • 机关智慧食堂后勤管理系统__Python django flask
  • 隧道能见度检测器:守护隧道安全的“火眼金睛”
  • 那就随便说说
  • Carsim联合仿真模型验证:十四自由度车辆动力学模型的应用
  • 2026 第八批 “小巨人” 申报收官在即 评审核心导向升级
  • 互联网大厂Java求职者面试实战:严肃面试官与搞笑程序员谢飞机的故事
  • 逆向新手之攻防世界--key
  • **Gemini2.5Pro去AI味2025指南,打造自然流畅的文本生成体验**
  • CUDA graph 简析
  • 基于微信小程序的课程作业管理系统[小程序]-计算机毕业设计源码+LW文档
  • 别死记硬背!Java的CountDownLatch 核心原理:AQS state 才是关键
  • 知识体系——MCP(四)demo(2)开发mcp client
  • OWASP Top10 2021 完整版:与 SAST 适配的深度解析
  • Rocky Linux 10 上搭建 社区版 GitLab CE
  • 2026年 智能制造实训设备厂家推荐排行榜:高校教学、模拟药厂、生产线实训平台与系统装置一站式解决方案 - 品牌企业推荐师(官方)
  • g更改linux root密码
  • LeetCode 76. 最小覆盖子串(详细技术解析)
  • 虚拟同步发电机(VSG)孤岛与并网的Simulink(2019a)仿真模型搭建与探索
  • 对于【LSTM与GRU在水文预测中的对比分析】的未来改进和建议
  • 工业清洁设备优质品牌推荐榜:驾驶式洗地机/1000公斤高压清洗机/商用洗地机/工业吸尘器/工业洗地机/工业清洗机厂家/选择指南 - 优质品牌商家
  • 2026年比较好的西安租赁洗地机工厂推荐:西安洗地机租赁稳定供应商推荐 - 行业平台推荐
  • visual studio编译wxWidgets
  • 防疫站疫苗预约管理系统_Python django flask
  • 2026宁波好用的芯轴品牌生产厂盘点,如何选择靠谱厂家 - 工业推荐榜
  • 2026河北新河优质MC浇筑尼龙加工件推荐榜:pa66尼龙棒/pp尼龙棒/尼龙加工件源头厂家/浇筑尼龙棒/玻纤mc尼龙浇铸棒/选择指南 - 优质品牌商家
  • Django + Vue3 + YOLO 实现车辆检测、测速预警与违章分析平台