generated from guanyuankai/bonus-edge-proxy
feat(video+battery): 完成视频服务,加入电池管理模块.
This commit is contained in:
parent
9280f52aef
commit
79b2616493
|
|
@ -72,6 +72,8 @@ add_library(vehicle_road_lib STATIC
|
||||||
src/mysqlManager/AlarmDao.cpp
|
src/mysqlManager/AlarmDao.cpp
|
||||||
src/mysqlManager/DeviceIdentificationDao.cpp
|
src/mysqlManager/DeviceIdentificationDao.cpp
|
||||||
src/mysqlManager/ResourceFileDao.cpp
|
src/mysqlManager/ResourceFileDao.cpp
|
||||||
|
#电池管理模块
|
||||||
|
src/batteryService/battery_service.cc
|
||||||
)
|
)
|
||||||
|
|
||||||
target_include_directories(vehicle_road_lib PUBLIC
|
target_include_directories(vehicle_road_lib PUBLIC
|
||||||
|
|
|
||||||
|
|
@ -20,12 +20,12 @@
|
||||||
"enable": true,
|
"enable": true,
|
||||||
"line": {
|
"line": {
|
||||||
"p1": {
|
"p1": {
|
||||||
"x": 0.39809998869895935,
|
"x": 0.2556999921798706,
|
||||||
"y": 0.8816999793052673
|
"y": 0.848800003528595
|
||||||
},
|
},
|
||||||
"p2": {
|
"p2": {
|
||||||
"x": 0.8337000012397766,
|
"x": 0.6531999707221985,
|
||||||
"y": 0.5864999890327454
|
"y": 0.8278999924659729
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"name": "Main_Gate_Line"
|
"name": "Main_Gate_Line"
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ services:
|
||||||
- /dev/ttyS7:/dev/ttyS7
|
- /dev/ttyS7:/dev/ttyS7
|
||||||
- /dev/ttyS9:/dev/ttyS9
|
- /dev/ttyS9:/dev/ttyS9
|
||||||
- /dev/snd:/dev/snd
|
- /dev/snd:/dev/snd
|
||||||
|
- /dev/ttyS4:/dev/ttyS4
|
||||||
|
|
||||||
# --- VPU/NPU/RGA/GPU 硬件访问 ---
|
# --- VPU/NPU/RGA/GPU 硬件访问 ---
|
||||||
- /dev/mpp_service:/dev/mpp_service
|
- /dev/mpp_service:/dev/mpp_service
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ struct TrackedVehicle {
|
||||||
|
|
||||||
// [预留] 如果需要记录车辆经过线条的时间,可以在这里加字段
|
// [预留] 如果需要记录车辆经过线条的时间,可以在这里加字段
|
||||||
// int64_t cross_line_timestamp = 0;
|
// int64_t cross_line_timestamp = 0;
|
||||||
|
float confidence;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 每一帧的数据包(用于线程间传递)
|
// 每一帧的数据包(用于线程间传递)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,208 @@
|
||||||
|
#include "battery_service.h"
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <termios.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "spdlog/spdlog.h"
|
||||||
|
|
||||||
|
// 协议常量
|
||||||
|
#define FRAME_HEAD 0xA5
|
||||||
|
#define CMD_REPORT 0x01
|
||||||
|
#define CMD_SET_MODE 0x02
|
||||||
|
#define CMD_SET_ALARM 0x03
|
||||||
|
#define CMD_ACK 0xAA
|
||||||
|
|
||||||
|
BatteryService::BatteryService(const std::string& port, int baud_rate)
|
||||||
|
: m_port_name(port), m_baud_rate(baud_rate), m_running(false) {
|
||||||
|
// 初始化数据结构为0
|
||||||
|
std::memset(&m_latest_data, 0, sizeof(m_latest_data));
|
||||||
|
}
|
||||||
|
|
||||||
|
BatteryService::~BatteryService() {
|
||||||
|
stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BatteryService::start() {
|
||||||
|
if (!openPort()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
m_running = true;
|
||||||
|
m_rx_thread = std::thread(&BatteryService::receiveLoop, this);
|
||||||
|
spdlog::info("BatteryService started on port {}", m_port_name);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BatteryService::stop() {
|
||||||
|
m_running = false;
|
||||||
|
if (m_rx_thread.joinable()) {
|
||||||
|
m_rx_thread.join();
|
||||||
|
}
|
||||||
|
if (m_fd >= 0) {
|
||||||
|
close(m_fd);
|
||||||
|
m_fd = -1;
|
||||||
|
}
|
||||||
|
spdlog::info("BatteryService stopped.");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BatteryService::openPort() {
|
||||||
|
m_fd = open(m_port_name.c_str(), O_RDWR | O_NOCTTY | O_NDELAY);
|
||||||
|
if (m_fd < 0) {
|
||||||
|
spdlog::error("Failed to open serial port: {}", m_port_name);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
fcntl(m_fd, F_SETFL, 0); // 恢复阻塞模式
|
||||||
|
|
||||||
|
struct termios options;
|
||||||
|
tcgetattr(m_fd, &options);
|
||||||
|
|
||||||
|
speed_t speed = (m_baud_rate == 115200) ? B115200 : B9600;
|
||||||
|
cfsetispeed(&options, speed);
|
||||||
|
cfsetospeed(&options, speed);
|
||||||
|
|
||||||
|
options.c_cflag |= (CLOCAL | CREAD);
|
||||||
|
options.c_cflag &= ~PARENB;
|
||||||
|
options.c_cflag &= ~CSTOPB;
|
||||||
|
options.c_cflag &= ~CSIZE;
|
||||||
|
options.c_cflag |= CS8;
|
||||||
|
options.c_cflag &= ~CRTSCTS;
|
||||||
|
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
|
||||||
|
options.c_iflag &= ~(IXON | IXOFF | IXANY);
|
||||||
|
options.c_iflag &= ~(ICRNL | INLCR);
|
||||||
|
options.c_oflag &= ~OPOST;
|
||||||
|
|
||||||
|
tcsetattr(m_fd, TCSANOW, &options);
|
||||||
|
tcflush(m_fd, TCIOFLUSH);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int BatteryService::writeData(const uint8_t* data, size_t len) {
|
||||||
|
if (m_fd < 0)
|
||||||
|
return -1;
|
||||||
|
return write(m_fd, data, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BatteryService::setMode(uint8_t mode) {
|
||||||
|
sendPacket(CMD_SET_MODE, &mode, 1);
|
||||||
|
spdlog::info("BatteryService: Set Mode to {}", mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BatteryService::setAlarm(bool on) {
|
||||||
|
uint8_t val = on ? 1 : 0;
|
||||||
|
sendPacket(CMD_SET_ALARM, &val, 1);
|
||||||
|
spdlog::info("BatteryService: Set Alarm to {}", val);
|
||||||
|
}
|
||||||
|
|
||||||
|
nlohmann::json BatteryService::getStatusJson() {
|
||||||
|
std::lock_guard<std::mutex> lock(m_data_mutex);
|
||||||
|
if (!m_has_data) {
|
||||||
|
return {{"status", "waiting_for_data"}};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {{"battery_cap", m_latest_data.battery_cap},
|
||||||
|
{"time_to_full_min", m_latest_data.time_to_full},
|
||||||
|
{"time_to_empty_min", m_latest_data.time_to_empty},
|
||||||
|
{"status_code", m_latest_data.battery_status},
|
||||||
|
{"temperature_c", (float)m_latest_data.temperature / 10.0f},
|
||||||
|
{"system_mode", m_latest_data.system_mode},
|
||||||
|
{"alarm_flag", m_latest_data.alarm_flag}};
|
||||||
|
}
|
||||||
|
|
||||||
|
void BatteryService::sendPacket(uint8_t cmd, const uint8_t* payload, uint8_t len) {
|
||||||
|
std::vector<uint8_t> packet;
|
||||||
|
packet.push_back(FRAME_HEAD);
|
||||||
|
packet.push_back(cmd);
|
||||||
|
packet.push_back(len);
|
||||||
|
if (len > 0 && payload) {
|
||||||
|
packet.insert(packet.end(), payload, payload + len);
|
||||||
|
}
|
||||||
|
uint32_t crc = calculateCRC32(packet.data(), packet.size());
|
||||||
|
packet.push_back((crc >> 0) & 0xFF);
|
||||||
|
packet.push_back((crc >> 8) & 0xFF);
|
||||||
|
packet.push_back((crc >> 16) & 0xFF);
|
||||||
|
packet.push_back((crc >> 24) & 0xFF);
|
||||||
|
|
||||||
|
writeData(packet.data(), packet.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t BatteryService::calculateCRC32(const uint8_t* data, size_t len) {
|
||||||
|
uint32_t crc = 0xFFFFFFFF;
|
||||||
|
for (size_t i = 0; i < len; i++) {
|
||||||
|
uint32_t byte = data[i];
|
||||||
|
crc = crc ^ byte;
|
||||||
|
for (int j = 0; j < 8; j++) {
|
||||||
|
if (crc & 1)
|
||||||
|
crc = (crc >> 1) ^ 0xEDB88320;
|
||||||
|
else
|
||||||
|
crc = crc >> 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return crc ^ 0xFFFFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BatteryService::processFrame(const uint8_t* frame, size_t totalLen) {
|
||||||
|
uint8_t cmd = frame[1];
|
||||||
|
const uint8_t* payload = &frame[3];
|
||||||
|
|
||||||
|
if (cmd == CMD_REPORT) {
|
||||||
|
if (totalLen >= sizeof(BatteryPacket_t) + 7) {
|
||||||
|
std::lock_guard<std::mutex> lock(m_data_mutex);
|
||||||
|
memcpy(&m_latest_data, payload, sizeof(BatteryPacket_t));
|
||||||
|
m_has_data = true;
|
||||||
|
|
||||||
|
// 可选:在这里记录日志,或者只在Debug时记录,避免刷屏
|
||||||
|
// spdlog::debug("Battery Update: {}%", m_latest_data.battery_cap);
|
||||||
|
|
||||||
|
uint8_t ack[] = "OK";
|
||||||
|
sendPacket(CMD_ACK, ack, 2);
|
||||||
|
}
|
||||||
|
} else if (cmd == CMD_ACK) {
|
||||||
|
spdlog::debug("BatteryService: Received ACK from MCU");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BatteryService::receiveLoop() {
|
||||||
|
uint8_t buf[128];
|
||||||
|
while (m_running) {
|
||||||
|
if (m_fd < 0) {
|
||||||
|
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int n = read(m_fd, buf, sizeof(buf));
|
||||||
|
if (n > 0) {
|
||||||
|
m_rx_buffer.insert(m_rx_buffer.end(), buf, buf + n);
|
||||||
|
while (m_rx_buffer.size() >= 7) {
|
||||||
|
if (m_rx_buffer[0] != FRAME_HEAD) {
|
||||||
|
m_rx_buffer.erase(m_rx_buffer.begin());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
uint8_t dataLen = m_rx_buffer[2];
|
||||||
|
size_t frameLen = 3 + dataLen + 4;
|
||||||
|
if (m_rx_buffer.size() < frameLen)
|
||||||
|
break;
|
||||||
|
|
||||||
|
uint32_t receivedCRC = 0;
|
||||||
|
receivedCRC |= m_rx_buffer[frameLen - 4] << 0;
|
||||||
|
receivedCRC |= m_rx_buffer[frameLen - 3] << 8;
|
||||||
|
receivedCRC |= m_rx_buffer[frameLen - 2] << 16;
|
||||||
|
receivedCRC |= m_rx_buffer[frameLen - 1] << 24;
|
||||||
|
|
||||||
|
if (calculateCRC32(m_rx_buffer.data(), frameLen - 4) == receivedCRC) {
|
||||||
|
processFrame(m_rx_buffer.data(), frameLen);
|
||||||
|
m_rx_buffer.erase(m_rx_buffer.begin(), m_rx_buffer.begin() + frameLen);
|
||||||
|
} else {
|
||||||
|
spdlog::warn("BatteryService: CRC Error");
|
||||||
|
m_rx_buffer.erase(m_rx_buffer.begin());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,64 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
#include <functional>
|
||||||
|
#include <mutex>
|
||||||
|
#include <string>
|
||||||
|
#include <thread>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "nlohmann/json.hpp"
|
||||||
|
|
||||||
|
// 定义数据结构 (保持字节对齐)
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
struct BatteryPacket_t {
|
||||||
|
uint8_t battery_cap; // 1. 电量百分比
|
||||||
|
uint16_t time_to_full; // 2. 预测充满时间
|
||||||
|
uint16_t time_to_empty; // 3. 预测放电时间
|
||||||
|
uint8_t battery_status; // 4. 电池状态
|
||||||
|
int16_t temperature; // 5. 温度
|
||||||
|
uint8_t system_mode; // 6. 模式
|
||||||
|
uint8_t alarm_flag; // 7. 报警标志
|
||||||
|
};
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
class BatteryService {
|
||||||
|
public:
|
||||||
|
BatteryService(const std::string& port, int baud_rate);
|
||||||
|
~BatteryService();
|
||||||
|
|
||||||
|
// 初始化串口并启动接收线程
|
||||||
|
bool start();
|
||||||
|
// 停止线程并关闭串口
|
||||||
|
void stop();
|
||||||
|
|
||||||
|
// API 调用的控制接口
|
||||||
|
void setMode(uint8_t mode);
|
||||||
|
void setAlarm(bool on);
|
||||||
|
|
||||||
|
// 获取当前缓存的电池数据 (JSON格式)
|
||||||
|
nlohmann::json getStatusJson();
|
||||||
|
|
||||||
|
private:
|
||||||
|
// 内部串口操作
|
||||||
|
bool openPort();
|
||||||
|
void receiveLoop();
|
||||||
|
int writeData(const uint8_t* data, size_t len);
|
||||||
|
void sendPacket(uint8_t cmd, const uint8_t* payload, uint8_t len);
|
||||||
|
uint32_t calculateCRC32(const uint8_t* data, size_t len);
|
||||||
|
void processFrame(const uint8_t* frame, size_t totalLen);
|
||||||
|
|
||||||
|
// 成员变量
|
||||||
|
std::string m_port_name;
|
||||||
|
int m_baud_rate;
|
||||||
|
int m_fd = -1;
|
||||||
|
|
||||||
|
std::atomic<bool> m_running;
|
||||||
|
std::thread m_rx_thread;
|
||||||
|
std::vector<uint8_t> m_rx_buffer;
|
||||||
|
|
||||||
|
// 数据缓存与线程安全
|
||||||
|
BatteryPacket_t m_latest_data;
|
||||||
|
std::mutex m_data_mutex;
|
||||||
|
bool m_has_data = false;
|
||||||
|
};
|
||||||
|
|
@ -74,11 +74,10 @@ void poll_system_metrics(boost::asio::steady_timer& timer, SystemMonitor::System
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
// TODO: [GYK] DEV#1: 将 URL 放入 config.json 中读取
|
// TODO: [GYK] DEV#1: 将 URL 放入 config.json 中读取
|
||||||
// std::string cam_rtsp_input = "rtsp://admin:123456@192.168.1.57:554/stream0";
|
std::string cam_rtsp_input = "rtsp://admin:123456@192.168.1.57:554/stream0";
|
||||||
std::string cam_rtsp_input = "../data/test_car2.mp4";
|
// std::string cam_rtsp_input = "../data/test_car2.mp4";
|
||||||
// std::string cam_rtsp_input =
|
// std::string cam_rtsp_input =
|
||||||
// "rtsp://admin:hzx12345@192.168.1.10:554/Streaming/Channels/1901";
|
// "rtsp://admin:hzx12345@192.168.1.10:554/Streaming/Channels/1301";
|
||||||
|
|
||||||
std::string algorithm_rtsp_output = "rtsp://127.0.0.1:8554/processed";
|
std::string algorithm_rtsp_output = "rtsp://127.0.0.1:8554/processed";
|
||||||
const std::string config_path = "/app/config/config.json";
|
const std::string config_path = "/app/config/config.json";
|
||||||
if (!ConfigManager::getInstance().load(config_path)) {
|
if (!ConfigManager::getInstance().load(config_path)) {
|
||||||
|
|
|
||||||
|
|
@ -198,6 +198,7 @@ void VideoPipeline::processCrossing(const TrackedVehicle& vehicle, const cv::Mat
|
||||||
|
|
||||||
std::string fileName = fmt::format("{}_id{}.jpg", timeStr, vehicle.id);
|
std::string fileName = fmt::format("{}_id{}.jpg", timeStr, vehicle.id);
|
||||||
std::string fullPath = fmt::format("{}/{}", saveDir, fileName);
|
std::string fullPath = fmt::format("{}/{}", saveDir, fileName);
|
||||||
|
std::string dbPath = fmt::format("{}/{}", "/captures", fileName);
|
||||||
|
|
||||||
// === 2. 安全截图 (内存操作,无需加数据库锁) ===
|
// === 2. 安全截图 (内存操作,无需加数据库锁) ===
|
||||||
cv::Rect safeBox = vehicle.box;
|
cv::Rect safeBox = vehicle.box;
|
||||||
|
|
@ -258,7 +259,7 @@ void VideoPipeline::processCrossing(const TrackedVehicle& vehicle, const cv::Mat
|
||||||
bool fileSaved =
|
bool fileSaved =
|
||||||
fileDao.SaveFile("tb_device_identification_data", // source_table
|
fileDao.SaveFile("tb_device_identification_data", // source_table
|
||||||
dataId, // business_id
|
dataId, // business_id
|
||||||
fullPath, // file_path
|
dbPath, // file_path
|
||||||
fileName, // source_file_name
|
fileName, // source_file_name
|
||||||
FileType::ORIGINAL // file_type
|
FileType::ORIGINAL // file_type
|
||||||
);
|
);
|
||||||
|
|
@ -360,7 +361,7 @@ void VideoPipeline::updateTracker(const FrameData& frameData) {
|
||||||
newTrack.missing_frames = 0;
|
newTrack.missing_frames = 0;
|
||||||
newTrack.ev_score = current_is_ev;
|
newTrack.ev_score = current_is_ev;
|
||||||
newTrack.last_class_id = det.class_id;
|
newTrack.last_class_id = det.class_id;
|
||||||
|
newTrack.confidence = det.confidence;
|
||||||
tracks_[newTrack.id] = newTrack;
|
tracks_[newTrack.id] = newTrack;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -382,51 +383,43 @@ void VideoPipeline::updateTracker(const FrameData& frameData) {
|
||||||
void VideoPipeline::drawOverlay(cv::Mat& frame, const std::vector<TrackedVehicle>& trackedObjects) {
|
void VideoPipeline::drawOverlay(cv::Mat& frame, const std::vector<TrackedVehicle>& trackedObjects) {
|
||||||
std::lock_guard<std::mutex> lock(config_mtx_);
|
std::lock_guard<std::mutex> lock(config_mtx_);
|
||||||
|
|
||||||
// 1. 画绊线 (保持不变)
|
|
||||||
if (tripwire_config_.enabled) {
|
if (tripwire_config_.enabled) {
|
||||||
cv::line(frame, tripwire_p1_pixel_, tripwire_p2_pixel_, cv::Scalar(0, 255, 255), 2);
|
cv::line(frame, tripwire_p1_pixel_, tripwire_p2_pixel_, cv::Scalar(0, 255, 255), 2);
|
||||||
cv::putText(frame, tripwire_config_.name, tripwire_p1_pixel_, cv::FONT_HERSHEY_SIMPLEX, 0.7,
|
cv::putText(frame, tripwire_config_.name, tripwire_p1_pixel_, cv::FONT_HERSHEY_SIMPLEX, 0.7,
|
||||||
cv::Scalar(0, 255, 255), 2);
|
cv::Scalar(0, 255, 255), 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 画车辆 (已修改)
|
|
||||||
for (const auto& trk : trackedObjects) {
|
for (const auto& trk : trackedObjects) {
|
||||||
if (trk.missing_frames > 0)
|
if (trk.missing_frames > 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// 设置颜色:EV为绿色,燃油车为红色
|
|
||||||
cv::Scalar color = (trk.last_class_id == 1) ? cv::Scalar(0, 255, 0) : cv::Scalar(0, 0, 255);
|
cv::Scalar color = (trk.last_class_id == 1) ? cv::Scalar(0, 255, 0) : cv::Scalar(0, 0, 255);
|
||||||
|
|
||||||
// 绘制车辆边框
|
|
||||||
cv::rectangle(frame, trk.box, color, 2);
|
cv::rectangle(frame, trk.box, color, 2);
|
||||||
|
|
||||||
// === [修改开始] 文字居中显示 EV / FUEL ===
|
std::stringstream ss;
|
||||||
|
ss << trk.label << " " << std::fixed << std::setprecision(2) << trk.confidence;
|
||||||
|
std::string text = ss.str();
|
||||||
|
|
||||||
// 1. 确定显示的文本
|
int fontFace = cv::FONT_HERSHEY_SIMPLEX;
|
||||||
// std::string text = (trk.last_class_id == 1) ? "EV" : "FUEL";
|
double fontScale = 0.6;
|
||||||
|
int thickness = 1;
|
||||||
|
int baseline = 0;
|
||||||
|
|
||||||
// 2. 设置字体参数
|
cv::Size textSize = cv::getTextSize(text, fontFace, fontScale, thickness, &baseline);
|
||||||
// int fontFace = cv::FONT_HERSHEY_SIMPLEX;
|
|
||||||
// double fontScale = 0.8; // 稍微调大一点以便在框内看清
|
|
||||||
// int thickness = 2;
|
|
||||||
// int baseline = 0;
|
|
||||||
|
|
||||||
// 3. 计算文字本身的宽高
|
cv::Point textOrg(trk.box.x, trk.box.y - 5);
|
||||||
// cv::Size textSize = cv::getTextSize(text, fontFace, fontScale, thickness, &baseline);
|
|
||||||
|
|
||||||
// 4. 计算检测框的中心点
|
if (textOrg.y < textSize.height) {
|
||||||
// cv::Point boxCenter(trk.box.x + trk.box.width / 2, trk.box.y + trk.box.height / 2);
|
textOrg.y = trk.box.y + textSize.height + 5;
|
||||||
|
}
|
||||||
|
|
||||||
// 5. 计算文字绘制的起始点 (Origin)
|
cv::rectangle(frame, textOrg + cv::Point(0, baseline),
|
||||||
// 使得文字的中心与框的中心对齐
|
textOrg + cv::Point(textSize.width, -textSize.height), color, cv::FILLED);
|
||||||
// X轴: 框中心X - 文字宽度的一半
|
|
||||||
// Y轴: 框中心Y + 文字高度的一半 (注意OpenCV原点在左上角,文字基线在下方)
|
|
||||||
// cv::Point textOrg(boxCenter.x - textSize.width / 2, boxCenter.y + textSize.height / 2);
|
|
||||||
|
|
||||||
// 6. 绘制文字
|
cv::Scalar textColor =
|
||||||
// cv::putText(frame, text, textOrg, fontFace, fontScale, color, thickness);
|
(trk.last_class_id == 1) ? cv::Scalar(0, 0, 0) : cv::Scalar(255, 255, 255);
|
||||||
|
cv::putText(frame, text, textOrg, fontFace, fontScale, textColor, thickness);
|
||||||
// === [修改结束] ===
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 调试信息 (保持不变)
|
// 调试信息 (保持不变)
|
||||||
|
|
@ -450,7 +443,7 @@ void VideoPipeline::processLoop(std::string inputUrl, std::string outputUrl, boo
|
||||||
|
|
||||||
int width = cap.get(cv::CAP_PROP_FRAME_WIDTH);
|
int width = cap.get(cv::CAP_PROP_FRAME_WIDTH);
|
||||||
int height = cap.get(cv::CAP_PROP_FRAME_HEIGHT);
|
int height = cap.get(cv::CAP_PROP_FRAME_HEIGHT);
|
||||||
const double TARGET_FPS = 30.0;
|
const double TARGET_FPS = 20.0;
|
||||||
|
|
||||||
std::stringstream pipeline;
|
std::stringstream pipeline;
|
||||||
pipeline << "appsrc ! "
|
pipeline << "appsrc ! "
|
||||||
|
|
|
||||||
|
|
@ -67,6 +67,6 @@ private:
|
||||||
int model_data_size_;
|
int model_data_size_;
|
||||||
|
|
||||||
const std::vector<std::string> CLASS_NAMES = {"fuel_car", "new_energy_car"};
|
const std::vector<std::string> CLASS_NAMES = {"fuel_car", "new_energy_car"};
|
||||||
const float obj_thresh_ = 0.25f;
|
const float obj_thresh_ = 0.60f;
|
||||||
const float nms_thresh_ = 0.45f;
|
const float nms_thresh_ = 0.45f;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue