Compare commits

..

3 Commits

@ -103,6 +103,7 @@ public:
int ncamId; // 相机ID
BaseCheckFunction *pBaseCheckFunction;
std::string strChannel; // 通道
std::string strProductID; // 产品ID(定位存图文件名首位)
int nthresholdvalue; // 背景阈值
int nAIErodesize; // 边缘腐蚀强度
bool bSaveResultImg; // 保存结果图片
@ -118,6 +119,7 @@ public:
void Init()
{
pBaseCheckFunction = NULL;
strProductID = "";
ncamId = 0;
nthresholdvalue = 1;
nAIErodesize = 7;

@ -80,8 +80,18 @@ public:
// 抠出掩膜四周的凸起:主体近似矩形,凸起在该边表现为边界值的一次突变(进入)与一次反向突变(离开)
// binMask:掩膜(非零为前景,兼容 0/1 与 0/255);protrusions:输出的凸起列表
// nJumpThresh:边界突变阈值(输入图像素);nMinRun:凸起最小长度(输入图像素);nMinDepth:凸起最小深度(输入图像素)
// nMaxRun:凸起最大长度(输入图像素),<=0 时取 掩膜短边/3
// 参数调整影响(nJumpThresh/nMinRun/nMinDepth 为输入图像素,内部按降采样比例 nScale(1/2/4) 缩小后使用;nMaxRun 不换算,直接用工作图像素):
// nJumpThresh:边界突变阈值,相邻行/列边界值一次变化超过它才算"进入/离开"台阶;
// 调大:只认陡峭台阶,圆角/噪声/锯齿被过滤,过大时边缘圆滑的真把手会漏检;
// 调小:敏感,噪声/斜边易触发假配对(可能形成跨度很大的假凸起)。
// nMinRun:凸起最小长度("离开"突变搜索从 s+nMinRun 开始;profile 比它短的边直接跳过);
// 调大:短凸起被排除,若大于真把手长度,真"离开"突变被跳过、会配到更远突变 → 出更大的框;
// 调小:小抖动/碎框变多。
// nMinDepth:凸起最小深度,区间内 ≥80% 采样点相对首尾连线基线外偏 ≥ 它(且最大外偏 ≥ 它)才保留(滤斜边/圆角);
// 调大:只保留明显凸出的,浅凸起漏检,可挡"浅而长"的假配对;
// 调小:浅波纹/边缘抖动也过检,假凸起变多。
// nMaxRun:凸起最大长度(框沿边长度的硬上限);<=0 时取 max(100, 掩膜短边/3)(工作图像素);
// 调大:允许远距离突变配对 → 会出"覆盖整边"的大框;调小:框被截短,小于真把手长度时真把手漏检。
// 返回:0 成功、1 掩膜为空、2 无有效前景
static int GetMaskProtrusions(const cv::Mat &binMask, std::vector<Mask_Protrusion_> &protrusions,
int nJumpThresh = 40, int nMinRun = 40, int nMinDepth = 40, int nMaxRun = 0);

@ -79,6 +79,45 @@ struct Handle_Region_Result_
}
};
// 支架偏移检测的绘制信息(CheckRun 支架块计算 -> DrawResult_Step_1 绘制)
// 坐标均为原图坐标,绘制时经 m_matSrc2Det 映射到检测图后再缩放到结果图
struct Support_Draw_Info_
{
// 参与判定的单个方向:实测/标准距离 + 是否超标准(超标准画红色)
struct Edge_Draw_
{
std::string strEdge; // left/right/up/down
float fDist; // 实测距离(原图像素)
float fStandard; // 标准距离(原图像素)
bool bExceed; // |fDist-fStandard| 超限差(x_offset) -> 红色
Edge_Draw_()
{
fDist = 0.0f;
fStandard = 0.0f;
bExceed = false;
}
};
bool bValid; // 本次是否有效计算出支架偏移几何
bool bOffset; // 是否判偏移 NG(十字颜色:红=NG)
cv::Rect rpRect; // 产品区域外接矩形(原图坐标)
cv::Rect rsRect; // 支架区域外接矩形(原图坐标)
cv::Point2f ptCenter; // 支架中心(原图坐标)
std::vector<Edge_Draw_> edgeList; // 各参与判定方向的绘制信息
Support_Draw_Info_()
{
Reset();
}
void Reset()
{
bValid = false;
bOffset = false;
rpRect = cv::Rect(0, 0, 0, 0);
rsRect = cv::Rect(0, 0, 0, 0);
ptCenter = cv::Point2f(0.0f, 0.0f);
edgeList.clear();
}
};
class ImgCheckAnalysisy : public ImgCheckBase
{
@ -348,6 +387,8 @@ private:
bool m_bHandleDetSucc; // 本次是否完成把手检测
bool m_bHandleFound; // 所有非空把手区域是否都找到了把手
bool m_bHandleExpect; // 是否开启了把手缺失检测(且有非空把手区域)
// 支架偏移检测的绘制信息(CheckRun 支架块填充,DrawResult_Step_1 绘制)
Support_Draw_Info_ m_SupportDrawInfo;
};
#endif

@ -185,8 +185,8 @@ AI_Edge_Algin::AI_Edge_Algin(std::shared_ptr<DetLog> &log_ref)
m_bModelSucc = false;
m_bModel_Mark_Succ = false;
m_bshowimg = false;
m_strRootPath_Big = "/home/aidlux/BOE/Algin/";
m_strRootPath_Mark = "/home/aidlux/BOE/MarkLine/";
m_strRootPath_Big = "/home/aidlux/BOE/Algin/BM/";
m_strRootPath_Mark = "/home/aidlux/BOE/MarkLine/BM/";
creatsavedir();
std::string m_strSavePath;
@ -414,19 +414,13 @@ int AI_Edge_Algin::Get_Edge(int AIModel_type, const cv::Mat &img, DetConfig *pDe
if (pDetConfig->pBaseCheckFunction->saveImg.bSaveAlginImg)
{
creatsavedir();
static int sdk = 0;
std::string str = m_strSavePath_Big + std::to_string(sdk) + "_" + pDetConfig->strChannel + "_Img.png";
// 定位存图文件名:{产品ID}_{通道}_{模型序号(0大/1小/2Tag)}_Img(_mask).png
std::string str = m_strSavePath_Big + pDetConfig->strProductID + "_" + pDetConfig->strChannel + "_" + std::to_string(AIModel_type) + "_Img.png";
int sr = m_pImageStorage->addImage(str, detImg);
if (sr == 0)
{
str = m_strSavePath_Big + std::to_string(sdk) + "_" + pDetConfig->strChannel + "_Img_mask.png";
str = m_strSavePath_Big + pDetConfig->strProductID + "_" + pDetConfig->strChannel + "_" + std::to_string(AIModel_type) + "_Img_mask.png";
int sr = m_pImageStorage->addImage(str, mask, true);
sdk++;
if (sdk > 99999)
{
sdk = 0;
/* code */
}
}
}

@ -892,32 +892,9 @@ int ImageResultJudge::DrawResult(std::shared_ptr<ImageAllResult> pImageResult)
draw_str->txtP = cv::Point(draw_qx->cp.x + r, draw_qx->cp.y - r);
draw_str->txtsize = 0.5;
draw_str->txtbackgroundk = txtbackgroundk;
cv::Rect srcroi = pqx->srcImgroi;
cv::Point srccp = cv::Point(srcroi.x + srcroi.width * .5, srcroi.y + srcroi.height * 0.5);
char buffer[128];
{
std::string text = std::to_string(pqx->idx) + ":" + pqx->strTypeName;
draw_str->strlist.push_back(text);
}
{
sprintf(buffer, " center:%d %d", srccp.x, srccp.y);
std::string text = buffer;
draw_str->strlist.push_back(text);
}
{
sprintf(buffer, " len %0.2f A: %0.2f ", pqx->len, pqx->area);
std::string text = buffer;
draw_str->strlist.push_back(text);
}
{
sprintf(buffer, " breadth %0.2f A: %0.2f ", pqx->breadth, pqx->area);
std::string text = buffer;
draw_str->strlist.push_back(text);
}
{
sprintf(buffer, " E:%0.2f hj %0.2f", pqx->energy, pqx->hj);
std::string text = buffer;
// 只绘制 id:缺陷code (缺陷名可能中文乱码, 用code替代)
std::string text = std::to_string(pqx->idx) + ":" + pqx->qx_Code;
draw_str->strlist.push_back(text);
}
sendTask(draw_str);

@ -25,7 +25,7 @@
#define HANDLE_SIZE_MAX_RATIO 1.2f
// "附近"的搜索范围:把手区域外接矩形在宽/高方向各外扩该比例
#define HANDLE_NEAR_EXPAND_RATIO 5
// 把手缺失检测开关见 Function_Support_Det::bDetHandle(CheckConfigDefine.h)
// 把手缺失检测开关见 Base层 Function_Support_Det::bDetHandle(CheckConfigDefine.h)
// 用于排序轮廓的比较函数
static bool compareContourAreas(const vector<Point> &contour1, const vector<Point> &contour2)
@ -723,7 +723,6 @@ int ImgCheckAnalysisy::CheckRun()
long time_edge_s = CheckUtil::getcurTime();
m_pFuntion = GetChannelFuntion(m_strCurDetChannel);
int nfunction = 0;
if (m_pFuntion != NULL)
{
m_pdetlog->AddCheckstr(PrintLevel_0, "Detect function", "%s",
@ -731,12 +730,8 @@ int ImgCheckAnalysisy::CheckRun()
}
else
{
nfunction = 1;
m_pdetlog->AddCheckstr(PrintLevel_0, "Error", "m_pFuntion is NULL");
PublishAlignShare(false); // 本图不会产出定位结果,通知可能的等待方(暗场复用)
m_nErrorCode = 22;
m_nCheckResultErrorCode = m_nErrorCode;
return m_nErrorCode;
// 通道层允许为空(仅打印,不再按错误处理)
m_pdetlog->AddCheckstr(PrintLevel_0, "Detect function", "no channel config, use base function only");
}
/*AI 边缘定位(内外边缘)*/
@ -764,7 +759,7 @@ int ImgCheckAnalysisy::CheckRun()
}
// 标签检测(独立步骤):暗场图像 + 明场 bigmask(不再沿用明场检出的标签);bDetTag 关闭时跳过
{
if (m_pFuntion->function.f_supportDet.bDetTag)
if (m_pbaseCheckFunction->supportDet.bDetTag)
{
long tag_s = CheckUtil::getcurTime();
int reTag = CheckTagByBigMask(m_CheckResult_shareP->in_shareImage->img, m_pEdge_Align_Result->bigmask);
@ -895,8 +890,9 @@ int ImgCheckAnalysisy::CheckRun()
3、按 edge_select 指定方向(left/right/up/down)计算 rs 中心到 rp 对应边缘的距离
4、计算值与标准值(x_standard/y_standard)做差取平均,平均差超过 offset(x_offset) → 偏移 */
{
Function_Support_Det &supportDet = m_pFuntion->function.f_supportDet;
if (supportDet.bOpen && supportDet.bDetSupport)
Function_Support_Det &supportDet = m_pbaseCheckFunction->supportDet;
m_SupportDrawInfo.Reset(); // 清空本帧绘制信息(未开启/计算无效时不绘制)
if (supportDet.bDetSupport)
{
const cv::Mat &bigmask = m_pEdge_Align_Result->bigmask;
const cv::Mat &smallmask = m_pEdge_Align_Result->smallmask;
@ -1013,6 +1009,15 @@ int ImgCheckAnalysisy::CheckRun()
float fDiff = fabs(fDist - fStandard);
fSumDiff += fDiff;
nDiffNum++;
// 记录该方向绘制信息:|实测-标准|超限差(x_offset)则绘制为红色
{
Support_Draw_Info_::Edge_Draw_ edgeDraw;
edgeDraw.strEdge = strEdge;
edgeDraw.fDist = fDist;
edgeDraw.fStandard = fStandard;
edgeDraw.bExceed = (fDiff > supportDet.x_offset);
m_SupportDrawInfo.edgeList.push_back(edgeDraw);
}
sprintf(strTmp, "%s(%.1f/%.1f) ", strEdge.c_str(), fDist, fStandard);
strSelect += strTmp;
sprintf(strTmp, "%.1f ", fDiff);
@ -1022,6 +1027,13 @@ int ImgCheckAnalysisy::CheckRun()
float fAvgDiff = (nDiffNum > 0) ? (fSumDiff / nDiffNum) : 0.0f;
bool bOffset = (nDiffNum > 0) && (fAvgDiff > supportDet.x_offset);
// 记录绘制信息(DrawResult_Step_1 用):支架中心十字 + 各方向距离
m_SupportDrawInfo.bValid = true;
m_SupportDrawInfo.bOffset = bOffset;
m_SupportDrawInfo.rpRect = rpRect;
m_SupportDrawInfo.rsRect = rsRect;
m_SupportDrawInfo.ptCenter = cv::Point2f(fCx, fCy);
m_pdetlog->AddCheckstr(PrintLevel_0, "支架检测",
"rp [%d %d %d %d] rs [%d %d %d %d] scale (%.4f %.4f) center (%.1f %.1f) dL %.1f dR %.1f dT %.1f dB %.1f | select %s diff %s avgDiff %.1f limit %.1f ng %d",
rpRect.x, rpRect.y, rpRect.width, rpRect.height,
@ -1138,7 +1150,7 @@ int ImgCheckAnalysisy::CheckRun()
/* Tag检测(bDetTag 关闭时不上报标签 NG) */
{
if (!m_pFuntion->function.f_supportDet.bDetTag)
if (!m_pbaseCheckFunction->supportDet.bDetTag)
{
m_tag_roiList.clear();
}
@ -2045,6 +2057,16 @@ int ImgCheckAnalysisy::AI_Detect_Thread(const cv::Mat &img, cv::Mat &ResultImg)
m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, strBaseLog, "AI_Detect End");
if (m_pbaseCheckFunction->saveImg.bSaveAIDetImg && !ResultImg.empty())
{
std::string strSaveDir = "/home/aidlux/BOE/AI_Detect/KK/" + DetImgInfo_shareP->strImgProductID + "/";
CheckUtil::CreateDir(strSaveDir);
std::string strSavePath_in = strSaveDir + m_strCurDetChannel + "_in.png";
std::string strSavePath_out = strSaveDir + m_strCurDetChannel + "_out.png";
cv::imwrite(strSavePath_in, inputImg);
cv::imwrite(strSavePath_out, ResultImg);
}
// 临时存图
if (DetImgInfo_shareP->bsaveProcessImg)
{
@ -2338,21 +2360,7 @@ int ImgCheckAnalysisy::DrawResult_Step_1()
float fs_resize_y = m_pImageAllResult->resultImg.rows * 1.0f / m_pImageAllResult->detImg.rows;
// 绘制m_inner_rroi(蓝色),原图坐标 -> 检测图(裁剪) -> 结果图
{
cv::Point2f vertices[4];
m_inner_rroi.points(vertices);
std::vector<cv::Point> draw_pts;
draw_pts.reserve(4);
for (int i = 0; i < 4; i++)
{
cv::Point2f detPt = MatAffinePoint(m_matSrc2Det, vertices[i]);
draw_pts.emplace_back(cvRound(detPt.x * fs_resize_x),
cvRound(detPt.y * fs_resize_y));
}
cv::polylines(m_CheckResult_shareP->resultimg, draw_pts, true,
CheckUtil::GetDrawColor(m_CheckResult_shareP->resultimg, cv::Scalar(255, 0, 0)), 1);
}
// 注:不再绘制 inner 定位蓝色框(m_inner_rroi 为大轮廓裁剪子图局部坐标,直接映射会缺裁剪原点偏移)
if (m_pbaseCheckFunction && m_pbaseCheckFunction->markLine.region.size() > 1)
{
@ -2395,6 +2403,63 @@ int ImgCheckAnalysisy::DrawResult_Step_1()
}
}
// 支架偏移检测绘制:支架中心十字(绿=正常/红=偏移NG)+ 支架到边缘的距离(绿=正常/红=超标准)
if (m_SupportDrawInfo.bValid && !m_CheckResult_shareP->resultimg.empty())
{
// 支架中心:原图坐标 -> 检测图(裁剪) -> 结果图
cv::Point2f detPt = MatAffinePoint(m_matSrc2Det, m_SupportDrawInfo.ptCenter);
cv::Point pCenter(cvRound(detPt.x * fs_resize_x), cvRound(detPt.y * fs_resize_y));
// 支架中心十字:NG 红色 / 正常绿色
cv::Scalar colorCross = m_SupportDrawInfo.bOffset ? cv::Scalar(0, 0, 255) : cv::Scalar(0, 255, 0);
colorCross = CheckUtil::GetDrawColor(m_CheckResult_shareP->resultimg, colorCross);
const int nCrossLen = 40; // 结果图上十字半长(px)
cv::line(m_CheckResult_shareP->resultimg, cv::Point(pCenter.x - nCrossLen, pCenter.y), cv::Point(pCenter.x + nCrossLen, pCenter.y), colorCross, 2);
cv::line(m_CheckResult_shareP->resultimg, cv::Point(pCenter.x, pCenter.y - nCrossLen), cv::Point(pCenter.x, pCenter.y + nCrossLen), colorCross, 2);
// 支架到边缘的距离:中心 -> 产品区域对应边缘连线 + 实测/标准(像素)文字
char strTxt[64];
for (size_t i = 0; i < m_SupportDrawInfo.edgeList.size(); i++)
{
const Support_Draw_Info_::Edge_Draw_ &edgeDraw = m_SupportDrawInfo.edgeList[i];
cv::Point2f ptEdge = m_SupportDrawInfo.ptCenter;
if (edgeDraw.strEdge == "left")
{
ptEdge.x = (float)m_SupportDrawInfo.rpRect.x;
}
else if (edgeDraw.strEdge == "right")
{
ptEdge.x = (float)(m_SupportDrawInfo.rpRect.x + m_SupportDrawInfo.rpRect.width);
}
else if (edgeDraw.strEdge == "up")
{
ptEdge.y = (float)m_SupportDrawInfo.rpRect.y;
}
else if (edgeDraw.strEdge == "down")
{
ptEdge.y = (float)(m_SupportDrawInfo.rpRect.y + m_SupportDrawInfo.rpRect.height);
}
else
{
continue;
}
cv::Point2f detEdge = MatAffinePoint(m_matSrc2Det, ptEdge);
cv::Point pEdge(cvRound(detEdge.x * fs_resize_x), cvRound(detEdge.y * fs_resize_y));
// 超标准红色 / 正常绿色
cv::Scalar colorEdge = edgeDraw.bExceed ? cv::Scalar(0, 0, 255) : cv::Scalar(0, 255, 0);
colorEdge = CheckUtil::GetDrawColor(m_CheckResult_shareP->resultimg, colorEdge);
cv::line(m_CheckResult_shareP->resultimg, pCenter, pEdge, colorEdge, 2);
// 距离文字:实测/标准(原图像素)
snprintf(strTxt, sizeof(strTxt), "%s %.0f/%.0f", edgeDraw.strEdge.c_str(), edgeDraw.fDist, edgeDraw.fStandard);
cv::putText(m_CheckResult_shareP->resultimg, strTxt,
cv::Point((pCenter.x + pEdge.x) / 2 + 6, (pCenter.y + pEdge.y) / 2 - 6),
cv::FONT_HERSHEY_SIMPLEX, 0.8, colorEdge, 2);
}
}
// cv::imwrite("sss.png", m_CheckResult_shareP->resultimg);
return 0;
}
@ -2536,7 +2601,8 @@ int ImgCheckAnalysisy::AI_Edge(const cv::Mat &img, cv::RotatedRect &outerRoi, cv
}
config.strChannel = DetImgInfo_shareP->strChannel;
config.pBaseCheckFunction = m_pbaseCheckFunction;
config.bDetTag = m_pFuntion->function.f_supportDet.bDetTag; // 标签检测开关:关闭时不跑 Tag_Loc
config.bDetTag = m_pbaseCheckFunction->supportDet.bDetTag; // 标签检测开关:关闭时不跑 Tag_Loc
config.strProductID = DetImgInfo_shareP->strImgProductID; // 定位存图文件名首位使用产品ID
/* 定位获取三个roi */
int re = m_pAI_Edge_Algin.Detect(img, &config, m_pEdge_Align_Result);
@ -2598,9 +2664,9 @@ int ImgCheckAnalysisy::CheckHandleByBigMask(const cv::Mat &bigmask)
// 2、把手检测开关 + 把手区域(最多4个,非空区域表示该处应该有一个把手)
bool bDetHandle = false;
std::vector<cv::Rect> regionBoxList;
if (m_pFuntion != NULL)
if (m_pbaseCheckFunction != NULL)
{
const Function_Support_Det &supportDet = m_pFuntion->function.f_supportDet;
const Function_Support_Det &supportDet = m_pbaseCheckFunction->supportDet;
bDetHandle = supportDet.bDetHandle;
for (size_t i = 0; i < supportDet.handleBoxes.size() && i < HANDLE_REGION_MAX_NUM; i++)
{

@ -919,26 +919,28 @@ struct Function_Image_Align
// 把手区域最大数量(参数里最多可画4个把手区域)
#define HANDLE_REGION_MAX_NUM 4
// 支架检测
struct Function_Support_Det
{
bool bOpen; // 是否开启
// 支架参数
bool bDetSupport;
std::vector<cv::Point> supportRegion;
cv::RotatedRect supportRect;
// 支架参数(Support_Detect)
bool bDetSupport; // 支架偏位检测开关(Support_Detect.isOpen)
float x_standard; // 水平方向标准距离(left/right 用)
float y_standard; // 垂直方向标准距离(up/down 用)
std::vector<std::string> edge_select; // 参与计算的方向:up/down/left/right
float x_offset;
float y_offset;
float r_offset;
// 把手参数(Handle_Detect)
bool bDetHandle; // 把手缺失检测开关(Handle_Detect.isOpen)
// 把手区域(最多 HANDLE_REGION_MAX_NUM 个,只保存非空的;区域宽高用于把手卡控)
bool bDetHandle; // 把手缺失检测开关
std::vector<std::vector<cv::Point>> handleRegions;
std::vector<cv::Rect> handleBoxes;
// 标签参数
bool bDetTag;
float handle_diff; // 把手差异阈值
// 标签参数(BQ_Detect)
bool bDetTag; // 标签检测开关(BQ_Detect.isOpen)
float BQ_area; // 标签检测参数:面积
float BQ_energy; // 标签检测参数:能量
float BQ_len; // 标签检测参数:长度
float BQ_hj; // 标签检测参数:灰阶
Function_Support_Det ()
{
@ -947,10 +949,7 @@ struct Function_Support_Det
void Init()
{
bOpen = false;
bDetSupport = false;
supportRegion.clear();
supportRect = cv::RotatedRect();
x_standard = 0;
y_standard = 0;
edge_select.clear();
@ -960,14 +959,16 @@ struct Function_Support_Det
bDetHandle = false;
handleRegions.clear();
handleBoxes.clear();
handle_diff = 20;
bDetTag = false;
BQ_area = 0;
BQ_energy = 0;
BQ_len = 0;
BQ_hj = 0;
}
void copy(Function_Support_Det tem)
{
this->bOpen = tem.bOpen;
this->bDetSupport = tem.bDetSupport;
this->supportRegion.assign(tem.supportRegion.begin(), tem.supportRegion.end());
this->supportRect = tem.supportRect;
this->x_standard = tem.x_standard;
this->y_standard = tem.y_standard;
this->edge_select.assign(tem.edge_select.begin(), tem.edge_select.end());
@ -977,18 +978,23 @@ struct Function_Support_Det
this->bDetHandle = tem.bDetHandle;
this->handleRegions.assign(tem.handleRegions.begin(), tem.handleRegions.end());
this->handleBoxes.assign(tem.handleBoxes.begin(), tem.handleBoxes.end());
this->handle_diff = tem.handle_diff;
this->bDetTag = tem.bDetTag;
this->BQ_area = tem.BQ_area;
this->BQ_energy = tem.BQ_energy;
this->BQ_len = tem.BQ_len;
this->BQ_hj = tem.BQ_hj;
}
void print(std::string str)
{
printf("%s>>bOpen %d bDetSupport %d bDetHandle %d bDetTag %d x_standard %f y_standard %f x_offset %f y_offset %f r_offset %f edge num %ld handleRegion num %ld\n",
str.c_str(), bOpen, bDetSupport, bDetHandle, bDetTag, x_standard, y_standard, x_offset, y_offset, r_offset, edge_select.size(), handleRegions.size());
printf("%s>>bDetSupport %d bDetHandle %d bDetTag %d x_standard %f y_standard %f x_offset %f y_offset %f r_offset %f edge num %ld handleRegion num %ld handle_diff %f BQ[area %f energy %f len %f hj %f]\n",
str.c_str(), bDetSupport, bDetHandle, bDetTag, x_standard, y_standard, x_offset, y_offset, r_offset, edge_select.size(), handleRegions.size(), handle_diff, BQ_area, BQ_energy, BQ_len, BQ_hj);
}
std::string GetInfo(std::string str)
{
char buffer[256];
sprintf(buffer, "%s>>bOpen %d bDetSupport %d bDetHandle %d bDetTag %d x_standard %f y_standard %f x_offset %f y_offset %f r_offset %f edge num %ld handleRegion num %ld\n",
str.c_str(), bOpen, bDetSupport, bDetHandle, bDetTag, x_standard, y_standard, x_offset, y_offset, r_offset, edge_select.size(), handleRegions.size());
char buffer[512];
sprintf(buffer, "%s>>bDetSupport %d bDetHandle %d bDetTag %d x_standard %f y_standard %f x_offset %f y_offset %f r_offset %f edge num %ld handleRegion num %ld handle_diff %f BQ[area %f energy %f len %f hj %f]\n",
str.c_str(), bDetSupport, bDetHandle, bDetTag, x_standard, y_standard, x_offset, y_offset, r_offset, edge_select.size(), handleRegions.size(), handle_diff, BQ_area, BQ_energy, BQ_len, BQ_hj);
std::string str123 = buffer;
return str123;
}
@ -1004,7 +1010,6 @@ struct CheckFunction
Function_ShieldRegion f_ShieldRegion;
Function_EdgeROI f_EdgeROI;
Function_Image_Align f_Image_Align; // 图片特征对齐
Function_Support_Det f_supportDet;
CheckFunction()
{
Init();
@ -1017,7 +1022,6 @@ struct CheckFunction
f_ShieldRegion.Init();
f_EdgeROI.Init();
f_Image_Align.Init();
f_supportDet.Init();
}
void copy(CheckFunction tem)
{
@ -1028,7 +1032,6 @@ struct CheckFunction
this->f_ShieldRegion.copy(tem.f_ShieldRegion);
this->f_EdgeROI.copy(tem.f_EdgeROI);
this->f_Image_Align.copy(tem.f_Image_Align);
this->f_supportDet.copy(tem.f_supportDet);
}
void print(std::string str)
{
@ -1039,7 +1042,6 @@ struct CheckFunction
f_ShieldRegion.print("ShieldRegion");
f_EdgeROI.print("EdgeROI");
f_Image_Align.print("Image_Align");
f_supportDet.print("supportDet");
}
std::string GetInfo(std::string str)
{
@ -1051,7 +1053,6 @@ struct CheckFunction
str123 += f_ShieldRegion.GetInfo("ShieldRegion");
str123 += f_EdgeROI.GetInfo("EdgeROI");
str123 += f_Image_Align.GetInfo("Image_Align");
str123 += f_supportDet.GetInfo("supportDet");
return str123;
}
};
@ -1148,9 +1149,9 @@ struct Base_Function_SaveImg
{
bool bOpen; // 是否开启
bool bSaveMarkImg; // mark 存图
bool bSaveAIDetImg; // mark 存图
bool bSaveClsImg; // 分类 存图
bool bSaveAlginImg; // 分类 存图
bool bSaveAlginImg; // 定位 存图
Base_Function_SaveImg()
{
@ -1159,7 +1160,7 @@ struct Base_Function_SaveImg
void Init()
{
bOpen = false;
bSaveMarkImg = false;
bSaveAIDetImg = false;
bSaveClsImg = false;
bSaveAlginImg = false;
}
@ -1168,20 +1169,20 @@ struct Base_Function_SaveImg
{
this->bOpen = tem.bOpen;
this->bSaveMarkImg = tem.bSaveMarkImg;
this->bSaveAIDetImg = tem.bSaveAIDetImg;
this->bSaveClsImg = tem.bSaveClsImg;
this->bSaveAlginImg = tem.bSaveAlginImg;
}
void print(std::string str)
{
printf("%s>>bOpen %d bSaveMarkImg %d bSaveClsImg %d bSaveAlginImg %d \n", str.c_str(),
bOpen, bSaveMarkImg, bSaveClsImg, bSaveAlginImg);
printf("%s>>bOpen %d bSaveAIDetImg %d bSaveClsImg %d bSaveAlginImg %d \n", str.c_str(),
bOpen, bSaveAIDetImg, bSaveClsImg, bSaveAlginImg);
}
std::string GetInfo(std::string str)
{
char buffer[256];
sprintf(buffer, "%s>>bOpen %d bSaveMarkImg %d bSaveClsImg %d bSaveAlginImg %d \n", str.c_str(),
bOpen, bSaveMarkImg, bSaveClsImg, bSaveAlginImg);
sprintf(buffer, "%s>>bOpen %d bSaveAIDetImg %d bSaveClsImg %d bSaveAlginImg %d \n", str.c_str(),
bOpen, bSaveAIDetImg, bSaveClsImg, bSaveAlginImg);
std::string str123 = buffer;
return str123;
}
@ -1377,6 +1378,7 @@ struct BaseCheckFunction
Base_Function_Edge_Det edgeDet;
Base_Function_SaveImg saveImg;
Base_Function_BigNG bigNG;
Function_Support_Det supportDet; // 支架/把手/标签检测(Support_Detect/Handle_Detect/BQ_Detect)
BaseCheckFunction()
{
@ -1388,6 +1390,7 @@ struct BaseCheckFunction
edgeDet.Init();
saveImg.Init();
bigNG.Init();
supportDet.Init();
}
void copy(BaseCheckFunction tem)
{
@ -1395,6 +1398,7 @@ struct BaseCheckFunction
this->edgeDet.copy(tem.edgeDet);
this->saveImg.copy(tem.saveImg);
this->bigNG.copy(tem.bigNG);
this->supportDet.copy(tem.supportDet);
}
void print(std::string str)
{
@ -1403,6 +1407,7 @@ struct BaseCheckFunction
edgeDet.print("edgeDet");
saveImg.print("saveImg");
bigNG.print("bigNG");
supportDet.print("supportDet");
}
std::string GetInfo(std::string str)
{
@ -1411,6 +1416,7 @@ struct BaseCheckFunction
str123 += edgeDet.GetInfo("edgeDet");
str123 += saveImg.GetInfo("saveImg");
str123 += bigNG.GetInfo("bigNG");
str123 += supportDet.GetInfo("supportDet");
// str123 += "\n";
return str123;
}

@ -411,130 +411,8 @@ int ChannelFuntonConfigJson::GetFunction(Json::Value value, CheckFunction &funct
std::string strCode = value[i]["itemCode"].asString();
// std::cout << strCode << std::endl;
// 支架偏移缺失检测
if ("Support_QX_Detect" == strCode)
{
auto value_f = value[i];
// std::cout << value_f << std::endl;
function.f_supportDet.bOpen = value_f["isOpen"].asBool();
if (function.f_supportDet.bOpen)
{
// 支架参数
{
if (value_f["form"]["support_param"]["bDetSupport"])
{
function.f_supportDet.bDetSupport = value_f["form"]["support_param"]["bDetSupport"].asBool();
}
// 注:支架/把手/标签检测(Support_Detect/Handle_Detect/BQ_Detect)已移至Base层(baseCheckData)解析
auto value_region = value_f["form"]["support_param"]["support_region"];
if (value_region.isArray())
{
for (int idx = 0; idx < value_region.size(); idx++)
{
cv::Point p;
p.x = value_region[idx][0].asInt();
p.y = value_region[idx][1].asInt();
function.f_supportDet.supportRegion.emplace_back(p);
}
if (function.f_supportDet.supportRegion.size() > 0)
{
function.f_supportDet.supportRect = minAreaRect(function.f_supportDet.supportRegion);
}
}
if (value_f["form"]["support_param"]["x_standard"])
{
function.f_supportDet.x_standard = value_f["form"]["support_param"]["x_standard"].asFloat();
}
if (value_f["form"]["support_param"]["y_standard"])
{
function.f_supportDet.y_standard = value_f["form"]["support_param"]["y_standard"].asFloat();
}
auto value_qx = value_f["form"]["support_param"]["edge_select"];
if (value_qx.isArray())
{
for (int idx = 0; idx < value_qx.size(); idx++)
{
std::string channel = value_qx[idx].asString();
function.f_supportDet.edge_select.push_back(channel);
}
}
if (value_f["form"]["support_param"]["x_offset"])
{
function.f_supportDet.x_offset = value_f["form"]["support_param"]["x_offset"].asFloat();
}
if (value_f["form"]["support_param"]["y_offset"])
{
function.f_supportDet.y_offset = value_f["form"]["support_param"]["y_offset"].asFloat();
}
if (value_f["form"]["support_param"]["r_offset"])
{
function.f_supportDet.r_offset = value_f["form"]["support_param"]["r_offset"].asFloat();
}
}
// 把手参数
{
if (value_f["form"]["handle_param"]["bDetHandle"])
{
function.f_supportDet.bDetHandle = value_f["form"]["handle_param"]["bDetHandle"].asBool();
}
auto handle_p = value_f["form"]["handle_param"];
bool bNewFormat = handle_p["handle_region1"].isArray();
for (int idx = 0; idx < HANDLE_REGION_MAX_NUM; idx++)
{
std::string strKey = bNewFormat ? ("handle_region" + std::to_string(idx + 1))
: ((idx == 0) ? std::string("handle_region") : std::string(""));
if (strKey.empty())
{
break;
}
// 该把手区域被禁用时跳过
if (handle_p[strKey + "_disabled"].isBool() && handle_p[strKey + "_disabled"].asBool())
{
continue;
}
auto value_region = handle_p[strKey];
if (!value_region.isArray() || value_region.size() < 3)
{
continue; // 空区域:表示该处不需要检测把手
}
std::vector<cv::Point> region;
for (int ip = 0; ip < value_region.size(); ip++)
{
if (!value_region[ip].isArray() || value_region[ip].size() < 2)
{
continue;
}
cv::Point p;
p.x = value_region[ip][0].asInt();
p.y = value_region[ip][1].asInt();
region.emplace_back(p);
}
if (region.size() < 3)
{
continue;
}
function.f_supportDet.handleRegions.push_back(region);
function.f_supportDet.handleBoxes.push_back(cv::boundingRect(region));
}
}
// 标签参数
{
if (value_f["form"]["tag_param"]["bDetTag"])
{
function.f_supportDet.bDetTag = value_f["form"]["tag_param"]["bDetTag"].asBool();
}
}
}
else
{
function.f_supportDet.Init();
}
}
// 大缺陷检测
if ("BigQX_Detect" == strCode)
{
@ -973,7 +851,8 @@ int BaseFuntonConfigJson::GetFunction(Json::Value value)
_config.markLine.Init();
}
}
if ("Det_Image_Save" == strCode)
// 存图项(2026-10 平台将 Det_Image_Save 改名为 BM_Image_Save,两个名称都兼容)
if ("Det_Image_Save" == strCode || "BM_Image_Save" == strCode)
{
auto value_f = value;
// std::cout << value_f << std::endl;
@ -982,10 +861,6 @@ int BaseFuntonConfigJson::GetFunction(Json::Value value)
if (_config.saveImg.bOpen)
{
if (value_f["form"]["SaveImg_Config"]["Mark_Save"])
{
_config.saveImg.bSaveMarkImg = value_f["form"]["SaveImg_Config"]["Mark_Save"].asBool();
}
if (value_f["form"]["SaveImg_Config"]["Cls_Save"])
{
_config.saveImg.bSaveClsImg = value_f["form"]["SaveImg_Config"]["Cls_Save"].asBool();
@ -994,6 +869,10 @@ int BaseFuntonConfigJson::GetFunction(Json::Value value)
{
_config.saveImg.bSaveAlginImg = value_f["form"]["SaveImg_Config"]["Align_Big_Save"].asBool();
}
if (value_f["form"]["SaveImg_Config"]["AI_Det_Save"])
{
_config.saveImg.bSaveAIDetImg = value_f["form"]["SaveImg_Config"]["AI_Det_Save"].asBool();
}
}
else
{
@ -1032,5 +911,128 @@ int BaseFuntonConfigJson::GetFunction(Json::Value value)
// _config.edgeDet.print("edgeDet");
// getchar();
}
// 支架偏位检测(Support_Detect,2026-10 从通道层 Support_QX_Detect 移至Base层并拆分独立)
if ("Support_Detect" == strCode)
{
auto value_f = value;
// 检测项开关即支架偏位检测开关
_config.supportDet.bDetSupport = value_f["isOpen"].asBool();
if (_config.supportDet.bDetSupport)
{
auto value_param = value_f["form"]["support_param"];
if (value_param["x_standard"])
{
_config.supportDet.x_standard = value_param["x_standard"].asFloat();
}
if (value_param["y_standard"])
{
_config.supportDet.y_standard = value_param["y_standard"].asFloat();
}
if (value_param["x_offset"])
{
_config.supportDet.x_offset = value_param["x_offset"].asFloat();
}
if (value_param["y_offset"])
{
_config.supportDet.y_offset = value_param["y_offset"].asFloat();
}
if (value_param["r_offset"])
{
_config.supportDet.r_offset = value_param["r_offset"].asFloat();
}
auto value_qx = value_param["edge_select"];
if (value_qx.isArray())
{
for (int idx = 0; idx < value_qx.size(); idx++)
{
std::string strEdge = value_qx[idx].asString();
_config.supportDet.edge_select.push_back(strEdge);
}
}
}
}
// 把手检测(Handle_Detect,2026-10 从通道层 Support_QX_Detect 移至Base层并拆分独立)
if ("Handle_Detect" == strCode)
{
auto value_f = value;
// 检测项开关即把手缺失检测开关
_config.supportDet.bDetHandle = value_f["isOpen"].asBool();
if (_config.supportDet.bDetHandle)
{
auto handle_p = value_f["form"]["handle_param"];
// 把手差异阈值
if (handle_p["handle_diff"])
{
_config.supportDet.handle_diff = handle_p["handle_diff"].asFloat();
}
bool bNewFormat = handle_p["handle_region1"].isArray();
for (int idx = 0; idx < HANDLE_REGION_MAX_NUM; idx++)
{
std::string strKey = bNewFormat ? ("handle_region" + std::to_string(idx + 1))
: ((idx == 0) ? std::string("handle_region") : std::string(""));
if (strKey.empty())
{
break;
}
// 该把手区域被禁用时跳过
if (handle_p[strKey + "_disabled"].isBool() && handle_p[strKey + "_disabled"].asBool())
{
continue;
}
auto value_region = handle_p[strKey];
if (!value_region.isArray() || value_region.size() < 3)
{
continue; // 空区域:表示该处不需要检测把手
}
std::vector<cv::Point> region;
for (int ip = 0; ip < value_region.size(); ip++)
{
if (!value_region[ip].isArray() || value_region[ip].size() < 2)
{
continue;
}
cv::Point p;
p.x = value_region[ip][0].asInt();
p.y = value_region[ip][1].asInt();
region.emplace_back(p);
}
if (region.size() < 3)
{
continue;
}
_config.supportDet.handleRegions.push_back(region);
_config.supportDet.handleBoxes.push_back(cv::boundingRect(region));
}
}
}
// 标签检测(BQ_Detect,2026-10 从通道层 Support_QX_Detect 移至Base层并拆分独立)
if ("BQ_Detect" == strCode)
{
auto value_f = value;
// 检测项开关即标签检测开关
_config.supportDet.bDetTag = value_f["isOpen"].asBool();
if (_config.supportDet.bDetTag)
{
auto tag_p = value_f["form"]["tag_param"];
if (tag_p["BQ_area"])
{
_config.supportDet.BQ_area = tag_p["BQ_area"].asFloat();
}
if (tag_p["BQ_energy"])
{
_config.supportDet.BQ_energy = tag_p["BQ_energy"].asFloat();
}
if (tag_p["BQ_len"])
{
_config.supportDet.BQ_len = tag_p["BQ_len"].asFloat();
}
if (tag_p["BQ_hj"])
{
_config.supportDet.BQ_hj = tag_p["BQ_hj"].asFloat();
}
}
}
return 0;
}

Loading…
Cancel
Save