|
|
|
@ -14,6 +14,9 @@
|
|
|
|
#include "AlignShare.h"
|
|
|
|
#include "AlignShare.h"
|
|
|
|
#include <algorithm>
|
|
|
|
#include <algorithm>
|
|
|
|
#include <cctype>
|
|
|
|
#include <cctype>
|
|
|
|
|
|
|
|
#include <cstdlib>
|
|
|
|
|
|
|
|
#include <fstream>
|
|
|
|
|
|
|
|
#include <map>
|
|
|
|
|
|
|
|
|
|
|
|
// AI缺陷分类模型开关:当前暂无分类模型(Class.engine),分类流程代码先预留;
|
|
|
|
// AI缺陷分类模型开关:当前暂无分类模型(Class.engine),分类流程代码先预留;
|
|
|
|
// 待分类模型部署后,将 AI_CLASS_MODEL_ENABLE 置 1,即可恢复 AI_QX_Class_Thread 中的AI分类流程
|
|
|
|
// 待分类模型部署后,将 AI_CLASS_MODEL_ENABLE 置 1,即可恢复 AI_QX_Class_Thread 中的AI分类流程
|
|
|
|
@ -27,6 +30,165 @@
|
|
|
|
#define HANDLE_NEAR_EXPAND_RATIO 5
|
|
|
|
#define HANDLE_NEAR_EXPAND_RATIO 5
|
|
|
|
// 把手缺失检测开关见 Base层 Function_Support_Det::bDetHandle(CheckConfigDefine.h)
|
|
|
|
// 把手缺失检测开关见 Base层 Function_Support_Det::bDetHandle(CheckConfigDefine.h)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 分类映射配置文件(每行:label索引:缺陷名称;冒号后名称为该缺陷类型名称,行的顺序即缺陷类型索引)
|
|
|
|
|
|
|
|
static const std::string CLS_LABEL_CONFIG_FILE = "/home/aidlux/BOE/UseModel_ZB/BM_cls.txt";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 去掉字符串首尾的空白字符和引号
|
|
|
|
|
|
|
|
static std::string ClsTrimStr(const std::string &str)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
size_t begin = str.find_first_not_of(" \t\r\n\"");
|
|
|
|
|
|
|
|
if (begin == std::string::npos)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
return "";
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t end = str.find_last_not_of(" \t\r\n\"");
|
|
|
|
|
|
|
|
return str.substr(begin, end - begin + 1);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 组装程序内默认缺陷名称列表(AI_CLass_QX_NAME_Names)
|
|
|
|
|
|
|
|
static std::vector<std::string> BuildDefaultAIQXNames()
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
std::vector<std::string> vecNames;
|
|
|
|
|
|
|
|
for (int i = 0; i < AI_CLass_QX_NAME_count; i++)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
vecNames.push_back(AI_CLass_QX_NAME_Names[i]);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return vecNames;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 分类映射配置:缺陷名称列表(索引=行序) + 分类label->缺陷名称 映射
|
|
|
|
|
|
|
|
struct ClsLabelConfig
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
std::vector<std::string> vecNames; // 缺陷名称列表
|
|
|
|
|
|
|
|
std::map<int, std::string> mapLabelName; // 分类 label -> 缺陷名称
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 读取分类映射配置(每行:label索引:缺陷名称;冒号后名称按行序构成缺陷名称列表;# 后内容忽略)
|
|
|
|
|
|
|
|
static ClsLabelConfig ReadClsLabelConfig(const std::string &strFilePath)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
ClsLabelConfig config;
|
|
|
|
|
|
|
|
std::ifstream ifs(strFilePath.c_str());
|
|
|
|
|
|
|
|
if (!ifs.is_open())
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
printf("Open cls label config failed, use default mapping: %s\n", strFilePath.c_str());
|
|
|
|
|
|
|
|
return config;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
std::string strLine;
|
|
|
|
|
|
|
|
while (std::getline(ifs, strLine))
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
// # 后内容(含注释)忽略
|
|
|
|
|
|
|
|
size_t nPosComment = strLine.find('#');
|
|
|
|
|
|
|
|
if (nPosComment != std::string::npos)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
strLine = strLine.substr(0, nPosComment);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t nPos = strLine.find(':');
|
|
|
|
|
|
|
|
if (nPos == std::string::npos)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
// 无冒号:非标准行,跳过并提示(仅支持 label索引:缺陷名称 格式)
|
|
|
|
|
|
|
|
std::string strTrim = ClsTrimStr(strLine);
|
|
|
|
|
|
|
|
if (!strTrim.empty())
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
printf("Cls label config skip invalid line: %s\n", strTrim.c_str());
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// label索引:缺陷名称(冒号后名称按行序构成缺陷名称列表)
|
|
|
|
|
|
|
|
std::string strKey = ClsTrimStr(strLine.substr(0, nPos));
|
|
|
|
|
|
|
|
std::string strValue = ClsTrimStr(strLine.substr(nPos + 1));
|
|
|
|
|
|
|
|
if (!strKey.empty() && !strValue.empty())
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
config.mapLabelName[atoi(strKey.c_str())] = strValue;
|
|
|
|
|
|
|
|
config.vecNames.push_back(strValue); // 行序即缺陷类型索引
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return config;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 获取分类映射配置(只读一次)
|
|
|
|
|
|
|
|
static const ClsLabelConfig &GetClsLabelConfig()
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
static const ClsLabelConfig config = ReadClsLabelConfig(CLS_LABEL_CONFIG_FILE);
|
|
|
|
|
|
|
|
return config;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 获取缺陷名称列表:优先取配置文件的名称列表,读不到用程序内默认列表
|
|
|
|
|
|
|
|
static const std::vector<std::string> &GetAIQXNameList()
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
static const std::vector<std::string> vecDefaultNames = BuildDefaultAIQXNames();
|
|
|
|
|
|
|
|
const ClsLabelConfig &config = GetClsLabelConfig();
|
|
|
|
|
|
|
|
if (!config.vecNames.empty())
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
return config.vecNames;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return vecDefaultNames;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 缺陷名称 -> AI_CLass 枚举(找不到返回 count 表示无效)
|
|
|
|
|
|
|
|
static int ClsNameToAItype(const std::string &strName)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
const std::vector<std::string> &vecNames = GetAIQXNameList();
|
|
|
|
|
|
|
|
for (size_t i = 0; i < vecNames.size(); i++)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if (strName == vecNames[i])
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
return (int)i;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return AI_CLass_QX_NAME_count;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 解析 label->缺陷名称 映射为 label->AI_CLass枚举(只读一次;无效名称仅提示一次)
|
|
|
|
|
|
|
|
static std::map<int, int> BuildLabelTypeMap()
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
const ClsLabelConfig &config = GetClsLabelConfig();
|
|
|
|
|
|
|
|
std::map<int, int> mapLabelType;
|
|
|
|
|
|
|
|
for (std::map<int, std::string>::const_iterator it = config.mapLabelName.begin(); it != config.mapLabelName.end(); ++it)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
int nType = ClsNameToAItype(it->second);
|
|
|
|
|
|
|
|
if (nType < AI_CLass_QX_NAME_count)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
mapLabelType[it->first] = nType;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
printf("Cls label config unknown name: %s\n", it->second.c_str());
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return mapLabelType;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 获取分类 label 对应的 AI 缺陷类型:优先配置文件(只读一次),读不到用默认顺序
|
|
|
|
|
|
|
|
static int GetClsTypeByLabel(int nLabel)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
static const std::map<int, int> mapLabelType = BuildLabelTypeMap();
|
|
|
|
|
|
|
|
std::map<int, int>::const_iterator it = mapLabelType.find(nLabel);
|
|
|
|
|
|
|
|
if (it != mapLabelType.end())
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
return it->second;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 映射文件未读到、或该 label 未在文件中配置时,按程序内默认顺序兜底(避免文件缺失/不全导致异常)
|
|
|
|
|
|
|
|
int cls_num = AI_CLass_QX_NAME_count;
|
|
|
|
|
|
|
|
switch (nLabel)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
case 0:
|
|
|
|
|
|
|
|
cls_num = AI_CLass_QX_NAME_CGMark;
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 1:
|
|
|
|
|
|
|
|
cls_num = AI_CLass_QX_NAME_BQBMark;
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 2:
|
|
|
|
|
|
|
|
cls_num = AI_CLass_QX_NAME_TBMark;
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
|
|
cls_num = AI_CLass_QX_NAME_CGMark;
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return cls_num;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 用于排序轮廓的比较函数
|
|
|
|
// 用于排序轮廓的比较函数
|
|
|
|
static bool compareContourAreas(const vector<Point> &contour1, const vector<Point> &contour2)
|
|
|
|
static bool compareContourAreas(const vector<Point> &contour1, const vector<Point> &contour2)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
@ -2165,27 +2327,9 @@ int ImgCheckAnalysisy::AI_QX_Class_Thread()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
int temClass = result->cls_label;
|
|
|
|
int temClass = result->cls_label;
|
|
|
|
int cls_num = 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 分类模型label顺序:0-把手标记(CGMark) 1-补强板标记(BQBMark) 2-铜箔标记(TBMark)
|
|
|
|
|
|
|
|
switch (temClass)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
case 0:
|
|
|
|
|
|
|
|
cls_num = AI_CLass_QX_NAME_CGMark;
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case 1:
|
|
|
|
// 分类 label 映射:优先读映射配置文件(BM_cls.txt),读不到用默认顺序
|
|
|
|
cls_num = AI_CLass_QX_NAME_BQBMark;
|
|
|
|
int cls_num = GetClsTypeByLabel(temClass);
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case 2:
|
|
|
|
|
|
|
|
cls_num = AI_CLass_QX_NAME_TBMark;
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
|
|
cls_num = AI_CLass_QX_NAME_CGMark;
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// std::string strclassName = AI_CLass_QX_NAME_Names[cls_num];
|
|
|
|
// std::string strclassName = AI_CLass_QX_NAME_Names[cls_num];
|
|
|
|
// printf("AI Class num %d = %s %f\n", cls_num, strclassName.c_str(), result->cls_score);
|
|
|
|
// printf("AI Class num %d = %s %f\n", cls_num, strclassName.c_str(), result->cls_score);
|
|
|
|
@ -2480,6 +2624,9 @@ int ImgCheckAnalysisy::AIClassTypeToConfigType(int nAIQXType)
|
|
|
|
case AI_CLass_QX_NAME_TBMark:
|
|
|
|
case AI_CLass_QX_NAME_TBMark:
|
|
|
|
resultError_type = CONFIG_QX_NAME_cell_TBMark;
|
|
|
|
resultError_type = CONFIG_QX_NAME_cell_TBMark;
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case AI_CLass_QX_NAME_count: // 无效类别(分类映射配置中不存在):不参与缺陷分析
|
|
|
|
|
|
|
|
resultError_type = CONFIG_QX_NAME_count;
|
|
|
|
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@ -2516,6 +2663,13 @@ int ImgCheckAnalysisy::BLobToDetResult()
|
|
|
|
roi.height = blobs.blobTab[i].maxy - blobs.blobTab[i].miny + 1;
|
|
|
|
roi.height = blobs.blobTab[i].maxy - blobs.blobTab[i].miny + 1;
|
|
|
|
|
|
|
|
|
|
|
|
int config_qx_type = blobs.blobTab[i].AIclasstype;
|
|
|
|
int config_qx_type = blobs.blobTab[i].AIclasstype;
|
|
|
|
|
|
|
|
if (config_qx_type < 0 || config_qx_type >= CONFIG_QX_NAME_count)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
// AI 分类无对应缺陷类型(无效类别)时,不参与缺陷结果分析
|
|
|
|
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "BLobToDetResult",
|
|
|
|
|
|
|
|
"blob idx %d invalid AIclasstype %d skip", i, config_qx_type);
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
float JudgArea = blobs.blobTab[i].JudgArea;
|
|
|
|
float JudgArea = blobs.blobTab[i].JudgArea;
|
|
|
|
float fsecondArea = JudgArea;
|
|
|
|
float fsecondArea = JudgArea;
|
|
|
|
|