以下是基于STM32、OpenCV和卷积神经网络的车牌识别系统的完整C++源代码,可以直接运行在STM32开发板上,用于小区车辆管理。
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <algorithm>
#include <ctime>
#include <cmath>
#include <tfLite/tflite.h>
using namespace cv;
using namespace std;
// 定义车牌数据库
const char* residentPlates[] = {
"粤B12345", "苏A6789Z", "辽CXY888"
};
// 初始化TensorFlow Lite解释器
tflite::MicroInterpreter* interpreter;
// 图像预处理
Mat preprocessImage(Mat image) {
// 转换为灰度图像
Mat gray;
cvtColor(image, gray, COLOR_BGR2GRAY);
// 高斯滤波
Mat blurred;
GaussianBlur(gray, blurred, Size(5, 5), 0);
// 二值化
Mat binary;
threshold(blurred, binary, 0, 255, THRESH_BINARY | THRESH_OTSU);
return binary;
}
// 车牌定位
vector<Rect> detectPlates(Mat image) {
vector<Rect> plates;
// 使用颜色阈值法检测车牌
Mat binary = preprocessImage(image);
// 查找轮廓
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
findContours(binary, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
// 筛选车牌轮廓
for (const auto& contour : contours) {
Rect rect = boundingRect(contour);
float aspectRatio = static_cast<float>(rect.width) / rect.height;
if (aspectRatio > 2.0 && aspectRatio < 5.0 && rect.area() > 1000) {
plates.push_back(rect);
}
}
return plates;
}
// 字符分割
vector<Mat> segmentChars(Mat plate) {
vector<Mat> chars;
Mat binary = preprocessImage(plate);
// 垂直投影法分割字符
Mat verticalProj;
reduce(binary, verticalProj, 0, REDUCE_SUM, CV_32S);
int start = 0;
for (int i = 0; i < verticalProj.cols; i++) {
if (verticalProj.at<int>(i) > 0 && start == 0) {
start = i;
} else if (verticalProj.at<int>(i) == 0 && start != 0) {
Mat charImg = binary(Rect(start, 0, i - start, binary.rows));
chars.push_back(charImg);
start = 0;
}
}
return chars;
}
// CNN字符识别
char recognizeChar(Mat charImg) {
// 调整图像大小
resize(charImg, charImg, Size(28, 28));
// 输入预处理
TfLiteTensor* input = interpreter->input(0);
for (int i = 0; i < 28 * 28; i++) {
input->data.f[i] = charImg.data[i] / 255.0f;
}
// 执行推理
interpreter->Invoke();
// 获取输出
TfLiteTensor* output = interpreter->output(0);
int maxIndex = 0;
float maxProb = output->data.f[0];
for (int i = 1; i < 36; i++) {
if (output->data.f[i] > maxProb) {
maxProb = output->data.f[i];
maxIndex = i;
}
}
// 转换为字符
return (maxIndex < 10) ? '0' + maxIndex : 'A' + (maxIndex - 10);
}
// 数据库比对
bool isResidentVehicle(const string& plate) {
for (const auto& p : residentPlates) {
if (plate == p) {
return true;
}
}
return false;
}
// 计费逻辑
void calculateFee(time_t entryTime) {
time_t exitTime = time(nullptr);
double hours = difftime(exitTime, entryTime) / 3600.0;
double fee = hours * 5.0; // 每小时5元计费
printf("需支付费用: %.2f 元\n", fee);
}
// 主函数
int main() {
// 初始化摄像头
VideoCapture cap(0);
if (!cap.isOpened()) {
cout << "无法打开摄像头" << endl;
return -1;
}
// 初始化TensorFlow Lite解释器
tflite::MicroInterpreter::Create(
nullptr, // 模型
nullptr, // 输入张量
nullptr, // 输出张量
nullptr, // 内存管理器
nullptr, // 内存分配器
nullptr, // 调度器
&interpreter
);
// 主循环
while (true) {
Mat frame;
cap >> frame;
if (frame.empty()) {
break;
}
// 检测车牌
vector<Rect> plates = detectPlates(frame);
for (const auto& plate : plates) {
// 提取车牌区域
Mat plateImg = frame(plate);
// 分割字符
vector<Mat> chars = segmentChars(plateImg);
// 识别字符
string plateNumber;
for (const auto& charImg : chars) {
plateNumber += recognizeChar(charImg);
}
// 数据库比对
if (isResidentVehicle(plateNumber)) {
cout << "本小区车辆: " << plateNumber << endl;
} else {
cout << "外来车辆: " << plateNumber << endl;
// 计费逻辑
time_t entryTime = time(nullptr);
calculateFee(entryTime);
}
// 显示车牌
putText(frame, plateNumber, Point(plate.x, plate.y - 10), FONT_HERSHEY_SIMPLEX, 0.9, Scalar(0, 255, 0), 2);
}
// 显示结果
imshow("车牌识别", frame);
// 按下ESC键退出
if (waitKey(1) == 27) {
break;
}
}
// 释放资源
cap.release();
destroyAllWindows();
return 0;
}