# 停车场管理系统

# 实现功能

# UI 展示

整体页面
前端页面
微信小程序UI

# 环境

尽量选择已下文件版本
安装 Qt ,EasyPR,OpenCV 路径中不要出现任何中文路径

  • Qt5.12.1~3 //3 版本以上需要自己编译 MySQL
  • Qt Creator 4.8.1
  • C++11
  • MySql 8.0.27
  • OpenCV3.4.5 (难点)
  • EasyPR 1.6 // 也会有警告,忽略 (大难点)
  • win10

# Qt 安装

由于直接将在 QT 中引用 MySQL 并不能 直接使用,所以需要将 MySQL 的动态链接库存放到 QT 的 bin 目录下,才可以调用 MySQL。QT 默认使用 C++11 编译

  • Qt 下载链接

编译选择要选 mingw73_64,调试 OpenCV 需要

# MySql 配置

  • 下载没有要求,能在 CMD 运行,Navicat 调用基本没有问题
  • Qt+MySql

1, 在 QT 所创建项目中的 pro 文件中添加 sql

QT       += core gui sql

2, 将 MySQLlib 库里面的 libmysql.dll 文件和 libmysql.lib 文件赋值粘贴到 QT5.12.1msvc2017_64 文件夹 bin 文件内即可成功调用

mysql环境

# OpenCV3.4.5

仔细阅读参考 OpenCV 的安装

# 参考上面连接注意

  • 使用 Qt 自带的 C和C++编译器
C: "D:\Qt\Qt5.13.2\Tools\mingw730_64\bin\gcc.exe"
C++: "D:\Qt\Qt5.13.2\Tools\mingw730_64\bin\g++.exe"
  • 不用编译生成 OpenCV_world 也可

不想编译 / 编译失败,偷懒版,百度网盘下载

:https://pan.baidu.com/s/1UXjX8DrKgBaW5nWF-XppzQ?pwd=13v2
  • 将下面对应的链接加入换将变量 (解压,修改为自己位置)
D:\Qt\openCV3.4.12\openCV3.4.12-build\install\x64\mingw\bin
  • 添加环境变量后,配置换将即可运行,关键是 Qt对应的环境 一定要对,博主使用的 Qt5.13,我使用的 5.12.1 理论上中间版本都可以
  • 修建 Qt 项目,配置.pro 文件, 链接修改对 ,很 关键
INCLUDEPATH += D:\Qt\openCV3.4.12\openCV3.4.12-build\install\include\
               D:\Qt\openCV3.4.12\openCV3.4.12-build\install\include\opencv2\
               D:\Qt\openCV3.4.12\openCV3.4.12-build\install\include\opencv
LIBS += -L D:\Qt\openCV3.4.12\openCV3.4.12-build\install\x64\mingw\lib\libopencv_*.a
  • 修改 main 函数,测试
#include "mainwindow.h"
#include <QApplication>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace cv;
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
	// 修改为自己的图片链接,使用绝对地址,使用 `\\` 区分,注意 `多` 一个,或 `少` 一个
    cv::Mat image = imread("D:\\Qt\\Project\\OpenCV_Test\\1.jpg");
    namedWindow("Display window",WINDOW_AUTOSIZE);
    imshow("Display window",image);
    waitKey(0);
    
    MainWindow w;
    w.show();
    return a.exec();
}
  • 测试视频
#include "mainwindow.h"
#include <QApplication>
#include <QDebug>
#include <QFileDialog>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace cv;
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    namedWindow("Display", WINDOW_AUTOSIZE);
    VideoCapture cap;
    cap.open("D:/Qt/Project/OpenCV_Test/Resources/test.mp4");
    if(cap.isOpened())
        qDebug()<<"Sucess!";
    else
        qDebug()<<"False!";
    Mat frame;
    for(;;)
    {
        cap >> frame;
        if(frame.empty())
            break;
        imshow("Display", frame);
        if(waitKey(33) >= 0)
            break;
    }
    return a.exec();
}

到此出 OpenCV 环境变量成功,如果失败,注意 qt的版本 ,以及使用 qt 编译的版本是不是 qt 编译时用的 mingw73_64

# EasyPR

其实也简单,关键时导入换将之后会有很多报错,对于初学者,慢慢修改是个挺熬人的过程

  • 下载源文件 EasyPR
  • OpenCV 的引用,直接使用上面的就行
  • 使用 C++11 编译
CONFIG += c++11
QMAKE_CXXFLAGS+=-std=c++11
  • 下载 EasyPR1.6 之后的文件目录,我们需要也就是 所选的test 也要,要部分代码
    01

  • 将上面 个文件夹保存到 Qt 创建 的项目地址 对应根目录

  • qt 创建一个普通项目之后,添加已经存在的文件
    image-20230417205708627

  • test 不用添加,将剩余 4 个文件夹全部选进去,选好之后对应的.pro 文件,# 为删掉的,切记可能在加入 test 后,将会对应两个 main.cpp 导致最后无法运行

SOURCES += \
	    main.cpp \
    mainwindow.cpp \
        src/core/chars_identify.cpp \
    src/core/chars_recognise.cpp \
    src/core/chars_segment.cpp \
    src/core/core_func.cpp \
    src/core/feature.cpp \
    src/core/params.cpp \
    src/core/plate_detect.cpp \
    src/core/plate_judge.cpp \
    src/core/plate_locate.cpp \
    src/core/plate_recognize.cpp \
#    src/train/ann_train.cpp \
#    src/train/annCh_train.cpp \
#    src/train/create_data.cpp \
#    src/train/svm_train.cpp \
#    src/train/train.cpp \
    src/util/kv.cpp \
    src/util/program_options.cpp \
    src/util/util.cpp \
    thirdparty/LBP/helper.cpp \
    thirdparty/LBP/lbp.cpp \
    thirdparty/mser/mser2.cpp \
    thirdparty/svm/corrected_svm.cpp \
    thirdparty/textDetect/erfilter.cpp \
    thirdparty/xmlParser/xmlParser.cpp
HEADERS += \
    car.h \
    mainwindow.h \
    signup.h \
    mysql.h \
    initfile.h\
    include/easypr/core/character.hpp \
    include/easypr/core/chars_identify.h \
    include/easypr/core/chars_recognise.h \
    include/easypr/core/chars_segment.h \
    include/easypr/core/core_func.h \
    include/easypr/core/feature.h \
    include/easypr/core/params.h \
    include/easypr/core/plate.hpp \
    include/easypr/core/plate_detect.h \
    include/easypr/core/plate_judge.h \
    include/easypr/core/plate_locate.h \
    include/easypr/core/plate_recognize.h \
#    include/easypr/train/ann_train.h \
#    include/easypr/train/annCh_train.h \
#    include/easypr/train/create_data.h \
#    include/easypr/train/svm_train.h \
#    include/easypr/train/train.h \
    include/easypr/util/kv.h \
    include/easypr/util/program_options.h \
    include/easypr/util/switch.hpp \
    include/easypr/util/util.h \
    include/easypr/api.hpp \
    include/easypr/config.h \
    include/easypr/version.h \
    include/easypr.h \
#    test/accuracy.hpp \
#    test/chars.hpp \
#    test/config.hpp \
#    test/plate.hpp \
#    test/result.hpp \
    thirdparty/LBP/helper.hpp \
    thirdparty/LBP/lbp.hpp \
    thirdparty/mser/mser2.hpp \
    thirdparty/svm/precomp.hpp \
    thirdparty/textDetect/erfilter.hpp \
    thirdparty/xmlParser/xmlParser.h
# 引入easyPR所需要的依赖
DISTFILES += \
#    resources/train/ann.7z \
#    resources/train/annCh.7z \
#    resources/train/annGray.7z \
#    resources/train/svm.7z \
    model/ann.xml \
    model/ann_chinese.xml \
    model/annCh.xml \
    model/svm_hist.xml \
#    resources/image/general_test/GroundTruth_others.xml \
#    resources/image/general_test/GroundTruth_windows.xml \
#    resources/image/native_test/GroundTruth_others.xml \
#    resources/image/native_test/GroundTruth_windows.xml \
#    resources/result/Result.xml \
#    resources/text/chinese_mapping \
#    resources/text/dev_team \
#    resources/text/province_mapping \
#    resources/text/thanks \
#    resources/text/batch_test_menu \
#    resources/text/main_menu \
#    resources/text/test_menu \
#    resources/text/train_menu
  • 加入 EasyPR 文件成功,接下来该 Bug
  • 首先打开 Header/include/config.h#define 的修改为
#define CV_VERSION_THREE_TWO
  • 接下来发现所有的文件好像 都无法 加载 EasyPR 对应的 文件

  • 每个文件都打开,将头 文件无法读取 的, 看对应的 位置 ,都是在 include 文件夹下的文件 无法 读取,所以在 头文件 上面 include , 例如下面,有耐心查看,基本上每个文件都要修改。 所有文件都打开一遍
    image-20230417210720275

  • 修改 Header/include/config.h 读取的 model 路径全部该为自己的 绝对路径 ,记得 // 很容易 不细心 ,最后 OpenCV 无法读取失败 。例如下面的报错

加载断点
OpenCV: terminate handler is called! The last OpenCV error is:
OpenCV(3.4.5) Error: Parsing error (Missing or invalid SVM type) in read_params, file C:\Users\Administrator\Desktop\opencv-3.4.5\opencv-3.4.5\modules\ml\src\svm.cpp, line 2203
  • 将其修改为如下,改成自己的路径,当然会有文件不存在的,改成统一路径就可
static const char* kDefaultSvmPath = "E://Cstudy//QT//QT_exercise//easyPR//easypr2//model/svm_hist.xml";
static const char* kLBPSvmPath = "E://Cstudy//QT//QT_exercise//easyPR//easypr2//model/svm_lbp.xml";
static const char* kHistSvmPath = "E://Cstudy//QT//QT_exercise//easyPR//easypr2//model/svm_hist.xml";
static const char* kDefaultAnnPath = "E://Cstudy//QT//QT_exercise//easyPR//easypr2//model/ann.xml";
static const char* kChineseAnnPath = "E://Cstudy//QT//QT_exercise//easyPR//easypr2//model/ann_chinese.xml";
static const char* kGrayAnnPath = "E://Cstudy//QT//QT_exercise//easyPR//easypr2//model/annCh.xml";
//This is important to for key transform to chinese
static const char* kChineseMappingPath = "E://Cstudy//QT//QT_exercise//easyPR//easypr2//model/province_mapping";
  • 修改 Qt 项目 创建对应的 main.cpp 文件
#include <QCoreApplication>
#include <opencv2/opencv.hpp>
#include "include/easypr.h"
#include <QDebug>
using namespace easypr;
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    qDebug()<<"加载断点";
    // 1. 加载车牌识别模型
    CPlateRecognize pr;
    pr.LoadSVM("E://Cstudy//QT//QT_exercise//easyPR//easypr2//model//svm_hist.xml");
    qDebug()<<"AVM";
    pr.LoadANN("E://Cstudy//QT//QT_exercise//easyPR//easypr2//model//ann.xml");
    qDebug()<<"ANN";
    pr.LoadChineseANN("E://Cstudy//QT//QT_exercise//easyPR//easypr2//model//ann_chinese.xml");
    qDebug()<<"ChineseANN";
    // new in v1.6
    pr.LoadGrayChANN("E://Cstudy//QT//QT_exercise//easyPR//easypr2//model//annCh.xml");
    pr.LoadChineseMapping("E://Cstudy//QT//QT_exercise//easyPR//easypr2//model//province_mapping");
    // 2. 读入待识别的车牌图片
    cv::Mat src = cv::imread("D://car.png");
    // 3. 车牌识别
    std::vector<CPlate> plates;
    pr.plateRecognize(src, plates);
    // 4. 输出识别结果
    for (auto plate : plates) {
        std::cout << "plate: " << plate.getPlateStr() << std::endl;
    }
    return a.exec();
}
  • 修改 main.cpp 后会有大量的警告 unused ,或者使用 老旧 的格式,会警告, 用管,毕竟八年没有更新

image-20230417212952648

  • 当然编译运行后,肯定 不会成功 ,会有 各种各样 的找不到,报错 ,肯定会有下面函数找不到,根据对应名字,在 core 文件里,找到头文件,把它 添加到对应的文件当中
文件解释
plate_locate车牌定位
plate_judge车牌判断
plate_detect车牌检测,是车牌定位与车牌判断功能的组合
chars_segment字符分割
chars_identify字符鉴别
chars_recognise字符识别,是字符分割与字符鉴别功能的组合
plate_recognize车牌识别,是车牌检测与字符识别的共有子类
feature特征提取回调函数
plate车牌抽象
core_func.h共有的一些函数

当然不想修改 EasyPR,你可以把我改好的拿过去,直接修改一下 model 对应的绝对路径就可以运行啦。又节约了好长时间
EasyPR+OpenCV +Qt 代码测试,从停车场管理信息系统中提取吧!!!

https://github.com/foryouos/Parking_System

# EasyPR 在停车管理系统中的使用

代码不全,仅为例子

#include <opencv2/opencv.hpp>
#include "include/easypr.h"
#include <QDebug>
using namespace easypr;
// 1. 加载车牌识别模型
    CPlateRecognize pr;
// 加载模型
pr.LoadSVM("E://Cstudy//QT//QT_exercise//easyPR//easypr2//model//svm_hist.xml");
    qDebug()<<"AVM";
    pr.LoadANN("E://Cstudy//QT//QT_exercise//easyPR//easypr2//model//ann.xml");
    qDebug()<<"ANN";
    pr.LoadChineseANN("E://Cstudy//QT//QT_exercise//easyPR//easypr2//model//ann_chinese.xml");
    qDebug()<<"ChineseANN";
    // new in v1.6
    pr.LoadGrayChANN("E://Cstudy//QT//QT_exercise//easyPR//easypr2//model//annCh.xml");
    pr.LoadChineseMapping("E://Cstudy//QT//QT_exercise//easyPR//easypr2//model//province_mapping");
// 如果摄像头播放
    if(camera->state() == QCamera::ActiveState)
    {
        camera->setCaptureMode(QCamera::CaptureStillImage);  // 捕获图片
        // 弹出标准对话框
        //QString fileName = QFileDialog::getSaveFileName (nullptr, QString (), QString (), QString (), nullptr, QFileDialog::DontConfirmOverwrite); // 保存的文件名字
        imageCapture = new QCameraImageCapture(camera);  // 创建一个用于捕获图片的对象
      // 当摄像头成功捕获一张图片后进行车牌识别
      connect(imageCapture, &QCameraImageCapture::imageCaptured, this, [=](int /*id*/, const QImage& img)
      {
          Mat src;
          Mat rgbImg;
          //src = Mat(img.height(), img.width(), CV_8UC4, (uchar*)img.bits(), img.bytesPerLine()).clone();
          src = Mat(img.height(), img.width(), CV_8UC4, const_cast<unsigned char*>(img.bits()), static_cast<size_t>(img.bytesPerLine())).clone();
          cvtColor(src, rgbImg, CV_BGRA2RGB);  // 将 OpenCV 中颜色通道排列方式与 Qt 中不同的图片格式转换为 Qt 中正常的图片格式
          //QImage qImg(rgbImg.data, rgbImg.cols, rgbImg.rows, rgbImg.step, QImage::Format_RGB888);
          QImage qImg(rgbImg.data, rgbImg.cols, rgbImg.rows, static_cast<int>(rgbImg.step), QImage::Format_RGB888);
          // 缩放图片到指定大小
          QSize newSize(200,100);
          QImage scaledImg = qImg.scaled(newSize,Qt::KeepAspectRatio);
          // 使用 easyPR 获取车牌信息
          std::vector<easypr::CPlate> plates;
          m_plateRecognize.plateRecognize(rgbImg,plates,0);
          for (auto plate : plates) {
              std::cout << "plate: " << plate.getPlateStr() << std::endl;
          }
          qDebug()<<"内部输出";
          if(plates.size()>0)
          {
              // 显示车牌图片和号码
              easypr::CPlate plate = plates[0];
              Mat plateImg = plate.getPlateMat();
              QImage qPlateImg(plateImg.data,plateImg.cols,plateImg.rows,static_cast<int>(plateImg.step), QImage::Format_RGB888);
              ui->screen_label->setPixmap(QPixmap::fromImage(qPlateImg));
              QString plateStr = QString::fromLocal8Bit(plate.getPlateStr().c_str());
              // 获取车牌号码的部分字符串
              QStringList list = plateStr.split(":");
              if (list.size() >= 2) {
                  plateStr = list[1].trimmed();
              }
              ui->Car_idinput->setText(plateStr);
              ui->Car_output->setText(plateStr);
              qDebug()<<plateStr;
              std::cout << "plate: " << plate.getPlateStr() << std::endl;
          }
      });
        // 开始进行捕获
        imageCapture->capture(fileName);  // 捕获图片,保存到要保存的目录为上面对话框设定的目录
    }

# 小程序模块

# 停车管理系统模块解析