#include "QX_Merge_Analysis.h" #include #include #include #include #include #include "CheckUtil.hpp" #include "CheckConfigDefine.h" QX_Merge_Analysis::QX_Merge_Analysis() { m_bExit = false; Clear(); StartThread(0); } QX_Merge_Analysis::~QX_Merge_Analysis() { StopThread(); } std::shared_ptr QX_Merge_Analysis::GetInstance() { std::shared_ptr instance = std::make_shared(); return instance; } int QX_Merge_Analysis::Clear() { m_pdetlogList.clear(); m_statusList.clear(); { std::lock_guard lock(mtx_correlatedQx); m_correlatedQxMap.clear(); } return 0; } int QX_Merge_Analysis::AddCamer(std::string cameraName) { setSendStatus(cameraName, RUN_STATUS_NULL); for (auto &it : m_statusList) { m_pMergedetlog->AddCheckstr(PrintLevel_2, 3, "QX_Merge_Analysis", "AddCamer %s %d", it.first.c_str(), it.second); } m_pMergedetlog->AddCheckstr(PrintLevel_2, 3, "QX_Merge_Analysis", "AddCamer %s %s", cameraName.c_str(),CheckUtil::getCurTimeHMS().c_str()); return 0; } int QX_Merge_Analysis::InitData() { m_reultList.Init(); { std::lock_guard lock(mtx_correlatedQx); m_correlatedQxMap.clear(); } m_pMergedetlog = std::make_shared(); m_pMergedetlog->AddCheckstr(PrintLevel_2, 3, "QX_Merge_Analysis", "InitData %s",CheckUtil::getCurTimeHMS().c_str()); { std::lock_guard lock(mtx_QXList); for (int i = 0; i < QX_ANALYSIS_COUNT; i++) { m_QXList[i].Init(); } } return 0; } int QX_Merge_Analysis::GetReusult(QX_Analysis_Result_List *&presult) { presult = &m_reultList; return 0; } void QX_Merge_Analysis::SetConfig(std::string cameraName, int qxidx, QXAnalysis_Config config) { if (cameraName == "") { return; } // if (cameraName != QX_MEREGE_CONFIG_CAMERA_NAME) // { // return; // } ALL_QX_ParamList *pqxConfigList = nullptr; { std::lock_guard lock(mtx_ConfigList); // pqxConfigList = &m_ConfigList[qxidx]; pqxConfigList->configlsit.push_back(config); } m_pMergedetlog->AddCheckstr(PrintLevel_2, 3, "QX_Merge_Analysis", "SetConfig cameraName %s qxidx %d ", cameraName.c_str(), qxidx); } void QX_Merge_Analysis::InitConfig(std::string cameraName) { // if (cameraName != QX_MEREGE_CONFIG_CAMERA_NAME) // { // return; // } { std::lock_guard lock(mtx_ConfigList); for (int i = 0; i < QX_ANALYSIS_COUNT; i++) { m_ConfigList[i].Init(); } } m_pMergedetlog->AddCheckstr(PrintLevel_2, 3, "QX_Merge_Analysis", "InitConfig cameraName %s ", cameraName.c_str()); } void QX_Merge_Analysis::SetbaseCheckFunction(std::string cameraName, ALLChannelCheckFunction *pChannelFuntion, BaseCheckFunction *pbaseCheckFunction) { if (cameraName == "") { return; } // if (cameraName != QX_MEREGE_CONFIG_CAMERA_NAME) // { // return; // } m_pChannelFuntion = pChannelFuntion; m_pbaseCheckFunction = pbaseCheckFunction; } int QX_Merge_Analysis::ConfigTypeToQXAnalysis(int nconfigType) { int QXAnalysis_type = -1; switch (nconfigType) { case CONFIG_QX_NAME_POL_Cell: QXAnalysis_type = QX_ANALYSIS_POL_CELL; // 异物 break; case CONFIG_QX_NAME_AD: QXAnalysis_type = QX_ANALYSIS_AD; // 暗点 break; case CONFIG_QX_NAME_Scratch_L1: case CONFIG_QX_NAME_Scratch_L2: QXAnalysis_type = QX_ANALYSIS_Scratch; // 划伤 break; case CONFIG_QX_NAME_X_line: case CONFIG_QX_NAME_Y_line: case CONFIG_QX_NAME_line: case CONFIG_QX_NAME_Fangge: QXAnalysis_type = QX_ANALYSIS_LINE; // 线类 break; case CONFIG_QX_NAME_MTX: QXAnalysis_type = QX_ANALYSIS_MTX; // MTX break; // case CONFIG_QX_NAME_Broken_line: // QXAnalysis_type = QX_ANALYSIS_ALL, // MTX&异物 // break; default: QXAnalysis_type = -1; break; } return QXAnalysis_type; } bool QX_Merge_Analysis::Idx(int qxidx) { if (qxidx < 0 || qxidx >= QX_ANALYSIS_COUNT) { return false; } return true; } bool QX_Merge_Analysis::AddQxInfo(int qxidx, QX_Info qxinfo, std::shared_ptr plog, std::shared_ptr pchannelLog) { std::string channel_name = qxinfo.channel_name; std::string cam_name = qxinfo.camera_name; ALL_QX_ParamList *pconfigList = nullptr; { std::lock_guard lock(mtx_ConfigList); pconfigList = &m_ConfigList[qxidx]; } if (pconfigList == nullptr) { plog->AddCheckstr(PrintLevel_3, 3, "AddQxInfo", "cam_name = %s config error", cam_name.c_str()); return false; } if (!Idx(qxidx)) { plog->AddCheckstr(PrintLevel_3, 3, "AddQxInfo", "qxidx error"); return false; } // 初步筛选一次 bool badd = false; { std::lock_guard lock(mtx_ConfigList); for (int i = 0; i < (int)pconfigList->configlsit.size(); i++) { QXAnalysis_Config *pconfig = &pconfigList->configlsit.at(i); // 面积 灰阶满足要求 if (qxinfo.area >= pconfig->area && qxinfo.hj >= pconfig->hj && qxinfo.length >= pconfig->len && qxinfo.density >= pconfig->density) { badd = true; } plog->AddCheckstr(PrintLevel_3, 3, "preA", "add = %s congfig idx %d / %d ", BOOL_TO_STR(badd), i, (int)pconfigList->configlsit.size()); plog->AddCheckstr(PrintLevel_4, 3, "Area", "%s -> %f %s %f ", BOOL_TO_STR(qxinfo.area >= pconfig->area), qxinfo.area, BOOL_TO_ThanLess(qxinfo.area >= pconfig->area), pconfig->area); plog->AddCheckstr(PrintLevel_4, 3, "HJ", "%s -> %f %s %d ", BOOL_TO_STR(qxinfo.hj >= pconfig->hj), qxinfo.hj, BOOL_TO_ThanLess(qxinfo.hj >= pconfig->hj), pconfig->hj); plog->AddCheckstr(PrintLevel_4, 3, "Len", "%s -> %f %s %f ", BOOL_TO_STR(qxinfo.length >= pconfig->len), qxinfo.length, BOOL_TO_ThanLess(qxinfo.length >= pconfig->len), pconfig->len); plog->AddCheckstr(PrintLevel_4, 3, "md", "%s -> %f %s %f ", BOOL_TO_STR(qxinfo.density >= pconfig->density), qxinfo.density, BOOL_TO_ThanLess(qxinfo.density >= pconfig->density), pconfig->density); if (badd) { break; /* code */ } } } { std::lock_guard lock(mtx_QXList); if (badd) { QX_channel_List *pQXChannelList = nullptr; for (auto &config : m_QXList[qxidx].channelqxList) { if (config.channel_name == channel_name) { pQXChannelList = &config; break; } } if (pQXChannelList == nullptr) { plog->AddCheckstr(PrintLevel_3, 3, "AddQxInfo", "new channel_name %s ", channel_name.c_str()); QX_channel_List tempchannel; tempchannel.channel_name = channel_name; tempchannel.pChannelDetlog = pchannelLog; tempchannel.qxList.push_back(qxinfo); m_QXList[qxidx].channelqxList.push_back(tempchannel); } else { plog->AddCheckstr(PrintLevel_3, 3, "AddQxInfo", "have channel_name %s ", channel_name.c_str()); pQXChannelList->pChannelDetlog2 = pchannelLog; pQXChannelList->qxList.push_back(qxinfo); } m_pMergedetlog->AddCheckstr(PrintLevel_3, 3, "AddQxInfo", "m_QXList[%d].channelqxList.size() = %d cam %s channel %s %s", qxidx, (int)m_QXList[qxidx].channelqxList.size(), cam_name.c_str(), channel_name.c_str(), CheckUtil::getCurTimeHMS().c_str()); } } return badd; } bool QX_Merge_Analysis::setSendStatus(std::string cameraName, RUN_STATUS_ status) { { std::lock_guard lock(mtx_status); m_statusList[cameraName] = status; } cv_status.notify_all(); return false; } /** * @brief 判断缺陷配置类型是否为脏污(dirty) * @param nconfigType 缺陷配置类型 CONFIG_QX_NAME_ * @return bool 是脏污返回true */ static bool IsDirtyConfigType(int nconfigType) { return nconfigType == CONFIG_QX_NAME_Dirty_L0 || nconfigType == CONFIG_QX_NAME_Dirty_L1 || nconfigType == CONFIG_QX_NAME_Dirty_L2; } /** * @brief 判断关联通道名称是否需要参与判断(为空或NONE则不参与) * @param strChannelName 关联通道名称 * @return bool 需要判断返回true */ static bool IsValidCorrelatedChannel(const std::string &strChannelName) { if (strChannelName == "") { return false; } if (CheckUtil::compareIgnoreCase(strChannelName, "NONE")) { return false; } return true; } bool QX_Merge_Analysis::AddCorrelatedQxInfo(Correlated_Qx_Info_ qxinfo, std::shared_ptr plog) { // 防御:通道为空或ROI非法时不登记,避免无效数据参与后续判断 if (qxinfo.channel_name == "" || qxinfo.product_roi.width <= 0 || qxinfo.product_roi.height <= 0) { return false; } { std::lock_guard lock(mtx_correlatedQx); std::vector &qxList = m_correlatedQxMap[qxinfo.channel_name]; // 同一相机同一通道同一位置只登记一次,避免同一缺陷被重复登记 for (int i = 0; i < (int)qxList.size(); i++) { if (qxList.at(i).camera_name == qxinfo.camera_name && qxList.at(i).config_qx_type == qxinfo.config_qx_type && qxList.at(i).product_roi == qxinfo.product_roi) { return true; } } qxList.push_back(qxinfo); } if (plog) { plog->AddCheckstr(PrintLevel_3, 3, "AddCorrelatedQxInfo", "add %s", qxinfo.GetInfo().c_str()); } if (m_pMergedetlog) { m_pMergedetlog->AddCheckstr(PrintLevel_3, 3, "AddCorrelatedQxInfo", "add %s", qxinfo.GetInfo().c_str()); } return true; } bool QX_Merge_Analysis::IsOverlapDirtyInCorrelatedChannel(const std::vector &correlated_channels, const std::string &cur_channel_name, const std::string &cur_camera_name, const cv::Rect &qx_product_roi, int roi_expand, float iou_threshold, std::shared_ptr plog) { // 未配置关联通道(NONE/空)时不需要判断 if (correlated_channels.empty()) { return false; } // 防御:ROI非法时不判断,避免无效计算与除零 if (qx_product_roi.width <= 0 || qx_product_roi.height <= 0) { return false; } // 拷贝出需要比较的脏污缺陷列表,避免在锁内做IoU计算 std::vector dirtyList; { std::lock_guard lock(mtx_correlatedQx); for (int i = 0; i < (int)correlated_channels.size(); i++) { const std::string &channel_name = correlated_channels.at(i); if (!IsValidCorrelatedChannel(channel_name)) { continue; } auto it = m_correlatedQxMap.find(channel_name); if (it == m_correlatedQxMap.end()) { continue; } for (int j = 0; j < (int)it->second.size(); j++) { if (IsDirtyConfigType(it->second.at(j).config_qx_type)) { dirtyList.push_back(it->second.at(j)); } } } } if (dirtyList.empty()) { return false; } // 与 Analysis_AD_Bind 中主次通道判断保持一致:双方均按 AD_Expand 扩张后再计算 IOU cv::Rect roi_expanded(qx_product_roi.x - roi_expand, qx_product_roi.y - roi_expand, qx_product_roi.width + roi_expand * 2, qx_product_roi.height + roi_expand * 2); for (int i = 0; i < (int)dirtyList.size(); i++) { cv::Rect dirty_roi = dirtyList.at(i).product_roi; cv::Rect dirty_expanded(dirty_roi.x - roi_expand, dirty_roi.y - roi_expand, dirty_roi.width + roi_expand * 2, dirty_roi.height + roi_expand * 2); float fiou = CheckUtil::CalIoU(roi_expanded, dirty_expanded); if (plog) { plog->AddCheckstr(PrintLevel_3, 3, "CorrelatedDirty", "cur %s cam %s roi %s <-> dirty %s roi %s expand %d iou %f", cur_channel_name.c_str(), cur_camera_name.c_str(), CheckUtil::GetRectString(qx_product_roi).c_str(), dirtyList.at(i).channel_name.c_str(), CheckUtil::GetRectString(dirty_roi).c_str(), roi_expand, fiou); } // IOU 为 NaN(ROI 非法导致的除零)时比较结果为 false,不会误抑制 NG if (fiou > iou_threshold) { if (plog) { plog->AddCheckstr(PrintLevel_1, 3, "CorrelatedDirty", "cur %s cam %s roi %s overlap dirty %s cam %s roi %s expand %d iou %f > %f", cur_channel_name.c_str(), cur_camera_name.c_str(), CheckUtil::GetRectString(qx_product_roi).c_str(), dirtyList.at(i).channel_name.c_str(), dirtyList.at(i).camera_name.c_str(), CheckUtil::GetRectString(dirty_roi).c_str(), roi_expand, fiou, iou_threshold); } return true; } } return false; } /** * @brief 等待所有任务完成 * @param timeoutMs 超时时间(毫秒) * @return bool 如果所有任务在超时前完成返回true,否则返回false */ bool QX_Merge_Analysis::waitComplete(int timeoutMs) { // 使用互斥锁保护共享资源m_statusList std::unique_lock lock(mtx_status); // 记录开始时间 auto startTime = std::chrono::steady_clock::now(); // 循环检查直到所有任务完成或超时或退出标志被设置 while (!m_bExit) { // 假设所有任务已完成 bool allComplete = !m_statusList.empty(); // 遍历状态列表检查每个任务的状态 for (auto &it : m_statusList) { // 如果发现未完成的任务,设置allComplete为false并跳出循环 if (it.second != RUN_STATUS_COMPLETE) { allComplete = false; break; } } // 如果所有任务都已完成,返回true if (allComplete) { return true; } auto elapsedMs = std::chrono::duration_cast( std::chrono::steady_clock::now() - startTime) .count(); if (elapsedMs >= timeoutMs) { return false; } cv_status.wait_for(lock, std::chrono::milliseconds(100)); } return false; } int QX_Merge_Analysis::Run(int nId) { std::unique_lock lock(mtx_status); while (!m_bExit) { cv_status.wait(lock, [this]() { if (m_bExit) return true; if (m_statusList.empty()) return false; for (auto &it : m_statusList) { if (it.second != RUN_STATUS_READY) return false; } return true; }); if (m_bExit) break; if (!m_statusList.empty()) { for (auto &it : m_statusList) { it.second = RUN_STATUS_BUSY; } lock.unlock(); StartAnalysis(); lock.lock(); for (auto &it : m_statusList) { it.second = RUN_STATUS_COMPLETE; } cv_status.notify_all(); } } return 0; } int QX_Merge_Analysis::StartThread(int nId) { // 开启检测线程 ptr_thread_Run = std::make_shared(std::bind(&QX_Merge_Analysis::Run, this, nId)); return 0; } int QX_Merge_Analysis::StopThread() { m_bExit = true; cv_status.notify_all(); if (ptr_thread_Run != nullptr) { if (ptr_thread_Run->joinable()) { ptr_thread_Run->join(); } } return 0; } int QX_Merge_Analysis::StartAnalysis() { m_pMergedetlog->AddCheckstr(PrintLevel_0, 3, "Num And Dis Judge", "==========Start========%s", CheckUtil::getCurTimeHMS().c_str()); // 分析每一个缺陷类型 for (int i = 0; i < QX_ANALYSIS_COUNT; i++) { if (QX_ANALYSIS_POL_CELL != i && QX_ANALYSIS_AD != i && QX_ANALYSIS_MTX != i && QX_ANALYSIS_Scratch != i && QX_ANALYSIS_LINE != i) { m_pMergedetlog->AddCheckstr(PrintLevel_0, 3, "Num And Dis Judge", "== %d 11", i); continue; } if (m_QXList[i].channelqxList.size() <= 0 || m_ConfigList[i].configlsit.size() <= 0) { m_pMergedetlog->AddCheckstr(PrintLevel_0, 3, "Num And Dis Judge", "== %d channelqxList %ld configlsit %ld", i, m_QXList[i].channelqxList.size(), m_ConfigList[i].configlsit.size()); continue; } m_pMergedetlog->AddCheckstr(PrintLevel_0, 3, "Num And Dis Judge", "%s start", QX_ANALYSIS_NAME_Names[i].c_str()); Analysis_QXtype(&m_QXList[i], i); m_pMergedetlog->AddCheckstr(PrintLevel_0, 3, "Num And Dis Judge", "%s end", QX_ANALYSIS_NAME_Names[i].c_str()); } // presult = &m_reultList; return 0; } int QX_Merge_Analysis::Analysis_single_Config(QXAnalysis_Config *pconfig, QX_channel_List *pqxList, int qx_type, std::shared_ptr pchannelLog) { // AD 单通道参数判定受 merge_analysy_region_sf 通道过滤约束 if (qx_type == QX_ANALYSIS_AD && m_pbaseCheckFunction) { std::vector merge_analysy_region_sf = m_pbaseCheckFunction->ad_check.analysis_sf.region_sf; if (std::find(merge_analysy_region_sf.begin(), merge_analysy_region_sf.end(), pqxList->channel_name) == merge_analysy_region_sf.end()) { pchannelLog->AddCheckstr(PrintLevel_1, 3, "Analysis_single_Config", "merge_analysy_region_sf not found %s --> skip", pqxList->channel_name.c_str()); return 0; } } pchannelLog->AddCheckstr(PrintLevel_2, 3, "param", " okparam = %d area %f max_area %f hj %d num %d dis %f len %f md %f", pconfig->bok, pconfig->area, pconfig->sum_area, pconfig->hj, pconfig->num, pconfig->dis, pconfig->len, pconfig->density); float sumarea = 0; float fmaxarea = 0; int num = 0; // 遍历每一个相机 Pre_Analysisy_Param param; param.fAreaMin = pconfig->area; param.fHJMin = pconfig->hj; param.fLenMin = pconfig->len; param.fMdMin = pconfig->density; pqxList->Initstatus(); for (int i = 0; i < (int)pqxList->qxList.size(); i++) { std::string str = ""; // 面积 灰阶满足要求 if (pqxList->preDet(i, param, str)) { num++; pqxList->qxList.at(i).nstatus = 1; sumarea += pqxList->qxList.at(i).area; if (pqxList->qxList.at(i).area > fmaxarea) { fmaxarea = pqxList->qxList.at(i).area; } } pchannelLog->AddCheckstr(PrintLevel_3, 3, "preA", "qx_idx %d : %s count = %d; %s ", i, Re_TO_STR_Pass_1(pqxList->qxList.at(i).nstatus), num, pqxList->qxList.at(i).GetInfo().c_str(), str.c_str()); } if (num <= 0 && pconfig->num > 0) { pchannelLog->AddCheckstr(PrintLevel_3, 3, "result", "fail num = 0"); return 0; } // 对距离有要求 if (pconfig->dis > 0) { pqxList->claDis(); } if (pconfig->bok == 1 && num > 0) { // 只要有一个条件大于阈值参数,就NG; std::string strresult = "param type=OK:"; bool bresult = true; // 数量不满足要求。 if (num >= pconfig->num) { bresult = false; strresult += "Num = false : " + std::to_string(num) + ">=" + std::to_string(pconfig->num) + ";"; int are = QX_ERROR_TYPE_NUM; for (int i = 0; i < (int)pqxList->qxList.size(); i++) { if (pqxList->qxList.at(i).nstatus == 1) { pqxList->qxList.at(i).nqx_type = QX_ERROR_TYPE_NUM; } } } else { strresult += "Num = true: " + std::to_string(num) + "<" + std::to_string(pconfig->num) + ";"; } float fmaxLen = 0; bool blenerror = false; float allmindis = 99999999999; bool bdiserror = false; for (int i = 0; i < (int)pqxList->qxList.size(); i++) { if (pqxList->qxList.at(i).nstatus == 1) { if (pqxList->qxList.at(i).length > fmaxLen) { fmaxLen = pqxList->qxList.at(i).length; } // 长度超过阈值 if (pconfig->len > 0 && pqxList->qxList.at(i).length > pconfig->len) { blenerror = true; pqxList->qxList.at(i).nqx_type = QX_ERROR_TYPE_Len; } // 对距离有要求 if (pconfig->dis > 0) { if (pqxList->qxList.at(i).tem_dis_idx >= 0) { // 最小距离 大于 阈值 if (pqxList->qxList.at(i).tem_dis <= pconfig->dis) { bdiserror = true; pqxList->qxList.at(i).nqx_type = QX_ERROR_TYPE_DIS; pqxList->qxList.at(i).fmindis = pqxList->qxList.at(i).tem_dis; pqxList->qxList.at(i).nmindis_BlobIdx = pqxList->qxList.at(i).tem_dis_idx; } if (pqxList->qxList.at(i).tem_dis < allmindis) { allmindis = pqxList->qxList.at(i).tem_dis; } } } } } if (blenerror) { bresult = false; strresult += "Len = false : " + std::to_string(fmaxLen) + ">=" + std::to_string(pconfig->len) + ";"; } else { strresult += "Len = true: " + std::to_string(fmaxLen) + ">=" + std::to_string(pconfig->len) + ";"; } if (bdiserror) { bresult = false; strresult += "dis = false : " + std::to_string(allmindis) + ">=" + std::to_string(pconfig->dis) + ";"; } else { strresult += "dis = true: " + std::to_string(allmindis) + ">=" + std::to_string(pconfig->dis) + ";"; } for (int i = 0; i < (int)pqxList->qxList.size(); i++) { if (pqxList->qxList.at(i).nqx_type > QX_ERROR_TYPE_OK) { if (pqxList->qxList.at(i).result == 0) { pqxList->qxList.at(i).result = 1; QX_RESULT tem; tem.blobIdx = pqxList->qxList.at(i).blobIdx; tem.qx_Num = num; tem.mindis = pqxList->qxList.at(i).fmindis; tem.flen = pqxList->qxList.at(i).length; tem.error_Type = pqxList->qxList.at(i).nqx_type; tem.camera_name = pqxList->qxList.at(i).camera_name; tem.channel_name = pqxList->qxList.at(i).channel_name; pchannelLog->AddCheckstr(PrintLevel_4, 3, "result = NG", "Add New qx,Blob idx %d type %d num %d dis %f len %f ", tem.blobIdx, tem.error_Type, tem.qx_Num, tem.mindis, tem.flen); m_reultList.resultList.push_back(tem); } } } } else { std::string strresult = "param type=NG:"; bool bpass = true; if (num >= pconfig->num) { strresult += "Num = true : " + std::to_string(num) + ">=" + std::to_string(pconfig->num) + ";"; } else { bpass = false; strresult += "Num = false: " + std::to_string(num) + "<" + std::to_string(pconfig->num) + ";"; } if (fmaxarea >= pconfig->sum_area) { strresult += "maxarea = true : " + std::to_string(fmaxarea) + ">=" + std::to_string(pconfig->sum_area) + ";"; } else { bpass = false; strresult += "maxarea = false: " + std::to_string(fmaxarea) + "<" + std::to_string(pconfig->sum_area) + ";"; } // 数量满足要求 if (bpass) { float allmindis = 99999999999; for (int i = 0; i < (int)pqxList->qxList.size(); i++) { // pchannelLog->AddCheckstr(PrintLevel_4, 3, "ddddddd", "%d %f %f %s ", // i, pqxList->qxList.at(i).plocatin_mm.x, pqxList->qxList.at(i).plocatin_mm.y, // pqxList->qxList.at(i).GetInfo().c_str()); // 面积 灰阶满足要求 if (pqxList->qxList.at(i).nstatus == 1) { int minidx = -1; bool bdis = (pconfig->dis > 0); double remindis = 0; // 对距离有要求 if (pconfig->dis > 0) { // pchannelLog->AddCheckstr(PrintLevel_3, 3, "result", "%d %f",i,pqxList->qxList.at(i).tem_dis); if (pqxList->qxList.at(i).tem_dis_idx >= 0) { // 最小距离 大于 阈值 if (pqxList->qxList.at(i).tem_dis > pconfig->dis) { bdis = false; } if (pqxList->qxList.at(i).tem_dis < allmindis) { allmindis = pqxList->qxList.at(i).tem_dis; } } else { // 无邻近缺陷,距离检查自动通过 bdis = false; } remindis = pqxList->qxList.at(i).tem_dis; } // 距离满足要求 if (bdis && pqxList->qxList.at(i).result == 0) { pqxList->qxList.at(i).result = 1; QX_RESULT tem; tem.blobIdx = pqxList->qxList.at(i).blobIdx; tem.qx_Num = num; tem.mindis = remindis; tem.camera_name = pqxList->qxList.at(i).camera_name; tem.channel_name = pqxList->qxList.at(i).channel_name; if (pconfig->num <= 0 && pconfig->dis <= 0) { tem.error_Type = QX_ERROR_TYPE_AREA; } else if (pconfig->dis <= 0) { tem.error_Type = QX_ERROR_TYPE_NUM; } else { tem.error_Type = QX_ERROR_TYPE_DIS; } pchannelLog->AddCheckstr(PrintLevel_4, 3, "Add New QX", "result = NG, Add New qx,Blob idx %d -> num %d >= %d is true; dis %f <= %f is true; max_area %f >= %f is true ", tem.blobIdx, num, pconfig->num, remindis, pconfig->dis, fmaxarea, pconfig->sum_area); m_reultList.resultList.push_back(tem); } } } if (pconfig->dis > 0) { if (allmindis <= pconfig->dis) { strresult += "dis = true : " + std::to_string(allmindis) + "<=" + std::to_string(pconfig->dis) + ";"; } else { bpass = false; strresult += "dis = false : " + std::to_string(allmindis) + ">" + std::to_string(pconfig->dis) + ";"; } } else { strresult += "dis = true : dis param is 0"; } } if (!bpass) { pchannelLog->AddCheckstr(PrintLevel_2, 3, "result", "OK==>%s", strresult.c_str()); } else { pchannelLog->AddCheckstr(PrintLevel_2, 3, "result", "NG==>%s", strresult.c_str()); } } return 0; } int QX_Merge_Analysis::Analysis_QXtype(ALL_Qx_DataList *pALLTypeqxList, int qx_idx) { m_pMergedetlog->AddCheckstr(PrintLevel_2, 3, "Num And Dis Judge", "pALLTypeqxList->channelqxList.size() %ld", pALLTypeqxList->channelqxList.size()); for (int i = 0; i < pALLTypeqxList->channelqxList.size(); i++) { QX_channel_List *pQXChannelList = &pALLTypeqxList->channelqxList[i]; Analysis_Channel(pQXChannelList, qx_idx); } // AD 要进行额外的分析 if (qx_idx == QX_ANALYSIS_AD) { if(m_pbaseCheckFunction->ad_check.analysis_bind.bUse) { Analysis_AD_Bind(pALLTypeqxList, qx_idx); } else { Analysis_AD(pALLTypeqxList, qx_idx); } } return 0; } int QX_Merge_Analysis::Analysis_Channel(QX_channel_List *pChannelqxList, int qx_idx) { int param_num = 0; int param_dis = 0; ALL_QX_ParamList *pConfigList = &m_ConfigList[qx_idx]; // 用单面相机的参数去处理 所有相机的缺陷。 m_pMergedetlog->AddCheckstr(PrintLevel_3, 3, "Num And Dis Judge", "pConfigList->configlsit.size() %ld", pConfigList->configlsit.size()); for (int i = 0; i < (int)pConfigList->configlsit.size(); i++) { pChannelqxList->pChannelDetlog->AddCheckstr(PrintLevel_1, 3, "Num And Dis Judge", "QX %s channel %s param %d / %d Analysis start ", QX_ANALYSIS_NAME_Names[qx_idx].c_str(), pChannelqxList->channel_name.c_str(), i, (int)pConfigList->configlsit.size()); Analysis_single_Config(&pConfigList->configlsit.at(i), pChannelqxList, qx_idx, pChannelqxList->pChannelDetlog); } if (pChannelqxList->pChannelDetlog2 && pChannelqxList->pChannelDetlog) { for (auto log : pChannelqxList->pChannelDetlog->logList) { pChannelqxList->pChannelDetlog2->logList.push_back(log); } } return 0; } int QX_Merge_Analysis::Judge_OK_Config() { return 0; } int QX_Merge_Analysis::Judge_NG_Config() { return 0; } int QX_Merge_Analysis::Analysis_AD(ALL_Qx_DataList *pALLTypeqxList, int qx_idx) { AD_list.clear(); if (!m_pbaseCheckFunction) { return 1; } Base_Function_AD_Check *pAd_checkParma = &m_pbaseCheckFunction->ad_check; int product_AD_num = 0; // 整个产品的 暗点数目。 int check_s_Num = 0; int s_param_value = -1; int s_param_num = 0; // 遍历每个通道,找到开启的 进行分析。 for (int i = 0; i < pALLTypeqxList->channelqxList.size(); i++) { QX_channel_List *pQXChannelList = &pALLTypeqxList->channelqxList[i]; if (!pAd_checkParma) { continue; } if (pAd_checkParma && !pAd_checkParma->bOpen) { pQXChannelList->pChannelDetlog->AddCheckstr(PrintLevel_2, 3, "Analysis_AD ", "channel %s AD Check is close", pQXChannelList->channel_name.c_str()); continue; } bool bana_num = false; bool bana_dis = false; bool bana_S = false; if (pAd_checkParma->analysis_num.bOpen) { bana_num = true; } if (pAd_checkParma->analysis_dis.bOpen) { bana_dis = true; } if (pAd_checkParma->analysis_s.bOpen) { bana_S = true; } { pQXChannelList->pChannelDetlog->AddCheckstr(PrintLevel_2, 3, "Analysis_AD ", "NUM --> %s Param num check %d dis check %d S check %d", pQXChannelList->channel_name.c_str(), bana_num, bana_dis, bana_S); } if (!bana_num && !bana_dis && !bana_S) { continue; } for (int j = 0; j < pQXChannelList->qxList.size(); j++) { if (pQXChannelList->qxList[j].area >= pAd_checkParma->S_standard_1s.area && pQXChannelList->qxList[j].length >= pAd_checkParma->S_standard_1s.len) { } else { continue; } tem_AD_QX_Info tem_AD_qx; // 暗点信息 tem_AD_qx.channelidx = i; tem_AD_qx.qxidx = j; int s_det_value = 0; // 当前通道 要参与s标准分析 if (pAd_checkParma->analysis_s.bOpen) { s_param_num = pAd_checkParma->analysis_s.Check_s_Num; s_param_value = pAd_checkParma->analysis_s.Check_s_Value; if (pQXChannelList->qxList[j].area >= pAd_checkParma->S_standard_3s.area && pQXChannelList->qxList[j].length >= pAd_checkParma->S_standard_3s.len) { s_det_value = 3; pQXChannelList->pChannelDetlog->AddCheckstr(PrintLevel_3, 3, "add AD ", "%d %s 3S: cur[A %0.2f L %0.2f] parm[A %0.2f L %0.2f]", j, pQXChannelList->channel_name.c_str(), pQXChannelList->qxList[j].area, pQXChannelList->qxList[j].length, pAd_checkParma->S_standard_3s.area, pAd_checkParma->S_standard_3s.len); } else if (pQXChannelList->qxList[j].area >= pAd_checkParma->S_standard_2s.area && pQXChannelList->qxList[j].length >= pAd_checkParma->S_standard_2s.len) { s_det_value = 2; pQXChannelList->pChannelDetlog->AddCheckstr(PrintLevel_3, 3, " add AD ", "%d %s 2S: cur[A %0.2f L %0.2f] parm[A %0.2f L %0.2f]", j, pQXChannelList->channel_name.c_str(), pQXChannelList->qxList[j].area, pQXChannelList->qxList[j].length, pAd_checkParma->S_standard_2s.area, pAd_checkParma->S_standard_2s.len); } else { pQXChannelList->pChannelDetlog->AddCheckstr(PrintLevel_3, 3, "add AD ", "%d %s 1S: cur[A %0.2f L %0.2f] parm[A %0.2f L %0.2f]", j, pQXChannelList->channel_name.c_str(), pQXChannelList->qxList[j].area, pQXChannelList->qxList[j].length, pAd_checkParma->S_standard_1s.area, pAd_checkParma->S_standard_1s.len); s_det_value = 1; } if (s_det_value >= s_param_value) { check_s_Num++; } } cv::Rect roi = pQXChannelList->qxList[j].product_roi; int list_idx = -1; int channel_s = 0; int roi_expand = (round)(pAd_checkParma->analysis_iou.AD_Expand); bool bnew_add = true; for (int idx = 0; idx < AD_list.size(); idx++) { cv::Rect tem_roi(AD_list.at(idx).roi.x-roi_expand, AD_list.at(idx).roi.y-roi_expand, AD_list.at(idx).roi.width+2*roi_expand, AD_list.at(idx).roi.height+2*roi_expand); cv::Rect tem_roi2(roi.x-roi_expand, roi.y-roi_expand, roi.width+2*roi_expand, roi.height+2*roi_expand); float fiou = CheckUtil::CalIoU(AD_list.at(idx).roi, roi); m_pMergedetlog->AddCheckstr(PrintLevel_3, 3, "CalIoU", "roi1 %s roi2 %s expand %d iou %f", CheckUtil::GetRectString(AD_list.at(idx).roi).c_str(), CheckUtil::GetRectString(roi).c_str(), roi_expand, fiou); if (fiou > pAd_checkParma->analysis_iou.AD_IOU) { list_idx = idx; } } // 在list已存在。 if (list_idx >= 0) { AD_list.at(list_idx).num++; AD_list.at(list_idx).numIdxList.push_back(tem_AD_qx); channel_s = AD_list.at(list_idx).num; if (s_det_value == 1) { AD_list.at(list_idx).num_1s++; } else if (s_det_value == 2) { AD_list.at(list_idx).num_2s++; AD_list.at(list_idx).num_2sIdxList.push_back(tem_AD_qx); } else { AD_list.at(list_idx).num_3s++; AD_list.at(list_idx).num_3sIdxList.push_back(tem_AD_qx); } bnew_add = false; } else { // 在list不存在。 AD_Channel_Info_ tem; tem.roi = roi; tem.location_product_mm = pQXChannelList->qxList[j].pLocation_Product_mm; tem.num = 1; channel_s = 1; tem.fdis = 99999999999; tem.numIdxList.push_back(tem_AD_qx); if (s_det_value == 1) { tem.num_1s++; } else if (s_det_value == 2) { tem.num_2s++; tem.num_2sIdxList.push_back(tem_AD_qx); } else { tem.num_3s++; tem.num_3sIdxList.push_back(tem_AD_qx); } AD_list.push_back(tem); // 如果要参与数量统计 if (bana_num) { product_AD_num++; } } m_pMergedetlog->AddCheckstr(PrintLevel_2, 3, "AD RGBL255", "AD list size %ld; channel %s blob idx %d,new_add %d ,A %f len %f p %d %d", AD_list.size(), pQXChannelList->channel_name.c_str(), j, bnew_add, pQXChannelList->qxList[j].area, pQXChannelList->qxList[j].length, roi.x, roi.y); pQXChannelList->pChannelDetlog->AddCheckstr(PrintLevel_2, 3, "Analysis_AD ", "%d %s AD list size %ld product_AD_num Num %d; cur channel num = %d;cur S = %ds; param :%ds num %d;->S check_s_Num = %d", j, pQXChannelList->channel_name.c_str(), AD_list.size(), product_AD_num, channel_s, s_det_value, s_param_value, s_param_num, check_s_Num); } } float min_dis = 9999999999; // 求最小距离 if (true) { for (int ad_i = 0; ad_i < AD_list.size(); ad_i++) { for (int ad_j = 0; ad_j < AD_list.size(); ad_j++) { if (ad_i == ad_j) { continue; } // double dis = DistanceBetweenRectCenters(AD_list.at(ad_i).roi, AD_list.at(ad_j).roi, // 1, // 1); float dis = CheckUtil::calDis(AD_list.at(ad_i).location_product_mm, AD_list.at(ad_j).location_product_mm); if (dis < AD_list.at(ad_i).fdis) { AD_list.at(ad_i).fdis = dis; AD_list.at(ad_i).dist_idx = ad_j; if (dis < min_dis) { min_dis = dis; } } } } } int A_2S_num = 0; int A_3S_num = 0; // 统计 2s 总数 if (s_param_value > 0) { int channels = 0; int oneimgs = check_s_Num; for (int ad_i = 0; ad_i < AD_list.size(); ad_i++) { if (AD_list.at(ad_i).num > 1) { AD_list.at(ad_i).num_2s++; for (int i = 0; i < AD_list.at(ad_i).numIdxList.size(); i++) { AD_list.at(ad_i).num_2sIdxList.push_back(AD_list.at(ad_i).numIdxList.at(i)); } } A_2S_num += AD_list.at(ad_i).num_2s; A_3S_num += AD_list.at(ad_i).num_3s; if(AD_list.at(ad_i).num_1s >= 3) A_3S_num++; m_pMergedetlog->AddCheckstr(PrintLevel_2, 3, "AD RGBL255", "AD_list %d %s", ad_i, AD_list.at(ad_i).GetInfo().c_str()); } m_pMergedetlog->AddCheckstr(PrintLevel_2, 3, "AD RGBL255", "product_AD_num %d 2S_num = %d 3S_num s = %d min_dis %0.2f", product_AD_num, A_2S_num, A_3S_num, min_dis); } for (int i = 0; i < pALLTypeqxList->channelqxList.size(); i++) { QX_channel_List *pQXChannelList = &pALLTypeqxList->channelqxList[i]; if (!pAd_checkParma->bOpen) { continue; } bool bNG = false; bool NG_num = false; bool NG_3S = false; bool NG_2S = false; bool NG_dis = false; if (pAd_checkParma->analysis_num.bOpen) { // 数量分析 if (product_AD_num >= pAd_checkParma->analysis_num.numT) { m_pMergedetlog->AddCheckstr(PrintLevel_2, 3, "AD RGBL255", "Num Analysis --> %s result NG ,product_AD_num %d >= parm num %d", pQXChannelList->channel_name.c_str(), product_AD_num, pAd_checkParma->analysis_num.numT); bNG = true; NG_num = true; } else { m_pMergedetlog->AddCheckstr(PrintLevel_2, 3, "AD RGBL255", "Num Analysis--> %s result OK ,product_AD_num %d < parm num %d", pQXChannelList->channel_name.c_str(), product_AD_num, pAd_checkParma->analysis_num.numT); } } // 不NG if (!bNG) { // 3S直接 NG if (pAd_checkParma->analysis_s.NG_3s) { // 数量分析 if (A_3S_num >= 1) { m_pMergedetlog->AddCheckstr(PrintLevel_2, 3, "AD RGBL255", "3S Analysis --> %s result NG 3S %d >= 1", pQXChannelList->channel_name.c_str(), A_3S_num); bNG = true; NG_3S = true; } else { m_pMergedetlog->AddCheckstr(PrintLevel_2, 3, "AD RGBL255", "3S Analysis --> %s result OK 3S %d < 1", pQXChannelList->channel_name.c_str(), A_3S_num); } } } // 不NG if (!bNG) { // 距离判断 if (pAd_checkParma->analysis_dis.bOpen) { // 数量分析 if (min_dis <= pAd_checkParma->analysis_dis.disT) { m_pMergedetlog->AddCheckstr(PrintLevel_2, 3, "AD RGBL255", "Dis Analysis--> %s Dis result NG ,min dis %f <= parm dis %f", pQXChannelList->channel_name.c_str(), min_dis, pAd_checkParma->analysis_dis.disT); bNG = true; NG_2S = true; } else { m_pMergedetlog->AddCheckstr(PrintLevel_2, 3, "AD RGBL255", "Dis Analysis--> %s Dis result OK ,min dis %f > parm dis %f", pQXChannelList->channel_name.c_str(), min_dis, pAd_checkParma->analysis_dis.disT); } } } // 不NG if (!bNG) { // S标准判断 if (pAd_checkParma->analysis_s.bOpen) { // 数量分析 if (A_2S_num >= pAd_checkParma->analysis_s.Check_s_Num) { m_pMergedetlog->AddCheckstr(PrintLevel_2, 3, "AD RGBL255", "S Analysis--> %s result NG , Check %ds Num %d >= parm S Num %d", pQXChannelList->channel_name.c_str(), pAd_checkParma->analysis_s.Check_s_Value, A_2S_num, pAd_checkParma->analysis_s.Check_s_Num); bNG = true; NG_2S = true; } else { m_pMergedetlog->AddCheckstr(PrintLevel_2, 3, "AD RGBL255", "S Analysis--> %s result OK , Check %ds Num %d < parm S Num %d", pQXChannelList->channel_name.c_str(), pAd_checkParma->analysis_s.Check_s_Value, A_2S_num, pAd_checkParma->analysis_s.Check_s_Num); } } } // 已经NG if (bNG) { QX_channel_List *pqxList = pQXChannelList; for (int i = 0; i < (int)pqxList->qxList.size(); i++) { if (pqxList->qxList.at(i).result == 0) { pqxList->qxList.at(i).result = 1; QX_RESULT tem; tem.blobIdx = pqxList->qxList.at(i).blobIdx; tem.mindis = pqxList->qxList.at(i).fmindis; tem.flen = pqxList->qxList.at(i).length; tem.error_Type = pqxList->qxList.at(i).nqx_type; tem.camera_name = pqxList->qxList.at(i).camera_name; tem.channel_name = pqxList->qxList.at(i).channel_name; pqxList->pChannelDetlog->AddCheckstr(PrintLevel_4, 3, "result = NG", "Add New qx,Blob idx %d type %d num %d dis %f len %f ", tem.blobIdx, tem.error_Type, tem.qx_Num, tem.mindis, tem.flen); m_pMergedetlog->AddCheckstr(PrintLevel_4, 3, "result = NG", "%s Add New qx,Blob idx %d type %d num %d dis %f len %f ", tem.channel_name.c_str(), tem.blobIdx, tem.error_Type, tem.qx_Num, tem.mindis, tem.flen); m_reultList.resultList.push_back(tem); } } } } return 0; } int QX_Merge_Analysis::Analysis_AD_Bind(ALL_Qx_DataList *pALLTypeqxList, int qx_idx) { if (!m_pbaseCheckFunction) { return 1; } Base_Function_AD_Check *pAd_checkParma = &m_pbaseCheckFunction->ad_check; int check_s_Num = 0; int s_param_value = -1; int s_param_num = 0; bool bana_num = false; bool bana_dis = false; bool bana_S = false; if (pAd_checkParma->analysis_num.bOpen) { bana_num = true; } if (pAd_checkParma->analysis_dis.bOpen) { bana_dis = true; } if (pAd_checkParma->analysis_s.bOpen) { bana_S = true; } m_pMergedetlog->AddCheckstr(PrintLevel_1, 3, "Analysis_AD_Bind", "start bOpen %d num %d dis %d S %d", pAd_checkParma->bOpen, bana_num, bana_dis, bana_S); /* 获取绑定通道 */ vector merge_analysy_s_sf = pAd_checkParma->analysis_sf.s_sf; vector main_channel_2s = pAd_checkParma->analysis_bind.main_channel_2s; vector second_channel_2s = pAd_checkParma->analysis_bind.second_channel_2s; vector main_channel_3s = pAd_checkParma->analysis_bind.main_channel_3s; vector second_channel_3s = pAd_checkParma->analysis_bind.second_channel_3s; /* 获取关联通道 */ vector correlated_channels = pAd_checkParma->analysis_bind.correlated_channels; m_pMergedetlog->AddCheckstr(PrintLevel_2, 3, "Analysis_AD_Bind", "bind main_2s %d second_2s %d main_3s %d second_3s %d", (int)main_channel_2s.size(), (int)second_channel_2s.size(), (int)main_channel_3s.size(), (int)second_channel_3s.size()); /* 获取主次通道的缺陷列表 */ vector main_channel_s_qxList; vector second_channel_s_qxList; for (int i = 0; i < pALLTypeqxList->channelqxList.size(); i++) { QX_channel_List *pQXChannelList = &pALLTypeqxList->channelqxList[i]; if (!pAd_checkParma) { continue; } if (pAd_checkParma && !pAd_checkParma->bOpen) { pQXChannelList->pChannelDetlog->AddCheckstr(PrintLevel_2, 3, "Analysis_AD ", "channel %s AD Check is close", pQXChannelList->channel_name.c_str()); continue; } { pQXChannelList->pChannelDetlog->AddCheckstr(PrintLevel_2, 3, "Analysis_AD ", "NUM --> %s Param num check %d dis check %d S check %d", pQXChannelList->channel_name.c_str(), bana_num, bana_dis, bana_S); } string cur_channel_name = pQXChannelList->channel_name; if (std::find(main_channel_2s.begin(), main_channel_2s.end(), cur_channel_name) != main_channel_2s.end() || std::find(main_channel_3s.begin(), main_channel_3s.end(), cur_channel_name) != main_channel_3s.end()) { main_channel_s_qxList.push_back(pALLTypeqxList->channelqxList[i]); } if (std::find(second_channel_2s.begin(), second_channel_2s.end(), cur_channel_name) != second_channel_2s.end() || std::find(second_channel_3s.begin(), second_channel_3s.end(), cur_channel_name) != second_channel_3s.end()) { second_channel_s_qxList.push_back(pALLTypeqxList->channelqxList[i]); } } m_pMergedetlog->AddCheckstr(PrintLevel_2, 3, "Analysis_AD_Bind", "main_channel %d second_channel %d", (int)main_channel_s_qxList.size(), (int)second_channel_s_qxList.size()); /* 画面分析 */ AD_list_bind.clear(); for(int i_main = 0; i_main < main_channel_s_qxList.size(); i_main++) { string main_channel_name = main_channel_s_qxList[i_main].channel_name; QX_channel_List *pQXChannelList_main = &main_channel_s_qxList[i_main]; vector tmp_main_qxInfo_all; // 遍历主通道cur_channel_name通道的缺陷 for (int j_main = 0; j_main < pQXChannelList_main->qxList.size(); j_main++) { AD_Channel_BD_Info_ tmp_main_qxInfo; // 主通道单个缺陷 if (pQXChannelList_main->qxList[j_main].area >= pAd_checkParma->S_standard_1s.area && pQXChannelList_main->qxList[j_main].length >= pAd_checkParma->S_standard_1s.len) { } else { continue; } tmp_main_qxInfo.roi = pQXChannelList_main->qxList[j_main].product_roi; tmp_main_qxInfo.location_product_mm = pQXChannelList_main->qxList[j_main].pLocation_Product_mm; /*单画面*/ // 当前通道 要参与s标准分析 if (pAd_checkParma->analysis_s.bOpen) { s_param_num = pAd_checkParma->analysis_s.Check_s_Num; s_param_value = pAd_checkParma->analysis_s.Check_s_Value; if (pQXChannelList_main->qxList[j_main].area >= pAd_checkParma->S_standard_3s.area && pQXChannelList_main->qxList[j_main].length >= pAd_checkParma->S_standard_3s.len) { tmp_main_qxInfo.s_type = 3; pQXChannelList_main->pChannelDetlog->AddCheckstr(PrintLevel_3, 3, "add AD ", "%d %s 3S: cur[A %0.2f L %0.2f] parm[A %0.2f L %0.2f]", j_main, pQXChannelList_main->channel_name.c_str(), pQXChannelList_main->qxList[j_main].area, pQXChannelList_main->qxList[j_main].length, pAd_checkParma->S_standard_3s.area, pAd_checkParma->S_standard_3s.len); } else if (pQXChannelList_main->qxList[j_main].area >= pAd_checkParma->S_standard_2s.area && pQXChannelList_main->qxList[j_main].length >= pAd_checkParma->S_standard_2s.len) { tmp_main_qxInfo.s_type = 2; pQXChannelList_main->pChannelDetlog->AddCheckstr(PrintLevel_3, 3, " add AD ", "%d %s 2S: cur[A %0.2f L %0.2f] parm[A %0.2f L %0.2f]", j_main, pQXChannelList_main->channel_name.c_str(), pQXChannelList_main->qxList[j_main].area, pQXChannelList_main->qxList[j_main].length, pAd_checkParma->S_standard_2s.area, pAd_checkParma->S_standard_2s.len); } else { pQXChannelList_main->pChannelDetlog->AddCheckstr(PrintLevel_3, 3, "add AD ", "%d %s 1S: cur[A %0.2f L %0.2f] parm[A %0.2f L %0.2f]", j_main, pQXChannelList_main->channel_name.c_str(), pQXChannelList_main->qxList[j_main].area, pQXChannelList_main->qxList[j_main].length, pAd_checkParma->S_standard_1s.area, pAd_checkParma->S_standard_1s.len); tmp_main_qxInfo.s_type = 1; } } cv::Rect roi_main = pQXChannelList_main->qxList[j_main].product_roi; int roi_expand = (round)(pAd_checkParma->analysis_iou.AD_Expand); roi_main = cv::Rect(roi_main.x - roi_expand, roi_main.y - roi_expand, roi_main.width + roi_expand * 2, roi_main.height + roi_expand * 2); // 遍历次通道 for(int i_second = 0; i_second < second_channel_s_qxList.size(); i_second++) { string second_channel_name = second_channel_s_qxList[i_second].channel_name; if(second_channel_name == main_channel_name) { continue; } QX_channel_List *pQXChannelList_second = &second_channel_s_qxList[i_second]; // 遍历次通道second_channel_name通道的缺陷 for (int j_second = 0; j_second < pQXChannelList_second->qxList.size(); j_second++) { if (pQXChannelList_second->qxList[j_second].area >= pAd_checkParma->S_standard_1s.area && pQXChannelList_second->qxList[j_second].length >= pAd_checkParma->S_standard_1s.len) { } else { continue; } cv::Rect roi_second = pQXChannelList_second->qxList[j_second].product_roi; roi_second = cv::Rect(roi_second.x - roi_expand, roi_second.y - roi_expand, roi_second.width + roi_expand * 2, roi_second.height + roi_expand * 2); float fiou = CheckUtil::CalIoU(roi_main, roi_second); // m_pMergedetlog->AddCheckstr(PrintLevel_3, 3, "CalIoU", // "roi1 %s roi2 %s expand %d iou %f", // CheckUtil::GetRectString(roi_main).c_str(), // CheckUtil::GetRectString(roi_second).c_str(), // roi_expand, fiou); if (fiou > pAd_checkParma->analysis_iou.AD_IOU) { if (std::find(second_channel_2s.begin(), second_channel_2s.end(), second_channel_name) != second_channel_2s.end()) { tmp_main_qxInfo.s_name_2.push_back(second_channel_name); m_pMergedetlog->AddCheckstr(PrintLevel_3, 3, "Add 2s", "%s roi1 %s roi2 %s expand %d iou %f", second_channel_name.c_str(), CheckUtil::GetRectString(roi_main).c_str(),CheckUtil::GetRectString(roi_second).c_str(),roi_expand, fiou); } if(std::find(second_channel_3s.begin(), second_channel_3s.end(), second_channel_name) != second_channel_3s.end()) { tmp_main_qxInfo.s_name_3.push_back(second_channel_name); m_pMergedetlog->AddCheckstr(PrintLevel_3, 3, "Add 3s", "%s roi1 %s roi2 %s expand %d iou %f", second_channel_name.c_str(), CheckUtil::GetRectString(roi_main).c_str(),CheckUtil::GetRectString(roi_second).c_str(),roi_expand, fiou); } break; } } } m_pMergedetlog->AddCheckstr(PrintLevel_3, 3, "Analysis_AD_Bind", "main %s blob %d s_type %d s_name_2 %d s_name_3 %d roi %s", main_channel_name.c_str(), j_main, tmp_main_qxInfo.s_type, (int)tmp_main_qxInfo.s_name_2.size(), (int)tmp_main_qxInfo.s_name_3.size(), CheckUtil::GetRectString(tmp_main_qxInfo.roi).c_str()); tmp_main_qxInfo_all.push_back(tmp_main_qxInfo); } AD_list_bind[main_channel_name] = tmp_main_qxInfo_all; } /* 数量距离统计 */ std::unordered_map AD_stat_map; for(int i_main = 0; i_main < main_channel_s_qxList.size(); i_main++) { string main_channel_name = main_channel_s_qxList[i_main].channel_name; AD_Channel_Stat_ &stat = AD_stat_map[main_channel_name]; for(int j = 0; j < AD_list_bind[main_channel_name].size(); j++) { bool bproduct_AD_num = false; // 数量统计 if(AD_list_bind[main_channel_name][j].s_type == 1) { bproduct_AD_num = true; stat.num_1s++; } if(AD_list_bind[main_channel_name][j].s_type == 2 || AD_list_bind[main_channel_name][j].s_name_2.size() >= 2) { if(AD_list_bind[main_channel_name][j].s_type == 2) stat.num_2s_s++; if(AD_list_bind[main_channel_name][j].s_name_2.size() >= 2) stat.num_2s_m++; bproduct_AD_num = true; stat.num_2s++; } if(AD_list_bind[main_channel_name][j].s_type == 3 || AD_list_bind[main_channel_name][j].s_name_3.size() >= 3) { if(AD_list_bind[main_channel_name][j].s_type == 3) stat.num_3s_s++; if(AD_list_bind[main_channel_name][j].s_name_3.size() >= 3) stat.num_3s_m++; bproduct_AD_num = true; stat.num_3s++; } if(bproduct_AD_num) { stat.product_AD_num++; } // 距离计算 for(int k = j + 1; k < AD_list_bind[main_channel_name].size(); k++) { float dis = CheckUtil::calDis(AD_list_bind[main_channel_name][j].location_product_mm, AD_list_bind[main_channel_name][k].location_product_mm); if (dis < stat.min_dis) { stat.min_dis = dis; } } } m_pMergedetlog->AddCheckstr(PrintLevel_1, 3, "Analysis_AD_Bind", "stat %s num_1s %d | num_2s %d [s %d m %d] | num_3s %d [s %d m %d] | product_AD_num %d | min_dis %0.2f", main_channel_name.c_str(), stat.num_1s, stat.num_2s, stat.num_2s_s, stat.num_2s_m, stat.num_3s, stat.num_3s_s, stat.num_3s_m, stat.product_AD_num, stat.min_dis); } /* NG分析 */ for (int i = 0; i < pALLTypeqxList->channelqxList.size(); i++) { QX_channel_List *pQXChannelList = &pALLTypeqxList->channelqxList[i]; if (!pAd_checkParma->bOpen) { continue; } if(std::find(merge_analysy_s_sf.begin(), merge_analysy_s_sf.end(), pQXChannelList->channel_name) != merge_analysy_s_sf.end()) { } else { m_pMergedetlog->AddCheckstr(PrintLevel_1, 3, "Analysis_AD_Bind", "merge_analysy_s_sf not found %s --> skip", pQXChannelList->channel_name.c_str()); continue; } // 获取该通道独立的统计 auto it_stat = AD_stat_map.find(pQXChannelList->channel_name); if (it_stat == AD_stat_map.end()) { m_pMergedetlog->AddCheckstr(PrintLevel_1, 3, "Analysis_AD_Bind", "AD_stat_map not found %s --> skip", pQXChannelList->channel_name.c_str()); continue; } AD_Channel_Stat_ &stat = it_stat->second; bool bNG = false; bool NG_num = false; bool NG_3S = false; bool NG_2S = false; bool NG_dis = false; if (pAd_checkParma->analysis_num.bOpen) { // 数量分析 if (stat.product_AD_num >= pAd_checkParma->analysis_num.numT) { m_pMergedetlog->AddCheckstr(PrintLevel_2, 3, "AD RGBL255", "Num Analysis --> %s result NG ,product_AD_num %d >= parm num %d", pQXChannelList->channel_name.c_str(), stat.product_AD_num, pAd_checkParma->analysis_num.numT); bNG = true; NG_num = true; } else { m_pMergedetlog->AddCheckstr(PrintLevel_2, 3, "AD RGBL255", "Num Analysis--> %s result OK ,product_AD_num %d < parm num %d", pQXChannelList->channel_name.c_str(), stat.product_AD_num, pAd_checkParma->analysis_num.numT); } } // 不NG if (!bNG) { // 3S直接 NG if (pAd_checkParma->analysis_s.NG_3s) { if (stat.num_3s >= 1) { m_pMergedetlog->AddCheckstr(PrintLevel_2, 3, "AD RGBL255", "3S Analysis --> %s result NG 3S %d >= 1", pQXChannelList->channel_name.c_str(), stat.num_3s); bNG = true; NG_3S = true; } else { m_pMergedetlog->AddCheckstr(PrintLevel_2, 3, "AD RGBL255", "3S Analysis --> %s result OK 3S %d < 1", pQXChannelList->channel_name.c_str(), stat.num_3s); } } } // 不NG if (!bNG) { // 距离判断 if (pAd_checkParma->analysis_dis.bOpen) { if (stat.min_dis <= pAd_checkParma->analysis_dis.disT) { m_pMergedetlog->AddCheckstr(PrintLevel_2, 3, "AD RGBL255", "Dis Analysis--> %s Dis result NG ,min dis %f <= parm dis %f", pQXChannelList->channel_name.c_str(), stat.min_dis, pAd_checkParma->analysis_dis.disT); bNG = true; NG_dis = true; } else { m_pMergedetlog->AddCheckstr(PrintLevel_2, 3, "AD RGBL255", "Dis Analysis--> %s Dis result OK ,min dis %f > parm dis %f", pQXChannelList->channel_name.c_str(), stat.min_dis, pAd_checkParma->analysis_dis.disT); } } } // 不NG if (!bNG) { // S标准判断 if (pAd_checkParma->analysis_s.bOpen) { if (stat.num_2s >= pAd_checkParma->analysis_s.Check_s_Num) { m_pMergedetlog->AddCheckstr(PrintLevel_2, 3, "AD RGBL255", "S Analysis--> %s result NG , Check %ds Num %d >= parm S Num %d", pQXChannelList->channel_name.c_str(), pAd_checkParma->analysis_s.Check_s_Value, stat.num_2s, pAd_checkParma->analysis_s.Check_s_Num); bNG = true; NG_2S = true; } else { m_pMergedetlog->AddCheckstr(PrintLevel_2, 3, "AD RGBL255", "S Analysis--> %s result OK , Check %ds Num %d < parm S Num %d", pQXChannelList->channel_name.c_str(), pAd_checkParma->analysis_s.Check_s_Value, stat.num_2s, pAd_checkParma->analysis_s.Check_s_Num); } } } // 已经NG if (bNG) { // 注意:按缺陷(blob)粒度逐条判断,避免把同一通道内与脏污无关的缺陷也一并放过 const int roi_expand = (int)(round)(pAd_checkParma->analysis_iou.AD_Expand); const float iou_threshold = pAd_checkParma->analysis_iou.AD_IOU; QX_channel_List *pqxList = pQXChannelList; for (int idx = 0; idx < (int)pqxList->qxList.size(); idx++) { if (pqxList->qxList.at(idx).result != 0) { continue; } // 关联通道存在与当前缺陷重叠的脏污缺陷时,该缺陷不记录NG结果 if (IsOverlapDirtyInCorrelatedChannel(correlated_channels, pqxList->qxList.at(idx).channel_name, pqxList->qxList.at(idx).camera_name, pqxList->qxList.at(idx).product_roi, roi_expand, iou_threshold, pqxList->pChannelDetlog)) { pqxList->pChannelDetlog->AddCheckstr(PrintLevel_1, 3, "result = NG skip", "channel %s cam %s blob %d roi %s : 关联通道存在重叠, 不记录NG结果", pqxList->qxList.at(idx).channel_name.c_str(), pqxList->qxList.at(idx).camera_name.c_str(), pqxList->qxList.at(idx).blobIdx, CheckUtil::GetRectString(pqxList->qxList.at(idx).product_roi).c_str()); m_pMergedetlog->AddCheckstr(PrintLevel_1, 3, "result = NG skip", "channel %s cam %s blob %d roi %s : 关联通道存在重叠, 不记录NG结果", pqxList->qxList.at(idx).channel_name.c_str(), pqxList->qxList.at(idx).camera_name.c_str(), pqxList->qxList.at(idx).blobIdx, CheckUtil::GetRectString(pqxList->qxList.at(idx).product_roi).c_str()); continue; } pqxList->qxList.at(idx).result = 1; QX_RESULT tem; tem.blobIdx = pqxList->qxList.at(idx).blobIdx; tem.mindis = pqxList->qxList.at(idx).fmindis; tem.flen = pqxList->qxList.at(idx).length; tem.error_Type = pqxList->qxList.at(idx).nqx_type; tem.camera_name = pqxList->qxList.at(idx).camera_name; tem.channel_name = pqxList->qxList.at(idx).channel_name; pqxList->pChannelDetlog->AddCheckstr(PrintLevel_4, 3, "result = NG", "Add New qx,Blob idx %d type %d num %d dis %f len %f ", tem.blobIdx, tem.error_Type, tem.qx_Num, tem.mindis, tem.flen); m_pMergedetlog->AddCheckstr(PrintLevel_4, 3, "result = NG", "%s Add New qx,Blob idx %d type %d num %d dis %f len %f ", tem.channel_name.c_str(), tem.blobIdx, tem.error_Type, tem.qx_Num, tem.mindis, tem.flen); m_reultList.resultList.push_back(tem); } } } return 0; } ChannelCheckFunction *QX_Merge_Analysis::GetChannelFuntion(std::string strChannelName) { ChannelCheckFunction *p = NULL; for (int i = 0; i < m_pChannelFuntion->channelFunctionArr.size(); i++) { if (CheckUtil::compareIgnoreCase(m_pChannelFuntion->channelFunctionArr[i].strChannelName, strChannelName)) { p = &m_pChannelFuntion->channelFunctionArr[i]; } } return p; } double QX_Merge_Analysis::DistanceBetweenRectCenters(const cv::Rect &rect1, const cv::Rect &rect2, float fx, float fy) { // 计算矩形1的中心点 cv::Point center1(rect1.x + rect1.width / 2, rect1.y + rect1.height / 2); // 计算矩形2的中心点 cv::Point center2(rect2.x + rect2.width / 2, rect2.y + rect2.height / 2); center1.x *= fx; center1.y *= fy; center2.x *= fx; center2.y *= fy; // 计算中心点之间的欧几里得距离 double distance = cv::norm(center1 - center2); return distance; }