diff --git a/AlgorithmModule/include/ALLImgCheckAnalysisy.hpp b/AlgorithmModule/include/ALLImgCheckAnalysisy.hpp index 5de6285..3d578b4 100644 --- a/AlgorithmModule/include/ALLImgCheckAnalysisy.hpp +++ b/AlgorithmModule/include/ALLImgCheckAnalysisy.hpp @@ -61,6 +61,9 @@ public: // 更新参数 pconfig 参数指针,nConfigType 需要更新的参数类型 返回:0 成功 其他异常 int UpdateConfig(void *pconfig, int nConfigType); + // 获取指定相机在更新参数后回传的参数值(strCamera 为相机名) 返回:0 成功 其他异常 + int GetUpdateParamOut(const std::string &strCamera, UpdateParamOutST &outParam); + std::string GetVersion(); std::string GetErrorInfo(); @@ -72,6 +75,9 @@ private: // 加载分析参数 int LoadCheckConfig(void *p); + // 更新参数后, 按相机从配置中提取需要回传的参数值 + int UpdateParamOutConfig(); + /// @brief 初始化并且启动程序 /// @return int InitRun(); @@ -139,6 +145,10 @@ private: ConfigManagerBase *m_pConfigManager; + // 更新参数后需要回传给调用方的参数值: 相机名 -> 参数 + std::unordered_map m_UpdateParamOutMap; + std::mutex mtx_UpdateParamOut; // 互斥量, 保护 m_UpdateParamOutMap + // 图片处理线程 // 相机处理模块,负责完成对应相机图片的处理功能。 diff --git a/AlgorithmModule/include/ImgCheckBase.h b/AlgorithmModule/include/ImgCheckBase.h index 771dfd8..b7f00f8 100644 --- a/AlgorithmModule/include/ImgCheckBase.h +++ b/AlgorithmModule/include/ImgCheckBase.h @@ -51,6 +51,52 @@ struct RunInfoST this->str2 = tem.str2; } }; + +/*******************更新参数回传结构***********************************************************************************************************************/ +// 说明: 更新参数(UpdateConfig / 检测前更新参数)时, 算法侧把从 json 读到的参数值填进本结构体, +// 再通过接口返回给调用方。需要回传的字段直接往这里加即可。 +struct flaw_info +{ + float area; // 缺陷面积 + float gray_dis; // 缺陷灰阶 + flaw_info() + { + area = 0.0f; + gray_dis = 0.0f; + } + void copy(flaw_info tem) + { + this->area = tem.area; + this->gray_dis = tem.gray_dis; + } +}; +struct UpdateParamOutST +{ + float pixel_precision_x; // x成像检测精度 + float pixel_precision_y; // y成像检测精度 + flaw_info aotudian; // 凹凸点参数 + flaw_info zangwu; // 脏污参数 + flaw_info line; // 线状参数 + flaw_info dianzhuang; // 点状参数 + flaw_info xianwei; // 纤维参数 + flaw_info posun; // 破损参数 + UpdateParamOutST() + { + pixel_precision_x = 0.0f; + pixel_precision_y = 0.0f; + } + void copy(UpdateParamOutST tem) + { + this->pixel_precision_x = tem.pixel_precision_x; + this->pixel_precision_y = tem.pixel_precision_y; + this->aotudian.copy(tem.aotudian); + this->zangwu.copy(tem.zangwu); + this->line.copy(tem.line); + this->dianzhuang.copy(tem.dianzhuang); + this->xianwei.copy(tem.xianwei); + this->posun.copy(tem.posun); + } +}; /*******************一般调用流程*************************************************************************************************************************/ /*******************1、初始化 UpdateConfig*************************************************************************************************************************/ /*******************2、初始化 Init 并开启 *************************************************************************************************************************/ @@ -84,6 +130,9 @@ public: // 更新参数 pconfig 参数指针,nConfigType 需要更新的参数类型 返回:0 成功 其他异常 virtual int UpdateConfig(void *pconfig, int nConfigType) = 0; + // 获取指定相机在更新参数后回传的参数值(strCamera 为相机名) 返回:0 成功 其他异常 + virtual int GetUpdateParamOut(const std::string &strCamera, UpdateParamOutST &outParam) = 0; + // 返回检测版本信息 virtual std::string GetVersion() = 0; // 返回错误信息 diff --git a/AlgorithmModule/src/ALLImgCheckAnalysisy.cpp b/AlgorithmModule/src/ALLImgCheckAnalysisy.cpp index d385ea2..f8f96db 100644 --- a/AlgorithmModule/src/ALLImgCheckAnalysisy.cpp +++ b/AlgorithmModule/src/ALLImgCheckAnalysisy.cpp @@ -238,6 +238,8 @@ int ALLImgCheckAnalysisy::UpdateConfig(void *pconfig, int nConfigType) break; case CHECK_CONFIG_Module: m_pConfigManager = (ConfigManagerBase *)pconfig; + // 更新参数后, 立即按相机提取需要回传的参数值 + UpdateParamOutConfig(); break; default: break; @@ -246,6 +248,128 @@ int ALLImgCheckAnalysisy::UpdateConfig(void *pconfig, int nConfigType) return 0; } +// 缺陷项 -> 回传结构体字段 的对应关系 +struct QX_FIELD_MAP_ +{ + int nQxType; // 缺陷类型(CONFIG_QX_NAME_) + flaw_info UpdateParamOutST::*pField; // 回传结构体中对应的缺陷参数 +}; + +// 从单个相机的配置中提取需要回传的参数值 +// 取值位置与 ImageResultJudge::GetParamidx() 保持一致: +// 成像精度 <- commonCheckConfig.baseConfig.fImage_Scale_x / y +// 缺陷面积/灰阶 <- 第0个节点第0个区域的参数, 按缺陷名(param_name)匹配 +static void FillUpdateParamOut(const AnalysisyConfigST &config, UpdateParamOutST &outParam) +{ + // 1、成像检测精度 + outParam.pixel_precision_x = config.commonCheckConfig.baseConfig.fImage_Scale_x; + outParam.pixel_precision_y = config.commonCheckConfig.baseConfig.fImage_Scale_y; + + // 2、缺陷参数(面积/灰阶) + if (config.commonCheckConfig.nodeConfigArr.size() <= 0) + { + return; + } + const CommonConfigNodeST &node = config.commonCheckConfig.nodeConfigArr.at(0); + if (node.regionConfigArr.size() <= 0) + { + return; + } + const RegionConfigST ®ion = node.regionConfigArr.at(0); + const CheckConfig_Regions_type &typeParam = region.checkConfig_Regions_type[ANALYSIS_TYPE_TF]; + + const QX_FIELD_MAP_ qxFieldMap[] = { + {CONFIG_QX_NAME_cell_aotudian, &UpdateParamOutST::aotudian}, + {CONFIG_QX_NAME_cell_zangwu, &UpdateParamOutST::zangwu}, + {CONFIG_QX_NAME_cell_line, &UpdateParamOutST::line}, + {CONFIG_QX_NAME_cell_dianzhuang, &UpdateParamOutST::dianzhuang}, + {CONFIG_QX_NAME_cell_xianwei, &UpdateParamOutST::xianwei}, + {CONFIG_QX_NAME_cell_posun, &UpdateParamOutST::posun}, + }; + const int nQxFieldNum = sizeof(qxFieldMap) / sizeof(qxFieldMap[0]); + + for (int i = 0; i < nQxFieldNum; i++) + { + const std::string strQxName = CONFIG_QX_NAME_Names[qxFieldMap[i].nQxType]; + flaw_info *pOut = &(outParam.*(qxFieldMap[i].pField)); + + for (int j = 0; j < typeParam.checkConfig_Regions_Param.size(); j++) + { + const CheckConfig_Regions_Param ¶m = typeParam.checkConfig_Regions_Param.at(j); + if (param.param_name != strQxName || param.paramArr.size() <= 0) + { + continue; + } + pOut->area = param.paramArr.at(0).area; // 缺陷面积 + pOut->gray_dis = param.paramArr.at(0).hj; // 缺陷灰阶 + break; + } + } +} + +int ALLImgCheckAnalysisy::UpdateParamOutConfig() +{ + std::lock_guard lock(mtx_UpdateParamOut); + m_UpdateParamOutMap.clear(); + + if (m_pConfigManager == nullptr) + { + return 1; + } + + // 每个相机一份参数(Config_instances_ 的 key 为 json 中的 cameraCode) + for (const auto &config : m_pConfigManager->Config_instances_) + { + if (!config.second) + { + continue; + } + + AnalysisyConfigST analysisyConfig; + if (config.second->GetConfig(ConfigType_Analysisy_Common_XL, &analysisyConfig) != 0) + { + continue; + } + + UpdateParamOutST paramOut; + FillUpdateParamOut(analysisyConfig, paramOut); + m_UpdateParamOutMap[config.first] = paramOut; + } + + printf("ALLImgCheckAnalysisy::UpdateParamOutConfig cam num %zu \n", m_UpdateParamOutMap.size()); + return m_UpdateParamOutMap.size() > 0 ? 0 : 2; +} + +int ALLImgCheckAnalysisy::GetUpdateParamOut(const std::string &strCamera, UpdateParamOutST &outParam) +{ + std::lock_guard lock(mtx_UpdateParamOut); + + auto it = m_UpdateParamOutMap.find(strCamera); + if (it != m_UpdateParamOutMap.end()) + { + outParam.copy(it->second); + return 0; + } + + // 兜底: 缓存中没有时, 直接按相机名从参数模块实时取一次 + if (m_pConfigManager != nullptr) + { + auto itConfig = m_pConfigManager->Config_instances_.find(strCamera); + if (itConfig != m_pConfigManager->Config_instances_.end() && itConfig->second) + { + AnalysisyConfigST analysisyConfig; + if (itConfig->second->GetConfig(ConfigType_Analysisy_Common_XL, &analysisyConfig) == 0) + { + FillUpdateParamOut(analysisyConfig, outParam); + m_UpdateParamOutMap[strCamera] = outParam; + return 0; + } + } + } + + return 1; +} + std::string ALLImgCheckAnalysisy::GetVersion() { return std::string("BOE_2.0.5"); diff --git a/example/deal.cpp b/example/deal.cpp index f2ed195..fad1a3b 100644 --- a/example/deal.cpp +++ b/example/deal.cpp @@ -310,6 +310,112 @@ int deal::InitConfig() return 0; } +// 测试用: 仅加载配置, 调用 GetUpdateParamOut 把各相机的参数导出到 txt +// 不启动检测线程, 不加载模型 +int deal::DumpUpdateParamOut(const std::string &strOutPath) +{ + // 1、读取系统参数(含配置根目录 Config_Root_Path) + if (!ReadSystemConfig(FILE_SYSTEM_RUN_CONFIG)) + { + printf("[outparam] ReadSystemConfig error\n"); + return 1; + } + + // 2、初始化参数模块并加载 param_*.json + InitConfig(); + int re = LoadAnalysisConfig(); + if (re != 0) + { + printf("[outparam] LoadAnalysisConfig error %d, Config_Root_Path = %s\n", + re, m_system_param.config_Root_Path.c_str()); + return 2; + } + + // 3、走“更新参数”流程(内部会按相机填充回传参数) + m_pALLImgCheckAnalysisy = ALLImgCheckBase::GetInstance(); + if (m_pALLImgCheckAnalysisy == NULL || m_pConfigManager == NULL) + { + printf("[outparam] GetInstance error\n"); + return 3; + } + + re = m_pALLImgCheckAnalysisy->UpdateConfig((void *)m_pConfigManager, CHECK_CONFIG_Module); + if (re != 0) + { + printf("[outparam] UpdateConfig Module error %d\n", re); + return 4; + } + + // 4、逐相机调用 GetUpdateParamOut 并写入 txt + std::ofstream ofs(strOutPath); + if (!ofs.is_open()) + { + printf("[outparam] open out file fail: %s\n", strOutPath.c_str()); + return 5; + } + + ofs << "============ UpdateParamOut (cameraCode -> param) ============" << std::endl; + ofs << "Config_Root_Path : " << m_system_param.config_Root_Path << std::endl; + ofs << "camera num : " << m_pConfigManager->Config_instances_.size() << std::endl; + ofs << std::endl; + + // 输出一行缺陷参数 + auto writeFlaw = [&ofs](const std::string &strName, const flaw_info &info) + { + char line[128]; + sprintf(line, " %-12s area %-14.6f gray_dis %.6f", strName.c_str(), info.area, info.gray_dis); + ofs << line << std::endl; + }; + + int nSucc = 0; + for (const auto &config : m_pConfigManager->Config_instances_) + { + const std::string strCamera = config.first; + UpdateParamOutST paramOut; + int rGet = m_pALLImgCheckAnalysisy->GetUpdateParamOut(strCamera, paramOut); + + ofs << "----------------- camera: " << strCamera + << " GetUpdateParamOut = " << rGet << " -----------------" << std::endl; + + if (rGet != 0) + { + ofs << " GetUpdateParamOut Fail " << rGet << std::endl + << std::endl; + printf("[outparam] cam %-8s GetUpdateParamOut Fail %d\n", strCamera.c_str(), rGet); + continue; + } + + { + char line[128]; + sprintf(line, " pixel_precision_x %.6f pixel_precision_y %.6f", + paramOut.pixel_precision_x, paramOut.pixel_precision_y); + ofs << line << std::endl; + } + ofs << " qx area / gray_dis" << std::endl; + writeFlaw("aotudian", paramOut.aotudian); + writeFlaw("zangwu", paramOut.zangwu); + writeFlaw("line", paramOut.line); + writeFlaw("dianzhuang", paramOut.dianzhuang); + writeFlaw("xianwei", paramOut.xianwei); + writeFlaw("posun", paramOut.posun); + ofs << std::endl; + + printf("[outparam] cam %-8s ok pixel %.6f/%.6f aotudian(%.6f,%.6f) zangwu(%.6f,%.6f) line(%.6f,%.6f)\n", + strCamera.c_str(), paramOut.pixel_precision_x, paramOut.pixel_precision_y, + paramOut.aotudian.area, paramOut.aotudian.gray_dis, + paramOut.zangwu.area, paramOut.zangwu.gray_dis, + paramOut.line.area, paramOut.line.gray_dis); + nSucc++; + } + + ofs << "============ end, camera ok num " << nSucc << " ============" << std::endl; + ofs.close(); + + printf("[outparam] dump done, cam ok %d / %zu, file: %s\n", + nSucc, m_pConfigManager->Config_instances_.size(), strOutPath.c_str()); + return nSucc > 0 ? 0 : 6; +} + int deal::InitExtractImg() { m_pextractImg = ExtractBase::GetInstance(); diff --git a/example/deal.h b/example/deal.h index 8b473e6..66db572 100644 --- a/example/deal.h +++ b/example/deal.h @@ -517,6 +517,9 @@ public: ~deal(); int start(); + // 测试用: 仅加载配置, 调用 GetUpdateParamOut 把各相机的参数导出到 txt + int DumpUpdateParamOut(const std::string &strOutPath); + private: // 初始化 int Init(); diff --git a/example/test_example.cpp b/example/test_example.cpp index 5a077ae..052bfb6 100644 --- a/example/test_example.cpp +++ b/example/test_example.cpp @@ -92,6 +92,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_CellAOI -decode [dir]: 批量解码 .ytimage → .png 到 /home/aidlux/BOE/CELL_AOI/decode_img" << endl; + cout << "*** 8、./test_CellAOI -outparam [txt]: 导出各相机更新参数后的参数值到 txt,默认 ./UpdateParamOut.txt" << endl; cout << "******************************************************" << endl; return 0; @@ -106,6 +107,9 @@ int main(int argc, char *argv[]) bool bDecodeMode = false; std::string decodeInputDir; + bool bOutParamMode = false; + std::string outParamTxt = "./UpdateParamOut.txt"; + if (argc > 1 && string(argv[1]) != "-h") { @@ -158,6 +162,15 @@ int main(int argc, char *argv[]) { test.runConfig.det_Type = RUNTYPE_RUN_Merge_Img; } + else if (string(argv[i]) == "-outparam") + { + bOutParamMode = true; + if (i + 1 < argc && argv[i + 1][0] != '-') + { + outParamTxt = string(argv[i + 1]); + i++; + } + } if (string(argv[i]) == "-s") { test.runConfig.bSaveProcessImg = true; @@ -310,6 +323,18 @@ int main(int argc, char *argv[]) return (successCount > 0) ? 0 : -1; } + // ====== 参数导出模式 (-outparam) ====== + if (bOutParamMode) + { + printf("\n========== 参数导出模式 (-outparam) ==========\n"); + printf(" 输出文件: %s\n", outParamTxt.c_str()); + printf("==============================================\n\n"); + + int re = test.DumpUpdateParamOut(outParamTxt); + printf("[outparam] DumpUpdateParamOut return %d\n", re); + return re; + } + test.runConfig.print("config"); // getchar(); signal(SIGINT, handler);