#include <atlbase.h> #include <atlconv.h> #include <sqlite3.h> #include <openssl/pem.h> #include <openssl/err.h> #include <openssl/pkcs12.h> #include <HPSocket.h> #include <fstream> #include <cassert> #include <string> #include <queue> #include <map> #include <time.h> #include <sys/timeb.h> #include <ctime> #include <stdio.h> #include <stdlib.h> #include <iomanip> #include <algorithm> #include <cmath> #include <direct.h> #include <WinSock2.h> #include <Iphlpapi.h> //#include <thread> //#include <mutex> #include "CppSQLite3.h" #include "libhnsw.h" #include "WmAceKG-x86.h" #include "CommonTools.h" #include "rapidjson/document.h" #include "rapidjson/writer.h" #include "rapidjson/pointer.h" #include "rapidjson/stringbuffer.h" #include "rapidjson/filereadstream.h" #include "rapidjson/filewritestream.h" #include "DirectoryDel.h" #include "SocketServer.h" #include "SocketClient.h" #include "ThreadPool.h" #include "spdlog/spdlog.h" #include "spdlog/sinks/daily_file_sink.h" #include "ini.h" #include "videopipe.h" #include "libretri.h" #include "CharacterConversion.h" #include "MarkSave.h" #include <vector> #include <opencv2/imgproc/imgproc.hpp> #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <iostream> #include <ncnn/benchmark.h> #include <ncnn/platform.h> #include <ncnn/net.h> #include "libstrret.h" // #undef NCNN_VULKAN #pragma comment(lib, "IPHLPAPI.lib") #define ERROR_SIMILARITY 0.95//纠错的相似度 #define FEATURE_COUNT 128 //特征的个数 #define DATABASE_SIZE 120000 //索引大小 #define APPOINT_LIBRARY 0 //指定目录 #define NCNN_USING 1 //ncnn #define FRESH_DETECT 0 #define PREVENT_LOSS 1 #define VIDEOCOUNT 49 #define VIDEOCOINTIN 49 //纠错存 code和id unordered_map<string, int>reassion; string realProductCodes[10]; //空盘图向量 float feature_empty[FEATURE_COUNT]; string empty_pic = "empty_pic"; //视频流存图 int rest_count; int rest_in = 0; int rest_out = 0; string dir_in; string dir_out; //视频流抓图时间 int video_time; using namespace std; using namespace cv; using namespace rapidjson; struct VIDEO_FRAME_INFO { UINT64 timestamp; // 时间戳 Mat img; }; struct DETECT_RESULT { char productCodes[100]; char sessionId[100]; int state; }; struct FOOD_PARAM_DATA { Mat back; // 用于创建算法的初始化图像,一般是裁剪具有标志物的空秤盘 string back_mat_path; // 加载temp的路径 bool end_thread; // 控制视频流线程 Rect roi; // 识别区域 bool has_roi; // 是否启用识别区域 int max_in_frame_queue; // 最大缓存图片数 queue<VIDEO_FRAME_INFO> frame_in; // q1 queue<libvideopipe::FOOD_VIDEOPIPE_INPUT> videopipe_in; // q2 vector<VIDEO_FRAME_INFO> frame_out; // q2 HANDLE hMutex; //互斥量 bool debug_mode; // 是否启用调试 libvideopipe::MotionVideoPipe* mvp; //追踪器 queue<DETECT_RESULT> result_queue; //结果队列 int queue_max; //结果队列上限 string detect_image_path; bool scan; //是否扫描 }; //返回结果 DETECT_RESULT result; // step0: 初始化param FOOD_PARAM_DATA param_in; //文件的路径 const char *gszFile = "featurexYz.db"; const char* log_path = "logs/daily.txt"; std::shared_ptr<spdlog::logger> logger; vector<float>solve_cost; //索引 libhnsw::Index* idx = nullptr; // 测试提交 // api列表 // 租户 string tenantStr; // mac地址 string macAddr; // 开发版本 string dev; float filterScore = 0.85f; float markDownScoreLimit = 0.9f; int mode; // 版本文本 const char* dev_ini_path = "dev.ini"; // 租户json const char* json_tenant_path = "tenant.json"; // posId json const char* posId_json_path = "posId.json"; // pos机注册api const char* wmpos_bind_url = "%s.wmdigit.com/%s/newretail/api/pos/machine/bind"; // pos机解绑api const char* wmpos_unbind_url = "%s.wmdigit.com/%s/newretail/api/pos/machine/unbind?mac=%s&snNo=%s"; // 保存称重记录 const char* save_record_url = "%s.wmdigit.com/%s/newretail/api/search/product/saveImageIdentify"; // 上传文件 const char* upload_file_url = "%s.wmdigit.com/%s/newretail/api/dfs/upload"; // 上传视频流的照片文件 const char* upload_file1_url = "%s.wmdigit.com/%s/newretail/api/dfs/upload2"; // 重置mac地址为有线网卡的mac 地址 const char* reset_mac_url = "%s.wmdigit.com/%s/newretail/api/pos/machine/updateMacByOld"; // 验证租户是否正确 const char* query_tenant_url = "%s.wmdigit.com/0/newretail/api/sys/org/queryTenant?tenantCode=%s"; // pos机试用api const char* wmpos_probation_url = "%s.wmdigit.com/free-sample/newretail/api/pos/probationSdk/download?macAddress=%s"; //自动配图 const char* pictured_json_url = "%s.wmdigit.com/%s/newretail/api/mall/productMatch/match"; // 是否连接网络 bool connectNet = true; //用于打开摄像头 cv::VideoCapture cap; //// 一帧图片 //cv::Mat frame; // 三帧图片 cv::Mat frame_pipe; cv::Mat frame_one; cv::Mat frame_two; cv::Mat frame_thr; // Mat mask; // 裁剪的坐标值 int x, y, width, height; int ai_x, ai_y, ai_width, ai_height; // 摄像头序号 int cameraNum; // 存储的json文件路径 const char* json_path = "coordinate.json"; // 是否验证过 bool authed = false; string wmphoto_path = "WMPhoto"; // 获取dll所在目录 EXTERN_C IMAGE_DOS_HEADER __ImageBase;//申明为全局变量 // posId string posId; string mac_date = "2021-11-24 14:00:00"; libbm25::Index *match_map = nullptr; //视频流算法参数 float MarkThreshold; float AiMarkThreshold; //是否使用gpu和ai bool using_ai = true; bool drive_ai = 1; //元芒加速库句柄 void* handle = nullptr; //debug模式 bool debug = false; //抓图线程安全 HANDLE PhotoMutex; //视频流是否正在处理图片(因为出现过处理一帧需要2s的问题,改了算法逻辑,添加了该参数) bool in_image = false; //是否已经返回前端结果(因为前端node的线程问题,添加了改参数,防止一直访问结果队列。(待优化???)) bool re_ret = false; //扫描开始,停止视频流 bool plu_input_stop_video = false; //视频流是否初始化完成 bool g_video_init = false; //防止多次初始化 bool init_finish = false; // 是否触发视频流识别 bool video_detect = true; /*******************************Socket相关************************************/ bool openSync = false; // TCP服务端口 int port = 10083; // 最大连接数 const int maxConnectionCount = 20; // 真实Ip char realIp[16]; // 连接Ids vector<CONNID> connIds; // udp节点 UdpNodeListenerImpl udpNodeListener; CUdpNodePtr udp_node(&udpNodeListener); // tcp客户端 ClientListenerImpl clientListener; CTcpPackClientPtr s_pclient(&clientListener); // tcp服务端 ServerListenerImpl serverListener; CTcpPackServerPtr s_pserver(&serverListener); void getFiles(string path, vector<string>& files) { //文件句柄 intptr_t hFile = 0; //文件信息 struct _finddata_t fileinfo; string p; if ((hFile = _findfirst(p.assign(path).append("\\*").c_str(), &fileinfo)) != -1) { do { if ((fileinfo.attrib & _A_SUBDIR)) { if (strcmp(fileinfo.name, ".") != 0 && strcmp(fileinfo.name, "..") != 0) getFiles(p.assign(path).append("\\").append(fileinfo.name), files); } else { files.push_back(p.assign(path).append("\\").append(fileinfo.name)); } } while (_findnext(hFile, &fileinfo) == 0); _findclose(hFile); } } //删除日志 int delete_daily() { string filePath = "logs\\"; vector<string> files; getFiles(filePath, files); int size = files.size(); sort(files.begin(), files.end()); if (size > 7) { for (int i = 0; i < size - 7; i++) { remove(files[i].c_str()); } } return 0; } float average_cost() { if(solve_cost.size() == 0 && (!in_image)) { return 67; } while (solve_cost.size() == 0 && in_image) { Sleep(100); } float ret = solve_cost[0]; solve_cost.erase(solve_cost.begin()); if (ret > 3000) { ret = 3000; } if (ret < 67) { ret = 67; } return ret; } void sendTcpServerCreateBroadCast(const char* data) { BOOL result = udp_node->SendCast((const BYTE*)data, strlen(data)); if (!result) { int code = SYS_GetLastError(); logger->info("当前ip:{},发送广播消息失败,错误码:{}", realIp, code); } else { logger->info("ip:{},UDP广播消息:{},发送成功", realIp, data); } } void createUdpNode() { if (!udp_node->Start(char2TCAHR(realIp), 11184, CM_BROADCAST, L"255.255.255.255")) { int code = GetLastError(); logger->info("当前ip:{},创建udp节点错误,错误码:{}", realIp, code); } else { logger->info("ip:{},UDP节点创建成功", realIp); } } void createClient(LPCTSTR remoteAddress) { if (s_pclient->HasStarted()) { s_pclient->Stop(); } // 3. Start component object s_pclient->SetMaxPackSize(1024 * 100); if (!s_pclient->Start(remoteAddress, port)) { int code = GetLastError(); logger->info("当前ip:{},socket客户端启动失败,错误码:{}", realIp, code); } else { logger->info("ip:{},socket客户端启动成功", realIp); } } // 1 代表索引添加 2 代表商品模型关系添加 //{\"type\":1,\"feature\":\"1\",\"productCode\":\"1\",\"modelCodes\":[{\"modelCode\":1,\"productCode\":\"123\"},{\"modelCode\":2,\"productCode\":\"345\"}]} void sendClientModelMessage(vector<int> modelCodes, vector<string> productCodes) { if (modelCodes.size() == 0) { return; } // 等待2秒客户端连接 Sleep(2000); if (s_pclient->HasStarted()) { Document d; Document::AllocatorType& a = d.GetAllocator(); Value a1(kArrayType); for (unsigned int i = 0; i < modelCodes.size(); i++) { Value o1(kObjectType); o1.AddMember("productCode", Value(productCodes[i], a), a); o1.AddMember("modelCode", Value(modelCodes[i]), a); a1.PushBack(o1, a); } Pointer("/type").Set(d, 2); Pointer("/modelCodes").Set(d, a1); StringBuffer buffer; Writer<StringBuffer> writer(buffer); d.Accept(writer); logger->info(buffer.GetString()); s_pclient->Send((const BYTE*)buffer.GetString(), buffer.GetLength()); } else if (s_pserver->HasStarted()) { Document d; Document::AllocatorType& a = d.GetAllocator(); Value a1(kArrayType); for (unsigned int i = 0; i < modelCodes.size(); i++) { Value o1(kObjectType); o1.AddMember("productCode", Value(productCodes[i], a), a); o1.AddMember("modelCode", Value(modelCodes[i]), a); a1.PushBack(o1, a); } Pointer("/type").Set(d, 2); Pointer("/modelCodes").Set(d, a1); StringBuffer buffer; Writer<StringBuffer> writer(buffer); d.Accept(writer); logger->info(buffer.GetString()); for (unsigned long i = 0; i < connIds.size(); i++) { s_pserver->Send(connIds[i], (const BYTE*)buffer.GetString(), buffer.GetLength()); } } else { // do nothing } } int initTcpServer() { if (!openSync) { return 0; } // 设置真实ip GetIp(realIp); // 创建udp节点 createUdpNode(); // 创建tcp服务 s_pserver->SetMaxConnectionCount(maxConnectionCount); s_pserver->SetMaxPackSize(1024 * 100); if (!s_pserver->Start(char2TCAHR(realIp), port)) { int code = GetLastError(); logger->info("当前ip:{},socket服务端启动失败,错误码:{}", realIp, code); } else { logger->info("当前ip:{},socket服务端启动成功", realIp); sendTcpServerCreateBroadCast("hello i am tcp server"); } return 0; } // 获取mac地址 void GetMacByGetAdaptersAddresses(std::string& macOUT) { bool ret = false; ULONG ulOutBufLen = sizeof(IP_ADAPTER_INFO); PIP_ADAPTER_INFO pAdapterInfo = (IP_ADAPTER_INFO*)malloc(sizeof(IP_ADAPTER_INFO)); if (pAdapterInfo == NULL) return; if (GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) == ERROR_BUFFER_OVERFLOW) { free(pAdapterInfo); pAdapterInfo = (IP_ADAPTER_INFO*)malloc(ulOutBufLen); if (pAdapterInfo == NULL) return; } if (GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) == NO_ERROR) { for (PIP_ADAPTER_INFO pAdapter = pAdapterInfo; pAdapter != NULL; pAdapter = pAdapter->Next) { // 确保是以太网 if (pAdapter->Type != MIB_IF_TYPE_ETHERNET || pAdapter->Type == 71 || strstr(pAdapter->Description, "Bluetooth") > 0) continue; // 过滤vpn 和 虚拟机 if (strstr(pAdapter->Description, "VPN") > 0 || strstr(pAdapter->Description, "Virtual") > 0 || strstr(pAdapter->Description, "UU") > 0) { continue; } // 确保MAC地址的长度为 00-00-00-00-00-00 if (pAdapter->AddressLength != 6) continue; char acMAC[32]; sprintf_s(acMAC, 32, "%02X-%02X-%02X-%02X-%02X-%02X", int(pAdapter->Address[0]), int(pAdapter->Address[1]), int(pAdapter->Address[2]), int(pAdapter->Address[3]), int(pAdapter->Address[4]), int(pAdapter->Address[5])); cout << "找到了有线网卡: " << acMAC << endl; cout << "当前类型为: " << pAdapter->Type << endl; cout << "当前描述为: " << pAdapter->Description << endl; macOUT = acMAC; ret = true; } // 没有找到有线网卡 开始设置无线网卡 if (!ret) { for (PIP_ADAPTER_INFO pAdapter = pAdapterInfo; pAdapter != NULL; pAdapter = pAdapter->Next) { // 确保是以太网 if (pAdapter->Type == MIB_IF_TYPE_ETHERNET || pAdapter->Type != 71 || strstr(pAdapter->Description, "Bluetooth") > 0) continue; // 过滤vpn 和 虚拟机 if (strstr(pAdapter->Description, "VPN") > 0 || strstr(pAdapter->Description, "Virtual") > 0 || strstr(pAdapter->Description, "UU") > 0) { continue; } // 确保MAC地址的长度为 00-00-00-00-00-00 if (pAdapter->AddressLength != 6) continue; char acMAC[32]; sprintf_s(acMAC, 32, "%02X-%02X-%02X-%02X-%02X-%02X", int(pAdapter->Address[0]), int(pAdapter->Address[1]), int(pAdapter->Address[2]), int(pAdapter->Address[3]), int(pAdapter->Address[4]), int(pAdapter->Address[5])); cout << "找到了无线网卡: " << acMAC << endl; cout << "当前类型为: " << pAdapter->Type << endl; cout << "当前描述为: " << pAdapter->Description << endl; macOUT = acMAC; break; } } } free(pAdapterInfo); } /** * 字符分割算法 , * @param str * @param data * @return */ void split(char* str, float* data) { const char* regex = ","; str = strtok(str, regex); int i = 0; while (str) { data[i] = atof(str); i++; str = strtok(NULL, regex); } } inline bool exists_file(const std::string& name) { if (FILE* file = fopen(name.c_str(), "r")) { fclose(file); return true; } else { return false; } } /** * 字符分割算法 int * @param str * @param data * @return */ void splitStringColon(char* str, string* data) { const char* regex = ":"; str = strtok(str, regex); int i = 0; while (str) { data[i] = str; i++; str = strtok(NULL, regex); } } /** * 字符分割算法 int * @param str * @param data * @return */ void splitString(char* str, string* data) { const char* regex = ","; str = strtok(str, regex); int i = 0; while (str) { data[i] = str; i++; str = strtok(NULL, regex); } } // 读取文件 string readTxt(string file) { ifstream infile; infile.open(file.data()); //将文件流对象与文件连接起来 assert(infile.is_open()); //若失败,则输出错误消息,并终止程序运行 string s; while (getline(infile, s)) { cout << s << endl; } infile.close(); //关闭文件输入流 return s; } void del_rod(char* src) { char* fp = src; while (*src) { if (*src != '-') { *fp = *src; fp++; } src++; } *fp = '\0'; //封闭字符串 } void del_rod(string& str) { // 因为str.c_str() 是const的,不能直接修改, // 所以要复制一个临时的,然后修改后换回去 char tmp[18 + 1]; memcpy(&tmp, str.c_str(), str.size() + 1); del_rod(tmp); // 重载del_rod,调用C风格的函数 str = tmp; } std::string tool_get_dll_path() { char dir[_MAX_DIR]; char drive[_MAX_DRIVE]; char DllPath[MAX_PATH]; GetModuleFileNameA((HINSTANCE)&__ImageBase, DllPath, _countof(DllPath)); //截取DLL所在目录(去掉DLL文件名) char fname[_MAX_FNAME]; char ext[_MAX_EXT]; _splitpath(DllPath, drive, dir, fname, ext); std::string new_dir = std::string(drive) + std::string(dir); return new_dir; } time_t StringToDatetime(string str) { char* cha = (char*)str.data(); // 将string转换成char*。 tm tm_; // 定义tm结构体。 int year, month, day, hour, minute, second;// 定义时间的各个int临时变量。 sscanf(cha, "%d-%d-%d %d:%d:%d", &year, &month, &day, &hour, &minute, &second);// 将string存储的日期时间,转换为int临时变量。 tm_.tm_year = year - 1900; // 年,由于tm结构体存储的是从1900年开始的时间,所以tm_year为int临时变量减去1900。 tm_.tm_mon = month - 1; // 月,由于tm结构体的月份存储范围为0-11,所以tm_mon为int临时变量减去1。 tm_.tm_mday = day; // 日。 tm_.tm_hour = hour; // 时。 tm_.tm_min = minute; // 分。 tm_.tm_sec = second; // 秒。 tm_.tm_isdst = 0; // 非夏令时。 time_t t_ = mktime(&tm_); // 将tm结构体转换成time_t格式。 return t_; // 返回值。 } int GetFileInfo(string& strPath,time_t& createTime) { struct _stat tmpInfo; if (_stat(strPath.c_str(), &tmpInfo) != 0) { return FALSE; } createTime = tmpInfo.st_ctime; return TRUE; } // 私钥解密 std::string rsa_pri_decrypt(const std::string& cipherText, const std::string& priKey) { std::string strRet; RSA* rsa = RSA_new(); BIO* keybio; // keybio = BIO_new_mem_buf((unsigned char*)priKey.c_str(), -1); keybio = BIO_new_file(priKey.c_str(), "r"); // 此处有三种方法 // 1, 读取内存里生成的密钥对,再从内存生成rsa // 2, 读取磁盘里生成的密钥对文本文件,在从内存生成rsa // 3,直接从读取文件指针生成rsa rsa = PEM_read_bio_RSAPrivateKey(keybio, &rsa, NULL, NULL); int len = RSA_size(rsa); char* decryptedText = (char*)malloc(len + 1); memset(decryptedText, 0, len + 1); // 解密函数 int ret = RSA_private_decrypt(cipherText.length(), (const unsigned char*)cipherText.c_str(), (unsigned char*)decryptedText, rsa, RSA_PKCS1_PADDING); if (ret >= 0) strRet = std::string(decryptedText, ret); // 释放内存 free(decryptedText); BIO_free_all(keybio); RSA_free(rsa); return strRet; } static inline bool is_base64(unsigned char c) { return (isalnum(c) || (c == '+') || (c == '/')); } // base64 解码 std::string base64Decode(std::string const& encoded_string) { std::string base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "0123456789+/"; size_t in_len = encoded_string.size(); int i = 0; int j = 0; int in_ = 0; unsigned char char_array_4[4], char_array_3[3]; std::string ret; while (in_len-- && (encoded_string[in_] != '=') && is_base64(encoded_string[in_])) { char_array_4[i++] = encoded_string[in_]; in_++; if (i == 4) { for (i = 0; i < 4; i++) char_array_4[i] = base64_chars.find(char_array_4[i]) & 0xff; char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; for (i = 0; (i < 3); i++) ret += char_array_3[i]; i = 0; } } if (i) { for (j = 0; j < i; j++) char_array_4[j] = base64_chars.find(char_array_4[j]) & 0xff; char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); for (j = 0; (j < i - 1); j++) ret += char_array_3[j]; } return ret; } void loadIndexFromDB(CppSQLite3DB& db, libhnsw::Index* newIndex) { double start_time = clock();//1计时开始 if (db.tableExists("feature_code")) { CppSQLite3Query q = db.execQuery("select id,feature from feature_code where deleted = 0"); while (!q.eof()) { float features[FEATURE_COUNT]; int id = q.getIntField(0); const char* sql_feature = q.getStringField(1); char* c = const_cast<char*>(sql_feature); split(c, features); newIndex->Addsample(features, id - 1); q.nextRow(); } q.finalize(); } double end_time = clock();//1计时开始 logger->info("load index elapsed {}ms\n", end_time - start_time); } int retri_Init() { logger->info("初始化元芒图像加速库"); int ret = 0; if (drive_ai == 0) { ret = RETRI_Init(NULL, RETRI_DEVICE::RETRI_CPU, &handle); } else { ret = RETRI_Init(NULL, RETRI_DEVICE::RETRI_GPU, &handle); } if (ret != 0) { logger->info("初始化元芒图像加速库失败:{0:x}",ret); return -1; } else { logger->info("初始化元芒图像加速库成功"); return 0; } } /** * 初始化faiss索引 */ int WMAI_API Init(char* path) { if (init_finish == true) { logger->info("二次初始化"); return 0; } #if APPOINT_LIBRARY char DllPath[MAX_PATH] = { 0 }; GetModuleFileNameA((HINSTANCE)&__ImageBase, DllPath, _countof(DllPath)); //截取DLL所在目录(去掉DLL文件名) char fname[_MAX_FNAME]; char ext[_MAX_EXT]; _splitpath(DllPath, drive, dir, fname, ext); string new_dir = string(drive) + dir; char* ini_path = new char[MAX_PATH]; strcpy(ini_path, (new_dir + "dev.ini").c_str()); dev_ini_path = ini_path; char* gsz_file = new char[MAX_PATH]; string ascll_gsz_file = new_dir + "featurexYz.db"; string utf_8_gsz_file = ASCII2UTF_8(ascll_gsz_file); strcpy(gsz_file, utf_8_gsz_file.c_str()); gszFile = gsz_file; char* imagePath = new char[MAX_PATH]; string ascll_imagePath = new_dir + "AiImageWmAceKG.db"; string utf_8_imagePath = ASCII2UTF_8(ascll_imagePath); strcpy(imagePath, utf_8_imagePath.c_str()); wmimage = imagePath; char* tenant_path = new char[MAX_PATH]; strcpy(tenant_path, (new_dir + "tenant.json").c_str()); json_tenant_path = tenant_path; char* posId_path = new char[MAX_PATH]; strcpy(posId_path, (new_dir + "posId.json").c_str()); posId_json_path = posId_path; char* coordinate = new char[MAX_PATH]; strcpy(coordinate, (new_dir + "coordinate.json").c_str()); json_path = coordinate; char* logPath = new char[MAX_PATH]; strcpy(logPath, (new_dir + "logs/daily.txt").c_str()); log_path = logPath; char* wmphotoPath = new char[MAX_PATH]; strcpy(wmphotoPath, (new_dir + "WMphoto").c_str()); wmphoto_path = wmphotoPath; #else // do nothing #endif // 0 if (logger == nullptr) { logger = spdlog::daily_logger_mt("daily_logger", log_path, 2, 7); logger->flush_on(spdlog::level::info); delete_daily(); } char* js_path = new char[MAX_PATH]; string ascll_json_file = string(path) + "\\" + "coordinate.json"; string utf_8_json_file = ASCII2UTF_8(ascll_json_file); std::strcpy(js_path, utf_8_json_file.c_str()); json_path = js_path; FILE* fp = fopen(json_path, "rb"); // 非 Windows 平台使用 "r" if (fp) { char readBuffer[65536]; FileReadStream is(fp, readBuffer, sizeof(readBuffer)); Document d; d.ParseStream(is); x = d["x"].GetInt(); y = d["y"].GetInt(); width = d["width"].GetInt(); height = d["height"].GetInt(); ai_x = d["ai_x"].GetInt(); ai_y = d["ai_y"].GetInt(); ai_width = d["ai_width"].GetInt(); ai_height = d["ai_height"].GetInt(); cameraNum = d["cameraNum"].GetInt(); fclose(fp); } mask = imread("mask\\mask.jpg"); char* json_ten = new char[MAX_PATH]; string ascll_ten_file = string(path) + "\\" + "tenant.json"; string utf_8_ten_file = ASCII2UTF_8(ascll_ten_file); std::strcpy(json_ten, utf_8_ten_file.c_str()); json_tenant_path = json_ten; FILE* fp2 = fopen(json_tenant_path, "rb"); // 非 Windows 平台使用 "r" if (fp2) { char readBuffer2[65536]; FileReadStream is2(fp2, readBuffer2, sizeof(readBuffer2)); Document d2; d2.ParseStream(is2); tenantStr = d2["demo"].GetString(); fclose(fp2); } char* posId_json = new char[MAX_PATH]; string ascll_posid_file = string(path) + "\\" + "posId.json"; string utf_8_posid_file = ASCII2UTF_8(ascll_posid_file); std::strcpy(posId_json, utf_8_posid_file.c_str()); posId_json_path = posId_json; FILE* fp3 = fopen(posId_json_path, "rb"); // 非 Windows 平台使用 "r" if (fp3) { char readBuffer3[65536]; FileReadStream is3(fp3, readBuffer3, sizeof(readBuffer3)); Document d3; d3.ParseStream(is3); posId = d3["posId"].GetString(); fclose(fp3); } GetMacByGetAdaptersAddresses(macAddr); del_rod(macAddr); mINI::INIFile file(dev_ini_path); mINI::INIStructure ini; file.read(ini); dev = ini["default"]["dev"]; mode = atoi(ini["default"]["mode"].c_str()); drive_ai = atoi(ini["default"]["drive_ai"].c_str()); openSync = atoi(ini["default"]["openSync"].c_str()); filterScore = atof(ini["default"]["filterScore"].c_str()); video_time = atoi(ini["default"]["videoTime"].c_str()); // 开始创建tcp服务端 initTcpServer(); //初始化图形加速库 int ret = retri_Init(); logger->info("图形加速库初始化结果:{0:x}", ret); //添加索引 float idx_start = clock(); char* gsz_file = new char[MAX_PATH]; string ascll_gsz_file = string(path)+"\\" + "featurexYz.db"; string utf_8_gsz_file = ASCII2UTF_8(ascll_gsz_file); std::strcpy(gsz_file, utf_8_gsz_file.c_str()); gszFile = gsz_file; logger->info("gszFile is {}", gszFile); CppSQLite3DB db; db.open(gszFile); db.setBusyTimeout(5000); if (db.tableExists("feature_code")) { CppSQLite3Query queryColumn3 = db.execQuery("select * from sqlite_master where name='feature_code' and sql like '%deleted%';"); if (queryColumn3.eof()) { //没有 "列名" 列 //新增列 db.execDML("ALTER TABLE feature_code ADD COLUMN deleted INTEGER DEFAULT 0;"); } } idx = new libhnsw::Index(FEATURE_COUNT, DATABASE_SIZE, libhnsw::BRUTE_FORCE_KNN_CF,libhnsw::INNER_PRODUCT); loadIndexFromDB(db, idx); float idx_end = clock(); logger->info("idx init cost:{}",idx_end - idx_start); if (db.tableExists("product_record")) { CppSQLite3Buffer deleteProductRecord; deleteProductRecord.format("delete from product_record;"); int row = db.execDML(deleteProductRecord); logger->info("{} row product_record has been deleted", row); } db.execDML("CREATE TABLE IF NOT EXISTS product_model (id integer PRIMARY KEY AUTOINCREMENT, product_code text NOT NULL, model_code integer NOT NULL);"); db.execDML("CREATE TABLE IF NOT EXISTS product_model_counting (id integer PRIMARY KEY AUTOINCREMENT, product_code text NOT NULL, model_code integer NOT NULL, num integer NOT NULL);"); db.execDML("CREATE TABLE IF NOT EXISTS feature_code (id integer PRIMARY KEY AUTOINCREMENT, code text NOT NULL, feature text NOT NULL, update_time TIMESTAMP DEFAULT NULL, deleted integer DEFAULT NULL);"); db.execDML("CREATE TABLE IF NOT EXISTS feed_back_record (id integer PRIMARY KEY AUTOINCREMENT, code text NOT NULL, session_id text NOT NULL, hit integer NOT NULL);"); //储存空盘向量 db.execDML("CREATE TABLE IF NOT EXISTS empty_pan_feature (id integer PRIMARY KEY AUTOINCREMENT,feature text NOT NULL);"); //检测表单 if (!db.tableExists("record_count")) { db.execDML("CREATE TABLE IF NOT EXISTS record_count (id integer PRIMARY KEY AUTOINCREMENT, count integer NOT NULL);");; } //检测表单,此表单为计数 db.execDML("CREATE TABLE IF NOT EXISTS video_count (id integer PRIMARY KEY AUTOINCREMENT, count_in integer NOT NULL)"); //检测record_count表达数据 CppSQLite3Buffer selectvideocount; selectvideocount.format("select count(*) from video_count"); CppSQLite3Query q = db.execQuery(selectvideocount); int pre1; while (!q.eof()) { pre1 = q.getIntField(0); break; } q.finalize(); if (pre1 == 0) { rest_count = 0; logger->info("rest_count is{}", rest_count); } else { CppSQLite3Buffer selectvideo; selectvideo.format("select count_in from video_count where id=1;"); CppSQLite3Query q2 = db.execQuery(selectvideo); while (!q2.eof()) { rest_count = q2.getIntField(0); logger->info("rest_count is{}",rest_count); break; } q2.finalize(); } //检测record_count表达数据 CppSQLite3Buffer measure; measure.format("select count(*) from record_count;"); CppSQLite3Query q1 = db.execQuery(measure); ret = 0; while (!q1.eof()) { ret = q1.getIntField(0); break; } q1.finalize(); logger->info("record_count ret :{}", ret); if (ret == 0) { int count = 1; CppSQLite3Buffer insert; insert.format("insert into record_count(count) values (%d)", count); db.execDML(insert); } if (!db.tableExists("product_record")) { db.execDML("CREATE TABLE IF NOT EXISTS product_record (id integer PRIMARY KEY AUTOINCREMENT, session_id TEXT NOT NULL, model_code INTEGER NOT NULL, score REAL NOT NULL,feature_value TEXT NOT NULL,image_path TEXT NOT NULL,product_ids TEXT NOT NULL,real_codes TEXT NOT NULL,time TEXT NOT NULL);"); db.execDML("CREATE INDEX session_id_index ON product_record(session_id);"); } // sqlite_master 为sqlite隐藏系统表 CppSQLite3Query queryColumn = db.execQuery("select * from sqlite_master where name='product_record' and sql like '%real_codes%';"); if (queryColumn.eof()) { //没有 "列名" 列 //新增列 db.execDML("ALTER TABLE product_record ADD COLUMN real_codes TEXT NOT NULL;"); } CppSQLite3Query queryColumn2 = db.execQuery("select * from sqlite_master where name='feature_code' and sql like '%update_time%';"); if (queryColumn2.eof()) { //没有 "列名" 列 //新增列 db.execDML("ALTER TABLE feature_code ADD COLUMN update_time TIMESTAMP DEFAULT NULL;"); CppSQLite3Buffer updateFeatureCodeTime; updateFeatureCodeTime.format("update feature_code set update_time = datetime('now','localtime');"); db.execDML(updateFeatureCodeTime); } queryColumn.finalize(); queryColumn2.finalize(); db.close(); string dir_path = tool_get_dll_path(); wmphoto_path = dir_path + "WMPhoto"; DeleteDirectory(wmphoto_path.c_str()); init_finish = true; logger->info("init end"); return 0; } // Tenengrad模糊检测 float TenengradBlurDetect(const cv::Mat& srcimg) { cv::Mat x_grad, y_grad, src_gray; cv::cvtColor(srcimg, src_gray, 6); cv::Sobel(src_gray, x_grad, CV_16S, 1, 0, 3); cv::Sobel(src_gray, y_grad, CV_16S, 0, 1, 3); cv::Mat abs_grad_x, abs_grad_y; int width = srcimg.cols; int height = srcimg.rows; int step = srcimg.step; cv::convertScaleAbs(x_grad, abs_grad_x); cv::convertScaleAbs(y_grad, abs_grad_y); uchar* udata_x = abs_grad_x.data; uchar* udata_y = abs_grad_y.data; float sum = 0; for (int j = 0; j < height; j++) { for (int i = 0; i < width; i++) { float udata_x_d = udata_x[j * width + i] / 255; float udata_y_d = udata_y[j * width + i] / 255; sum = sum + udata_x_d * udata_x_d + udata_y_d * udata_y_d; } } // printf("TenengradBlurDetect=%f ms\n", ti); return 100 * sum / (width * height); } // 获取mac地址 bool checkMac(std::string& decryptText) { bool ret = false; ULONG outBufLen = sizeof(IP_ADAPTER_ADDRESSES); PIP_ADAPTER_ADDRESSES pAddresses = (IP_ADAPTER_ADDRESSES*)malloc(outBufLen); if (pAddresses == NULL) return false; // Make an initial call to GetAdaptersAddresses to get the necessary size into the ulOutBufLen variable if (GetAdaptersAddresses(AF_UNSPEC, 0, NULL, pAddresses, &outBufLen) == ERROR_BUFFER_OVERFLOW) { free(pAddresses); pAddresses = (IP_ADAPTER_ADDRESSES*)malloc(outBufLen); if (pAddresses == NULL) return false; } if (GetAdaptersAddresses(AF_UNSPEC, 0, NULL, pAddresses, &outBufLen) == NO_ERROR) { // If successful, output some information from the data we received for (PIP_ADAPTER_ADDRESSES pCurrAddresses = pAddresses; pCurrAddresses != NULL; pCurrAddresses = pCurrAddresses->Next) { // 确保MAC地址的长度为 00-00-00-00-00-00 if (pCurrAddresses->PhysicalAddressLength != 6) continue; char acMAC[32]; sprintf(acMAC, "%02X-%02X-%02X-%02X-%02X-%02X", int(pCurrAddresses->PhysicalAddress[0]), int(pCurrAddresses->PhysicalAddress[1]), int(pCurrAddresses->PhysicalAddress[2]), int(pCurrAddresses->PhysicalAddress[3]), int(pCurrAddresses->PhysicalAddress[4]), int(pCurrAddresses->PhysicalAddress[5])); if (decryptText == acMAC) { ret = true; break; } } } free(pAddresses); return ret; } // 判断是否授权 bool probationAuth() { logger->info("没有找到正式密钥 开始使用试用密钥"); #if APPOINT_LIBRARY string new_dir = string(drive) + dir; string pprikey = new_dir + "pprikey.pem"; string pwmkey = new_dir + "pwmkey.wm"; #else string pprikey = "pprikey.pem"; string pwmkey = "pwmkey.wm"; #endif // 0 if (!exists_file(pprikey) || !exists_file(pwmkey)) { return false; } string str = readTxt(pwmkey); string encryptText = base64Decode((char*)str.c_str()); string decryptText = rsa_pri_decrypt(encryptText, pprikey); string macTime[2]; char* decryptStr = const_cast<char*>(decryptText.c_str()); logger->info("decryptStr:{}", decryptStr); splitStringColon(decryptStr, macTime); // 校验mac地址 bool authorize = checkMac(macTime[0]); if (!authorize) { // mac不一致直接过期 return authorize; } // 校验有效期 long expireTime; std::stringstream sstr; sstr << macTime[1]; sstr >> expireTime; // 过期时间unix时间戳 - 当前unix时间戳 > 0 || 过期时间unix时间戳 - 当前unix时间戳 > 15 std::time_t t = std::time(0); long timeSpace = expireTime - t; if (timeSpace > 0 && timeSpace <= 15 * 86400) { int lastDays = timeSpace / 86400; logger->info("剩余使用天数为{}", lastDays); return true; } return false; } // 判断是否授权 bool authorize() { #if APPOINT_LIBRARY string new_dir = string(drive) + dir; string prikey = new_dir + "prikey.pem"; string wmkey = new_dir + "wmkey.wm"; #else string prikey = "prikey.pem"; string wmkey = "wmkey.wm"; #endif // 0 if (!exists_file(prikey) || !exists_file(wmkey)) { return probationAuth(); } string str = readTxt(wmkey); string encryptText = base64Decode((char*)str.c_str()); string decryptText = rsa_pri_decrypt(encryptText, prikey); bool authorize = checkMac(decryptText); return authorize; } //static int k; int detect_squeezenet(const cv::Mat& bgr, std::vector<float>& cls_scores, float* rhs) { // step1:初始化handle logger->info("进入元芒图像加速库"); if (handle == nullptr) { logger->info("初始化元芒图像加速库"); int hr = 0; if (drive_ai == 0) { hr = RETRI_Init(NULL, RETRI_DEVICE::RETRI_CPU, &handle); } else { hr = RETRI_Init(NULL, RETRI_DEVICE::RETRI_GPU, &handle); } if (hr != 0) { logger->info("元芒图形加速库初始化失败!error code:{o:x}\n", hr); return -1; } else { logger->info("元芒图形加速库初始化成功"); } } // step2:推理 RETRI_INPUT in_img; in_img.img = bgr.clone(); RETRI_OUTPUT clsretri_output; cv::imwrite("input.jpg", in_img.img); //string inimg = tool_get_dll_path()+"in-image"; //_mkdir(inimg.c_str()); //char image_name[120] = {}; //sprintf(image_name, "\\%lld.jpg", k); //std::string dir_path = inimg+"\\"+image_name; //imwrite(dir_path, in_img.img); //k++; int s_time = clock(); int hr = RETRI_Process(in_img, &clsretri_output, handle); int e_time = clock(); if (hr != 0) { logger->info("元芒图形加速库推理失败!error code:{0:x}\n", hr); return -2; } logger->info("元芒图形加速库耗时:{}ms\n", e_time - s_time); //step3.返回结果 for (int i = 0; i < FEATURE_COUNT; i++) { rhs[i] = clsretri_output.feat[i]; } return 0; } // 保存top10条记录 并且打印 int save_topk(const std::vector<float>& cls_scores, int topk, int* index, float* scores) { //index = new int[topk]; //scores = new float[topk]; std::vector< std::pair<float, int> > vec; // partial sort topk with index int size = cls_scores.size(); vec.resize(size); for (int i = 0; i < size; i++) { vec[i] = std::make_pair(cls_scores[i], i); } std::partial_sort(vec.begin(), vec.begin() + topk, vec.end(), std::greater< std::pair<float, int> >()); // print topk and score for (int i = 0; i < topk; i++) { scores[i] = vec[i].first; index[i] = vec[i].second; //float score = vec[i].first; //int index = vec[i].second; //logger->info("{} = {}\n", index[i], scores[i]); } return 0; } float calculSimilar(float v1[], float v2[], int size) { // assert(v1.size() == v2.size()); double ret = 0.0, mod1 = 0.0, mod2 = 0.0; for (int i = 0; i < size; ++i) { ret += v1[i] * v2[i]; mod1 += v1[i] * v1[i]; mod2 += v2[i] * v2[i]; } if (mod1 == 0 || mod2 == 0) return 0; return (ret / sqrt(mod1) / sqrt(mod2) + 1) / 2.0; } int compare_feature_faiss(float* rhs, string* code, int& biggerNinety) { try { CppSQLite3DB db; db.open(gszFile); if (!db.tableExists("feature_code")) { return 0; } // ============ 搜索 =================== reassion.clear(); double startTime1 = clock();//1计时开始 //logger->info("detect feature:{}", rhs); /// //char rhs_data[FEATURE_COUNT * 10] = { }; /* for (int i = 0; i < FEATURE_COUNT; ++i) { sprintf(rhs_data + strlen(rhs_data), "%f,", rhs[i]); } logger->info("detect feature:{}", rhs_data);*/ std::vector<std::pair<float, int>>res = idx->Search(rhs,6); for (unsigned int j = 0; j < res.size(); j++) { std::pair<float, int> r = res[j]; //logger->info("res[{}]:id {},prob {}\n", j, r.second, 1-r.first); int number = r.second; // 商品向量 float features[FEATURE_COUNT]; //获得对应的商品代 number = number + 1; CppSQLite3Buffer selectFeatureCode; selectFeatureCode.format("select code,feature,id from feature_code where id = %d;", number); CppSQLite3Query q = db.execQuery(selectFeatureCode); string sql_code; int id; while (!q.eof()) { sql_code = q.getStringField(0); const char* sql_feature = q.fieldValue(1); id = q.getIntField(2); char* c = const_cast<char*>(sql_feature); split(c, features); q.nextRow(); //logger->info("idx;{} feature:{}", j, sql_feature); } q.finalize(); float sim = calculSimilar(rhs, features, FEATURE_COUNT); logger->info("{} is {}", sql_code.c_str(), sim); if (sim > filterScore) { code[j + 3] = sql_code; reassion.emplace(sql_code, id); // 如果大于过滤值 说明该向量最近被使用 修改最后更新时间 CppSQLite3Buffer updateFeatureCode; updateFeatureCode.format("update feature_code set update_time = datetime('now','localtime') where id = %d", id); db.execDML(updateFeatureCode); } if (j == 0 && sim > 0.9) { logger->info("第一个向量大于0.9的置信度 置换第一个商品代码"); biggerNinety = 1; } // scores[j+3] = feature; } db.close(); for (int i = 0; i < 10; i++) { if (code[i].empty() || code[i] == "0") { continue; } for (int j = i + 1; j < 10; j++) { if (code[j].empty() || code[j] == "0") { continue; } if (code[i] == code[j]) { code[j] = "0"; } } } double endTime1 = clock();//1计时结束 double elasped = endTime1 - startTime1; logger->info("index time : elapsed {}ms\n", elasped); } catch (...) { logger->info("compare_feature_faiss failed"); } return 0; } const char* getMaxLimpidPic(const char* imagepath1, const char* imagepath2, const char* imagepath3, int count) { if (count == 1) { return imagepath1; } if (count == 2) { return imagepath2; } if (count == 3) { return imagepath3; } throw "imread read error"; } cv::Mat getMaxMat(const char* imagepath1, const char* imagepath2, const char* imagepath3, int& count) { cv::Mat m1 = cv::imread(imagepath1, 1); if (m1.empty()) { logger->info("cv::imread {} failed\n", imagepath1); throw "cv::imread failed"; } float f1 = TenengradBlurDetect(m1); cv::Mat m2 = cv::imread(imagepath2, 1); if (m2.empty()) { logger->info("cv::imread {} failed\n", imagepath2); throw "cv::imread failed"; } float f2 = TenengradBlurDetect(m2); cv::Mat m3 = cv::imread(imagepath3, 1); if (m3.empty()) { logger->info("cv::imread {} failed\n", imagepath3); throw "cv::imread failed"; } float f3 = TenengradBlurDetect(m3); float fmax = max(max(f1, f2), f3); if (fmax == f1) { count = 1; return m1; } else if (fmax == f2) { count = 2; return m2; } else if (fmax == f3) { count = 3; return m3; } else { throw "cv::imread failed"; } } // 保存打称记录 int save_record(std::string sessionId, int index, float score, float time, string imagepath, string features, string productcode, string codes) { try { CppSQLite3DB db; db.open(gszFile); CppSQLite3Buffer insertProductCode; insertProductCode.format("insert into product_record(session_id, model_code, score,feature_value,image_path,product_ids,real_codes,time) values (%Q,%d,%f,%Q,%Q,%Q,%Q,%f);", sessionId.c_str(), index, score, features.c_str(), imagepath.c_str(), productcode.c_str(), codes.c_str(), time); db.execDML(insertProductCode); db.close(); return 0; } catch (...) { logger->info("save_record failed"); return -1; } } // 获取10位sessionId string get_session_id() { char prefix[50]; time_t nowTime; tm* now; time(&nowTime); //获取系统当前时间戳 now = localtime(&nowTime); //将时间戳转化为时间结构体 srand((int)time(0)); long l = rand() % 9000000000 + 1000000000; ostringstream os; os << l; string result; istringstream is(os.str()); is >> result; sprintf(prefix, "%d%d%d%d%d%d%d%d", macAddr.c_str(), now->tm_year + 1900, now->tm_mon + 1, now->tm_mday, now->tm_hour + 8, now->tm_min, now->tm_sec, result.c_str()); string s(prefix, prefix + strlen(prefix)); return s; } int convert_model_code(int* index, float* scores, string* productcode) { CppSQLite3DB db; db.open(gszFile); if (!db.tableExists("product_model")) { for (int i = 0; i < 10; i++) { productcode[i] = "0"; } return 0; } vector<string> indexProductCodes = { "0","0" ,"0" ,"0" ,"0" ,"0" ,"0" }; CppSQLite3Query q; int count = 0; for (int i = 0; i < 10; i++) { if (count > 6) { break; } if (scores[i] > 0.01) { CppSQLite3Buffer selectProductCode; selectProductCode.format("select product_code from product_model where model_code = %d;", index[i]); cout << selectProductCode << endl; q = db.execQuery(selectProductCode); while (!q.eof()) { if (count > 6) { break; } string productCode = q.getStringField(0); indexProductCodes[count] = productCode; ++count; q.nextRow(); } } } q.finalize(); db.close(); for (int i = 0; i < 10; i++) { if (productcode[i] != "") { continue; } if (i < 3) { productcode[i] = indexProductCodes[i]; } else { productcode[i] = indexProductCodes[i - 3]; } } return 0; } void saveImg(string pic_Name, cv::Mat mat) { cv::imwrite(pic_Name, mat); } // 拍照 cv::Mat getScaleBitmap(char* rawPath, char* cropPath, bool saveRawImg) { cv::Mat returnFrame, frame1, frame2, frame3; double startTime1, endTime1, elasped; startTime1 = clock();//1计时开始 char pic_Name[128] = {}; //照片名称 char raw_pic_Name[128] = {}; //照片名称 if (!cap.isOpened()) { logger->info("The camera open failed!"); return returnFrame; } if (frame_one.empty() || frame_thr.empty() || frame_two.empty()) { logger->info("camera not init,please wait"); return returnFrame; } time_t nowTime; tm* now; WaitForSingleObject(PhotoMutex, INFINITE); frame1= frame_one.clone(); frame2= frame_two.clone(); frame3 =frame_thr.clone(); ReleaseMutex(PhotoMutex); endTime1 = clock(); elasped = endTime1 - startTime1; logger->info("camera load elapsed {}ms\n", elasped); time(&nowTime); //获取系统当前时间戳 now = localtime(&nowTime); //将时间戳转化为时间结构体 _mkdir(wmphoto_path.c_str()); if (saveRawImg) { #if APPOINT_LIBRARY string new_dir = wmphoto_path; char photoPath[MAX_PATH]; strcpy(photoPath, (new_dir + "\\raw%d%d%d%d%d%d.jpg").c_str()); #else char photoPath[MAX_PATH]; std::strcpy(photoPath, (wmphoto_path+"\\raw%d%d%d%d%d%d.jpg").c_str()); #endif // 0 sprintf(raw_pic_Name, photoPath, now->tm_year + 1900, now->tm_mon + 1, now->tm_mday, now->tm_hour + 8, now->tm_min, now->tm_sec); cv::imwrite(raw_pic_Name, frame1); std::strcpy(rawPath, raw_pic_Name); } if (x && y && width && height) { #if APPOINT_LIBRARY string new_dir = wmphoto_path; char photoPath[MAX_PATH]; strcpy(photoPath, (new_dir + "\\%d%d%d%d%d%d.jpg").c_str()); #else char photoPath[MAX_PATH]; std::strcpy(photoPath, (wmphoto_path+"\\%d%d%d%d%d%d.jpg").c_str()); #endif // 0 sprintf(pic_Name, photoPath, now->tm_year + 1900, now->tm_mon + 1, now->tm_mday, now->tm_hour + 8, now->tm_min, now->tm_sec); cv::Mat catImage1, catImage2, catImage3; copyTo(frame1,catImage1,mask); catImage1 = catImage1(cv::Rect(x, y, width, height)); copyTo(frame2, catImage2, mask); catImage2 = catImage2(cv::Rect(x, y, width, height)); copyTo(frame3, catImage3, mask); catImage3 = catImage3(cv::Rect(x, y, width, height)); float f1 = TenengradBlurDetect(catImage1); float f2 = TenengradBlurDetect(catImage2); float f3 = TenengradBlurDetect(catImage3); float maxF = max(max(f1, f2), f3); if (maxF == f1) { returnFrame = catImage1.clone(); if (saveRawImg) { // 如果是主动拍照 路径同步返回 cv::imwrite(pic_Name, catImage1); } else { std::thread t(saveImg, string(pic_Name), catImage1); //将Mat数据写入文件 t.detach(); } } if (maxF == f2) { returnFrame = catImage2.clone(); if (saveRawImg) { // 如果是主动拍照 路径同步返回 cv::imwrite(pic_Name, catImage2); } else { std::thread t(saveImg, string(pic_Name), catImage2); //将Mat数据写入文件 t.detach(); } } if (maxF == f3) { returnFrame = catImage3.clone(); if (saveRawImg) { // 如果是主动拍照 路径同步返回 cv::imwrite(pic_Name, catImage3); } else { std::thread t(saveImg, string(pic_Name), catImage3); //将Mat数据写入文件 t.detach(); } } std::strcpy(cropPath, pic_Name); } endTime1 = clock();//1计时开始 elasped = endTime1 - startTime1; logger->info("camera all elapsed {}ms\n", elasped); return returnFrame; } void _stringCpy(string* des,string* rec,int len) { for (size_t i = 0; i < len; i++) { des[i] = rec[i]; } } // 主动识别接口 int MatDetect(char* productcodes, char* sessionId) { double all_start_time = clock();//1计时开始 if (!authed) { authed = authorize(); if (!authed) { logger->info("验证失败"); return -2001; }; } if (!x && !y && !width && !height) { logger->info("没有设置摄像头剪辑坐标"); return -2009; } int thread = 4; int use_gpu = 0; #if NCNN_VULKAN // ncnn::create_gpu_instance(); #endif // NCNN_VULKAN char rawPath[128]; char cropPath[128]; cv::Mat m = getScaleBitmap(rawPath, cropPath, false); if (m.empty()) { logger->info("cv::imread failed\n"); return -2002; } int biggerNinety = 0; // 拷贝图片地址 //strncpy(image, cropPath, 128); string productcode[10]; std::vector<float> cls_scores; float rhs[FEATURE_COUNT]; double start_time = ncnn::get_current_time(); int ret = detect_squeezenet(m, cls_scores, rhs); double elasped = ncnn::get_current_time() - start_time; logger->info("category elapsed {}ms\n", elasped); compare_feature_faiss(rhs, productcode, ref(biggerNinety)); double save_record_start_time = clock();//1计时开始 string newSessionId = get_session_id(); std::strcpy(sessionId, newSessionId.c_str()); // 组装返回的商品代码 char codes[10 * 10] = { }; for (int i = 0; i < 10; ++i) { if (productcode[i].empty() || productcode[i] == "0") { continue; } sprintf(codes + strlen(codes), "%s,", productcode[i].c_str()); } logger->info("productcodes:{}", codes); std::strcpy(productcodes, codes); string product_codes = productcodes; char* realIds = const_cast<char*>(product_codes.c_str()); splitString(realIds, realProductCodes); // 将图片向量进行逗号组装 char featureValue[FEATURE_COUNT * 10] = { }; for (int i = 0; i < FEATURE_COUNT; ++i) { sprintf(featureValue + strlen(featureValue), "%f,", rhs[i]); } // 组装productIds char productIds[10 * 10] = { }; for (int i = 0; i < 10; ++i) { if (productcode[i].empty()) { continue; } sprintf(productIds + strlen(productIds), "%s,", productcode[i].c_str()); } //判断是否识别到了空盘 double empty_find_begin = clock(); //打开数据库 CppSQLite3DB db; db.open(gszFile); for (int i = 1; i < 31; ++i) { float features[128]; CppSQLite3Buffer select_empty; select_empty.format("select feature from empty_pan_feature where id=%d", i); CppSQLite3Query q = db.execQuery(select_empty); while (!q.eof()) { const char* sql_feature = q.fieldValue(0); char* c = const_cast<char*>(sql_feature); split(c, features); break; } q.finalize(); //判断是否识别到了空盘 float sim = calculSimilar(rhs, features, FEATURE_COUNT); char rhs_data[FEATURE_COUNT * 10] = { }; logger->info("相似度为 sim is{}", sim); if (sim >= 0.95) { result.state = 2; logger->info("result.state is {}", result.state); memset(productIds, '\0', sizeof(productIds)); logger->info("productIds is {}", productIds); break; } //logger->info("result.state is {}", result.state); //param_in.result_queue.push(result); } db.close(); double empty_find_end = clock(); logger->info("result.state is {}", result.state); logger->info("判断是否为空盘的时间为:{}", empty_find_end- empty_find_begin); save_record(newSessionId, 0, 0, elasped, string(cropPath), string(featureValue), string(productIds), string(codes)); double save_record_end_time = clock();//1计时开始 logger->info("save record elapsed {}ms\n", save_record_end_time - save_record_start_time); double all_end_time = clock();//1计时开始 logger->info("all time elapsed {}ms\n", all_start_time - all_end_time); return 0; } // 主动识别接口 int WMAI_API DemoDetect(const char* imagePath, char* productcodes, char* sessionId) { double all_start_time = clock();//1计时开始 if (!authed) { authed = authorize(); if (!authed) { cout << "验证失败" << endl; return -1; }; } int use_gpu = 0; #if NCNN_VULKAN // ncnn::create_gpu_instance(); #endif // NCNN_VULKAN cv::Mat m = cv::imread(imagePath, 1); if (m.empty()) { logger->info("cv::imread {} failed\n", imagePath); return -1; } int biggerNinety = 0; string productcode[10]; std::vector<float> cls_scores; float rhs[FEATURE_COUNT]; double start_time = ncnn::get_current_time(); int ret = detect_squeezenet(m, cls_scores, rhs); if (ret != 0) { logger->info("元芒图形加速识别失败,error:ret",ret); return -2004; } std::thread t(compare_feature_faiss, rhs, productcode, ref(biggerNinety)); t.join(); double elasped = ncnn::get_current_time() - start_time; logger->info("category elapsed %.2fms\n", elasped); double save_record_start_time = clock();//1计时开始 string newSessionId = get_session_id().c_str(); std::strcpy(sessionId, newSessionId.c_str()); // 0 1 2 3 4 5 6 7 8 9 // 3 0 1 2 4 5 6 7 8 9 string returnCodes[10]; _stringCpy(returnCodes, productcode, 10); if (biggerNinety) { string codeFour; for (int i = 3; i > 0; i--) { if (i == 3) { codeFour = returnCodes[i]; } returnCodes[i] = returnCodes[i - 1]; } returnCodes[0] = codeFour; } // 去重returnCodes for (int i = 0; i < 10; i++) { if (returnCodes[i].empty() || returnCodes[i] == "0") { continue; } for (int j = i + 1; j < 10; j++) { if (returnCodes[j].empty() || returnCodes[j] == "0") { continue; } if (returnCodes[i] == returnCodes[j]) { returnCodes[j] = "0"; } } } // 组装返回的商品代码 char codes[10 * 10] = { }; for (int i = 0; i < 10; ++i) { if (returnCodes[i].empty() || returnCodes[i] == "0") { continue; } sprintf(codes + strlen(codes), "%s,", returnCodes[i].c_str()); } logger->info("productcodes:{}", codes); std::strcpy(productcodes, codes); // 将图片向量进行逗号组装 char featureValue[FEATURE_COUNT * 10] = { }; for (int i = 0; i < FEATURE_COUNT; ++i) { sprintf(featureValue + strlen(featureValue), "%f,", rhs[i]); } // 组装productIds char productIds[10 * 10] = { }; for (int i = 0; i < 10; ++i) { sprintf(productIds + strlen(productIds), "%s,", productcode[i].c_str()); } double save_record_end_time = clock();//1计时开始 std::thread t1(save_record, newSessionId, 0, 0, elasped, string(imagePath), string(featureValue), string(productIds), string(codes)); t1.detach(); logger->info("save record elapsed {}ms\n", save_record_end_time - save_record_start_time); double all_end_time = clock();//1计时开始 logger->info("all time elapsed {}ms\n", all_start_time - all_end_time); return 0; } // 零食识别 int doSnacksAutoDetect(char* productcodes, char* sessionId, char* image) { double all_start_time = clock();//1计时开始 if (!authed) { authed = authorize(); if (!authed) { logger->info("验证失败"); return -2001; }; } if (!x && !y && !width && !height) { logger->info("没有设置摄像头剪辑坐标"); return -2009; } int thread = 4; int use_gpu = 0; #if NCNN_VULKAN // ncnn::create_gpu_instance(); #endif // NCNN_VULKAN char rawPath[128]; char cropPath[128]; cv::Mat m = getScaleBitmap(rawPath, cropPath, false); if (m.empty()) { logger->info("cv::imread failed\n"); return -2002; } int biggerNinety = 0; // 拷贝图片地址 strncpy(image, cropPath, 128); string productcode[10]; std::vector<float> cls_scores; float rhs[FEATURE_COUNT]; double start_time = ncnn::get_current_time(); int ret = detect_squeezenet(m, cls_scores, rhs); double elasped = ncnn::get_current_time() - start_time; logger->info("category elapsed {}ms\n", elasped); compare_feature_faiss(rhs, productcode, ref(biggerNinety)); double save_record_start_time = clock();//1计时开始 string newSessionId = get_session_id(); std::strcpy(sessionId, newSessionId.c_str()); // 组装返回的商品代码 char codes[10 * 10] = { }; for (int i = 0; i < 10; ++i) { if (productcode[i].empty() || productcode[i] == "0") { continue; } sprintf(codes + strlen(codes), "%s,", productcode[i].c_str()); } logger->info("productcodes:{}", codes); std::strcpy(productcodes, codes); string product_codes = productcodes; char* realIds = const_cast<char*>(product_codes.c_str()); splitString(realIds, realProductCodes); // 将图片向量进行逗号组装 char featureValue[FEATURE_COUNT * 10] = { }; for (int i = 0; i < FEATURE_COUNT; ++i) { sprintf(featureValue + strlen(featureValue), "%f,", rhs[i]); } // 组装productIds char productIds[10 * 10] = { }; for (int i = 0; i < 10; ++i) { if (productcode[i].empty()) { continue; } sprintf(productIds + strlen(productIds), "%s,", productcode[i].c_str()); } save_record(newSessionId, 0, 0, elasped, string(cropPath), string(featureValue), string(productIds), string(codes)); double save_record_end_time = clock();//1计时开始 logger->info("save record elapsed {}ms\n", save_record_end_time - save_record_start_time); double all_end_time = clock();//1计时开始 logger->info("all time elapsed {}ms\n", all_start_time - all_end_time); return 0; } // 主动识别接口 int WMAI_API AutoDetect(char* productcodes, char* sessionId) { char image[128]; int ret = doSnacksAutoDetect(productcodes, sessionId, image); return ret; } int getTopNo(string* productCodes, const char* code) { for (int i = 0; i < 10; i++) { if (productCodes[i] == code) { return i + 1; } } return -1; } string getNowDate() { char prefix[50]; time_t nowTime; tm* now; time(&nowTime); //获取系统当前时间戳 now = localtime(&nowTime); //将时间戳转化为时间结构体 sprintf(prefix, "%4d-%02d-%02d %02d:%02d:%02d.000", now->tm_year + 1900, now->tm_mon + 1, now->tm_mday, now->tm_hour, now->tm_min, now->tm_sec); return prefix; } int saveHnswCount = 0; void saveHnswIndex(string featureValue,int id) { try { //将数据加入索引 float features[FEATURE_COUNT]; char c[FEATURE_COUNT * 10]; strcpy_s(c, featureValue.c_str()); split(c, features); idx->Addsample(features, id - 1); logger->info("cover label is {}", id - 1); logger->info("index size is {}", idx->get_cur_element_count()); }catch(...){ logger->info("add simple error"); } } void saveDbIndex(CppSQLite3DB& db, const char* code, std::string& featureValue) { db.setBusyTimeout(3000); //检测feature_code表达数据 int size_f = 0; CppSQLite3Buffer measure; measure.format("select count(*) from feature_code;"); CppSQLite3Query q = db.execQuery(measure); while (!q.eof()) { size_f = q.getIntField(0); break; } q.finalize(); //查询表单大小,确认是否有未使用的id CppSQLite3Buffer measureCount; measureCount.format("select count(*) from record_count;"); CppSQLite3Query q1 = db.execQuery(measureCount); int size_r = 0; while (!q1.eof()) { size_r = q1.getIntField(0); break; } q1.finalize(); int lastId = idx->get_cur_element_count(); logger->info("lastId is {}", lastId); if (size_f >= 30000) { // 找到时间最小的向量 进行替换 int id = 0; int count = 0; // 找到第一个code的商品 替换他 CppSQLite3Buffer selectCount; if (size_r > 1) { //有积存id,取最后一条 selectCount.format("select id , count from record_count order by id desc limit 1;"); CppSQLite3Query q = db.execQuery(selectCount); while (!q.eof()) { id = q.getIntField(0); count = q.getIntField(1); break; } q.finalize(); logger->info("id:{}", id); logger->info("count:{}", count); //覆盖删除值 CppSQLite3Buffer updateFeatureCode; updateFeatureCode.format("update feature_code set code = %Q,feature= %Q,update_time = datetime('now','localtime') ,deleted = 0 where id = %d;", code, featureValue.c_str(), count); db.execDML(updateFeatureCode); logger->info("覆盖成功"); //删除用掉的id的记录 CppSQLite3Buffer delCount; selectCount.format("delete from record_count where id = %d;", id); db.execDML(selectCount); } else { //没有积存id,读取标记 selectCount.format("select count from record_count where id = 1;"); CppSQLite3Query q = db.execQuery(selectCount); while (!q.eof()) { count = q.getIntField(0); break; } q.finalize(); //判断是否超出上限 if (count > 30000) { CppSQLite3Buffer overDelete; overDelete.format("update record_count set count = 1 where id = 1"); count = 1; CppSQLite3Buffer updateCount; updateCount.format("update record_count set count = 1 where id = 1"); db.execDML(updateCount); } // 直接覆盖 CppSQLite3Buffer updateFeatureCode; updateFeatureCode.format("update feature_code set feature = %Q,code = %Q,update_time = datetime('now','localtime'),deleted = 0 where id = %d", featureValue.c_str(), code, count); db.execDML(updateFeatureCode); } logger->info("count :{}", count); // 删除label // idx->Removesample(id - 1); // 保存索引 //hnswExecutor->enqueue(saveHnswIndex, string(featureValue), id); saveHnswIndex(string(featureValue), count); CppSQLite3Buffer updateCount; updateCount.format("update record_count set count = count + 1 where id = 1"); db.execDML(updateCount); } else { // 记录feature 和 商品代码之间的关系 到sqlite 和 faiss索引 CppSQLite3Buffer insertFeatureCode; insertFeatureCode.format("insert into feature_code(code, feature,update_time,deleted) values (%Q,%Q,datetime('now','localtime'),0);", code, featureValue.c_str()); db.execDML(insertFeatureCode); int count = db.execScalar("select last_insert_rowid() from feature_code;"); logger->info("db add id is {}", count); //将数据加入索引 // 保存索引 //hnswExecutor->enqueue(saveHnswIndex, string(featureValue), count); saveHnswIndex(string(featureValue), count); } } void saveDbIndex2(CppSQLite3DB& db, const char* code, std::string& featureValue) { db.setBusyTimeout(3000); int lastId = idx->get_cur_element_count(); logger->info("lastId is {}", lastId); if (lastId >= 50000) { // 找到时间最小的向量 进行替换 int id = 0; // 找到第一个code的商品 替换他 CppSQLite3Buffer selectFeatureCode; selectFeatureCode.format("select id,min(update_time) from feature_code;"); CppSQLite3Query q = db.execQuery(selectFeatureCode); while (!q.eof()) { id = q.getIntField(0); break; } q.finalize(); // 直接覆盖 CppSQLite3Buffer updateFeatureCode; updateFeatureCode.format("update feature_code set feature = %Q,code = %Q,update_time = datetime('now','localtime') where id = %d", featureValue.c_str(), code, id); db.execDML(updateFeatureCode); // 保存索引 saveHnswIndex(string(featureValue), id); } else { // 记录feature 和 商品代码之间的关系 到sqlite 和 faiss索引 CppSQLite3Buffer insertFeatureCode; insertFeatureCode.format("insert into feature_code(code, feature,update_time) values (%Q,%Q,datetime('now','localtime'));", code, featureValue.c_str()); db.execDML(insertFeatureCode); float features[FEATURE_COUNT]; char c[FEATURE_COUNT * 10]; std::strcpy(c, featureValue.c_str()); split(c, features); int count = db.execScalar("select last_insert_rowid() from feature_code;"); logger->info("db add id is {}", count); // 保存索引 saveHnswIndex(string(featureValue), count); } } void sendClientFeatureMessage(const char* productCode, string featureValue) { if (s_pclient->HasStarted()) { Document d; Document::AllocatorType& allocator = d.GetAllocator(); Value str_val; char strBuffer[FEATURE_COUNT * 10]; int len = sprintf(strBuffer, featureValue.c_str()); str_val.SetString(strBuffer, len, allocator); Pointer("/type").Set(d, 1); Pointer("/productCode").Set(d, productCode); Pointer("/feature").Set(d, str_val, allocator); StringBuffer buffer; Writer<StringBuffer> writer(buffer); d.Accept(writer); logger->info(buffer.GetString()); s_pclient->Send((const BYTE*)buffer.GetString(), buffer.GetLength()); } else if (s_pserver->HasStarted()) { Document d; Document::AllocatorType& allocator = d.GetAllocator(); Value str_val; char strBuffer[FEATURE_COUNT * 10]; int len = sprintf(strBuffer, featureValue.c_str()); str_val.SetString(strBuffer, len, allocator); Pointer("/type").Set(d, 1); Pointer("/productCode").Set(d, productCode); Pointer("/feature").Set(d, str_val, allocator); StringBuffer buffer; Writer<StringBuffer> writer(buffer); d.Accept(writer); logger->info(buffer.GetString()); for (long i = 0; i < connIds.size(); i++) { logger->info("client connId is {}", connIds[i]); s_pserver->Send(connIds[i], (const BYTE*)buffer.GetString(), buffer.GetLength()); } } else { // do nothing } } int getNumByScore(float score) { return score >= markDownScoreLimit ? 1 : 0; } // 生鲜回传 int doFruitsSetFeedBack(const char* code, char* sessionId, bool hit, char* productName) { CppSQLite3DB db; db.open(gszFile); // 回传记录保存 CppSQLite3Buffer insertFeedBackRecord; insertFeedBackRecord.format("insert into feed_back_record(code, session_id,hit) values (%Q,%Q,%d);", code, sessionId, hit); db.execDML(insertFeedBackRecord); // 根据sessionId查询对应的打称记录 如果置信度>0.85 那么将商品代码 模型代码的计数器+1 如果计数器>=2 将商品模型的关系记录 // 首先查询根据sessionId查询product_record 得到模型代码 和 置信度 if (!db.tableExists("product_record")) { logger->info("product_record not found , please check AutoDetect success"); db.close(); return -2004; } int modelCode = 0; float score; string featureValue; string imagePath; string productIds; string time; string realCodes; for (int i = 0; i < 5; i++) { CppSQLite3Buffer selectProductRecord; selectProductRecord.format("select model_code,score,feature_value,image_path,product_ids,time,real_codes from product_record where session_id = %Q;", sessionId); CppSQLite3Query q = db.execQuery(selectProductRecord); while (!q.eof()) { modelCode = q.getIntField(0); score = q.getFloatField(1); featureValue = q.getStringField(2); imagePath = q.getStringField(3); productIds = q.getStringField(4); time = q.getStringField(5); realCodes = q.getStringField(6); q.nextRow(); } q.finalize(); if (!modelCode) { logger->info("sessionId not found , wait 200ms, times:{}", i + 1); Sleep(200); continue; } else { break; } } if (!modelCode) { logger->info("sessionId not found after 5 times"); db.close(); return -2005; } if (featureValue.empty()) { return -2005; }; // 首先查询商品模型表是否有该数据 string productCodes[10]; char* cIds = const_cast<char*>(productIds.c_str()); splitString(cIds, productCodes); int topNo = getTopNo(productCodes, code); string realProductCodes[10]; char* realIds = const_cast<char*>(realCodes.c_str()); splitString(realIds, realProductCodes); int realTopNo = getTopNo(realProductCodes, code); logger->info("sessionId is {},hit top {},real hit top is {}", sessionId, topNo, realTopNo); // 打标 markDown(code, db, modelCode, score); //} if (!hit|| !realProductCodes[1].empty()) { saveDbIndex(db, code, featureValue); sendClientFeatureMessage(code, featureValue); } db.close(); if (connectNet) { Document d; string response; char uploadUrl[200]; sprintf(uploadUrl, upload_file_url, dev.c_str(), tenantStr.c_str()); logger->info("upload url is {},imagePath is {}", uploadUrl, imagePath.c_str()); int curlCode = CommonTools::upload_file(uploadUrl, imagePath.c_str(), response); logger->info("response is {},curl code is {}", UTF_82ASCII(response), curlCode); if (curlCode != 0) { connectNet = false; logger->info("设备未联网不再上传"); return 0; } d.Parse(response.c_str()); int resultCode = d["code"].GetInt(); if (resultCode == 0) { Value& s1 = d["data"]["url"]; if (s1.IsNull()) { logger->info("上传失败"); return 0; } string imageUrl = s1.GetString(); d.Clear(); Pointer("/recommendTime").Set(d, time); Pointer("/productCode").Set(d, code); Pointer("/productName").Set(d, productName); Pointer("/weightingStartTime").Set(d, getNowDate()); Pointer("/sessionId").Set(d, sessionId); Pointer("/weighImageUrl").Set(d, imageUrl); Pointer("/aiType").Set(d, "WINMORE"); Pointer("/topNo").Set(d, realTopNo); Pointer("/identifyCode/code").Set(d, to_string(modelCode)); Pointer("/identifyCode/accuracy").Set(d, score); StringBuffer buffer; Writer<StringBuffer> writer(buffer); d.Accept(writer); char url[100]; sprintf(url, save_record_url, dev.c_str(), tenantStr.c_str()); logger->info("url2:{}", url); string response2; CommonTools::HttpPost(url, buffer.GetString(), response2, 3); cout << response2 << endl; } else { logger->info("upload error url is {}, error code is {}", uploadUrl, resultCode); connectNet = false; } } return 0; } void markDown(const char* code, CppSQLite3DB& db, int modelCode, float score) { // 1.查商品code product_model_counting 是否有记录 int id; string countProductCode; int countModelCode = 0; int num; // 3.根据商品Id查询计数器 CppSQLite3Buffer selectProductModelCountByProductCode; selectProductModelCountByProductCode.format("select id,product_code,model_code,num from product_model_counting where product_code = %Q;", code); CppSQLite3Query productModelCountByProductCode = db.execQuery(selectProductModelCountByProductCode); while (!productModelCountByProductCode.eof()) { id = productModelCountByProductCode.getIntField(0); countProductCode = productModelCountByProductCode.getStringField(1); countModelCode = productModelCountByProductCode.getIntField(2); num = productModelCountByProductCode.getIntField(3); productModelCountByProductCode.nextRow(); } // 2.如果没有记录 判断 top1置信度 >= 0.9 计数器 = 1 置信度< 0.9 计数器 = 0 记录 code modelCode 如果 记录到product_model_counting if (!countModelCode) { CppSQLite3Buffer insertProductModelCount; insertProductModelCount.format("insert into product_model_counting(product_code, model_code, num) values (%Q,%d,%d);", code, modelCode, getNumByScore(score)); db.execDML(insertProductModelCount); } else { // 3.如果有记录 并且modelCode = top1code 置信度>=0.9 计数器+1 更新 if (countModelCode == modelCode && score >= markDownScoreLimit) { ++num; CppSQLite3Buffer updateProductModelCountNum; updateProductModelCountNum.format("update product_model_counting set num = %d where id = %d", num, id); db.execDML(updateProductModelCountNum); } else if (countModelCode != modelCode && num <= 3) { CppSQLite3Buffer updateProductModelCountNum; updateProductModelCountNum.format("update product_model_counting set num = %d,model_code = %d where id = %d", getNumByScore(score), modelCode, id); db.execDML(updateProductModelCountNum); } else if (countModelCode != modelCode && num > 3) { num = num - 3; CppSQLite3Buffer updateProductModelCountNum; updateProductModelCountNum.format("update product_model_counting set num = %d,model_code = %d where id = %d", num, modelCode, id); db.execDML(updateProductModelCountNum); } else { logger->info("do nothing countModelCode is {} modelCode is {} score is {}", countModelCode, modelCode, score); } } } // 零食回传 int doSnacksSetFeedBack(const char* code, char* sessionId, bool hit, char* productName) { CppSQLite3DB db; db.open(gszFile); // 回传记录保存 CppSQLite3Buffer insertFeedBackRecord; insertFeedBackRecord.format("insert into feed_back_record(code, session_id,hit) values (%Q,%Q,%d);", code, sessionId, hit); db.execDML(insertFeedBackRecord); // 根据sessionId查询对应的打称记录 如果置信度>0.85 那么将商品代码 模型代码的计数器+1 如果计数器>=2 将商品模型的关系记录 // 首先查询根据sessionId查询product_record 得到模型代码 和 置信度 if (!db.tableExists("product_record")) { logger->info("product_record not found , please check AutoDetect success"); return -2004; } int modelCode = 0; float score; string featureValue; string imagePath; string productIds; string time; string realCodes; int realTopNo; if (!hit|| !realProductCodes[1].empty()) { CppSQLite3Buffer selectProductRecord; selectProductRecord.format("select model_code,score,feature_value,image_path,product_ids,time,real_codes from product_record where session_id = %Q;", sessionId); CppSQLite3Query q = db.execQuery(selectProductRecord); while (!q.eof()) { modelCode = q.getIntField(0); score = q.getFloatField(1); featureValue = q.getStringField(2); imagePath = q.getStringField(3); productIds = q.getStringField(4); time = q.getStringField(5); realCodes = q.getStringField(6); q.nextRow(); } q.finalize(); if (featureValue.empty()) { return -2005; }; // 获得topNo string productCodes[10]; char* cIds = const_cast<char*>(productIds.c_str()); splitString(cIds, productCodes); int topNo = getTopNo(productCodes, code); string realProductCodes[10]; char* realIds = const_cast<char*>(realCodes.c_str()); splitString(realIds, realProductCodes); realTopNo = getTopNo(realProductCodes, code); logger->info("sessionId is {},hit top {},real hit top is {}", sessionId, topNo, realTopNo); saveDbIndex(db, code, featureValue); sendClientFeatureMessage(code, featureValue); db.close(); } if (connectNet) { Document d; string response; char uploadUrl[200]; sprintf(uploadUrl, upload_file_url, dev.c_str(), tenantStr.c_str()); logger->info("upload url is {},imagePath is {}", uploadUrl, (tool_get_dll_path()+imagePath).c_str()); int resultCode = CommonTools::upload_file(uploadUrl, imagePath.c_str(), response); logger->info("code:{},response:{}", resultCode, UTF_82ASCII(response)); if (resultCode != 0) { connectNet = false; logger->info("设备未联网不再上传"); return 0; } d.Parse(response.c_str()); if (d["code"].GetInt() == 0) { Value& s1 = d["data"]["url"]; if (s1.IsNull()) { logger->info("上传失败"); return 0; } string imageUrl = s1.GetString(); d.Clear(); Pointer("/recommendTime").Set(d, time); Pointer("/productCode").Set(d, code); Pointer("/productName").Set(d, productName); Pointer("/weightingStartTime").Set(d, getNowDate()); Pointer("/sessionId").Set(d, sessionId); Pointer("/weighImageUrl").Set(d, imageUrl); Pointer("/aiType").Set(d, "WINMORE"); Pointer("/topNo").Set(d, realTopNo); Pointer("/identifyCode/code").Set(d, to_string(modelCode)); Pointer("/identifyCode/accuracy").Set(d, score); StringBuffer buffer; Writer<StringBuffer> writer(buffer); d.Accept(writer); char url[100] = {}; sprintf(url, save_record_url, dev.c_str(), tenantStr.c_str()); string response2; CommonTools::HttpPost(url, buffer.GetString(), response2, 3); } } return 0; } // 保存未识别商品 int WMAI_API SetFeedBack(const char* code, char* sessionId, bool hit, char* productName) { string name(productName); logger->info("code is {} sessionId is {} hit is {} productName is {}", code, sessionId,hit, UTF_82ASCII(name)); logger->info("start feed back"); int result = doSnacksSetFeedBack(code, sessionId, hit, productName); logger->info("end feed back"); return result; } int checkTenant(char* tenant) { Document d2; StringBuffer buffer2; Writer<StringBuffer> writer2(buffer2); d2.Accept(writer2); string response2; char tenantUrl[100]; sprintf(tenantUrl, query_tenant_url, dev.c_str(), tenant); logger->info("tenantUrl is {}", tenantUrl); CommonTools::HttpGet(tenantUrl, response2, 3); logger->info("reponse is {}", UTF_82ASCII(response2)); d2.Parse(response2.c_str()); Value& s2 = d2["code"]; if (s2.GetInt() != 0) { logger->info("tenantCode:{} 没有找到", tenant); return -4004; } else { bool tenantTrue = d2["data"].GetBool(); if (!tenantTrue) { logger->info("tenantCode:{} 没有找到", tenant); return -4004; } } return 0; } // 注册pos机 int WMAI_API InitPos(char* tenant, char* posCode, char* snNo) { logger->info("{},{},{}", tenant, posCode, snNo); posId = posCode; int checkTenantCode = checkTenant(tenant); if (checkTenantCode != 0) { return checkTenantCode; } //tenantStr = tenant; Document d; Pointer("/code").Set(d, posCode); string mac = ""; GetMacByGetAdaptersAddresses(mac); Pointer("/macAddress").Set(d, mac); Pointer("/snNo").Set(d, snNo); StringBuffer buffer; Writer<StringBuffer> writer(buffer); d.Accept(writer); char url[100]; sprintf(url, wmpos_bind_url, dev.c_str(), tenant); logger->info("url is {}", url); string response; CommonTools::HttpPut(url, buffer.GetString(), response, 3); logger->info("reponse is {}", UTF_82ASCII(response)); d.Parse(response.c_str()); Value& s = d["code"]; if (s.GetInt() == 0) { string wmKeyUrl = d["data"]["wmKeyUrl"].GetString(); string privateKeyUrl = d["data"]["privateKeyUrl"].GetString(); posId = d["data"]["id"].GetString(); #if APPOINT_LIBRARY string new_dir = string(drive) + dir; char wmkey_path[MAX_PATH]; strcpy(wmkey_path, (new_dir + "wmkey.wm").c_str()); const char* wmkey = wmkey_path; char prikey_path[MAX_PATH]; strcpy(prikey_path, (new_dir + "prikey.pem").c_str()); const char* prikey = prikey_path; #else const char* wmkey = "wmkey.wm"; const char* prikey = "prikey.pem"; #endif // 0 CommonTools::download_file(wmKeyUrl.c_str(), wmkey); CommonTools::download_file(privateKeyUrl.c_str(), prikey); tenantStr = tenant; if (!tenantStr.empty()) { Document d2; Pointer("/demo").Set(d2, tenant); FILE* fp = fopen(json_tenant_path, "wb");// 非 Windows 平台使用 "w" char writeBuffer[65536]; FileWriteStream os(fp, writeBuffer, sizeof(writeBuffer)); Writer<FileWriteStream> writer(os); d2.Accept(writer); fclose(fp); } Document d3; Pointer("/posId").Set(d3, posId); FILE* fp2 = fopen(posId_json_path, "wb"); // 非 Windows 平台使用 "w" char writeBuffer2[65536]; FileWriteStream os2(fp2, writeBuffer2, sizeof(writeBuffer2)); Writer<FileWriteStream> writer2(os2); d3.Accept(writer2); fclose(fp2); return 0; } else if (s.GetInt() == 65014) { logger->info("snCode没有找到{}", snNo); return -4001; } else if (s.GetInt() == 65017) { logger->info("该posCode:{},已经绑定过,并且绑定的mac地址和传入的mac地址不一致", posCode); return -4002; } else if (s.GetInt() == 65006) { logger->info("此POS的MAC地址:{} 绑定过其它POS机,请联系管理员确认POS机编号!", mac.c_str()); return -4003; } else { logger->info("initPos failed errorCode: {}", s.GetInt()); return -2006; } } // 解绑pos机 int WMAI_API UnbindPos(char* tenant, char* snNo) { int checkTenantCode = checkTenant(tenant); if (checkTenantCode != 0) { return checkTenantCode; } const char* pwmkey = "pwmkey.wm"; const char* pprikey = "pprikey.pem"; remove(pwmkey); remove(pprikey); string mac; GetMacByGetAdaptersAddresses(mac); Document d; StringBuffer buffer; Writer<StringBuffer> writer(buffer); d.Accept(writer); char url[200]; sprintf(url, wmpos_unbind_url, dev.c_str(), tenant, mac.c_str() ,snNo); logger->info("url is {}", url); string response; CommonTools::HttpGet(url, response, 3); logger->info("reponse is {}", UTF_82ASCII(response)); d.Parse(response.c_str()); Value& s = d["code"]; if (s.GetInt() == 0) { #if APPOINT_LIBRARY string new_dir = string(drive) + dir; char wmkey_path[MAX_PATH]; strcpy(wmkey_path, (new_dir + "wmkey.wm").c_str()); const char* wmkey = wmkey_path; char prikey_path[MAX_PATH]; strcpy(prikey_path, (new_dir + "prikey.pem").c_str()); const char* prikey = prikey_path; #else const char* wmkey = "wmkey.wm"; const char* prikey = "prikey.pem"; #endif // 0 remove(wmkey); remove(prikey); authed = false; return 0; }else if (s.GetInt() == 65014) { logger->info("snCode没有找到{}", snNo); return -4001; } else if (s.GetInt() == 65019) { logger->info("snCode:{}并未绑定无需解绑", snNo); return -4005; } else if (s.GetInt() == 65017) { logger->info("该pos现在的mac地址和服务器记录的mac地址不一致 无法解绑"); return -4006; } else { logger->info("initPos failed errorCode: {}", s.GetInt()); return -2006; } } void getNowMat() { int i = 1; while (cap.isOpened()) { cap >> frame_pipe; if (frame_pipe.empty()) { logger->info("frame_pipe empty"); continue; } WaitForSingleObject(PhotoMutex, INFINITE); if (i == 1) { frame_one = frame_pipe.clone(); //读取当前帧 ++i; } else if (i == 2) { frame_two = frame_pipe.clone(); //读取当前帧 ++i; } else if (i == 3) { frame_thr = frame_pipe.clone(); //读取当前帧 i = 1; } ReleaseMutex(PhotoMutex); if (cv::waitKey(30)) { //延时30ms continue; } } return; } // 设置摄像头序号 int WMAI_API SetCameraId(int num) { static int i=0; logger->info("开始打开摄像头:{}",i); cameraNum = num; Document d; logger->info("x:{},y:{},width:{},height:{}", x, y, width, height); if (width && height) { Pointer("/x").Set(d, x); Pointer("/y").Set(d, y); Pointer("/width").Set(d, width); Pointer("/height").Set(d, height); Pointer("/ai_x").Set(d, ai_x); Pointer("/ai_y").Set(d, ai_y); Pointer("/ai_width").Set(d, ai_width); Pointer("/ai_height").Set(d, ai_height); } Pointer("/cameraNum").Set(d, cameraNum); FILE* fp = fopen(json_path, "wb"); // 非 Windows 平台使用 "w" char writeBuffer[65536]; FileWriteStream os(fp, writeBuffer, sizeof(writeBuffer)); Writer<FileWriteStream> writer(os); d.Accept(writer); fclose(fp); PhotoMutex =CreateMutex(NULL, FALSE, (LPCWSTR)"PhotoMutex"); if (!cap.isOpened()) { cap.set(cv::CAP_PROP_FRAME_WIDTH, 640);//宽度 cap.set(cv::CAP_PROP_FRAME_HEIGHT, 480);//高度 cap.set(cv::CAP_PROP_FPS, 30); logger->info("准备打开摄像头序号{}", cameraNum); cap.open(cameraNum, CAP_DSHOW); std::thread t(getNowMat); t.detach(); } Sleep(3000); logger->info("结束打开摄像头"); return 0; } int WMAI_API GetScaleSetting(int &x1, int &y1, int &width1, int &height1) { x1 = x; y1 = y; width1 = width; height1 = height; return 0; } int WMAI_API SaveScaleSetting(int x1, int y1, int width1, int height1) { if (!(width1 && height1)) { logger->info("coordinate error"); return -2008; } if (x1 + width1 > 640 || y1 + height1 > 480) { logger->info("Scale not match 640*480 x={},y={},w={},h={}", x1, y1, width1, height1); return -2008; } x = x1; y = y1; width = width1; height = height1; Document d; Pointer("/x").Set(d, x); Pointer("/y").Set(d, y); Pointer("/width").Set(d, width); Pointer("/height").Set(d, height); Pointer("/ai_x").Set(d, ai_x); Pointer("/ai_y").Set(d, ai_y); Pointer("/ai_width").Set(d, ai_width); Pointer("/ai_height").Set(d, ai_height); Pointer("/cameraNum").Set(d, cameraNum); FILE* fp = fopen(json_path, "wb"); // 非 Windows 平台使用 "w" char writeBuffer[65536]; FileWriteStream os(fp, writeBuffer, sizeof(writeBuffer)); Writer<FileWriteStream> writer(os); d.Accept(writer); fclose(fp); return 0; } int WMAI_API GetScaleBitmap(char* rawPath, char* cropPath) { getScaleBitmap(rawPath, cropPath, true); return 0; } int WMAI_API SetNoRecommend(const char* code) { logger->info("开始清除商品:{}的学习记录", code); //计时开始 double start_time = clock(); CppSQLite3DB db; db.open(gszFile); //记录需要删除的id int id = 0; CppSQLite3Buffer selectFeatureCode; selectFeatureCode.format("select id from feature_code where code = %Q;", code); CppSQLite3Query q = db.execQuery(selectFeatureCode); while (!q.eof()) { id = q.getIntField(0); CppSQLite3Buffer insert; insert.format("insert into record_count(count) values (%d)", id); db.execDML(insert); q.nextRow(); } q.finalize(); // 清除数据库 if (db.tableExists("feature_code")) { CppSQLite3Buffer deleteSql; deleteSql.format("update feature_code set deleted = 1 where code = %Q;", code); db.execDML(deleteSql); } if (db.tableExists("product_model")) { CppSQLite3Buffer deleteSql; deleteSql.format("delete from product_model where product_code = %Q", code); db.execDML(deleteSql); } // 清除map // productModelMap.erase(code); // 重置索引 delete idx; idx = new libhnsw::Index(FEATURE_COUNT, DATABASE_SIZE, libhnsw::BRUTE_FORCE_KNN_CF); if (db.tableExists("feature_code")) { CppSQLite3Query q = db.execQuery("select id,feature from feature_code where deleted = 0"); while (!q.eof()) { float features[FEATURE_COUNT]; int id = q.getIntField(0); const char* sql_feature = q.getStringField(1); char* c = const_cast<char*>(sql_feature); split(c, features); idx->Addsample(features, id - 1); q.nextRow(); } q.finalize(); } db.close(); double end_time = clock(); logger->info("all elapsed {}ms\n", end_time - start_time); return 0; } int WMAI_API ExportData(char* path) { #if APPOINT_LIBRARY string new_dir = string(drive) + dir; char data_path[128] = {}; std::strcpy(data_path, (new_dir+"data-copy").c_str()); ifstream in(gszFile, ios::binary); ofstream out(data_path, ios::binary); if (!in) { printf("open file error"); return -2007; } if (!out) { printf("open file error"); return -2007; } char flush[8]; while (!in.eof()) { in.read(flush, 8); out.write(flush, in.gcount()); } in.close(); strcpy(path, data_path); #else ifstream in(gszFile, ios::binary); ofstream out("data-copy", ios::binary); if (!in) { printf("open file error"); return -2007; } if (!out) { printf("open file error"); return -2007; } char flush[8]; while (!in.eof()) { in.read(flush, 8); out.write(flush, in.gcount()); } in.close(); std::strcpy(path, "data-copy"); #endif // APPOINT_LIBRARY return 0; } int WMAI_API ImportData(char* path) { // 首先删除文件 remove("featurexYz.db"); ifstream in(path, ios::binary); ofstream out("featurexYz.db", ios::binary); if (!in) { printf("open file error"); return -2007; } if (!out) { printf("open file error"); return -2007; } char flush[8]; while (!in.eof()) { in.read(flush, 8); out.write(flush, in.gcount()); } in.close(); out.close(); // 删除索引文件 return 0; } // 1 代表索引添加 2 代表商品模型关系添加 //{\"type\":1,\"feature\":\"\",\"productCode\":\"\",\"modelCode\": 1} void saveOtherMachineIndex(const BYTE* pData, int length) { string a = (char*)pData; string data = a.substr(0, length); logger->info("data is {}", data.c_str()); CppSQLite3DB db; db.open(gszFile); StringStream s(data.c_str()); Document d; d.ParseStream(s); // 1 代表索引添加 2 代表商品模型关系添加 int type = d["type"].GetInt(); if (type == 1) { string productCode = d["productCode"].GetString(); string featureValue = d["feature"].GetString(); if (!productCode.empty() && !featureValue.empty()) { saveDbIndex2(db, productCode.c_str(), featureValue); } else { logger->info("productCode or else null"); } } else if (type == 2) { Value& items = d["modelCodes"]; assert(a.IsArray()); for (SizeType i = 0; i < items.Size(); i++) { string productCode = items[i]["productCode"].GetString(); int modelCode = items[i]["modelCode"].GetInt(); if (!productCode.empty() && modelCode != 0) { CppSQLite3Buffer selectProductModel; selectProductModel.format("select count(1) from product_model where product_code = %Q or model_code = %d;", productCode.c_str(), modelCode); int productModelCount = db.execScalar(selectProductModel); if (productModelCount < 1) { // 记录商品模型关系 CppSQLite3Buffer insertProductModel; insertProductModel.format("insert into product_model(product_code, model_code) values (%Q,%d);", productCode.c_str(), modelCode); db.execDML(insertProductModel); } } else { logger->info("productCode or modelCode null"); } } } db.close(); } EnHandleResult ServerListenerImpl::OnHandShake(ITcpServer* pSender, CONNID dwConnID) { logger->info("接收到客户端{}的握手请求,建立连接", dwConnID); connIds.push_back(dwConnID); return EnHandleResult(); } EnHandleResult ServerListenerImpl::OnClose(ITcpServer* pSender, CONNID dwConnID, EnSocketOperation enOperation, int iErrorCode) { logger->info("接收到客户端:{}的关闭请求", dwConnID); vector<CONNID>::iterator iter = connIds.begin(); while (iter != connIds.end()) { if (*iter == dwConnID) { iter = connIds.erase(iter); } else { iter++; } } return EnHandleResult(); } EnHandleResult ServerListenerImpl::OnReceive(ITcpServer* pSender, CONNID dwConnID, const BYTE* pData, int iLength) { logger->info("服务端Ip:{},接收到客户端: {}的回复", realIp, dwConnID); saveOtherMachineIndex(pData, iLength); //DWORD count; //CONNID connIdAll[maxConnectionCount]; //bool success = pSender->GetAllConnectionIDs(connIdAll, count); //if (!success) { //} for (long i = 0; i < connIds.size(); i++) { if (connIds[i] == dwConnID) { // 忽略传递过来的Id continue; } pSender->Send(connIds[i], pData, iLength); } /*else { logger->info("获取客户端Id失败"); }*/ return EnHandleResult(); } EnHandleResult ClientListenerImpl::OnReceive(ITcpClient* pSender, CONNID dwConnID, const BYTE* pData, int iLength) { logger->info("客户端ip:{},接收到服务端: {}的消息", realIp, dwConnID); saveOtherMachineIndex(pData, iLength); return EnHandleResult(); } /***********************************************************UDP****************************************************************************/ EnHandleResult UdpNodeListenerImpl::OnReceive(IUdpNode* pSender, LPCTSTR lpszRemoteAddress, USHORT usRemotePort, const BYTE* pData, int iLength) { char* ip = TCHAR2char(lpszRemoteAddress); if (strncmp(ip, realIp, 16) == 0) { // 忽略本身传递的广播 return EnHandleResult(); } // 如果接到新机器的创建消息 // 创建客户端连接新机器的服务 logger->info("接收到地址{}的 UDP NODE 的消息:{},开始注册TCP客户端", ip, pData); // 创建新的客户端 连接新的tcp服务端 createClient(lpszRemoteAddress); // 关闭之前的tcp服务端 if (s_pserver->HasStarted()) { logger->info("关闭ip:{}的tcp服务", realIp); s_pserver->Stop(); } return EnHandleResult(); } EnHandleResult UdpNodeListenerImpl::OnError(IUdpNode* pSender, EnSocketOperation enOperation, int iErrorCode, LPCTSTR lpszRemoteAddress, USHORT usRemotePort, const BYTE* pData, int iLength) { return EnHandleResult(); } int WMAI_API ClearTrainedData() { if (exists_file(gszFile)) { int res = remove(gszFile); if (res != 0) { logger->info("hnswIndex dose not exist\n"); } else { logger->info("remove gszfile successed\n"); } } delete idx; idx = nullptr; return 0; } int WMAI_API QuickLearn(char* code, char* path) { cv::Mat m = cv::imread(path, 1); if (m.empty()) { logger->info("cv::imread failed\n"); return -2002; } string productcode[10]; std::vector<float> cls_scores; float rhs[FEATURE_COUNT]; double start_time = ncnn::get_current_time(); int ret = detect_squeezenet(m, cls_scores, rhs); // 将图片向量进行逗号组装 char featureValue[FEATURE_COUNT * 10] = { }; for (int i = 0; i < FEATURE_COUNT; ++i) { sprintf(featureValue + strlen(featureValue), "%f,", rhs[i]); } string tmp2 = featureValue; CppSQLite3DB db; db.open(gszFile); saveDbIndex(db, code, tmp2); db.close(); std::vector<std::pair<float, int>>res = idx->Search(rhs, 1); for (int j = 0; j < res.size(); j++) { std::pair<float, int> r = res[j]; int number = r.second; logger->info("index label is {}",number); } return 0; } int WMAI_API WMrelease() { if (cap.isOpened()) { cap.release(); } if (udp_node->HasStarted()) { udp_node->Stop(); } if (s_pclient->HasStarted()) { s_pclient->Stop(); } if (s_pserver->HasStarted()) { s_pserver->Stop(); } delete idx; //delete hnswExecutor; param_in.end_thread = true; RETRI_Release(&handle); init_finish = false; return 0; } int WMAI_API Close() { logger->info("开始释放资源"); if (rest_in>0) { CppSQLite3DB db; db.open(gszFile); //检测表单,此表单为计数 db.execDML("CREATE TABLE IF NOT EXISTS video_count (id integer PRIMARY KEY AUTOINCREMENT, count_in integer NOT NULL)"); int pre; CppSQLite3Buffer selectvideocount; selectvideocount.format("select count(*) from video_count"); CppSQLite3Query q = db.execQuery(selectvideocount); while (!q.eof()) { pre = q.getIntField(0); break; } q.finalize(); if (pre == 0) { CppSQLite3Buffer insertvideocount; insertvideocount.format("insert into video_count(count_in) values (%d);", rest_in); db.execDML(insertvideocount); } else { CppSQLite3Buffer updatevideocount; updatevideocount.format("update video_count set count_in=%d where id = 1", rest_in); db.execDML(updatevideocount); } db.close(); } DeleteDirectory(dir_in.c_str()); DeleteDirectory(dir_out.c_str()); if (cap.isOpened()) { cap.release(); } if (udp_node->HasStarted()) { udp_node->Stop(); } if (s_pclient->HasStarted()) { s_pclient->Stop(); } if (s_pserver->HasStarted()) { s_pserver->Stop(); } if (idx != nullptr) { delete idx; idx = nullptr; } param_in.end_thread = true; RETRI_Release(&handle); init_finish = false; logger->info("释放资源结束"); return 0; } int FoodInitParam(FOOD_PARAM_DATA* param_in) { _mkdir("data"); // step1:先配置下数据源 param_in->back_mat_path = "data/back.jpg"; param_in->debug_mode = false; // step2:配置roi param_in->has_roi = true; cv::Rect roi; roi.x = ai_x; roi.y = ai_y; roi.width = ai_width; roi.height = ai_height; param_in->roi = roi; //step4.裁剪下当前帧照片,保存当前图片 param_in->back =cv::imread(param_in->back_mat_path); if (param_in->back.empty()) { param_in->back = frame_pipe.clone(); if (param_in->back.empty()) { logger->info("图片是空的,\n"); return -2002; } if (roi.area() != 0) { param_in->back = param_in->back(roi); } //获取空盘图向量 RETRI_INPUT empty_img; empty_img.img = param_in->back.clone(); RETRI_OUTPUT clsretri_output; int hr = RETRI_Process(empty_img, &clsretri_output, handle); if (hr != 0) { logger->info("元芒图形加速库推理失败!error code:{0:x}\n", hr); return -2008; } for (int i = 0; i < FEATURE_COUNT; i++) { feature_empty[i] = clsretri_output.feat[i]; } char pathName[128] = {}; sprintf(pathName, "%s", param_in->back_mat_path.c_str()); logger->info("要保存的文件路径[{}]\n", pathName); cv::imwrite(pathName, param_in->back); } else { //获取空盘图向量 RETRI_INPUT empty_img; empty_img.img = param_in->back.clone(); RETRI_OUTPUT clsretri_output; int hr = RETRI_Process(empty_img, &clsretri_output, handle); if (hr != 0) { logger->info("元芒图形加速库推理失败!error code:{o:x}\n", hr); return -2008; } for (int i = 0; i < FEATURE_COUNT; i++) { feature_empty[i] = clsretri_output.feat[i]; } } // step3: param_in->end_thread = false; param_in->max_in_frame_queue = 6; param_in->queue_max = 5; //step(-1):是否启用调试 param_in->debug_mode = debug; libvideopipe::INIT_INFO video_pipe; //video_pipe.gpu_enable = drive_ai; video_pipe.gpu_enable =true; video_pipe.lat3d_enable = true; param_in->mvp = new libvideopipe::MotionVideoPipe; param_in->mvp->Init(video_pipe); solve_cost.push_back(67); return 0; } UINT64 food_get_current_time_millis() { using namespace std; timeb now; ftime(&now); std::stringstream milliStream; // 由于毫秒数不一定是三位数,故设置宽度为3,前面补0 milliStream << setw(3) << setfill('0') << right << now.millitm; stringstream secStream; secStream << now.time; string timeStr(secStream.str()); timeStr.append(milliStream.str()); UINT64 timeLong; stringstream transStream(timeStr); transStream >> timeLong; return timeLong; } DWORD WINAPI FoodRealtimeCaptureImage(LPVOID params) { FOOD_PARAM_DATA* param_in = (FOOD_PARAM_DATA*)params; if (!param_in) { logger->info("FoodRealtimeCaptureImage:param_in NULL!\n", GetCurrentThreadId()); return 0; } while (!(param_in->end_thread)) { //float start = clock(); Sleep(average_cost()); // step1:获取当前帧 Mat img = frame_pipe.clone(); // step2:判断当前帧是否为空 if (img.empty()) { logger->info("PID[{}]ERROR: get img error!\n", GetCurrentThreadId()); param_in->end_thread = true; continue; } // step3:配置FRAME_INFO VIDEO_FRAME_INFO frame; frame.timestamp = food_get_current_time_millis(); if (param_in->roi.area() == 0) param_in->has_roi = false; if (param_in->has_roi) { frame.img = img(param_in->roi); } else { frame.img = img; } // step4:压入一个frame param_in->frame_in.push(frame); //step5:如果上一帧未处理,则丢帧 if (param_in->frame_in.size() > param_in->max_in_frame_queue) { logger->info("图片堆积"); WaitForSingleObject(param_in->hMutex, INFINITE); param_in->frame_in.pop(); // 删除一个原图 ReleaseMutex(param_in->hMutex); } //float end = clock(); //logger->info("get image cost:{}", end - start); } return 1; } void trace_detect_process() { result.state =1; logger->info("result.state is {}", result.state); if (video_detect) { char rawPath[128]; char cropPath[128]; logger->info("video_time is {}",video_time); Sleep(video_time); //cv::Mat m = getScaleBitmap(rawPath, cropPath, false); //if (m.empty())//获取图片失败编写日志 //{ // logger->info("cv::imread failed\n"); // return; //} int ret = MatDetect(result.productCodes, result.sessionId); //int ret = AutoDetect(result.productCodes, result.sessionId); if (ret != 0) { logger->info("Detect error:{}", ret); return; } } else { std::strcpy(result.productCodes, ""); std::strcpy(result.sessionId, ""); } if (param_in.result_queue.size()< param_in.queue_max) { DETECT_RESULT tem = result; param_in.result_queue.push(tem); } } void trace_judge_process() { Sleep(100); char path[128] = {}; char row_path[128] = {}; GetScaleBitmap(row_path, path); param_in.detect_image_path = string(path); } void save_in_image() { if (rest_in > VIDEOCOINTIN) { return; } logger->info("rest_in is{}",rest_in); std::string dir = "video_image_in"; std::string time = std::to_string(food_get_current_time_millis()); dir_in = dir; _mkdir(dir.c_str()); _mkdir((dir + "/" + time).c_str()); int i = 1; const char* path = "%s/%s/%s-%d.jpg"; char name2[128] = {}; char name3[128] = {}; char name4[128] = {}; vector<string>res; string pre1; string pre2; string pre3; sprintf(name2, path, dir.c_str(), time.c_str(), time.c_str(), i++); //图片命名 pre1 = pre1 + time.c_str() + "wmAce"+"-" + "1" + ".jpg"; res.push_back(pre1); //储存图片 cv::imwrite(name2, param_in.back); sprintf(name3, path, dir.c_str(), time.c_str(), time.c_str(), i++); pre2 = pre2 + time.c_str() +"wmAce"+ "-" + "2" + ".jpg"; res.push_back(pre2); cv::imwrite(name3, param_in.frame_out[3].img); sprintf(name4, path, dir.c_str(), time.c_str(), time.c_str(), i++); pre3 = pre3 + time.c_str() + "wmAce" + "-" + "3" + ".jpg"; res.push_back(pre3); cv::imwrite(name4, param_in.frame_out[4].img); char in[10] = "IN"; res.push_back(in); //上传照片 Document d; string response; char uploadUrl[200]; string tenantStrs; string posId_in; //获取租户信息 if (tenantStr.size() != 0&& json_tenant_path) { tenantStrs = tenantStrs + tenantStr; posId_in = posId_in + posId; } else { tenantStrs = tenantStrs + '0'; posId_in = '0'; } sprintf(uploadUrl, upload_file1_url, dev.c_str(), tenantStrs.c_str(), posId_in.c_str()); logger->info("upload url is {}", uploadUrl); res.push_back(tenantStrs); res.push_back(posId_in); int curlCode = CommonTools::upload_file1(uploadUrl,name2,name3,name4,res,response); string rrr= UTF_82ASCII(response); logger->info("response is {}",rrr); if (curlCode != 0) { logger->info("上传图片失败,退出"); return; } rest_in++; } void save_out_image() { if (rest_out > VIDEOCOINTIN) { return; } std::string dir = "video_image_out"; std::string time = std::to_string(food_get_current_time_millis()); dir_out = dir; _mkdir(dir.c_str()); _mkdir((dir + "/" + time).c_str()); int i = 1; const char* path = "%s/%s/%s-%d.jpg"; char name5[128] = {}; char name6[128] = {}; char name7[128] = {}; vector<string>res_out; string buf1, buf2, buf3; sprintf(name5, path, dir.c_str(), time.c_str(), time.c_str(), i++); buf1 = buf1 + time.c_str() + "wmAce" + "-" + "1" + ".jpg"; res_out.push_back(buf1); cv::imwrite(name5, param_in.back); sprintf(name6, path, dir.c_str(), time.c_str(), time.c_str(), i++); buf2 = buf2 + time.c_str() + "wmAce" + "-" + "2"+".jpg"; res_out.push_back(buf2); cv::imwrite(name6, param_in.frame_out[3].img); sprintf(name7, path, dir.c_str(), time.c_str(), time.c_str(), i++); buf3 = buf3 + time.c_str() + "wmAce" + "-" + "3" + ".jpg"; res_out.push_back(buf3); cv::imwrite(name7, param_in.frame_out[4].img); string out = "OUT"; res_out.push_back(out); Document d; string response; char uploadUrl[200]; string tenantStrs; string posId_out; if (tenantStr.size() != 0 && json_tenant_path) { tenantStrs = tenantStrs + tenantStr; posId_out = posId_out + posId; } else { tenantStrs = tenantStrs + '0'; posId_out = '0'; } sprintf(uploadUrl, upload_file1_url, dev.c_str(), tenantStrs.c_str(), posId_out.c_str()); logger->info("upload url is {}", uploadUrl); res_out.push_back(tenantStrs); res_out.push_back(posId_out); int curlCode = CommonTools::upload_file1(uploadUrl, name5, name6, name7,res_out, response); string rrr = UTF_82ASCII(response); logger->info("response is {}", rrr); if (curlCode != 0) { logger->info("上传图片失败,退出"); return; } rest_out++; } void video_trace_result_callback(const char* data, int len, void* user) { // AI识别 libvideopipe::MOTION_VIDEOPIPE_OUTPUT* output = (libvideopipe::MOTION_VIDEOPIPE_OUTPUT*)data; if (output->status == libvideopipe::MOTION_STATUS_TYPES::MOTION_IN) { logger->info("检测到物品进入"); if (mode == FRESH_DETECT) { thread t(trace_detect_process); t.detach(); if (rest_count < VIDEOCOUNT) { thread t_(save_in_image); t_.detach(); } } else if (mode == PREVENT_LOSS) { thread t(trace_judge_process); t.detach(); /*thread t_(save_in_image); t_.detach(); logger->info("没有进行存图!");*/ if (param_in.result_queue.size() < param_in.queue_max) { DETECT_RESULT tem = result; tem.state = 1; logger->info("tem.state is {}", tem.state); param_in.result_queue.push(tem); } } } if (output->status == libvideopipe::MOTION_STATUS_TYPES::MOTION_OUT) { logger->info("检测到物品离开"); if (rest_count < VIDEOCOUNT) { thread t_(save_out_image); t_.detach(); } if (param_in.result_queue.size() < param_in.queue_max) { DETECT_RESULT tem = result; tem.state = 0; logger->info("tem.state is {}", tem.state); param_in.result_queue.push(tem); } } } DWORD WINAPI FoodDetectTrace(LPVOID params) { auto start = clock(); FOOD_PARAM_DATA* param_in = (FOOD_PARAM_DATA*)params; if (param_in == NULL) { logger->info("FoodDetectTrace:param_in NULL!\n"); return 0; } // step0:初始化一个跟踪器 param_in->mvp->SetROI(param_in->roi); param_in->mvp->SetMarkMat(param_in->back); param_in->mvp->SetResultCallback(video_trace_result_callback, param_in); g_video_init = true; logger->info("videopipe init end"); while (!param_in->end_thread) { // step1:判断帧数据是否为空 if (param_in->frame_in.empty()) { Sleep(30); in_image = false; continue; } //处理图像开始 in_image = true; float start = clock(); // step2:获取输入数据 WaitForSingleObject(param_in->hMutex, INFINITE); VIDEO_FRAME_INFO frame; frame = param_in->frame_in.front(); param_in->frame_in.pop(); // 删除一个原图 ReleaseMutex(param_in->hMutex); param_in->frame_out.push_back(frame); if (param_in->frame_out.size() > param_in->max_in_frame_queue) { param_in->frame_out.erase(param_in->frame_out.begin()); } // step3:设置video input libvideopipe::MOTION_VIDEOPIPE_INPUT video_input; video_input.img = frame.img.clone(); video_input.pts = frame.timestamp; video_input.debug_mode = false; /*imshow("frame.img", video_input.img); cv::waitKey(1);*/ //step4:是否显示调试的视频 if (param_in->debug_mode == true) { imshow("frame.img", video_input.img); cv::waitKey(1); } // step5:开始Trace; //float _start = clock(); int rt = param_in->mvp->FeedFrame(video_input); //float _end = clock(); //logger->info("FeedFrame costs {} ms \n",_end - _start); if (rt != 0) { logger->info("Trace return error code:{o:x}\n", rt); } cv::waitKey(3); float end = clock(); solve_cost.push_back(end-start); //logger->info("dev solve cost:{}", end - start); } return 0; } void videoPipeDetect() { logger->info("videopipe init start"); FoodInitParam(¶m_in); // step1: 开线程测试 const int MAX_THREADS = 2; HANDLE hThread[MAX_THREADS]; hThread[0] = CreateThread(NULL, 0, FoodRealtimeCaptureImage, ¶m_in, 0, NULL); hThread[1] = CreateThread(NULL, 0, FoodDetectTrace, ¶m_in, 0, NULL); param_in.hMutex = CreateMutex(NULL, FALSE, (LPCWSTR)"screen"); bool getthread = false; // step2: Wait until all threads have terminated. WaitForMultipleObjects(MAX_THREADS, hThread, TRUE, INFINITE); for (int i = 0; i < MAX_THREADS; i++) { CloseHandle(hThread[i]); } ReleaseMutex(param_in.hMutex); delete param_in.mvp; g_video_init = false; //g_video_init = true; logger->info("process end"); } //识别函数主控 int WMAI_API VideopipeDetect() { thread t(videoPipeDetect); t.detach(); return 0; } int WMAI_API GetQueueSize() { if (re_ret) { return 0; } int ret = param_in.result_queue.size(); if (ret > 0) { re_ret = true; } return ret; } int WMAI_API RealTimeDetect(char* code, char* sessionId, int &state) { if (param_in.result_queue.size() <= 0) { logger->info("error get result"); return -5009; } logger->info("productCodes:{},sessionId:{},state:{}", param_in.result_queue.front().productCodes, param_in.result_queue.front().sessionId, param_in.result_queue.front().state); std::strcpy(code, param_in.result_queue.front().productCodes); std::strcpy(sessionId, param_in.result_queue.front().sessionId); state = param_in.result_queue.front().state; param_in.result_queue.pop(); re_ret = false; return 0; } void uploadImage() { Document d; string response; char uploadUrl[200]; sprintf(uploadUrl, upload_file_url, dev.c_str(), tenantStr.c_str()); logger->info("upload url is {},imagePath is {}", uploadUrl, param_in.back_mat_path.c_str()); int curlCode = CommonTools::upload_file(uploadUrl, param_in.back_mat_path.c_str(), response); //logger->info("response is {},curl code is {}", response.c_str(), curlCode); if (curlCode != 0) { logger->info("上传图片失败,退出"); return; } d.Parse(response.c_str()); int resultCode = d["code"].GetInt(); if (resultCode == 0) { Value& s1 = d["data"]["url"]; if (s1.IsNull()) { logger->info("上传失败"); return; } string imageUrl = s1.GetString(); d.Clear(); Pointer("/recommendTime").Set(d, 0); Pointer("/weightingStartTime").Set(d, getNowDate()); Pointer("/weighImageUrl").Set(d, imageUrl); Pointer("/aiType").Set(d, "WINMORE"); Pointer("/identifyCode/code").Set(d, to_string(99999)); Pointer("/identifyCode/accuracy").Set(d, 0.001); StringBuffer buffer; Writer<StringBuffer> writer(buffer); d.Accept(writer); char url[100]; sprintf(url, save_record_url, dev.c_str(), tenantStr.c_str()); logger->info("url:{}",url); string response2; CommonTools::HttpPost(url, buffer.GetString(), response2, 3); //logger->info("response2:{}", response2); } else { logger->info("upload error url is {}, error code is {}", uploadUrl, resultCode); } } void Capture_emp_pic() { double empty_save_beign = clock(); //打开数据库 CppSQLite3DB db; db.open(gszFile); int empty_pre; CppSQLite3Buffer select_emp; select_emp.format("select count(*) from empty_pan_feature"); CppSQLite3Query select_q = db.execQuery(select_emp); while (!select_q.eof()) { empty_pre = select_q.getIntField(0); break; } select_q.finalize(); _mkdir(empty_pic.c_str()); int i = 1; while (i < 31) { float feature_em[128]; //开始获取空盘图 WaitForSingleObject(param_in.hMutex, INFINITE); Sleep(67); Mat img_empty = frame_pipe.clone(); ReleaseMutex(param_in.hMutex); //判断当前帧是否为空 if (img_empty.empty()) { logger->info("图像为空"); continue; } img_empty = img_empty(param_in.roi); //存图 char raw_pic_Name[128] = {}; char photoPath[MAX_PATH]; std::strcpy(photoPath, (empty_pic + "\\%d.jpg").c_str()); sprintf(raw_pic_Name, photoPath, i); cv::imwrite(raw_pic_Name, img_empty); //图片转向量 std::vector<float> cls_scores; float rhs[FEATURE_COUNT]; int ret = detect_squeezenet(img_empty, cls_scores, rhs); char featureValue[FEATURE_COUNT * 10] = { }; for (int i = 0; i < FEATURE_COUNT; ++i) { sprintf(featureValue + strlen(featureValue), "%f,", rhs[i]); } if (empty_pre < 30) { CppSQLite3Buffer insert; insert.format("insert into empty_pan_feature(feature) values (%Q)", featureValue); db.execDML(insert); } else { CppSQLite3Buffer update_emp; update_emp.format("update empty_pan_feature set feature=%Q where id=%d;", featureValue, i); db.execDML(update_emp); } i++; } db.close(); double empty_save_end = clock(); logger->info("储存空盘图的时间为:{}", empty_save_end - empty_save_beign); if (i >= 31) { return; } } int WMAI_API ChangeBackPicture() { //step1.获取图像 logger->info("改变空盘图像开始"); cv::Mat img = frame_pipe.clone(); if (img.empty()) { logger->info("图片是空的,\n"); return -2002; } //step2.裁剪下当前帧照片,保存当前图片 cv::Rect roi; roi.x = ai_x ; roi.y = ai_y ; roi.width = ai_width; roi.height = ai_height; if (roi.area() == 0) { logger->info("裁剪错误"); return -2002; } param_in.roi = roi; param_in.has_roi = true; cv::Mat imgRoi = img(param_in.roi); ////更新空盘图的向量 //RETRI_INPUT empty_img; //empty_img.img = imgRoi.clone(); //RETRI_OUTPUT clsretri_output; //int hr = RETRI_Process(empty_img, &clsretri_output, handle); //if (hr != 0) //{ // logger->info("元芒图形加速库推理失败!error code:{0:x}\n", hr); // return -2008; //} //for (int i = 0; i < FEATURE_COUNT; i++) //{ // feature_empty[i] = clsretri_output.feat[i]; //} char pathName[128] = {}; sprintf(pathName, "%s", param_in.back_mat_path.c_str()); cv::imwrite(pathName, imgRoi); //step3.置换 param_in.back = imgRoi; param_in.mvp->SetMarkMat(imgRoi); logger->info("改变空盘图像结束"); DeleteDirectory(empty_pic.c_str()); //step4.上传图片 thread t(uploadImage); t.detach(); //捕获空盘图 thread t_emp(Capture_emp_pic); t_emp.detach(); //double empty_save_beign = clock(); //int empty_pre=0; // ////打开数据库 //CppSQLite3DB db; //db.open(gszFile); // // //CppSQLite3Buffer select_emp; //select_emp.format("select count(*) from empty_pan_feature"); //CppSQLite3Query select_q = db.execQuery(select_emp); //while (!select_q.eof()) //{ // empty_pre = select_q.getIntField(0); // break; //} //select_q.finalize(); //_mkdir(empty_pic.c_str()); // //int i = 1; //while (i < 31) //{ // float feature_em[128]; // //开始获取空盘图 // WaitForSingleObject(param_in.hMutex, INFINITE); // Sleep(67); // Mat img_empty = frame_pipe.clone(); // ReleaseMutex(param_in.hMutex); // //判断当前帧是否为空 // if (img_empty.empty()) // { // logger->info("图像为空"); // continue; // } // img_empty = img_empty(roi); // //存图 // char raw_pic_Name[128] = {}; // char photoPath[MAX_PATH]; // std::strcpy(photoPath, (empty_pic + "\\%d.jpg").c_str()); // sprintf(raw_pic_Name, photoPath, i); // cv::imwrite(raw_pic_Name, img_empty); // // //图片转向量 // std::vector<float> cls_scores; // float rhs[FEATURE_COUNT]; // int ret = detect_squeezenet(img_empty, cls_scores, rhs); // char featureValue[FEATURE_COUNT * 10] = { }; // for (int i = 0; i < FEATURE_COUNT; ++i) // { // sprintf(featureValue + strlen(featureValue), "%f,", rhs[i]); // } // if (empty_pre<=30) // { // CppSQLite3Buffer insert; // insert.format("insert into empty_pan_feature(feature) values (%Q)", featureValue); // db.execDML(insert); // } // else // { // CppSQLite3Buffer update_emp; // update_emp.format("update empty_pan_feature set feature=%Q where id=%d;", featureValue,i); // db.execDML(update_emp); // } // i++; // //} // //db.close(); //double empty_save_end = clock(); //logger->info("储存空盘图的时间为:{}", empty_save_end-empty_save_beign); return 0; } int WMAI_API Probation() { string mac; GetMacByGetAdaptersAddresses(mac); Document d; StringBuffer buffer; Writer<StringBuffer> writer(buffer); d.Accept(writer); char url[200]; sprintf(url, wmpos_probation_url, dev.c_str(), mac.c_str()); logger->info("url is {}", url); string response; CommonTools::HttpGet(url, response, 3); logger->info("reponse is {}", UTF_82ASCII(response)); d.Parse(response.c_str()); Value& s = d["code"]; if (s.GetInt() == 0) { #if APPOINT_LIBRARY string new_dir = string(drive) + dir; char wmkey_path[MAX_PATH]; strcpy(wmkey_path, (new_dir + "pwmkey.wm").c_str()); const char* wmkey = wmkey_path; char prikey_path[MAX_PATH]; strcpy(prikey_path, (new_dir + "pprikey.pem").c_str()); const char* prikey = prikey_path; #else string wmkey = "pwmkey.wm"; string prikey = "pprikey.pem"; #endif // 0 string wmKeyUrl = d["data"]["wmKeyUrl"].GetString(); string privateKeyUrl = d["data"]["privateKeyUrl"].GetString(); //const char* wmkey = "pwmkey.wm"; //const char* prikey = "pprikey.pem"; CommonTools::download_file(wmKeyUrl.c_str(), wmkey.c_str()); CommonTools::download_file(privateKeyUrl.c_str(), prikey.c_str()); if (json_tenant_path) { remove(posId_json_path); remove(json_tenant_path); } return 0; } else if (s.GetInt() == 65021) { logger->info("试用码已过期"); return -4010; } else{ logger->info("probation failed errorCode: {}", s.GetInt()); return -4011; } } int WMAI_API WriteLog(const char* txt) { logger->info("node:{}",txt); return 0; } int WMAI_API SetLogoCoordinate(int x1,int y1,int width1,int height1) { if (!(width1 && height1)) { logger->info("coordinate error"); return -2008; } ai_x = x1; ai_y = y1; ai_width = width1; ai_height = height1; Document d; Pointer("/x").Set(d, x); Pointer("/y").Set(d, y); Pointer("/width").Set(d, width); Pointer("/height").Set(d, height); Pointer("/ai_x").Set(d, ai_x); Pointer("/ai_y").Set(d, ai_y); Pointer("/ai_width").Set(d, ai_width); Pointer("/ai_height").Set(d, ai_height); Pointer("/cameraNum").Set(d, cameraNum); FILE* fp = fopen(json_path, "wb"); // 非 Windows 平台使用 "w" char *writeBuffer = (char *)calloc(65536,sizeof(char)); FileWriteStream os(fp, writeBuffer, sizeof(writeBuffer)); Writer<FileWriteStream> writer(os); d.Accept(writer); fclose(fp); free(writeBuffer); return 0; } int WMAI_API InputPluToDetect(char *code,char *sessionId) { if (g_video_init && init_finish) { param_in.scan = true; char detected_code[100] = {}; char path[128] = {}; doSnacksAutoDetect(detected_code, sessionId, path); param_in.detect_image_path = string(path); if (detected_code[0] == '\0') { logger->info("没有检测出该商品");; return -6001; } if (strstr(detected_code, code) == nullptr) { logger->info("没有检测出该商品"); return -6001; } return 0; } else { return -6002; } } int WMAI_API GetDetectImage(char* path) { logger->info("image_path:{}", param_in.detect_image_path); std::strcpy(path,param_in.detect_image_path.c_str()); logger->info("path:{}", path); return 0; } bool WMAI_API JudgeScanTheCode() { bool ret = param_in.scan; param_in.scan = false; return ret; } //bool WMAI_API getVideopipeInit() //{ // return g_video_init; //} bool WMAI_API GetInitResults() { return g_video_init; } bool WMAI_API ReturnCameraState() { return cap.isOpened(); } //纠错 int WMAI_API FreshChangeError(const char* code) { //检测表单是否存在 CppSQLite3DB db; db.open(gszFile); if (!db.tableExists("feature_code")) { return 0; } int r = reassion[code]; int number = r; float feature_a[FEATURE_COUNT]; CppSQLite3Buffer selectFeatureCode; selectFeatureCode.format("select code,feature,id from feature_code where id = %d;", number); CppSQLite3Query q = db.execQuery(selectFeatureCode); //接收数据搜索结果 int id; std::string sql_code; while (!q.eof()) { sql_code = q.getStringField(0); const char* sql_feature = q.getStringField(1); id = q.getIntField(2); char* feature_c = const_cast<char*>(sql_feature); split(feature_c, feature_a); q.nextRow(); } q.finalize(); //根据返回的plu查询结果 std::vector<std::pair<float, int>>res = idx->Search(feature_a, 10); for (unsigned int j = 0; j < res.size(); j++) { //索引结果 std::pair<float, int> f = res[j]; logger->info("res[{}]={} {}\n", j, f.first, f.second); //idx的id与数据库id有 1 的偏差 int number = f.second + 1; float feature_f[FEATURE_COUNT]; CppSQLite3Buffer selectFeatureCode; selectFeatureCode.format("select code,feature,id from feature_code where id = %d;", number); CppSQLite3Query q = db.execQuery(selectFeatureCode); //接收数据搜索结果 int id; std::string sql_code; while (!q.eof()) { sql_code = q.getStringField(0); const char* sql_feature = q.fieldValue(1); id = q.getIntField(2); char* feature_c = const_cast<char*>(sql_feature); split(feature_c, feature_f); q.nextRow(); } q.finalize(); float similarity = calculSimilar(feature_a, feature_f, FEATURE_COUNT); if (sql_code == string(code) && similarity > ERROR_SIMILARITY) { //删除相似度高的数据 CppSQLite3Buffer deleted_sql; deleted_sql.format("update feature_code set deleted = 1, update_time = datetime('now','localtime') where id = %d", number); db.execDML(deleted_sql); //将删除的数据加入record_count表中 CppSQLite3Buffer insertrecord; insertrecord.format("insert into record_count(count) values (%d)", number); db.execDML(insertrecord); idx->Removesample(f.second); q.finalize(); } } reassion.clear(); db.close(); return 0; } //自动配图 int WMAI_API SelectByName(char* name , char* code, char* image) { if (!authed) { authed = authorize(); if (!authed) { logger->info("验证失败"); return -2001; }; } string utf_name(name); logger->info("input name{}",UTF_82ASCII(utf_name)); Document d; d.SetObject(); Document::AllocatorType& a = d.GetAllocator(); Value array(kArrayType); Value o1(kObjectType); Value v1(name, a); Value v2(code, a); o1.AddMember("productName", v1, a); o1.AddMember("productNumber", v2, a); array.PushBack(o1, a); d.AddMember("productList", array, d.GetAllocator()); StringBuffer buffer; Writer<StringBuffer> writer(buffer); d.Accept(writer); string buffer1 = buffer.GetString(); string buffer2 = UTF_82ASCII(buffer1); char uploadUrl[200]; string tenant3; if (tenantStr.size() != 0) { tenant3 = tenant3 + tenantStr; } else if (tenantStr.size() == 0) { tenant3 = tenant3 + '0'; } sprintf(uploadUrl, pictured_json_url, dev.c_str(), tenant3.c_str()); string response; logger->info("uploadUrl:{}", uploadUrl); CommonTools::HttpPost(uploadUrl, buffer.GetString(), response, 3); logger->info("reponse is {}", UTF_82ASCII(response)); d.Parse(response.c_str()); Value& s = d["code"]; if (s.GetInt() == 0) { #if 0 string out; for (int i = 0; i < response.size() - 1; i++) { if (response[i] == 'h' && response[i + 1] == 't') { for (int j = i; j < response.size(); j++) { if (response[j] == '"') { break; } out += response[j]; } } } if (out.size() <= 0) { logger->info("该名称没有找到图片"); return -1; } //string out1 = UTF_82ASCII(out); strcpy(image, out.c_str()); #else Value& pro_list = d["data"]["productList"].GetArray(); if (pro_list.Empty()) { logger->info("该名称没有找到图片"); return -1; } string iup = pro_list[0]["matchProductUrl"].GetString(); strcpy(image, iup.c_str()); #endif } else { logger->info("匹配图片失败"); return -1; } return 0; } int WMAI_API SetVideoDetect(int ch) { video_detect = ch == 0 ? false : true; return 0; } int WMAI_API LrregularCrop(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4) { mask = Mat::zeros(480,640,CV_8UC1); vector<vector<Point2i>> contours; vector<Point2i>urelpoints; // 角点排序 Point2f verticess[4]; Point2f tempPoint; verticess[0] = Point2f(x1, y1); verticess[1] = Point2f(x2, y2); verticess[2] = Point2f(x3, y3); verticess[3] = Point2f(x4, y4); // 角点排序 // 按x轴坐标从小到大排序 for (int i = 0; i < 3; i++) { for (int j = i + 1; j < 4; j++) { if (verticess[i].x > verticess[j].x) { tempPoint = verticess[i]; verticess[i] = verticess[j]; verticess[j] = tempPoint; } } } int min_x = verticess[0].x; int max_x = verticess[3].x; int min_y1 = verticess[0].y; int min_y2 = verticess[2].y; int max_y1 = verticess[1].y; int max_y2 = verticess[3].y; // 按纵坐标排序,依次排为(): 0左上角 1左下角 2右上角 3右下角 if (verticess[0].y > verticess[1].y) { tempPoint = verticess[0]; verticess[0] = verticess[1]; verticess[1] = tempPoint; int tem = max_y1; max_y1 = min_y1; min_y1 = tem; } if (verticess[2].y > verticess[3].y) { tempPoint = verticess[2]; verticess[2] = verticess[3]; verticess[3] = tempPoint; int tem = max_y2; max_y2 = min_y2; min_y2 = tem; } int min_y = min_y1 < min_y2 ? min_y1 : min_y2; int max_y = max_y1 > max_y2 ? max_y1 : max_y2; //cout << min_y << max_y << endl; if (verticess[0].y > verticess[3].y) { urelpoints.push_back(verticess[0]); urelpoints.push_back(verticess[3]); urelpoints.push_back(verticess[2]); urelpoints.push_back(verticess[1]); } else { urelpoints.push_back(verticess[1]); urelpoints.push_back(verticess[3]); urelpoints.push_back(verticess[2]); urelpoints.push_back(verticess[0]); } contours.push_back(urelpoints); // 绘图 cv::drawContours(mask, contours, 0, Scalar::all(255), -1); _mkdir("masks"); imwrite("masks\\mask.jpg", mask); x = min_x; y = min_y; width = max_x - min_x; height = max_y - min_y; Document d; Pointer("/x").Set(d, x); Pointer("/y").Set(d, y); Pointer("/width").Set(d, width); Pointer("/height").Set(d, height); Pointer("/ai_x").Set(d, ai_x); Pointer("/ai_y").Set(d, ai_y); Pointer("/ai_width").Set(d, ai_width); Pointer("/ai_height").Set(d, ai_height); Pointer("/cameraNum").Set(d, cameraNum); FILE* fp = fopen(json_path, "wb"); // 非 Windows 平台使用 "w" char writeBuffer[200]; FileWriteStream os(fp, writeBuffer, sizeof(writeBuffer)); Writer<FileWriteStream> writer(os); d.Accept(writer); fclose(fp); return 0; }