基于STM32、OpenCV和卷积神经网络的车牌识别系统的完整C++源代码

以下是基于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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码力金矿

谢谢您的打赏,我将会更好创作。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值