版本: v43.2 fix24
作者: steven_roc
仓库: https://git.zhonjin.com:40717/steven_roc/PlateRecApp
最后更新: 2026-07-06
PlateRecApp(HyperLPR3-LinuxAPP)
面向渣土车/工程车辆管理的车牌识别+称重+联单上传一体化边缘计算系统。部署在工地出入口的树莓派5上,通过4路RTSP摄像头实时捕获车牌,结合称重仪表数据,自动完成:
工地/码头/回填点出入口,单点双向(进站+出站),支持4个摄像头(前低位×2 + 侧高位×2),支持共享摄像头模式。
| 参数 | 规格 |
|---|---|
| 主板 | 树莓派5 8GB |
| CPU | BCM2712, Quad-core Arm Cortex-A76 |
| GPU | VideoCore VII |
| 内存 | 8GB LPDDR4X |
| 参数 | 值 |
|---|---|
| OS | Ubuntu 24.04 LTS |
| 架构 | aarch64 (ARM64) |
| 内核 | Linux 6.x |
| 工具 | 版本/标准 |
|---|---|
| GCC | 11+ (aarch64-linux-gnu) |
| C++ 标准 | C++17 (CMAKE_CXX_STANDARD 17) |
| CMake | 3.25.1+ |
| 构建类型 | Release (默认) / Debug / MinSizeRel / RelWithDebInfo |
| 库名 | 用途 | 查找方式 |
|---|---|---|
| OpenCV | 图像处理、JPEG编解码、水印渲染 | find_package(OpenCV REQUIRED) |
| HyperLPR3 SDK | 车牌检测+识别(MNN推理) | 头文件 hyper_lpr_sdk.h,库 libhyperlpr3 |
| SQLite3 | 本地数据库(记录存储、认证、监控) | pkg_check_modules(SQLITE3 REQUIRED sqlite3) |
| cURL | HTTP客户端(API上传、飞书消息) | find_package(CURL REQUIRED) |
| OpenSSL | HTTPS/SSL、MD5计算 | find_package(OpenSSL REQUIRED) |
| FreeType2 | 中文字体渲染(水印文字) | pkg_check_modules(FREETYPE REQUIRED freetype2) |
| FFmpeg (libavformat/libavcodec/libavutil/libswscale) | RTSP流解码、DRM硬件加速 | pkg_check_modules |
| cJSON | JSON解析与生成 | 手动查找 + pkg-config 回退 |
| mosquitto / mosquittopp | MQTT客户端通信 | 直接链接 |
| libcrypt | bcrypt密码哈希(crypt_r) |
find_library(CRYPT_LIBRARY crypt) |
| inih | INI配置文件解析 | 第三方头文件 ini.h |
| httplib (cpp-httplib) | 轻量级HTTP/HTTPS服务器 | 第三方头文件 httplib.h |
| cvxFont | OpenCV中文字体绘制 | 第三方库 cvxFont.h |
┌─────────────────────────────────────────────────────────────────────┐
│ main.cpp (主调度) │
│ 配置加载 → 数据库初始化 → HyperLPR初始化 → 摄像头启动 → 主循环 │
└──────┬──────────┬──────────┬──────────┬──────────┬─────────────────┘
│ │ │ │ │
┌────▼───┐ ┌───▼────┐ ┌──▼───┐ ┌───▼────┐ ┌───▼──────┐
│ config │ │database│ │web │ │feishu │ │ MQTT + │
│ .cpp │ │ .cpp │ │server│ │client │ │ Weight │
└────────┘ └────────┘ └──────┘ └────────┘ │ Scale │
└──────────┘
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────────┐
│ RTSP │ │ Plate │ │ Station │ │ Network │
│ Capture │ │Recognize │ │ Lock │ │ Client │
│ (×4) │ │ r.cpp │ │ .cpp │ │ .cpp │
└──────────┘ └──────────┘ └──────────┘ └──────────────┘
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────────┐
│ Auth │ │ frpc │ │ SSH │ │ System │
│ System │ │ Manager │ │ Manager │ │ Monitor │
│(*.cpp) │ │ .cpp │ │ .cpp │ │ .cpp │
└──────────┘ └──────────┘ └──────────┘ └──────────────┘
┌──────────┐ ┌──────────────────────────────────────────┐
│ Log │ │ common.h (全局类型/结构体/指标) │
│ Manager │ │ MonitorMetrics / ROIConfig / ... │
└──────────┘ └──────────────────────────────────────────┘
common.h ← 所有模块(全局类型定义)
config.cpp ← main.cpp(配置加载)
rtsp_capture.cpp ← plate_recognizer.cpp(帧采集)
plate_recognizer.cpp ← main.cpp(识别主逻辑)
station_lock.cpp ← plate_recognizer.cpp(交替锁定)
database.cpp ← plate_recognizer.cpp, web_server.cpp(数据持久化)
network_client.cpp ← plate_recognizer.cpp, weight_scale.cpp(HTTP API)
feishu_client.cpp ← plate_recognizer.cpp(飞书通知)
mqtt_client.cpp ← weight_scale.cpp(MQTT发布)
weight_scale.cpp ← main.cpp(称重数据采集)
web_server.cpp ← main.cpp(Web服务线程)
auth_*.cpp ← web_server.cpp(认证中间件)
frpc_manager.cpp ← web_server.cpp(frpc管理API)
ssh_manager.cpp ← web_server.cpp(SSH密钥管理)
log_manager.cpp ← main.cpp(日志缓冲)
system_monitor.cpp ← web_server.cpp(系统监控)
RTSP摄像头(×4)
│
▼ FFmpeg解码(软解/DRM硬解)
帧队列(deque<cv::Mat>, 最大10帧)
│
▼ getFrame() 取出最新帧
ROI裁剪(可选, 按配置区域)
│
▼ HyperLPR3推理(HLPR_UpdateImage)
车牌检测结果(车牌号+置信度+类型)
│
▼ 帧级去重(2秒内同车牌跳过)
│
├─── 置信度 ≥ LOG_THRESHOLD? ──→ 保存照片(加水印) → 插入SQLite
│
▼ 置信度 ≥ CONFIDENCE_THRESHOLD?
│
├─── 交替锁定检查(try_lock_in/out_station)
│ │ BLOCKED → 跳过
│ ▼ ALLOWED
│
├─── 创建联单(lib_curl_create_bill_request) → 获取tb_num
│
├─── 上传照片(低位+高位×2组) → 平台API
│
├─── 飞书通知(send_feishu_msg) → 飞书开放API
│
└─── 称重+MQTT(weight_scale → mqtt_publish) → MQTT Broker
// hyperlpr_lib_init() — plate_recognizer.cpp
HLPR_ContextConfiguration configuration = { 0 };
configuration.models_path = (char*)model.c_str(); // hyperlpr3/resource/models/r2_mobile
configuration.max_num = 2; // 每帧最多检测2个车牌
configuration.det_level = DETECT_LEVEL_HIGH; // 高精度检测模式
configuration.use_half = false; // 不使用FP16半精度
configuration.nms_threshold = 0.5f; // NMS非极大值抑制阈值
configuration.rec_confidence_threshold = 0.6f; // 识别置信度阈值
configuration.box_conf_threshold = 0.30f; // 检测框置信度阈值
configuration.threads = 1; // 推理线程数
plate_rec_app.hlpr_ctx = HLPR_CreateContext(&configuration);
capture_do_work_thread() 主循环每500ms执行一次HLPR_CreateDataBuffer → HLPR_UpdateImageCarPlateInfoPLATE_LOG_THRESHOLD → 保存照片到磁盘PLATE_CONFIDENCE_THRESHOLD → 触发上传流程struct ROIConfig {
int x, y, width, height; // 裁剪区域
bool enabled; // 是否启用
cv::Rect getRect(int img_w, int img_h); // 安全边界裁剪
};
// 进站ROI: g_roi_in, 出站ROI: g_roi_out
// 支持通过Web界面手动绘制调整,写回config.ini
static const std::vector<std::string> TYPES = {
"蓝牌", "黄牌", "白牌单层", "绿牌", "黑牌港澳", "香港单层",
"香港双层", "澳门单层", "澳门双层", "黄牌双层"
};
struct CarPlateInfo {
std::string code; // 车牌号
float confidence; // 识别置信度
std::string type; // 车牌类型(蓝牌/黄牌等)
cv::Mat image_front; // 前向照片
cv::Mat image_side; // 侧向照片
int db_id; // 数据库记录ID
bool is_inbound/outbound; // 进站/出站标记
time_t db_capture_time; // 照片保存时固定的capture_time
std::atomic<bool> upload_in_progress{false}; // P0: 上传竞态保护
};
class RTSPCapture {
std::string rtspUrl_;
DecodeMode decodeMode_; // AUTO / SOFT / DRM
std::string drmDevice_; // 默认 /dev/dri/renderD128
std::string transport_; // tcp / udp
AVFormatContext* fmtCtx_;
AVCodecContext* codecCtx_;
AVBufferRef* hwDeviceCtx_; // DRM硬件设备上下文
SwsContext* swsCtx_; // 像素格式转换上下文
std::deque<cv::Mat> frameQueue_; // 帧队列(最大10帧)
std::thread captureThread_;
};
avformat_open_input() — 打开RTSP流avformat_find_stream_info() — 获取流信息av_find_best_stream() — 查找视频流avcodec_open2() — 打开解码器(thread_count=4)captureLoop() 循环读取帧 → decodeFrameToBGR() → 入队bool initDRMHwAccel() {
AVHWDeviceType type = av_hwdevice_find_type_by_name("drm");
av_hwdevice_ctx_create(&hwDeviceCtx_, type, "/dev/dri/renderD128", nullptr, 0);
codecCtx_->hw_device_ctx = av_buffer_ref(hwDeviceCtx_);
}
// 解码后检测 AV_PIX_FMT_DRM_PRIME 格式 → av_hwframe_transfer_data 转CPU
getFrame() — 取出并移除最新帧(供识别线程使用)peekFrame() — 只读取不移除(供MJPEG视频流使用,避免与识别线程竞争)std::mutex + condition_variable 同步av_read_frame 返回错误)→ cleanupFFmpeg() → 等待3秒 → 重新 initFFmpeg()timeout=5000000微秒)fflags=nobuffer+genpts, flags=low_delayav_dict_set(&opts, "rtsp_transport", "tcp", 0);
av_dict_set(&opts, "timeout", "5000000", 0); // 5秒超时
av_dict_set(&opts, "fflags", "nobuffer+genpts", 0);
av_dict_set(&opts, "flags", "low_delay", 0);
av_dict_set(&opts, "avoid_negative_ts", "make_zero", 0);
av_dict_set(&opts, "err_detect", "ignore_err", 0);
| 状态转换 | 等待时间 | 超时行为 |
|---|---|---|
| 进站完成 → 允许出站 | in_out_interval (默认300秒) |
等待≤2小时,超时清零 |
| 出站完成 → 允许进站 | in_out_interval + TIME_WINDOW (默认600秒) |
等待≤2小时,超时清零 |
| 出站无进站记录 | 永远拦截 | 必须先进站才能出站 |
| 同方向连续操作 | 永远拦截 | 必须先完成对端操作 |
INBOUND_ALLOWED → 上次出站完成,等待 in_out_interval+TIME_WINDOW 后允许进站
OUTBOUND_ALLOWED → 上次进站完成,等待 in_out_interval 后允许出站
无记录出站 → 永远拦截(必须先进站)
锁定超2小时 → 自动清零释放(视为车辆已离开)
bool try_lock_in_station(const std::string& plate); // 原子锁定进站
bool try_lock_out_station(const std::string&plate); // 原子锁定出站
void lock_in_station(const std::string& plate); // 确认进站锁定
void lock_out_station(const std::string& plate); // 确认出站锁定
void unlock_rollback_station(const std::string& plate, bool is_in); // 失败回滚
void cleanup_station_cache(); // 2小时超时清理
void load_station_cache_from_db(); // 重启恢复
station_lock_cacheplate_number, last_in_time, last_out_time, current_mode帧格式: 0x02 + sign(1字节) + digits(8字节) + status(1字节) + 0x03
帧长度: 12字节
数据解析: weight_kg = digits_value / 100.0 (单位: 分→公斤)
有效状态: 排除 status='G'/'H' 的帧
重量范围: g_weight_min_kg ~ g_weight_max_kg
tcp_connect_timeout(可配置)// 稳定性判定:连续 g_weight_stable_samples 个样本波动 ≤ g_weight_stable_threshold
g_stability_samples.push_back(weight_kg);
if (size > g_weight_stable_samples) g_stability_samples.erase(begin);
// 候选数据:收集 g_weight_candidate_count 个有效读数
struct WeightMqttTask {
std::string plate;
int station_type; // 1=进站, 2=出站
std::string tb_num;
};
// 去重机制:30秒内同车牌只发送一次MQTT消息
static std::unordered_map<std::string, time_t> g_mqtt_dedup_map;
static const int MQTT_DEDUP_INTERVAL_SEC = 30;
httplib::SSLServer 创建HTTPS服务器[server] ip 字段解析)// SSL会话缓存:10分钟有效期
SSL_CTX_set_session_cache_mode(ssl_ctx, SSL_SESS_CACHE_SERVER);
SSL_CTX_set_timeout(ssl_ctx, 600);
// 优先使用ECDHE+AESGCM/ChaCha20密码套件
SSL_CTX_set_cipher_list(ssl_ctx,
"ECDHE-ECDSA-AES128-GCM-SHA256:"
"ECDHE-RSA-AES128-GCM-SHA256:"
"ECDHE-ECDSA-CHACHA20-POLY1305:...");
SSL_CTX_set_ecdh_auto(ssl_ctx, 1); // 优先X25519
| 路径 | 方法 | 功能 | 认证要求 |
|---|---|---|---|
/ |
GET | 监控首页 | 公开/基础 |
/video |
GET | 4路视频预览 | 公开/基础 |
/login |
GET | 登录页面 | 公开 |
/config |
GET | 系统配置 | 管理员 |
/locks |
GET | 锁定管理 | 公开/基础 |
/system |
GET | 系统监控 | 公开/基础 |
/api/monitor |
GET | 监控指标JSON | 公开 |
/api/messages |
GET | 记录列表JSON | 公开 |
/api/system/status |
GET | 系统资源状态 | 公开 |
/api/frpc/status |
GET | frpc隧道状态 | 管理员 |
/api/frpc/config |
GET/POST | frpc配置读写 | 超级管理员 |
/api/auth/login |
POST | 登录认证 | 公开 |
/api/auth/logout |
POST | 登出 | 已登录 |
/api/auth/status |
GET | 会话状态 | 公开 |
/api/station_locks |
GET | 锁定记录列表 | 公开 |
/api/clear_lock |
POST | 清除锁定 | 管理员 |
/api/video/{stream} |
GET | MJPEG视频流 | 公开 |
/api/photo/{path} |
GET | 照片访问 | 公开 |
架构: bcrypt密码哈希 + 内存+SQLite双层Session + CSRF Token + IP速率限制
// auth_db.h — 数据库层
struct User {
int id; std::string username; std::string password_hash;
int role; // 0=user, 1=admin, 2=superadmin
int enabled;
int failed_attempts; time_t locked_until;
};
struct Session {
std::string session_id; // 64字符hex
std::string csrf_token; // 64字符hex
int user_id; std::string username;
time_t created_at, last_active, expires_at;
int remember; // 1=延长会话(7天)
int user_role;
};
// 数据库表: users, sessions, audit_log
// WAL模式 + busy_timeout=5000ms
Session管理:
速率限制:
CSRF保护:
X-CSRF-Token 头安全响应头:
X-Content-Type-Options: nosniffX-Frame-Options: DENYX-XSS-Protection: 1; mode=blockContent-Security-Policy: default-src 'self'API: POST https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=chat_id
消息格式:
{
"receive_id": "{chat_id}",
"msg_type": "text",
"content": "{\"text\":\"工程名: xxx\\n车牌号: xxx\\n时间: xxx\\n...\"}"
}
重试策略:
Token管理:
g_tenant_token: 飞书租户访问令牌g_token_expire_timeTOKEN_REFRESH_BUFFER_SECONDS)架构: 基于 mosquittopp 类,继承回调机制
class MqttClient : public mosqpp::mosquittopp {
std::atomic<bool> connected{false};
std::atomic<MqttState> current_state{DISCONNECTED};
static const int MAX_RECONNECT_ATTEMPTS = 30;
};
连接管理:
connect_async(host, port, keepalive=60){client_id}_{pid}_{timestamp}消息发布:
acked 原子变量)消息内容: 车牌号 + 车牌颜色 + 车型 + 联单编号 + 进出站类型
主表: upload_records
CREATE TABLE upload_records (
id INTEGER PRIMARY KEY AUTOINCREMENT,
create_time DATETIME DEFAULT (datetime('now', 'localtime')),
capture_time INTEGER, -- fix24-v13: 抓拍时刻Unix时间戳
plate_number TEXT NOT NULL,
tb_num TEXT NOT NULL,
station_type INTEGER, -- 1=进站, 2=出站
lo_photo_path TEXT,
hi_photo_path TEXT,
lo_upload_status INTEGER DEFAULT 0,
hi_upload_status INTEGER DEFAULT 0,
feishu_status INTEGER DEFAULT 0,
retry_count INTEGER DEFAULT 0
);
-- 索引
CREATE INDEX idx_plate_number ON upload_records(plate_number);
CREATE INDEX idx_tb_num ON upload_records(tb_num);
CREATE INDEX idx_create_time ON upload_records(create_time);
CREATE INDEX idx_plate_station_time_status ON upload_records(
plate_number, station_type, create_time, lo_upload_status, hi_upload_status);
交替锁定表: station_lock_cache
CREATE TABLE station_lock_cache (
plate_number TEXT PRIMARY KEY,
last_in_time INTEGER,
last_out_time INTEGER,
current_mode INTEGER -- 0=INBOUND_ALLOWED, 1=OUTBOUND_ALLOWED
);
TIME_WINDOW缓存表: time_window_cache
-- 存储进站/出站工单配额缓存
CREATE TABLE time_window_cache (...);
认证数据库表 (独立SQLite文件):
CREATE TABLE users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT UNIQUE NOT NULL,
password_hash TEXT NOT NULL, -- bcrypt hash
role INTEGER DEFAULT 0,
enabled INTEGER DEFAULT 1,
failed_attempts INTEGER DEFAULT 0,
locked_until INTEGER DEFAULT 0,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
);
CREATE TABLE sessions (...);
CREATE TABLE audit_log (...);
系统监控数据库 (独立SQLite文件):
data/system_metrics.dbsqlite3_busy_timeout(g_db, 100); // busy超时100ms
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX
// WAL模式(认证数据库)
// 认证数据库: busy_timeout=5000ms
g_plate_station_cache) + SQLite 双层g_in_bill_cache / g_out_bill_cache (内存)db_cleanup_old_records + db_vacuumSELECT 1 探活,失败自动重连DB_CLEANUP_THRESHOLD_MB)stdout/stderr → pipe() → 读取线程 → 内存buffer(vector<string>)
│
├── Web API读取(零磁盘I/O)
└── 定时刷盘(默认23:20) → 磁盘文件
| 参数 | 默认值 | 说明 |
|---|---|---|
enabled |
true | 1=内存缓冲模式, 0=直写文件 |
buffer_size_mb |
20MB | 内存缓冲区上限 |
flush_time |
23:20 | 每日刷盘时间 |
retention_days |
30天 | 日志保留天数 |
redirect_stdout |
true | 是否重定向stdout/stderr |
auto_flush_on_exit |
true | 程序退出时自动刷盘 |
flush_time 时将内存buffer全量写入磁盘buffer_size_mb 时丢弃最旧日志retention_days 清理过期日志文件通过 frpc admin HTTP API 获取隧道状态:
std::string call_admin_api(const std::string &endpoint) {
// URL: http://{admin_addr}:{admin_port}/api/serverinfo
// Basic Auth: g_frpc_admin_user : g_frpc_admin_password
// 超时: connect=1s, total=2s
}
systemctl is-active frpc — systemd状态pgrep -x frpc — 进程存在性frpc.toml 文件内容backup_path → 写入新配置systemctl restart frpc → 等待 restart_check_timeout 秒g_frpc_protected_tunnels(不可删除)authorized_keys 文件中的SSH公钥ed25519, ecdsa-sha2-*bool validate_key_format(const std::string &key_line) {
// 格式: type base64_data [comment]
// type必须是已知SSH密钥类型
// base64数据至少20字符
}
g_ssh_keys_path (默认 ~/.ssh/authorized_keys)| 参数 | 默认值 | 说明 |
|---|---|---|
project_name |
(必填) | 工程名 |
point_number |
(必填) | 点位编号 |
throughway |
(必填) | 出入口编号 |
rtsp_url_front_in |
(必填) | 进站前向摄像头RTSP URL |
rtsp_url_front_out |
(必填) | 出站前向摄像头RTSP URL |
rtsp_url_side_in |
(必填) | 进站侧向摄像头RTSP URL |
rtsp_url_side_out |
(必填) | 出站侧向摄像头RTSP URL |
app_api |
(必填) | 平台API地址 |
app_key |
(必填) | 平台API Key |
app_secret |
(必填) | 平台API Secret |
DEBUG_LOG |
0 | 调试日志(1=开启, 0=正式) |
TestFlag |
0 | 测试环境标记 |
wType |
1 | 工地类型(1=工地, 2=码头, 3=回填) |
TIME_WINDOW |
10 | 时间窗口(分钟),控制进站/出站配额 |
MAX_PHOTO_GROUPS |
2 | 每侧最大照片组数 |
in_out_interval |
5 | 进出站间隔(分钟),转换为秒: ×60 |
PLATE_CONFIDENCE_THRESHOLD |
0.8 | 上传触发置信度阈值 |
PLATE_LOG_THRESHOLD |
0.5 | 日志记录置信度阈值 |
AlternatingMerge |
0 | 交替锁定开关(1=启用) |
roi_in_x/y/w/h |
0 | 进站ROI区域坐标 |
roi_in_enabled |
0 | 进站ROI启用(1=启用) |
roi_out_x/y/w/h |
0 | 出站ROI区域坐标 |
roi_out_enabled |
0 | 出站ROI启用 |
roi_debug_enabled |
0 | ROI调试模式 |
hw_decode_mode |
auto | 解码模式(auto/soft/drm) |
hw_decode_device |
/dev/dri/renderD128 | DRM设备路径 |
rtsp_transport |
tcp | RTSP传输协议(tcp/udp) |
PhotoMaxCapacityMB |
1024 | 照片存储容量阈值(MB) |
LogRetentionDays |
30 | 日志保留天数 |
| 参数 | 默认值 | 说明 |
|---|---|---|
ip |
http://0.0.0.0:8080 | 服务地址(端口从此字段解析) |
| 参数 | 默认值 | 说明 |
|---|---|---|
enabled |
0 | SSL启用(1=启用) |
cert_path |
(空) | SSL证书文件路径 |
key_path |
(空) | SSL私钥文件路径 |
| 参数 | 默认值 | 说明 |
|---|---|---|
enabled |
0 | 认证启用(1=启用) |
db_path |
data/auth.db | 认证数据库路径(相对pathComm) |
| 参数 | 默认值 | 说明 |
|---|---|---|
APP_ID |
(必填) | 飞书应用ID |
APP_SECRET |
(必填) | 飞书应用密钥 |
CHAT_ID |
(必填) | 飞书群聊ID |
TIMEOUT_SECOND |
10 | HTTP超时(秒) |
WarningSigns |
0 | 抑制紧急告警(1=抑制) |
| 参数 | 默认值 | 说明 |
|---|---|---|
flagWeight |
0 | 称重启用(1=启用) |
weight_threshold_in |
(必填) | 进站重量阈值(公斤) |
weight_threshold_out |
(必填) | 出站重量阈值(公斤) |
default_entry_weight |
0 | 默认进站重量 |
default_exit_weight |
0 | 默认出站重量 |
weight_detection_time |
10 | 称重检测时间(秒) |
tcp_connect_timeout |
5 | TCP连接超时(秒) |
weight_server_ip |
(必填) | 仪表IP地址 |
weight_server_port |
(必填) | 仪表端口 |
MAX_WEIGHT |
100000 | 最大有效重量(公斤) |
STABLE_SAMPLE_COUNT |
5 | 稳定判定样本数 |
STABLE_THRESHOLD_KG |
50 | 稳定波动阈值(公斤) |
CANDIDATE_DATA_COUNT |
10 | 候选数据数量 |
MAX_UPLOAD_RETRIES |
3 | 最大重试次数 |
RETRY_DELAY_MS |
1000 | 重试延迟(毫秒) |
| 参数 | 默认值 | 说明 |
|---|---|---|
MQTT_HOST |
(空) | MQTT Broker地址 |
MQTT_PORT |
1883 | MQTT端口 |
MQTT_USER |
(空) | 用户名 |
MQTT_PASS |
(空) | 密码 |
MQTT_TOPIC |
(必填) | 发布主题 |
MQTT_CLIENT_ID |
PlateRecApp | 客户端ID |
PLATE_COLOR |
黄色 | 默认车牌颜色 |
VEHICLE_TYPE |
渣土车 | 默认车型 |
| 参数 | 默认值 | 说明 |
|---|---|---|
monitor_interval |
30 | 采样间隔(秒) |
temp_alert_threshold |
80 | 温度告警阈值(°C) |
cpu_alert_threshold |
90 | CPU告警阈值(%) |
db_path |
data/system_metrics.db | 监控数据库路径 |
history_retention_days |
30 | 全量数据保留天数 |
aggregation_retention_days |
365 | 聚合数据保留天数 |
flush_time |
23:20 | 每日刷盘时间 |
| 参数 | 默认值 | 说明 |
|---|---|---|
config_path |
/etc/frp/frpc.toml | frpc配置文件路径 |
backup_path |
(自动) | 备份文件路径 |
protected_tunnels |
(空) | 受保护隧道列表(逗号分隔) |
restart_check_timeout |
10 | 重启后等待检测时间(秒) |
auto_rollback |
1 | 失败自动回滚(1=启用) |
web_enabled |
1 | Web管理页面开关 |
admin_addr |
127.0.0.1 | frpc admin API地址 |
admin_port |
7400 | frpc admin API端口 |
admin_user |
(空) | admin用户名 |
admin_password |
(空) | admin密码 |
| 参数 | 默认值 | 说明 |
|---|---|---|
ttyd_port |
7681 | ttyd Web终端端口 |
ttyd_credential |
(空) | ttyd认证凭证(user:pass) |
ttyd_max_clients |
5 | 最大客户端数 |
ssh_keys_path |
~/.ssh/authorized_keys | SSH公钥文件路径 |
| 参数 | 默认值 | 说明 |
|---|---|---|
enabled |
1 | 内存日志模式(1=内存, 0=直写) |
log_file |
PlateRecApp.log | 日志文件名 |
buffer_size_mb |
20 | 缓冲区大小(MB) |
flush_time |
23:20 | 刷盘时间(HH:MM) |
retention_days |
30 | 保留天数 |
redirect_stdout |
1 | 重定向stdout/stderr |
auto_flush_on_exit |
1 | 退出时自动刷盘 |
cmake_minimum_required(VERSION 3.25.1)
project(HyperLPR3-LinuxAPP VERSION 1.0.0 LANGUAGES CXX C)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
构建类型默认: Release
| 标志 | 作用 |
|---|---|
-O3 |
最高级别速度优化 |
-s |
去除符号表(strip) |
--as-needed |
只链接实际使用的符号 |
--gc-sections |
删除未使用的段 |
| POST_BUILD strip | 编译后strip进一步减小体积 |
可选优化(注释状态):
-Os: 体积优先优化-flto: 链接时优化(减小10-30%体积)-fvisibility=hidden: 隐藏符号BUILD_SHARED_LIBS ON,可通过 -DUSE_STATIC_LIBS=ON 切换静态src/
├── main.cpp # 主入口 + 调度
├── common.cpp/h # 全局类型定义
├── config.cpp/h # 配置解析
├── plate_recognizer.cpp/h # 车牌识别引擎
├── rtsp_capture.cpp/h # RTSP视频采集
├── web_server.cpp/h # Web管理后台
├── database.cpp/h # SQLite数据库
├── network_client.cpp/h # HTTP API通信
├── feishu_client.cpp/h # 飞书推送
├── mqtt_client.cpp/h # MQTT客户端
├── weight_scale.cpp/h # 称重系统
├── station_lock.cpp/h # 交替锁定
├── log_manager.cpp/h # 日志管理
├── frpc_manager.cpp/h # frpc管理
├── ssh_manager.cpp/h # SSH管理
├── system_monitor.cpp/h # 系统监控
├── system_metrics_manager.cpp/h # 监控历史数据
├── monitor.cpp/h # 指标打印
├── utils.cpp/h # 工具函数
├── auth_api.cpp/h # 认证API
├── auth_crypto.cpp/h # bcrypt + 安全随机
├── auth_db.cpp/h # 认证数据库
├── auth_session.cpp/h # 会话管理
├── auth_middleware.cpp/h # 认证中间件
├── auth_rate_limiter.h # 速率限制(header-only)
└── bcrypt/ # bcrypt实现
/opt/openAI/project/003.PlateRecAPP/ # pathComm (可执行文件所在目录)
├── PlateRecApp # 可执行文件
├── config.ini # 主配置文件
├── config.txt # MD5校验配置
├── simsun.ttc # 中文字体文件
├── hyperlpr3/
│ └── resource/models/r2_mobile/ # HyperLPR3模型文件
├── assets/web/ # Web前端HTML页面
│ ├── login.html
│ ├── system.html
│ └── ...
├── data/ # 数据库目录
│ ├── upload_records.db # 主数据库
│ ├── auth.db # 认证数据库
│ └── system_metrics.db # 监控数据库
├── PlateJPG/ # 照片存储目录
├── third_party/ # 第三方依赖
└── sync_to_gogs.sh # Gogs同步脚本
[Unit]
Description=PlateRecApp License Plate Recognition
After=network.target
[Service]
Type=simple
WorkingDirectory=/opt/openAI/project/003.PlateRecAPP
ExecStart=/opt/openAI/project/003.PlateRecAPP/PlateRecApp config.ini
Restart=always
RestartSec=5
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
755644(含敏感信息,不可公开)7557551. 解析可执行文件路径 → 确定 pathComm
2. 读取CPU序列号 → MD5三重校验 → 验证config.txt
3. 解析config.ini → 加载所有配置
4. 计算时区偏移 → 初始化cURL
5. 初始化SQLite数据库 → 加载缓存
6. 初始化HyperLPR3模型
7. 创建4路RTSPCapture → 启动采集线程
8. 启动识别工作线程
9. 初始化认证系统 → 启动Web服务器
10. 启动称重系统 → 启动MQTT客户端
11. 进入主循环(100ms间隔)
crypt_r,成本因子自动调整failed_attempts + locked_until)audit_log 表crypt_r 系统调用)secure_compare 时间安全比较(防时序攻击)[ssl] enabled=1)is_safe_file_path() 防路径穿越.. / / / \ 字符realpath() 验证绝对路径在基础目录内详见 CHANGELOG.md
主要版本里程碑:
extern 全局变量,耦合度高,应逐步迁移到单例/依赖注入本文档持续更新
最后更新: 2026-07-06 | 基于 PlateRecApp v43.2 fix24 源码