|
|
#include "QX_Merge_Analysis.h"
|
|
|
#include <memory>
|
|
|
#include <string>
|
|
|
#include <mutex>
|
|
|
#include <thread>
|
|
|
#include <chrono>
|
|
|
#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> QX_Merge_Analysis::GetInstance()
|
|
|
{
|
|
|
std::shared_ptr<QX_Merge_Analysis> instance = std::make_shared<QX_Merge_Analysis>();
|
|
|
return instance;
|
|
|
}
|
|
|
int QX_Merge_Analysis::Clear()
|
|
|
{
|
|
|
m_pdetlogList.clear();
|
|
|
m_statusList.clear();
|
|
|
{
|
|
|
std::lock_guard<std::mutex> 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<std::mutex> lock(mtx_correlatedQx);
|
|
|
m_correlatedQxMap.clear();
|
|
|
}
|
|
|
m_pMergedetlog = std::make_shared<DetLog>();
|
|
|
m_pMergedetlog->AddCheckstr(PrintLevel_2, 3, "QX_Merge_Analysis", "InitData %s",CheckUtil::getCurTimeHMS().c_str());
|
|
|
|
|
|
{
|
|
|
std::lock_guard<std::mutex> 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<std::mutex> 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<std::mutex> 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<DetLog> plog, std::shared_ptr<DetLog> pchannelLog)
|
|
|
{
|
|
|
std::string channel_name = qxinfo.channel_name;
|
|
|
std::string cam_name = qxinfo.camera_name;
|
|
|
ALL_QX_ParamList *pconfigList = nullptr;
|
|
|
{
|
|
|
std::lock_guard<std::mutex> 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<std::mutex> 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<std::mutex> 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<std::mutex> 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<DetLog> plog)
|
|
|
{
|
|
|
// 防御:通道为空或ROI非法时不登记,避免无效数据参与后续判断
|
|
|
if (qxinfo.channel_name == "" || qxinfo.product_roi.width <= 0 || qxinfo.product_roi.height <= 0)
|
|
|
{
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
{
|
|
|
std::lock_guard<std::mutex> lock(mtx_correlatedQx);
|
|
|
std::vector<Correlated_Qx_Info_> &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<std::string> &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<DetLog> 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<Correlated_Qx_Info_> dirtyList;
|
|
|
{
|
|
|
std::lock_guard<std::mutex> 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<std::mutex> 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::milliseconds>(
|
|
|
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<std::mutex> 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::thread>(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<DetLog> pchannelLog)
|
|
|
{
|
|
|
// AD 单通道参数判定受 merge_analysy_region_sf 通道过滤约束
|
|
|
if (qx_type == QX_ANALYSIS_AD && m_pbaseCheckFunction)
|
|
|
{
|
|
|
std::vector<std::string> 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<string> merge_analysy_s_sf = pAd_checkParma->analysis_sf.s_sf;
|
|
|
vector<string> main_channel_2s = pAd_checkParma->analysis_bind.main_channel_2s;
|
|
|
vector<string> second_channel_2s = pAd_checkParma->analysis_bind.second_channel_2s;
|
|
|
vector<string> main_channel_3s = pAd_checkParma->analysis_bind.main_channel_3s;
|
|
|
vector<string> second_channel_3s = pAd_checkParma->analysis_bind.second_channel_3s;
|
|
|
/* 获取关联通道 */
|
|
|
vector<string> 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<QX_channel_List> main_channel_s_qxList;
|
|
|
vector<QX_channel_List> 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<AD_Channel_BD_Info_> 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<string, AD_Channel_Stat_> 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;
|
|
|
} |