From f1a813048e9e453c4611d364428e6ee55b8e5ef7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=A4=E7=9F=A5=E6=99=BA=E8=83=BD?= <2386089024@qq.com> Date: Mon, 17 Mar 2025 20:18:09 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E6=96=87=E4=BB=B6=E8=87=B3?= =?UTF-8?q?=20/?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- drm_func.c | 186 ++++++ main.cpp | 1605 +++++++++++++++++++++++++++++++++++++++++++++ main.h | 95 +++ rga_func.c | 129 ++++ yolov5_detect.cpp | 374 +++++++++++ 5 files changed, 2389 insertions(+) create mode 100644 drm_func.c create mode 100644 main.cpp create mode 100644 main.h create mode 100644 rga_func.c create mode 100644 yolov5_detect.cpp diff --git a/drm_func.c b/drm_func.c new file mode 100644 index 0000000..eb10de1 --- /dev/null +++ b/drm_func.c @@ -0,0 +1,186 @@ +// Copyright (c) 2021 by Rockchip Electronics Co., Ltd. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "drm_func.h" +#include + +int drm_init(drm_context *drm_ctx) +{ + static const char *card = "/dev/dri/card0"; + int flag = O_RDWR; + int drm_fd = -1; + + drm_fd = open(card, flag); + if (drm_fd < 0) + { + printf("failed to open %s\n", card); + return -1; + } + + drm_ctx->drm_handle = dlopen("libdrm.so", RTLD_LAZY); + + if (!drm_ctx->drm_handle) + { + printf("failed to dlopen libdrm.so\n"); + printf("dlopen error: %s\n", dlerror()); + drm_deinit(drm_ctx, drm_fd); + return -1; + } + + drm_ctx->io_func = (FUNC_DRM_IOCTL)dlsym(drm_ctx->drm_handle, "drmIoctl"); + if (drm_ctx->io_func == NULL) + { + dlclose(drm_ctx->drm_handle); + drm_ctx->drm_handle = NULL; + drm_deinit(drm_ctx, drm_fd); + printf("failed to dlsym drmIoctl\n"); + return -1; + } + return drm_fd; +} + +void drm_deinit(drm_context *drm_ctx, int drm_fd) +{ + if (drm_ctx->drm_handle) + { + dlclose(drm_ctx->drm_handle); + drm_ctx->drm_handle = NULL; + } + if (drm_fd > 0) + { + close(drm_fd); + } +} + +void *drm_buf_alloc(drm_context *drm_ctx, int drm_fd, int TexWidth, int TexHeight, int bpp, int *fd, unsigned int *handle, size_t *actual_size) +{ + // printf("0: Width %d, Heigh %d, bpp %d\n", TexWidth, TexHeight, bpp); + // printf("fd: %d, handle: %d, size: %d\n", fd, handle, actual_size); + int ret; + if (drm_ctx == NULL) + { + printf("drm context is unvalid\n"); + return NULL; + } + char *map = NULL; + + // printf("Width %d, Heigh %d\n", TexWidth, TexHeight); + + void *vir_addr = NULL; + struct drm_prime_handle fd_args; + struct drm_mode_map_dumb mmap_arg; + struct drm_mode_destroy_dumb destory_arg; + + struct drm_mode_create_dumb alloc_arg; + + memset(&alloc_arg, 0, sizeof(alloc_arg)); + alloc_arg.bpp = bpp; + alloc_arg.width = TexWidth; + alloc_arg.height = TexHeight; + // alloc_arg.flags = ROCKCHIP_BO_CONTIG; + + // printf("2: Width %d, Heigh %d\n", TexWidth, TexHeight); + + //获取handle和size + ret = drm_ctx->io_func(drm_fd, DRM_IOCTL_MODE_CREATE_DUMB, &alloc_arg); + // printf("3: Width %d, Heigh %d\n", TexWidth, TexHeight); + if (ret) + { + printf("failed to create dumb buffer: %s\n", strerror(errno)); + return NULL; + } + // printf("4: Width %d, Heigh %d\n", TexWidth, TexHeight); + if (handle != NULL) + { + *handle = alloc_arg.handle; + } + // printf("5: Width %d, Heigh %d\n", TexWidth, TexHeight); + if (actual_size != NULL) + { + *actual_size = alloc_arg.size; + } + // printf("create width=%u, height=%u, bpp=%u, size=%lu dumb buffer\n",alloc_arg.width,alloc_arg.height,alloc_arg.bpp,alloc_arg.size); + // printf("out handle= %d\n",alloc_arg.handle); + + //获取fd + memset(&fd_args, 0, sizeof(fd_args)); + fd_args.fd = -1; + fd_args.handle = alloc_arg.handle; + ; + fd_args.flags = 0; + ret = drm_ctx->io_func(drm_fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &fd_args); + if (ret) + { + printf("rk-debug handle_to_fd failed ret=%d,err=%s, handle=%x \n", ret, strerror(errno), fd_args.handle); + return NULL; + } + // printf("out fd = %d, drm fd: %d\n",fd_args.fd,drm_fd); + if (fd != NULL) + { + *fd = fd_args.fd; + } + + //获取虚拟地址 + memset(&mmap_arg, 0, sizeof(mmap_arg)); + mmap_arg.handle = alloc_arg.handle; + + ret = drm_ctx->io_func(drm_fd, DRM_IOCTL_MODE_MAP_DUMB, &mmap_arg); + if (ret) + { + printf("failed to create map dumb: %s\n", strerror(errno)); + vir_addr = NULL; + goto destory_dumb; + } + vir_addr = map = mmap(0, alloc_arg.size, PROT_READ | PROT_WRITE, MAP_SHARED, drm_fd, mmap_arg.offset); + if (map == MAP_FAILED) + { + printf("failed to mmap buffer: %s\n", strerror(errno)); + vir_addr = NULL; + goto destory_dumb; + } + // printf("alloc map=%x \n",map); + return vir_addr; +destory_dumb: + memset(&destory_arg, 0, sizeof(destory_arg)); + destory_arg.handle = alloc_arg.handle; + ret = drm_ctx->io_func(drm_fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destory_arg); + if (ret) + printf("failed to destory dumb %d\n", ret); + return vir_addr; +} + +int drm_buf_destroy(drm_context *drm_ctx, int drm_fd, int buf_fd, int handle, void *drm_buf, size_t size) +{ + int ret = -1; + if (drm_buf == NULL) + { + printf("drm buffer is NULL\n"); + return -1; + } + + munmap(drm_buf, size); + + struct drm_mode_destroy_dumb destory_arg; + memset(&destory_arg, 0, sizeof(destory_arg)); + destory_arg.handle = handle; + ret = drm_ctx->io_func(drm_fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destory_arg); + if (ret) + printf("failed to destory dumb %d, error=%s\n", ret, strerror(errno)); + if (buf_fd > 0) + { + close(buf_fd); + } + + return ret; +} diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..2bf8321 --- /dev/null +++ b/main.cpp @@ -0,0 +1,1605 @@ +#include "main.h" +//4 13 22 31 +#include +#include +#include +#include"yolov5_detect.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#define MSS_TEST_BUS_NAME "yolov5test" +static jbus_hdl_t g_jbus; +static jmss_hdl_t g_jmss; +static jisp_hdl_t g_jisp; +static bool g_running; +jmss_stm_t *g_stm[5]; + + +//配置文件路径 +#define modelpath_fire "/demo/bin/fire2025_pre.rknn" +#define DOWNLOAD_VERSION_PATH "/tmp/version" +#define ID_FILE_PWD "/etc/DeviceID" +std::string DeviceID; +std::string response_controllerId = "NULL"; + +static char labels_fire[2][20] = {"fire", "any"}; +static char labels_smog[2][20] = {"smog", "any"}; + +#define SERIAL_PORT_INFRARED_SENSOR "/dev/ttyS4" +#define SERIAL_PORT_SOLENOID "/dev/ttyS5" +#define BAUD_RATE B115200 +static int serialPortInfraredSensor; +static int serialPortSolenoid; +float temperature_img[24][32]; +unsigned char buffer[1544]; +std::mutex mtx; + +using namespace cv; +using namespace std; +using json = nlohmann::json; //使用nlohmann JSON 库 + + +// 定义GPIO控制引脚(假设GPIO2_B0已经设置好) +#define RELAY_GPIO_PIN 72 // 使用GPIO 72控制继电器 + +// 控制继电器复位的函数 +void reset_relay() { + // 导出GPIO引脚 + system("echo 72 > /sys/class/gpio/export"); + + // 设置GPIO引脚为输出 + system("echo out > /sys/class/gpio/gpio72/direction"); + + // 复位继电器 + system("echo 1 > /sys/class/gpio/gpio72/value"); // 设置高电平 + usleep(1000000); // 等待1秒 + system("echo 0 > /sys/class/gpio/gpio72/value"); // 设置低电平 + std::cout << "Relay reset!" << std::endl; +} + +constexpr auto CONFIG_FILE = "/demo/bin/jh.json"; +constexpr auto ID_FILE_PATH = "/etc/DeviceID"; +constexpr auto LICENSE_FILE = "/demo/bin/activation.lic"; +constexpr auto ENCRYPT_KEY = "YourSecretKey1234567890ABCDEF"; // 24字节密钥 + +// RSA公钥(PEM格式) +const string PUBLIC_KEY = R"( +-----BEGIN PUBLIC KEY----- +MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAK+UGGqE+K12kd5F5AH3GQNMSKZjq0l+IBTzF28YWTz+CWtRQ78eKOp3/fXZ8UBRQc2/nRT9Us24l9kPGJ2qUYECAwEAAQ== +-----END PUBLIC KEY----- +)"; + +// 全局变量 +mutex activation_mutex; + +class Config { + public: + static string getActivationUrl() { // 静态成员函数,用于获取激活 URL + try { + ifstream file(CONFIG_FILE); + if (!file) { + throw runtime_error("Config file not found"); + } + + json config = json::parse(file); // 使用 nlohmann JSON 库解析配置文件 + if (config.contains("activation_url")) { + string url = config["activation_url"]; + cout << "[INFO] Using activation URL from JSON config: " << url << endl; + return url; + } + throw runtime_error("activation_url not found in config"); + + } catch (const exception& e) { + cerr << "[WARN] " << e.what() << " - Using default URL" << endl; //捕获异常 + return "http://183.238.1.242:8889/api/label/security"; + } + } + }; + + class CryptoUtil { + public: + + // 异或加密(保留原有逻辑) + static string xorEncrypt(const string& plaintext) { + string encrypted = xorCipher(plaintext, ENCRYPT_KEY); + return base64Encode(encrypted); + } + + static string xorDecrypt(const string& ciphertext) { + string decoded = base64Decode(ciphertext); + return xorCipher(decoded, ENCRYPT_KEY); + } + + // URL编码 + static string urlEncode(const string& value) { + ostringstream escaped; + escaped.fill('0'); + escaped << hex; + for (char c : value) { + if (isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~') { + escaped << c; + } else { + escaped << '%' << setw(2) << int((unsigned char)c); + } + } + return escaped.str(); + } + + // 新增RSA加密 + static string rsaEncrypt(const string& plaintext) { + RSA* rsa = nullptr; + BIO* bio = nullptr; + string result; + + try { + bio = BIO_new_mem_buf(PUBLIC_KEY.c_str(), -1); + // rsa = PEM_read_bio_RSA_PUBKEY(bio, nullptr, nullptr, nullptr); + rsa = PEM_read_bio_RSA_PUBKEY(bio, nullptr, nullptr, nullptr); + if (!rsa) throw runtime_error("PEM_read_bio_RSA_PUBKEY failed"); + + int keySize = RSA_size(rsa); + vector encrypted(keySize); + + int len = RSA_public_encrypt( + plaintext.size(), + reinterpret_cast(plaintext.c_str()), + encrypted.data(), + rsa, + RSA_PKCS1_PADDING + ); + + if (len == -1) throw runtime_error("RSA encryption failed"); + + result = base64Encode(encrypted.data(), len); + + } catch (const exception& e) { + cerr << "[ERROR] RSA encryption failed: " << e.what() << endl; + ERR_print_errors_fp(stderr); + result.clear(); + } + + if (rsa) RSA_free(rsa); + if (bio) BIO_free_all(bio); + return result; + } + + private: + static string xorCipher(const string& data, const string& key) { + string result; + for (size_t i = 0; i < data.size(); ++i) { + result += data[i] ^ key[i % key.size()]; + } + return result; + } + + static string base64Encode(const string& data) { + BIO *bio, *b64; + BUF_MEM *bufferPtr; + + b64 = BIO_new(BIO_f_base64()); + bio = BIO_new(BIO_s_mem()); + bio = BIO_push(b64, bio); + + BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL); + BIO_write(bio, data.c_str(), data.size()); + BIO_flush(bio); + BIO_get_mem_ptr(bio, &bufferPtr); + BIO_set_close(bio, BIO_NOCLOSE); + BIO_free_all(bio); + + return string(bufferPtr->data, bufferPtr->length); + } + + static string base64Encode(const unsigned char* data, size_t len) { + BIO* b64 = BIO_new(BIO_f_base64()); + BIO* mem = BIO_new(BIO_s_mem()); + BIO_push(b64, mem); + + BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); + BIO_write(b64, data, len); + BIO_flush(b64); + + char* ptr; + long size = BIO_get_mem_data(mem, &ptr); + string result(ptr, size); + + BIO_free_all(b64); + return result; + } + + static string base64Decode(const string& encoded) { + BIO *bio, *b64; + char* buffer = (char*)malloc(encoded.size()); + memset(buffer, 0, encoded.size()); + + bio = BIO_new_mem_buf(encoded.c_str(), -1); + b64 = BIO_new(BIO_f_base64()); + bio = BIO_push(b64, bio); + + BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL); + int len = BIO_read(bio, buffer, encoded.size()); + BIO_free_all(bio); + + string result(buffer, len); + free(buffer); + return result; + } + }; + + class NetworkUtil { + public: + static int postRequest(const string& url, const string& postData, string& response) { + CURL* curl = curl_easy_init(); + if (!curl) return CURLE_FAILED_INIT; + + // 使用RSA加密数据 + string encryptedData = CryptoUtil::rsaEncrypt(postData); + string urlEncodedData = CryptoUtil::urlEncode(encryptedData); + + struct curl_slist* headers = nullptr; + headers = curl_slist_append(headers, "Accept: application/json"); // 修改Content-Type + + const string full_url = url + "?id=" + urlEncodedData; + // cout << "[DEBUG] full_url: " << full_url << endl; + + curl_easy_setopt(curl, CURLOPT_URL, full_url.c_str()); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeCallback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response); + curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10L); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L); + + CURLcode res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + curl_slist_free_all(headers); + return res; + } + + private: + static size_t writeCallback(void* contents, size_t size, size_t nmemb, string* output) { + output->append(static_cast(contents), size * nmemb); + return size * nmemb; + } + }; + + class ActivationManager { + public: + explicit ActivationManager(string device_id, string mac) + : device_id_(move(device_id)), mac_(move(mac)) {} + + bool checkActivation() { + lock_guard lock(activation_mutex); + + if (checkLocalLicense()) { + cout << "[INFO] Device already activated" << endl; + return true; + } + return processOnlineActivation(); + } + + + // 内部函数实现:checkLocalLicense, validateLicense, processOnlineActivation, generateLicenseFile + private: + string device_id_; + string mac_; + + bool checkLocalLicense() { + ifstream file(LICENSE_FILE, ios::binary); + if (!file) return false; + + string encrypted((istreambuf_iterator(file)), istreambuf_iterator()); + return validateLicense(encrypted); + } + + bool validateLicense(const string& encrypted) { + // 修改为使用xorDecrypt + string decrypted = CryptoUtil::xorDecrypt(encrypted); + auto pos = decrypted.find('|'); + if (pos == string::npos) return false; + + string storedId = decrypted.substr(0, pos); + string storedMac = decrypted.substr(pos + 1); + + return (storedId == device_id_ && storedMac == mac_); + } + + bool processOnlineActivation(int retry_count = 3) { + string activation_url = Config::getActivationUrl(); + const string post_data = device_id_ + "|" + mac_; + cout << "[DEBUG] Original POST data: " << post_data << endl; + + for (int i = 0; i < retry_count; ++i) { + string response; + int curl_code = NetworkUtil::postRequest(activation_url, post_data, response); + + if (curl_code != CURLE_OK) { + cerr << "[ERROR] Network error: " << curl_easy_strerror((CURLcode)curl_code) << endl; + continue; + } + + try { + auto json_resp = json::parse(response); + int code = json_resp["code"].get(); + + if (code == 0) { + generateLicenseFile(device_id_ + "|" + mac_); + return true; + } + + if (code == 60001 || code == 60002) { + cerr << "[FATAL] Activation failed: " << json_resp["msg"].get() << endl; + return false; + } + + if (code == 60003 && i < retry_count - 1) { + cout << "[WARN] Retrying... (" << i+1 << "/" << retry_count << ")" << endl; + this_thread::sleep_for(chrono::seconds(1)); + continue; + } + return false; + + } catch (const json::exception& e) { + cerr << "[ERROR] JSON parse error: " << e.what() << endl; + } + } + return false; + } + + void generateLicenseFile(const string& data) { + ofstream file(LICENSE_FILE, ios::binary); + // 修改为使用xorEncrypt + string encrypted = CryptoUtil::xorEncrypt(data); + file.write(encrypted.data(), encrypted.size()); + cout << "[INFO] License file created successfully" << endl; + } + }; + + string getDeviceID() { + ifstream file(ID_FILE_PATH); + string id; + if (!getline(file, id)) throw runtime_error("Failed to read device ID"); + return id; + } + + string getMACAddress() { + const vector interfaces = {"eth0", "eth1", "enp0s3", "wlan0"}; + + for (const auto& iface : interfaces) { + ifstream file("/sys/class/net/" + iface + "/address"); + if (file) { + string mac; + getline(file, mac); + mac.erase(remove(mac.begin(), mac.end(), '\n'), mac.end()); + + if (mac.length() == 17 && count(mac.begin(), mac.end(), ':') == 5) { + return mac; + } + } + } + throw runtime_error("No valid MAC address found"); + } + + +int ALARM_TEMPERATURE; +int WARN_TEMPERATURE; +int MOVE_THRESHOLD; +int IGNORE_TEMPERATURE; +double Confidence_Threshold; + +vector> last_result; +auto last_result_time = std::chrono::high_resolution_clock::now();// 时间 +vector> now_result; + +int width = 1920, height = 1080; +JMediaRawFrameType_e type = JMEDIA_RAWFRAMETYPE_NV12; + +//查看是否重合 +bool check_whether_in_last_result(vector> &last_result, vector &now, std::ofstream& temperature_log){ + if(last_result.empty()) return true; + //查找now的框坐标是否有出现在上一帧 + for(auto i : last_result){ + //范围5像素以内都视为不变 + if(abs(i[0] - now[0]) <= MOVE_THRESHOLD && abs(i[1] - now[1]) <= MOVE_THRESHOLD && abs(i[2] - now[2]) <= MOVE_THRESHOLD && abs(i[3] - now[3]) <= MOVE_THRESHOLD){ + temperature_log << "有重复 此帧结果:(" << now[0] << " " << now[1] << ") (" << now[2] << " " << now[3] << ")" + << " 上帧结果:(" << i[0] << " " << i[1] << ") (" << i[2] << " " << i[3] << ")"<< endl; + cout << "上帧结果:(" << i[0] << " " << i[1] << ") (" << i[2] << " " << i[3] << ")" << endl; + cout << "此帧结果:(" << now[0] << " " << now[1] << ") (" << now[2] << " " << now[3] << ")" << endl; + return true; + } + } + cout << "无重复 此帧结果:(" << now[0] << " " << now[1] << ") (" << now[2] << " " << now[3] << ")" << endl; + temperature_log << "无重复 此帧结果:(" << now[0] << " " << now[1] << ") (" << now[2] << " " << now[3] << ")" << endl; + return false; +} + + +//获取当前系统时间 +string Get_Time(int input){ + // 获取当前系统时间 + std::time_t alarmTime_std = std::time(nullptr); + // 将时间转换为本地时间 + std::tm* localTime = std::localtime(&alarmTime_std); + // 从本地时间结构中获取时间信息 + int year = localTime->tm_year + 1900; + int month = localTime->tm_mon + 1; + int day = localTime->tm_mday; + int hour = localTime->tm_hour; + int minute = localTime->tm_min; + int second = localTime->tm_sec; + // 拼接成字符串 + std::ostringstream oss_alarmTime; + if(input == 1){ + oss_alarmTime << std::setfill('0') + << std::setw(4) << year << "-" + << std::setw(2) << month << "-" + << std::setw(2) << day << " " + << std::setw(2) << hour << ":" + << std::setw(2) << minute << ":" + << std::setw(2) << second; + }else{ + oss_alarmTime << std::setfill('0') + << std::setw(2) << month << "_" + << std::setw(2) << day << "_" + << std::setw(2) << hour << "_" + << std::setw(2) << minute << "_" + << std::setw(2) << second; + } + // 获取拼接后的字符串 + std::string formattedTime = oss_alarmTime.str(); + return formattedTime; +} + + + +double calibration(double x){ + double p1 = -9.052e-08; + double p2 = 8.313e-05; + double p3 = -0.02813; + double p4 = 4.16; + double p5 = -219.7; + double res = p1*pow(x, 4) + p2*pow(x, 3) + p3*pow(x, 2) + p4*x + p5; + return res; +} + + +size_t WriteCallback(void* contents, size_t size, size_t nmemb, std::string* response){ + size_t totalSize = size * nmemb; + response->append(static_cast(contents), totalSize); + return totalSize; +} + + +bool _geturlFromfile(const char * filepath,char *url, int maxLength) { + if (filepath == NULL) { + printf("getrulVersion is error, url == null.\n"); + return false; + } + FILE *fp = fopen(filepath, "r"); + if (fp == NULL) { + printf("open %s failed, error is %s.\n", filepath, strerror(errno)); + return false; + } + int iffind=0; + char *line = NULL; + size_t len = 0; + size_t read; + while ((read = getline(&line, &len, fp)) != -1) { + if (read == 0 || line[0] == '#') { + continue; + } + char *pline = strstr(line, "upload_url"); + if (pline != NULL && (pline = strstr(pline, "=")) != NULL) { + pline++; //过滤掉等于号 + //过滤掉空格 + while (*pline == ' ') { + pline++; + } + int pline_len = strlen(pline) - 1; + int version_len = (pline_len > maxLength ? maxLength:pline_len); + memcpy(url, pline, version_len); + printf("upload_url = %s\n", url); + iffind=1; + break; + } + } + if (iffind == 0 ){ + printf("Can not find upload_url\n"); + return false; + } + free(line); + fclose(fp); + return true; +} + + +// 函数用于读取文件并将其内容保存在全局字符串变量中 +void readFileAndStoreInGlobal(const std::string& filename) { + std::ifstream file(filename); + if (file.is_open()) { + std::getline(file, DeviceID); // 读取一行并存储在全局字符串中 + file.close(); + } else { + std::cerr << "无法打开文件: " << filename << std::endl; + } +} + + +std::string generateIndices(char result[4],Alarm* Alarm) { + std::string indices; + for (int i = 0; i < 4; ++i) { + if (result[i] == '1') { + // 将索引值加入到生成的字符串中 + indices += std::to_string(i + 1); + Alarm->ifalarm = 1; + } + } + return indices; +} + + +void checkCoverage(int x1, int x2, int width, char result[4]) { + // 初始化为 '1',表示覆盖 + // std::string resultString1(result, 4); + // std::cout << "result in: " << resultString1 << std::endl; + char result_now[4]={'1','1','1','1'}; + int line1 = width*7/32; + int line2 = width/2; + int line3 = width*25/32; + if(x1>line1){ + result_now[3] = '0'; + } + if(x1>line2){ + result_now[3] = '0'; + result_now[2] = '0'; + } + if(x1>line3){ + result_now[3] = '0'; + result_now[2] = '0'; + result_now[1] = '0'; + } + + if(x2& data) { + uint16_t sum = 0; + for (size_t i = 0; i < data.size()-1; ++i) { + sum += data[i]; + } + return static_cast(sum & 0xFF); +} + + +void printVector(const std::vector& vec) { + std::cout << "Vector contents: "; + for (const auto& byte : vec) { + std::cout << std::hex << std::setw(2) << std::setfill('0') << static_cast(byte) << " "; + } + std::cout << std::dec << std::endl; // 切换回十进制 +} + + +int main(int argc, char **argv) +{ + std::string folderPath = "/demo/pic"; //保存图片的文件夹路径 + if(!createDirectory(folderPath)){ + return 0; + } + + // 打开 JSON 文件 + cout << "解析JSON文件" << endl; + std::ifstream file("/demo/bin/config.json"); + + // 检查文件是否成功打开 + if (!file.is_open()) { + std::cerr << "Failed to open json file" << std::endl; + return 1; + } + + try { + // 解析 JSON 文件 + json Config_jsonData; + file >> Config_jsonData; + // 关闭文件 + + // 赋值给全局常量 + WARN_TEMPERATURE = Config_jsonData["WARN_TEMPERATURE"]; + ALARM_TEMPERATURE = Config_jsonData["ALARM_TEMPERATURE"]; + MOVE_THRESHOLD = Config_jsonData["MOVE_THRESHOLD"]; + IGNORE_TEMPERATURE = Config_jsonData["IGNORE_TEMPERATURE"]; + Confidence_Threshold = Config_jsonData["Confidence_Threshold"]; + } + catch (const json::parse_error& e) + { + std::cerr << "JSON parsing error: " << e.what() << std::endl; + return 0; + } + file.close(); + + cout << "配置 WARN_TEMPERATURE :" << WARN_TEMPERATURE << endl; + cout << "配置 ALARM_TEMPERATURE :" << ALARM_TEMPERATURE << endl; + cout << "配置 MOVE_THRESHOLD :" << MOVE_THRESHOLD << endl; + cout << "配置 IGNORE_TEMPERATURE :" << IGNORE_TEMPERATURE << endl; + cout << "配置 Confidence_Threshold :" << Confidence_Threshold << endl; + cout << SERIAL_PORT_INFRARED_SENSOR <=2?(JMediaRawFrameType_e)atoi(argv[1]):JMEDIA_RAWFRAMETYPE_NV12; + int width = 1920, height = 1080; + jmss_raw_t *rawchn = JES_MSS_RawOpen(g_jmss, 0, width, height, type); + if(rawchn == NULL){ + printf("==============>>>: %s:%d open rawchn failed\n", strrchr(__FILE__,'/'),__LINE__); + return -1; + } + int ret; + + + readFileAndStoreInGlobal((char *)ID_FILE_PWD); + // 打印全局字符串变量 + std::cout << "ID内容:" << DeviceID < ControlInstructions(20,0x00); + ControlInstructions[0] = 0xCA; //协议头 + ControlInstructions[1] = 0x14; //总长度 + ControlInstructions[2] = 0x01; //操作指令 + + //打开JES的通道 + jmss_raw_t *rawchn = JES_MSS_RawOpen(g_jmss, 0, width, height, type); + if(rawchn == NULL){ + printf("==============>>>: %s:%d open rawchn failed\n", strrchr(__FILE__,'/'),__LINE__); + } + //日志相关内容 + std::string filename = "/demo/bin/temperature_log.txt"; + std::ofstream temperature_log(filename, std::ios::out | std::ios::trunc); + temperature_log << "配置 WARN_TEMPERATURE :" << WARN_TEMPERATURE << endl; + temperature_log << "配置 ALARM_TEMPERATURE :" << ALARM_TEMPERATURE << endl; + temperature_log << "配置 MOVE_THRESHOLD :" << MOVE_THRESHOLD << endl; + temperature_log << "配置 IGNORE_TEMPERATURE :" << IGNORE_TEMPERATURE << endl; + temperature_log << "配置 Confidence_Threshold :" << Confidence_Threshold << endl; + //环境温度 + double temp_env = 0; + + auto last_time = std::chrono::high_resolution_clock::now();// 记录开始时间 + // 创建一个 Alarm 结构体对象 + Alarm Alarm; + // 调用初始化函数来初始化结构体成员 + initializeAlarm(&Alarm); + //用于从全局buffer中复制数据 + unsigned char copyBuffer[1544]; + + /* 参数初始化 */ + int output_nboxes_left =0; + yolov5_detect_result_group_t detect_result_group; + + /* 算法模型初始化 */ + char *path = reinterpret_cast(args); + printf("loading model %s\n",path); + rknn_context ctx; + yolov5_detect_init(&ctx, path); + // yolov5_detect_init(&ctx, "./fire_rv1126.rknn"); + + //配置label + char labels[2][20]; + getLabels(path, labels); + // 设置压缩质量 + std::vector compression_params; + compression_params.push_back(cv::IMWRITE_JPEG_QUALITY); + compression_params.push_back(30); // 设置压缩质量,范围为 0-100 + int overtem_cnt = 0; + std::vector over_tmp_deque(10, 0); + /* 算法运行 */ + while(!quit){ + int time2run = 1; + // auto current_time = std::chrono::high_resolution_clock::now(); + // auto elapsed_time = std::chrono::duration_cast(current_time - last_time);// 计算距离开始时间的时间差 + + // if (elapsed_time.count() - 1000 > 0) { + // last_time = current_time; + // time2run = 1; + // } + sleep(2); + //获取摄像头buffer + JVMediaFrame_t frm; + if(JES_MSS_RawGetFrame(rawchn,&frm) < 0){ + sleep(1); + continue; + } + int overtmp_falg = 0; + Alarm.ifalarm = 0; + Alarm.ifwarn = 0; + + Mat src; + NV12ToRGB(width, height, frm.buffer, src); + //裁剪 + cv::Rect roi(220, 130, 1480, 570); + src = src(roi); + //固定时间间隔去处理红外参数 + char result[4]={'0','0','0','0'}; + char result_warn[4]={'0','0','0','0'}; + char result_fire_rknn[4]={'0','0','0','0'}; + //初始化ControlInstructions + ControlInstructions[3]=0x00; + ControlInstructions[4]=0x00; + ControlInstructions[5]=0x00; + ControlInstructions[6]=0x00; + + if(time2run){ + cout << "run ." << endl; + mtx.lock(); + memcpy(copyBuffer, buffer, sizeof(buffer)); + mtx.unlock(); + //计算温度 + double temperature; + int Col,Row; + int j = 0; + double max_temperature = 0; + for (int i = 4; i < 1540; i += 2) { + // temperature = calibration((buffer[i+1]*256+buffer[i])/100.0); + temperature = (buffer[i+1]*256+buffer[i])/100.0 + 6; + // cout << (buffer[i+1]*256+buffer[i])/100.0 << " " << temperature << endl; + + //按视觉顺序存入数组 + Col = 31-(j)%32; + Row = (j)/32; + temperature_img[Row][Col] = temperature; + j++; + } + temp_env = (buffer[1541]*256+buffer[1540])/100.0; + WARN_TEMPERATURE = (temp_env*2)>WARN_TEMPERATURE? (temp_env*2):WARN_TEMPERATURE; + // ALARM_TEMPERATURE = WARN_TEMPERATURE + 20; + //截去上下5行数据 + for(int i=5; i<19; i++){ + for(j=0; j<32; j++){ + if(temperature_img[i][j] > IGNORE_TEMPERATURE) continue; + if(temperature_img[i][j] > max_temperature) max_temperature = temperature_img[i][j]; + + if(temperature_img[i][j] > ALARM_TEMPERATURE){ + overtmp_falg = 1; + if (0 <= j && j <= 6) + result[0] = '1'; + else if (6 < j && j <= 15) + result[1] = '1'; + else if (15 < j && j <= 24) + result[2] = '1'; + else if (24 < j && j <= 31) + result[3] = '1'; + } + + if(temperature_img[i][j] > WARN_TEMPERATURE){ + Alarm.ifwarn = 1; + if (0 < j && j <= 6) + result_warn[0] = '1'; + else if (6 < j && j <= 15) + result_warn[1] = '1'; + else if (13 < j && j <= 24) + result_warn[2] = '1'; + else if (24 < j && j <= 31) + result_warn[3] = '1'; + } + } + } + + int overtem_cnt_for_log; + if(overtmp_falg){ + over_tmp_deque.push_back(1); + if (over_tmp_deque.size() > 10) { + over_tmp_deque.erase(over_tmp_deque.begin()); + } + overtem_cnt = 0; + for (int i = 0; i < over_tmp_deque.size(); ++i) { + if (over_tmp_deque[i] == 1) { + overtem_cnt++; + } + } + overtem_cnt_for_log = overtem_cnt; + + if(overtem_cnt >= 3){ + Alarm.ifalarm = 1; + over_tmp_deque.assign(9, 0); + over_tmp_deque.push_back(1); + }else{ + memset(result, '0', 4*sizeof(char)); + } + }else{ + over_tmp_deque.push_back(0); + // 保持队列长度为10,如果超过长度则移除最前面的元素 + if (over_tmp_deque.size() > 10) { + over_tmp_deque.erase(over_tmp_deque.begin()); + } + } + + + // temp_env = (buffer[1541]*256+buffer[1540])/100.0; + cout << "最大温度: " << max_temperature << endl; + cout << "环境温度" << temp_env << endl; + cout << "预警温度: " << WARN_TEMPERATURE << endl; + cout << "直接喷水温度: " << ALARM_TEMPERATURE << endl; + if(max_temperature>WARN_TEMPERATURE){ + temperature_log << endl << "---------------------------------------------------" << endl; + temperature_log << Get_Time(1) << endl; + temperature_log << "最大温度: " << max_temperature << endl; + temperature_log << "环境温度: " << temp_env << endl; + temperature_log << "预警温度: " << WARN_TEMPERATURE << endl; + temperature_log << "直接喷水温度: " << ALARM_TEMPERATURE << endl; + temperature_log << "超温队列:"; + for (int i = 0; i < over_tmp_deque.size(); ++i) { + temperature_log << over_tmp_deque[i] << " "; + } + temperature_log << endl; + } + if(Alarm.ifalarm){ + printf("temprature > %d°C !\n", ALARM_TEMPERATURE); + // 将字符数组拼接成字符串 + std::string resultString(result, 4); + std::cout << ALARM_TEMPERATURE <<"度结果: " << resultString << std::endl; + temperature_log << ALARM_TEMPERATURE <<"度结果: " << resultString << std::endl; + std::string resultString_warn(result_warn, 4); + std::cout << WARN_TEMPERATURE << "度结果: " << resultString_warn << std::endl; + temperature_log << WARN_TEMPERATURE <<"度结果: " << resultString_warn << std::endl; + }else if(Alarm.ifwarn){ + printf("temprature > %d°C !\n", WARN_TEMPERATURE); + std::string resultString_warn(result_warn, 4); + std::cout << WARN_TEMPERATURE << "结果: " << resultString_warn << std::endl; + temperature_log << WARN_TEMPERATURE << "结果: " << resultString_warn << std::endl; + } + } + + + if(Alarm.ifwarn){ + struct timeval start; + struct timeval end; + now_result.clear(); + temperature_log << "上帧总的结果:" << endl; + for(auto i : last_result){ + temperature_log << "(" << i[0] << " " << i[1] << ") (" << i[2] << " " << i[3] << ")" << endl; + } + printf("%s_rknn_run\n",labels[0]); + yolov5_detect_run(ctx, src, &detect_result_group); + } + + //计算时间差 + if( detect_result_group.count > 0 ){ + auto current_time_now = std::chrono::high_resolution_clock::now();// 时间 + auto value_time = std::chrono::duration_cast(current_time_now - last_result_time);// 计算距离开始时间的时间差 + + if (value_time.count() - 10000 > 0) { //如果上下帧大于十秒,则清除上一帧 + last_result.clear(); + } + } + + + + /* 算法结果在图像中画出并保存 */ + int name_int = 0; + // char result[4]={'0','0','0','0'}; + for (int i = 0; i < detect_result_group.count; i++) + { + yolov5_detect_result_t *det_result = &(detect_result_group.results[i]); + + if( det_result->prop < Confidence_Threshold ) + { + continue; + } + + + cout << "Detected object: " << det_result->name << endl; + + + //报警打印 + if(Alarm.ifwarn){ + printf("%s @ (%d %d %d %d) %f\n", + det_result->name, + det_result->box.left, det_result->box.top, det_result->box.right, det_result->box.bottom, + det_result->prop); + vector now; + now.push_back(det_result->box.left); + now.push_back(det_result->box.top); + now.push_back(det_result->box.right); + now.push_back(det_result->box.bottom); + now_result.push_back(now); + if(check_whether_in_last_result(last_result,now,temperature_log)){ + continue; + } + } + int x1 = det_result->box.left; + int y1 = det_result->box.top; + int x2 = det_result->box.right; + int y2 = det_result->box.bottom; + + //检测区域 + if(Alarm.ifwarn){ + checkCoverage(x1, x2, 1480, result_fire_rknn); + } + + char label_text[50]; + memset(label_text, 0 , sizeof(label_text)); + sprintf(label_text, "%s %0.2f",det_result->name, det_result->prop); + plot_one_box(src, x1, x2, y1, y2, label_text, i%10); + } + + if(Alarm.ifwarn){ + // if(!now_result.empty()){ + // last_result.clear(); + // last_result = now_result; + // } + + //若上帧结果为空,依然清理结果队列 --2024.11.4 + last_result.clear(); + last_result = now_result; + last_result_time = std::chrono::high_resolution_clock::now();// 时间 + std::string resultString_fire(result_fire_rknn, 4); + std::cout << "rknn检测结果: " << resultString_fire << std::endl; + temperature_log << "rknn检测结果: " << resultString_fire << std::endl; + //对45度区域和火焰检测区域做出 与操作 + and_result(result_warn,result_fire_rknn); + //对火与45度结果 与 60 度结果 做或操作 + or_result(result,result_warn); + temperature_log << "报警输入:" << string(result, 4) <(orig_data.c_str()), orig_data.length()); + Alarm.alarmBase64 = encoded_data; + Alarm.alarmMsg = std::string(labels[0]); + Alarm.alarmMsg = std::string(labels[name_int]); + pthread_t upload_message_tidp; + pthread_create(&upload_message_tidp, NULL, upload_message, static_cast(&Alarm)); + pthread_t upload_message_controller_tidp; + int ret =pthread_create(&upload_message_controller_tidp, NULL, upload_message_controller, static_cast(&Alarm)); + if (ret != 0) { + std::cerr << "Error creating controller thread: " << strerror(ret) << std::endl; + } else { + std::cerr << "success creating controller thread" << std::endl; + } + } + } + + /* 算法模型空间释放 */ + yolov5_detect_release(ctx); + //文件关闭 + temperature_log.close(); + return 0; + +} + +void *upload_message(void *args) +{ + pthread_detach(pthread_self()); + // 获取上报url + char upload_url[200] = {0}; + if(!_geturlFromfile(DOWNLOAD_VERSION_PATH,upload_url,sizeof(upload_url))){ + printf("结束进程\n"); + return 0; + } + + Alarm* alarm = static_cast(args); + + // 获取当前系统时间 + std::time_t alarmTime_std = std::time(nullptr); + + // 将时间转换为本地时间 + std::tm* localTime = std::localtime(&alarmTime_std); + + // 从本地时间结构中获取时间信息 + int year = localTime->tm_year + 1900; + int month = localTime->tm_mon + 1; + int day = localTime->tm_mday; + int hour = localTime->tm_hour; + int minute = localTime->tm_min; + int second = localTime->tm_sec; + + // 拼接成字符串 + std::ostringstream oss_alarmTime; + oss_alarmTime << std::setfill('0') + << std::setw(4) << year << "-" + << std::setw(2) << month << "-" + << std::setw(2) << day << " " + << std::setw(2) << hour << ":" + << std::setw(2) << minute << ":" + << std::setw(2) << second; + + // 获取拼接后的字符串 + std::string formattedTime = oss_alarmTime.str(); + + std::string cameraId = DeviceID; + std::string controllerId = response_controllerId; + std::string msg = (alarm->alarmMsg).c_str(); + std::string type = "1"; + std::string time = formattedTime; + std::string img = (alarm->alarmBase64).c_str(); + std::string Coverage = (alarm->alarmCoverage).c_str(); + + std::cout << "cameraId: " << cameraId << " msg: " << msg << " type: " << type << " time: " << time <(args); + + // 获取当前系统时间 + std::time_t alarmTime_std = std::time(nullptr); + + // 将时间转换为本地时间 + std::tm* localTime = std::localtime(&alarmTime_std); + + // 从本地时间结构中获取时间信息 + int year = localTime->tm_year + 1900; + int month = localTime->tm_mon + 1; + int day = localTime->tm_mday; + int hour = localTime->tm_hour; + int minute = localTime->tm_min; + int second = localTime->tm_sec; + + // 拼接成字符串 + std::ostringstream oss_alarmTime; + oss_alarmTime << std::setfill('0') + << std::setw(4) << year << "-" + << std::setw(2) << month << "-" + << std::setw(2) << day << " " + << std::setw(2) << hour << ":" + << std::setw(2) << minute << ":" + << std::setw(2) << second; + + // 获取拼接后的字符串 + std::string formattedTime = oss_alarmTime.str(); + + std::string cameraId = DeviceID; + std::string Coverage = (alarm->alarmCoverage).c_str(); + + std::cout << "cameraid: " << cameraId << " errNum: " << Coverage <(current_time - last_time);// 计算距离开始时间的时间差 + + if (elapsed_time.count() - 30000 > 0) { + last_time = current_time; + time2run = 1; + } + + if(time2run){ + std::cout << "心跳上报" << std::endl; + std::string cameraId = DeviceID; + std::string IP = "987654"; + int state = 1; + std::string http_address = "http"; + + std::string MessageString = +R"({ + "cameraId": ")" + cameraId + R"(", + "IP": ")" + IP + R"(", + "state": )" + std::to_string(state) + R"(, + "http_address": ")" + http_address + R"(" +})"; + CURL *curl; + CURLcode res; + curl_global_init(CURL_GLOBAL_ALL); + curl = curl_easy_init(); + + if(curl) + { + curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "GET"); + curl_easy_setopt(curl, CURLOPT_URL, "http://192.168.1.23:9527/device/heartbeat"); + /* Now specify the POST data */ + struct curl_slist *plist = nullptr; + plist = curl_slist_append(plist, "Content-Type:application/json;charset=UTF-8"); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, plist); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, MessageString.c_str()); + + std::string response; + curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10L); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response); + + res = curl_easy_perform(curl); + /* Check for errors */ + // if(res != CURLE_OK) + // fprintf(stderr, "curl_easy_perform() failed: %s\n",curl_easy_strerror(res)); + if (res != CURLE_OK) { + std::cerr << "heart beat: Failed to perform cURL request: " << curl_easy_strerror(res) << std::endl; + } else { + std::cout << "heart beat: Request successful!" << std::endl; + std::cout << "heart beat: Response: " << response << std::endl; + // 解析 JSON 字符串 + try { + json jsonData = json::parse(response); + + // 提取 controllerId 字段的内容 + response_controllerId = jsonData["controllerId"]; + + std::cout << "Controller ID: " << response_controllerId << std::endl; + } catch (const json::parse_error& e) { + std::cerr << "JSON parsing error: " << e.what() << std::endl; + } + } + + + curl_easy_cleanup(curl); + } + curl_global_cleanup(); + } + time2run = 0; + } +} + + +void *read_serial_thread(void *args) +{ + pthread_detach(pthread_self()); + ssize_t bytesRead; + + // 打开红外传感器对应的串口设备 + serialPortInfraredSensor = open(SERIAL_PORT_INFRARED_SENSOR, O_RDWR | O_NOCTTY | O_NDELAY); + if (serialPortInfraredSensor == -1) { + printf("Failed to open serial port: %s\n", SERIAL_PORT_INFRARED_SENSOR); + return 0; + } + + struct termios tty; + memset(&tty, 0, sizeof(tty)); // 初始化配置结构体,清零 + if (tcgetattr(serialPortInfraredSensor, &tty) != 0) { + printf("Failed to get serial port attributes\n"); + close(serialPortInfraredSensor); + return 0; + } + // 设置串口输入和输出波特率 + cfsetospeed(&tty, BAUD_RATE); + cfsetispeed(&tty, BAUD_RATE); + tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8; + tty.c_cflag &= ~(PARENB | PARODD); + tty.c_cflag &= ~CSTOPB; + tty.c_cflag |= CREAD | CLOCAL; + tty.c_iflag = IGNPAR; + tty.c_oflag = 0; + tty.c_lflag = 0; + if (tcsetattr(serialPortInfraredSensor, TCSANOW, &tty) != 0) { + printf("Failed to set serial port attributes\n"); + close(serialPortInfraredSensor); + return 0; + } + + // while(1){ + // mtx.lock(); + // bytesRead = read(serialPortInfraredSensor, buffer, sizeof(buffer)); + // mtx.unlock(); + // if (bytesRead>0) { + // if((buffer[0]== 0x5a)&&(buffer[1]==0x5a)) { + // // printf("readed serialPortInfraredSensor date\n"); + // }else{ + // // printf("read failed\n"); + // } + // }else{ + // // printf("empty to read\n"); + // } + // } + + // 设置文件描述符集合和超时时间,准备使用 select() 进行串口数据的检测 + fd_set readfds; + struct timeval timeout; + int selectResult; + // 此处后续可以继续添加使用 select() 监听串口数据的逻辑… + + while (1) { + FD_ZERO(&readfds); + FD_SET(serialPortInfraredSensor, &readfds); + + timeout.tv_sec = 5; // 5秒超时 + timeout.tv_usec = 0; + + selectResult = select(serialPortInfraredSensor + 1, &readfds, NULL, NULL, &timeout); + + if (selectResult > 0) { + if (FD_ISSET(serialPortInfraredSensor, &readfds)) { + mtx.lock(); + bytesRead = read(serialPortInfraredSensor, buffer, sizeof(buffer)); + mtx.unlock(); + + if (bytesRead > 0) { + if (buffer[0] == 0x5a && buffer[1] == 0x5a) { + // printf("readed serialPortInfraredSensor date\n"); + } else { + // printf("read failed\n"); + } + } + } + } else if (selectResult == 0) { + // 超时,没有数据可读 + // printf("Timeout, no data available\n"); + } else { + // select出错 + printf("select() failed\n"); + break; + } + } +} \ No newline at end of file diff --git a/main.h b/main.h new file mode 100644 index 0000000..dd91d70 --- /dev/null +++ b/main.h @@ -0,0 +1,95 @@ +#ifndef _ATK_YOLOV5_OBJECT_RECOGNIZE_H +#define _ATK_YOLOV5_OBJECT_RECOGNIZE_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define _BASETSD_H + +#include "im2d.h" +#include "rga.h" +#include "drm_func.h" +#include "rga_func.h" +#include "rknn_api.h" +#include "rkmedia_api.h" +#include "rkmedia_venc.h" +#include "sample_common.h" +#include "opencv2/opencv.hpp" + +#include "librtsp/rtsp_demo.h" +#include "rk_aiq_user_api_sysctl.h" +#include "rk_aiq_user_api_afec.h" +// #include "rk_aiq_uapi_afec_int.h" + +#include +#include +#include "opencv2/imgcodecs.hpp" + +using namespace cv; + + + +RK_U32 video_width = 1920; +RK_U32 video_height = 1072; +// RK_U32 video_height = 720; +int disp_width = 720; +int disp_height = 1280; + +static bool quit = false; +rtsp_demo_handle g_rtsplive = NULL; +static rtsp_session_handle g_rtsp_session; + +int rgb24_resize(unsigned char *input_rgb, unsigned char *output_rgb, int width,int height, int outwidth, int outheight); + +static unsigned char *load_model(const char *filename, int *model_size); + +static void printRKNNTensor(rknn_tensor_attr *attr); + +void *rkmedia_rknn_thread(void *args); +void *venc_rtsp_tidp(void *args); +void *upload_message(void *args); //上传检测信息与截取的图片 +void *upload_message_controller(void *args); +void *heart_beat(void *args); //上传心跳检测 +void *distortion(void *args); //矫正 +void *read_serial_thread(void *args); //读取串口传来的红外温度数据 + +struct Alarm { + int ifalarm; + int ifwarn; + std::string alarmMsg; + std::string alarmType; + std::string alarmBase64; + std::string alarmCoverage; + float alarmprop; +}; + +void initializeAlarm(Alarm* Alarm) { + // 初始化结构体成员 + Alarm->ifalarm = 0; + Alarm->ifwarn = 0; + Alarm->alarmMsg = "无"; + Alarm->alarmType = "无"; + Alarm->alarmBase64 = "无"; + Alarm->alarmCoverage = "无"; + Alarm->alarmprop = 0.0; +} + +void NV12ToRGB(int width, int height, unsigned char* nv12, Mat& rgb) { + // Step 1: Create a cv::Mat object for NV12 data + Mat nv12Mat(height + height / 2, width, CV_8UC1, nv12); + + // Step 2: Convert NV12 to RGB + cvtColor(nv12Mat, rgb, COLOR_YUV2RGB_NV12); +} + +#endif \ No newline at end of file diff --git a/rga_func.c b/rga_func.c new file mode 100644 index 0000000..aaea364 --- /dev/null +++ b/rga_func.c @@ -0,0 +1,129 @@ +// Copyright (c) 2021 by Rockchip Electronics Co., Ltd. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include "rga_func.h" + +int RGA_init(rga_context *rga_ctx) +{ + rga_ctx->rga_handle = dlopen("librga.so", RTLD_LAZY); + if (!rga_ctx->rga_handle) + { + printf("dlopen librga.so failed\n"); + printf("dlopen error: %s\n", dlerror()); + return -1; + } + rga_ctx->init_func = (FUNC_RGA_INIT)dlsym(rga_ctx->rga_handle, "c_RkRgaInit"); + rga_ctx->deinit_func = (FUNC_RGA_DEINIT)dlsym(rga_ctx->rga_handle, "c_RkRgaDeInit"); + rga_ctx->blit_func = (FUNC_RGA_BLIT)dlsym(rga_ctx->rga_handle, "c_RkRgaBlit"); + rga_ctx->init_func(); + return 0; +} + +void img_resize_fast(rga_context *rga_ctx, int src_fd, int src_w, int src_h, uint64_t dst_phys, int dst_w, int dst_h) +{ + // printf("rga use fd, src(%dx%d) -> dst(%dx%d)\n", src_w, src_h, dst_w, dst_h); + + if (rga_ctx->rga_handle) + { + int ret = 0; + rga_info_t src, dst; + + memset(&src, 0, sizeof(rga_info_t)); + src.fd = src_fd; + src.mmuFlag = 1; + // src.virAddr = (void *)psrc; + + memset(&dst, 0, sizeof(rga_info_t)); + dst.fd = -1; + dst.mmuFlag = 0; + +#if defined(__arm__) + dst.phyAddr = (void *)((uint32_t)dst_phys); +#else + dst.phyAddr = (void *)dst_phys; +#endif + + dst.nn.nn_flag = 0; + + rga_set_rect(&src.rect, 0, 0, src_w, src_h, src_w, src_h, RK_FORMAT_RGB_888); + rga_set_rect(&dst.rect, 0, 0, dst_w, dst_h, dst_w, dst_h, RK_FORMAT_RGB_888); + + ret = rga_ctx->blit_func(&src, &dst, NULL); + if (ret) + { + printf("c_RkRgaBlit error : %s\n", strerror(errno)); + } + + return; + } + return; +} + +void img_resize_slow(rga_context *rga_ctx, void *src_virt, int src_w, int src_h, void *dst_virt, int dst_w, int dst_h, + int w_offset, int h_offset, RgaSURF_FORMAT color, bool add_extra_sz_w, bool add_extra_sz_h) +{ + // printf("rga use virtual, src(%dx%d) -> dst(%dx%d)\n", src_w, src_h, dst_w, dst_h); + if (rga_ctx->rga_handle) + { + int ret = 0; + rga_info_t src, dst; + + memset(&src, 0, sizeof(rga_info_t)); + src.fd = -1; + src.mmuFlag = 1; + src.virAddr = (void *)src_virt; + + memset(&dst, 0, sizeof(rga_info_t)); + dst.fd = -1; + dst.mmuFlag = 1; + dst.virAddr = dst_virt; + + dst.nn.nn_flag = 0; + // printf("input to rga para, w_offset: %d, h_offset: %d, dst_w: %d, dst_h: %d\n", + // w_offset, h_offset, dst_w, dst_h); + + rga_set_rect(&src.rect, 0, 0, src_w, src_h, src_w, src_h, RK_FORMAT_RGB_888); + int src_w = dst_w + 2*w_offset; + int src_h = dst_h + 2*h_offset; + if (add_extra_sz_w){ + src_w += 1; + // printf("Adding extra sz w: %d\n", src_w); + } + else if (add_extra_sz_h){ + src_h += 1; + // printf("Adding extra sz h: %d\n", src_h); + } + + //rga_set_rect(&dst.rect, w_offset, h_offset, dst_w, dst_h, src_w, dst_h + 2*h_offset, color); + rga_set_rect(&dst.rect, w_offset, h_offset, dst_w, dst_h, src_w, src_h, color); + + ret = rga_ctx->blit_func(&src, &dst, NULL); + if (ret){ + printf("c_RkRgaBlit error : %s\n", strerror(errno)); + } + + return; + } + return; +} + +int RGA_deinit(rga_context *rga_ctx) +{ + if(rga_ctx->rga_handle) + { + dlclose(rga_ctx->rga_handle); + rga_ctx->rga_handle = NULL; + } +} \ No newline at end of file diff --git a/yolov5_detect.cpp b/yolov5_detect.cpp new file mode 100644 index 0000000..96f082d --- /dev/null +++ b/yolov5_detect.cpp @@ -0,0 +1,374 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "yolov5_detect.h" +#include "rknn_api.h" + +#include + +using namespace std; +using namespace cv; + + +//unsigned char *model; +//detection* dets; + +static void printRKNNTensor(rknn_tensor_attr *attr) +{ + printf("index=%d name=%s n_dims=%d dims=[%d %d %d %d] n_elems=%d size=%d " + "fmt=%d type=%d qnt_type=%d fl=%d zp=%d scale=%f\n", + attr->index, attr->name, attr->n_dims, attr->dims[3], attr->dims[2], + attr->dims[1], attr->dims[0], attr->n_elems, attr->size, 0, attr->type, + attr->qnt_type, attr->fl, attr->zp, attr->scale); +} + +static int letter_box(cv::Mat input_image, cv::Mat *output_image, int model_input_size) +{ + int input_width, input_height; + + input_width = input_image.cols; + input_height = input_image.rows; + float ratio; + ratio = min((float)model_input_size / input_width, (float)model_input_size / input_height); + + int new_width, new_height; + new_width = round(ratio * input_width ); + new_height = round(ratio * input_height); + + + int height_padding = 0; + int width_padding = 0; + int top = 0; + int bottom = 0; + int left = 0; + int right = 0; + if( new_width >= new_height) + { + height_padding = new_width - new_height; + if( (height_padding % 2) == 0 ) + { + top = (int)((float)(height_padding/2)); + bottom = (int)((float)(height_padding/2)); + } + else + { + top = (int)((float)(height_padding/2)); + bottom = (int)((float)(height_padding/2))+1; + } + } + else + { + width_padding = new_height - new_width; + if( (width_padding % 2) == 0 ) + { + left = (int)((float)(width_padding/2)); + right = (int)((float)(width_padding/2)); + } + else + { + left = (int)((float)(width_padding/2)); + right = (int)((float)(width_padding/2))+1; + } + + } + + cv::Mat resize_img; + + cv::resize(input_image, resize_img, cv::Size(new_width, new_height)); + cv::copyMakeBorder(resize_img, *output_image, top, bottom, left, right, cv::BORDER_CONSTANT, cv::Scalar(0, 0, 0)); + + return 0; +} + +int yolov5_detect_init(rknn_context *ctx, const char * path) +{ + int ret; + + // Load model + FILE *fp = fopen(path, "rb"); + if(fp == NULL) + { + printf("fopen %s fail!\n", path); + return -1; + } + fseek(fp, 0, SEEK_END); //fp指向end,fseek(FILE *stream, long offset, int fromwhere); + int model_len = ftell(fp); //相对文件首偏移 + unsigned char *model_data = (unsigned char*)malloc(model_len); + + fseek(fp, 0, SEEK_SET); //SEEK_SET为文件头 + if(model_len != fread(model_data, 1, model_len, fp)) + { + printf("fread %s fail!\n", path); + free(model_data); + return -1; + } + fclose(fp); + + //init + ret = rknn_init(ctx, model_data, model_len, RKNN_FLAG_PRIOR_MEDIUM); + if(ret < 0) + { + printf("rknn_init fail! ret=%d\n", ret); + return -1; + } + + free(model_data); + + return 0; +} + +static int scale_coords(yolov5_detect_result_group_t *detect_result_group, int img_width, int img_height, int model_size) +{ + for (int i = 0; i < detect_result_group->count; i++) + { + yolov5_detect_result_t *det_result = &(detect_result_group->results[i]); + + + int x1 = det_result->box.left; + int y1 = det_result->box.top; + int x2 = det_result->box.right; + int y2 = det_result->box.bottom; + + + if( img_width >= img_height ) + { + int image_max_len = img_width; + float gain; + gain = (float)model_size / image_max_len; + int resized_height = img_height * gain; + int height_pading = (model_size - resized_height)/2; + y1 = (y1 - height_pading); + y2 = (y2 - height_pading); + x1 = int(x1 / gain); + y1 = int(y1 / gain); + x2 = int(x2 / gain); + y2 = int(y2 / gain); + + det_result->box.left = x1; + det_result->box.top = y1; + det_result->box.right = x2; + det_result->box.bottom = y2; + } + else + { + int image_max_len = img_height; + float gain; + gain = (float)model_size / image_max_len; + int resized_width = img_width * gain; + int width_pading = (model_size - resized_width)/2; + x1 = (x1 - width_pading); + x2 = (x2 - width_pading); + x1 = int(x1 / gain); + y1 = int(y1 / gain); + x2 = int(x2 / gain); + y2 = int(y2 / gain); + + det_result->box.left = x1; + det_result->box.top = y1; + det_result->box.right = x2; + det_result->box.bottom = y2; + } + + } + + return 0; +} + + +int yolov5_detect_run(rknn_context ctx, cv::Mat input_image, yolov5_detect_result_group_t *detect_result_group) +{ + int img_width = 0; + int img_height = 0; + int img_channel = 0; + + size_t actual_size = 0; + const float vis_threshold = 0.1; + const float nms_threshold = 0.5; + const float conf_threshold = 0.2; + int ret; + + img_width = input_image.cols; + img_height = input_image.rows; + + rknn_sdk_version version; + ret = rknn_query(ctx, RKNN_QUERY_SDK_VERSION, &version, + sizeof(rknn_sdk_version)); + if (ret < 0) + { + printf("rknn_init error ret=%d\n", ret); + return -1; + } + /* + printf("sdk version: %s driver version: %s\n", version.api_version, + version.drv_version); + */ + + rknn_input_output_num io_num; + ret = rknn_query(ctx, RKNN_QUERY_IN_OUT_NUM, &io_num, sizeof(io_num)); + if (ret < 0) + { + printf("rknn_init error ret=%d\n", ret); + return -1; + } + /* + printf("model input num: %d, output num: %d\n", io_num.n_input, + io_num.n_output); + */ + + rknn_tensor_attr input_attrs[io_num.n_input]; + memset(input_attrs, 0, sizeof(input_attrs)); + for (int i = 0; i < io_num.n_input; i++) + { + input_attrs[i].index = i; + ret = rknn_query(ctx, RKNN_QUERY_INPUT_ATTR, &(input_attrs[i]), + sizeof(rknn_tensor_attr)); + if (ret < 0) + { + printf("rknn_init error ret=%d\n", ret); + return -1; + } + //printRKNNTensor(&(input_attrs[i])); + } + + rknn_tensor_attr output_attrs[io_num.n_output]; + memset(output_attrs, 0, sizeof(output_attrs)); + for (int i = 0; i < io_num.n_output; i++) + { + output_attrs[i].index = i; + ret = rknn_query(ctx, RKNN_QUERY_OUTPUT_ATTR, &(output_attrs[i]), + sizeof(rknn_tensor_attr)); + //printRKNNTensor(&(output_attrs[i])); + } + + int input_channel = 3; + int input_width = 0; + int input_height = 0; + if (input_attrs[0].fmt == RKNN_TENSOR_NCHW) + { + //printf("model is NCHW input fmt\n"); + input_width = input_attrs[0].dims[0]; + input_height = input_attrs[0].dims[1]; + } + else + { + //printf("model is NHWC input fmt\n"); + input_width = input_attrs[0].dims[1]; + input_height = input_attrs[0].dims[2]; + } + + /* + printf("model input height=%d, width=%d, channel=%d\n", height, width, + channel); + */ + + /* Init input tensor */ + rknn_input inputs[1]; + memset(inputs, 0, sizeof(inputs)); + inputs[0].index = 0; + inputs[0].type = RKNN_TENSOR_UINT8; + inputs[0].size = input_width * input_height * input_channel; + inputs[0].fmt = RKNN_TENSOR_NHWC; + inputs[0].pass_through = 0; + + /* Init output tensor */ + rknn_output outputs[io_num.n_output]; + memset(outputs, 0, sizeof(outputs)); + + for (int i = 0; i < io_num.n_output; i++) + { + outputs[i].want_float = 0; + } + + cv::Mat letter_image; + letter_box(input_image, &letter_image, input_width); + inputs[0].buf = letter_image.data; + + rknn_inputs_set(ctx, io_num.n_input, inputs); + ret = rknn_run(ctx, NULL); + ret = rknn_outputs_get(ctx, io_num.n_output, outputs, NULL); + + // Post process + std::vector out_scales; + std::vector out_zps; + for (int i = 0; i < io_num.n_output; ++i) + { + out_scales.push_back(output_attrs[i].scale); + out_zps.push_back(output_attrs[i].zp); + } + + + yolov5_post_process_u8((uint8_t *)outputs[0].buf, (uint8_t *)outputs[1].buf, (uint8_t *)outputs[2].buf, input_height, input_width, + conf_threshold, nms_threshold, out_zps, out_scales, detect_result_group); + + + /* + yolov5_post_process_fp((float *)outputs[0].buf, (float *)outputs[1].buf, (float *)outputs[2].buf, input_height, input_width, + conf_threshold, nms_threshold, &detect_result_group); + */ + + rknn_outputs_release(ctx, io_num.n_output, outputs); + + scale_coords(detect_result_group, img_width, img_height, input_width); + + return 0; +} + +int yolov5_detect_release(rknn_context ctx) +{ + rknn_destroy(ctx); + return 0; +} + + +std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len) { + std::string ret; + int i = 0; + int j = 0; + unsigned char char_array_3[3]; + unsigned char char_array_4[4]; + + while (in_len--) { + char_array_3[i++] = *(bytes_to_encode++); + if (i == 3) { + char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; + char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); + char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); + char_array_4[3] = char_array_3[2] & 0x3f; + + for(i = 0; (i <4) ; i++) + ret += base64_chars[char_array_4[i]]; + i = 0; + } + } + + if (i) { + for(j = i; j < 3; j++) + char_array_3[j] = '\0'; + + char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; + char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); + char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); + char_array_4[3] = char_array_3[2] & 0x3f; + + for (j = 0; (j < i + 1); j++) + ret += base64_chars[char_array_4[j]]; + + while((i++ < 3)) + ret += '='; + } + + return ret; +} + +static inline bool is_base64(unsigned char c) { + return (isalnum(c) || (c == '+') || (c == '/')); +} \ No newline at end of file