From 3fabada8750578aebb4268ee77e371445c2a7e15 Mon Sep 17 00:00:00 2001 From: liusiyang Date: Thu, 15 Oct 2026 20:24:11 +0800 Subject: [PATCH] =?UTF-8?q?feat=20=E5=AE=8C=E5=96=84-f=E6=89=B9=E9=87=8F?= =?UTF-8?q?=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- example/deal.cpp | 178 +++++++++++++++++++++++++++++++++++++++ example/deal.h | 3 + example/test_example.cpp | 1 + 3 files changed, 182 insertions(+) diff --git a/example/deal.cpp b/example/deal.cpp index 3b96ced..3b6ff5b 100644 --- a/example/deal.cpp +++ b/example/deal.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include "CheckUtil.hpp" std::string ExtractFileNameWithoutExtension(const std::string &strImgPath) { @@ -822,6 +823,8 @@ void deal::ResultThread(int id) { strlog += "/result"; } + // 确保日志目录存在(否则 writeLog 报 Failed to open file) + _sysmkdirs_1(strlog.substr(0, strlog.find_last_of('/'))); writeLog(strlog, m_DetResult.strlist); mutex_DetResult_.unlock(); @@ -911,6 +914,30 @@ bool deal::ReadSystemConfig(const std::string &strPath) } int deal::GetDetImageInfo(std::string strProductID, std::string strSearchImg, std::vector &jcImageInfoList) { + // -f 批量跑新格式: 产品目录下 input 子目录, 只取 _src 原图 + // (如 1M10121554R2B3_buckle_down2_src.jpg, 从图片名解析产品ID和相机名) + if (fs::is_directory(strSearchImg + "/input")) + { + jcImageInfoList.erase(jcImageInfoList.begin(), jcImageInfoList.end()); + std::vector srcImgPaths; + cv::glob(strSearchImg + "/input/*.jpg", srcImgPaths, false); + for (int idx = 0; idx < srcImgPaths.size(); idx++) + { + JC_IMAGE_INFO_ tem; + int re = GetImgInfo_SOCKET_SRC(srcImgPaths.at(idx), &tem); + if (re != 0) + { + continue; + } + if (tem.strProductID == "") + { + tem.strProductID = strProductID; + } + jcImageInfoList.push_back(tem); + } + return 0; + } + // 1、获取图片路径 std::vector img_paths; std::string strs1 = strSearchImg + "/*.jpg"; @@ -1008,6 +1035,66 @@ int deal::GetImgInfo_POL_ET_PNG(std::string strImgPath, JC_IMAGE_INFO_ *pImageIn } return 0; } +// -f 批量跑新格式: 解析图片名组装产品信息 +// 图片名示例: 1M10121554R2B3_buckle_down2_src.jpg +// 产品ID: 第一个 '_' 之前的部分 (1M10121554R2B3) +// 相机名/通道名: 直接匹配文件名中的相机名(如 buckle), 只处理后缀为 _src 的原图 +int deal::GetImgInfo_SOCKET_SRC(std::string strImgPath, JC_IMAGE_INFO_ *pImageInfo) +{ + if (pImageInfo == NULL) + { + return 1; + } + + std::string strName = ExtractFileNameWithoutExtension(strImgPath); + + // 只处理后缀为 _src 的原图, 跳过 _roi 等其它图 + const std::string strSrcSuffix = "_src"; + if (strName.size() <= strSrcSuffix.size() || + strName.compare(strName.size() - strSrcSuffix.size(), strSrcSuffix.size(), strSrcSuffix) != 0) + { + return 1; + } + + // 直接匹配文件名中的相机名, 相机名同时作为通道名 + std::string strCamName = ""; + if (strName.find("buckle") != std::string::npos) + { + strCamName = "buckle"; + } + else if (strName.find("t_face_bright") != std::string::npos) + { + strCamName = "t_face_bright"; + } + else if (strName.find("t_face_dark") != std::string::npos) + { + strCamName = "t_face_dark"; + } + if (strCamName == "") + { + printf("GetImgInfo_SOCKET_SRC: no camera match, skip %s\n", strImgPath.c_str()); + return 1; + } + + // 产品ID = 文件名第一个 '_' 之前的部分 + std::string strProductID = strName; + size_t nPos = strName.find('_'); + if (nPos != std::string::npos) + { + strProductID = strName.substr(0, nPos); + } + + pImageInfo->strProductID = strProductID; + pImageInfo->strCamID = strCamName; + pImageInfo->strchannelName = strCamName; + pImageInfo->strName = strName; + pImageInfo->strPath = strImgPath; + + printf("strImgPath %s strName %s strProductID %s strCam %s\n", + strImgPath.c_str(), strName.c_str(), strProductID.c_str(), strCamName.c_str()); + + return 0; +} int deal::InsertDetResult(ReadImgInfo tem) { std::lock_guard lock(mtx_List[Mutex_Type_DetResult]); @@ -1204,6 +1291,36 @@ int deal::DetImg() // getchar(); m_nSystemCheckType = CHECK_TYPE_OFFLING; StartThread(THREAD_RUN_ALL); + + // -8 循环执行:保持常驻,重复处理同一批产品 + if (runConfig.bLoop) + { + while (true) + { + usleep(1000 * 1000); + } + } + + // -f 批量(不加 -8 只执行一次):等待全部产品处理完成后退出 + // DealImg 线程处理完一批后会清空 m_product_ID_List 并等待结果队列清空 + while (true) + { + usleep(200 * 1000); + size_t nResultSize = 0; + { + std::lock_guard lock(mutex_Result_list); + nResultSize = m_Result_list.size(); + } + if (m_product_ID_List.empty() && nResultSize <= 0) + { + break; + } + } + // 留时间给结果线程把最后一组结果写完 + usleep(2 * 1000 * 1000); + printf(">>> -f batch complete, exit \n"); + fflush(NULL); + _exit(0); return 0; } int deal::ReJson_product(std::vector &jsonList, std::string strProductName) @@ -1553,6 +1670,55 @@ int deal::LoadProductID(std::string strImgPath) m_product_ID_List.erase(m_product_ID_List.begin(), m_product_ID_List.end()); std::vector img_paths; + // -f 批量跑新格式适配(参考 data/img/test-2 结构): + // /<产品ID>_<时间戳>/input/<产品ID>_<相机名>_<位置>_src.jpg + // 也支持直接传入单个产品目录或产品目录下的 input 目录 + { + std::string strPath = strImgPath; + while (!strPath.empty() && strPath[strPath.size() - 1] == '/') + { + strPath.erase(strPath.size() - 1); + } + fs::path rootPath(strPath); + if (!strPath.empty() && fs::is_directory(rootPath)) + { + // 兼容直接传入 input 目录: 使用其上一级产品目录 + if (rootPath.filename() == "input" && rootPath.has_parent_path()) + { + rootPath = rootPath.parent_path(); + } + + std::vector productDirList; + if (fs::is_directory(rootPath / "input")) + { + // 直接传入单个产品目录 + productDirList.push_back(rootPath.string()); + } + else + { + // 批量根目录: 含 input 子目录的子目录视为一个产品 + for (const auto &entry : fs::directory_iterator(rootPath)) + { + if (entry.is_directory() && fs::is_directory(entry.path() / "input")) + { + productDirList.push_back(entry.path().string()); + } + } + } + + if (!productDirList.empty()) + { + std::sort(productDirList.begin(), productDirList.end()); + for (const auto &strProductDir : productDirList) + { + m_product_ID_List.push_back(strProductDir); + std::cout << "new format product dir: " << strProductDir << std::endl; + } + return 0; + } + } + } + // tif 格式 { std::string str_bmp = strImgPath + "/*.jpg"; @@ -1601,6 +1767,11 @@ int deal::LoadProductID(std::string strImgPath) } } + if (m_product_ID_List.empty()) + { + printf("warning: no product dir/image found under %s\n", strImgPath.c_str()); + } + return 0; } int deal::DelImg_Cell_ET() @@ -1651,6 +1822,13 @@ int deal::Det_OneProduct_Cell_ET(std::string strProductName, int Idx) { std::string strProductID = GetFileName(strProductName); + // -f 批量跑新格式: 产品目录名为 <产品ID>_<时间戳>(如 1M10121554R2B3_20261012.151453.582176) + // 取第一个 '_' 之前的部分作为产品ID; 旧格式目录名本身即产品ID(无 '_')不受影响 + size_t nProductIDPos = strProductID.find('_'); + if (nProductIDPos != std::string::npos) + { + strProductID = strProductID.substr(0, nProductIDPos); + } // 获取图片路径 std::vector detImgInfoList; diff --git a/example/deal.h b/example/deal.h index 4b5b8de..6f465a4 100644 --- a/example/deal.h +++ b/example/deal.h @@ -551,6 +551,9 @@ private: int GetImgInfo_POL_ET_PNG(std::string strImgPath, JC_IMAGE_INFO_ *pImageInfo); + // -f 批量跑新格式: 解析 <产品ID>_<相机名>_<位置>_src.jpg 图片名组装产品信息(相机名同时作为通道名) + int GetImgInfo_SOCKET_SRC(std::string strImgPath, JC_IMAGE_INFO_ *pImageInfo); + // 功能测试 int Det_Funtion_Test(); // 边缘测试 diff --git a/example/test_example.cpp b/example/test_example.cpp index 0cfad56..0ff0c59 100644 --- a/example/test_example.cpp +++ b/example/test_example.cpp @@ -86,6 +86,7 @@ int main(int argc, char *argv[]) cout << "*** 6、./test_JBL_Check -rjson filepath: 单张复测,filepath xx/xx/3A3K380001B1DK_20240408_152157_Main_0_2_L255" << endl; cout << "*** 6、./test_JBL_Check -rjsonall filepath: 一套图复测,filepath xx/xx/" << endl; cout << "*** 7、./test_SOCKET -8: 循环执行程序(常驻),不加 -8 只执行一次" << endl; + cout << "*** 8、./test_SOCKET -f filepath: 批量执行 filepath 下的套图(新格式: <产品ID>_<时间戳>/input/<产品ID>_<相机名>_xxx_src.jpg)" << endl; cout << "******************************************************" << endl; return 0;