diff --git a/AlgorithmModule/src/ImgCheckAnalysisy.cpp b/AlgorithmModule/src/ImgCheckAnalysisy.cpp index c2bebe5..115958b 100644 --- a/AlgorithmModule/src/ImgCheckAnalysisy.cpp +++ b/AlgorithmModule/src/ImgCheckAnalysisy.cpp @@ -51,6 +51,14 @@ #define HANDLE_EDGE_MARGIN_STEP_COEF 3 // 把手缺失检测开关见 Base层 Function_Support_Det::bDetHandle(CheckConfigDefine.h) +// 支架边缘原图精细化默认参数(JSON: Support_Detect.form.support_param 下的 edge_refine_search / edge_refine_step): +// 仅对 edge_select 选中的边缘生效:沿边缘按步长采样,从边缘向产品内侧逐像素找第一个 255 像素作为新边缘点, +// 有效点足够时重新拟合边缘线(找不到的采样点没有新信息,不参与拟合,相当于沿用原边缘点)。 +// edge_refine_search:最多向内搜索的像素数。搜不到 → 该采样点无贡献;调大更灵敏但可能搜到内部亮区 +#define EDGE_REFINE_SEARCH_DEFAULT 80 +// edge_refine_step:沿边采样步长(像素)。不需要每个点都找,调大可省时间;调小边缘拟合更稳 +#define EDGE_REFINE_STEP_DEFAULT 40 + // 分类映射配置文件(每行:label索引:缺陷名称;冒号后名称为该缺陷类型名称,行的顺序即缺陷类型索引) static const std::string CLS_LABEL_CONFIG_FILE = "/home/aidlux/BOE/UseModel_ZB/BM_cls.txt"; @@ -277,6 +285,92 @@ static cv::Mat MatAffineCompose(const cv::Mat &mA, const cv::Mat &mB) return hC(cv::Rect(0, 0, 3, 2)).clone(); } +// 稳健直线拟合:pts 为 (t, v) 采样点,拟合 v = k*t + b(左右边 t=y,v=x;上下边 t=x,v=y) +// 先最小二乘,再按“残差中位数的绝对偏差(MAD)”剔除离群点(把手凸起/边缘缺口/内部亮区等),重新拟合; +// 返回参与拟合的内点数,<4 表示拟合失败(调用方沿用原边缘) +static int FitLineRobustTV(const std::vector &pts, double &fK, double &fB) +{ + auto fnFit = [](const std::vector &p, double &k, double &b) -> bool { + if (p.size() < 2) + { + return false; + } + double fSumT = 0, fSumV = 0; + for (size_t i = 0; i < p.size(); i++) + { + fSumT += p[i].x; + fSumV += p[i].y; + } + const double fMeanT = fSumT / p.size(); + const double fMeanV = fSumV / p.size(); + double fSxx = 0, fSxy = 0; + for (size_t i = 0; i < p.size(); i++) + { + const double fDt = p[i].x - fMeanT; + fSxx += fDt * fDt; + fSxy += fDt * (p[i].y - fMeanV); + } + if (fSxx < 1e-6) + { + return false; + } + k = fSxy / fSxx; + b = fMeanV - k * fMeanT; + return true; + }; + + if (pts.size() < 4) + { + return 0; + } + double fKFit = 0, fBFit = 0; + if (!fnFit(pts, fKFit, fBFit)) + { + return 0; + } + + std::vector vecInlier; + for (int nIter = 0; nIter < 2; nIter++) + { + std::vector vecRes; + vecRes.reserve(pts.size()); + for (size_t i = 0; i < pts.size(); i++) + { + vecRes.push_back(pts[i].y - (fKFit * pts[i].x + fBFit)); + } + std::vector vecAbs = vecRes; + std::nth_element(vecAbs.begin(), vecAbs.begin() + vecAbs.size() / 2, vecAbs.end()); + const double fMed = vecAbs[vecAbs.size() / 2]; + for (size_t i = 0; i < vecAbs.size(); i++) + { + vecAbs[i] = std::fabs(vecAbs[i] - fMed); + } + std::nth_element(vecAbs.begin(), vecAbs.begin() + vecAbs.size() / 2, vecAbs.end()); + const double fMad = vecAbs[vecAbs.size() / 2]; + const double fThr = std::max(2.0, 3.0 * 1.4826 * fMad); + + vecInlier.clear(); + for (size_t i = 0; i < pts.size(); i++) + { + if (std::fabs(pts[i].y - (fKFit * pts[i].x + fBFit)) <= fThr) + { + vecInlier.push_back(pts[i]); + } + } + if (vecInlier.size() < 4 || !fnFit(vecInlier, fKFit, fBFit)) + { + break; + } + } + if (vecInlier.size() < 4) + { + return 0; + } + fK = fKFit; + fB = fBFit; + return (int)vecInlier.size(); +} + ImgCheckAnalysisy::ImgCheckAnalysisy() : m_pAI_Edge_Algin(m_pdetlog) { @@ -1076,6 +1170,9 @@ int ImgCheckAnalysisy::CheckRun() 3、产品边缘:优先复用把手提取对 bigmask 做的"四边抗凸起拟合"主体四边形 (CheckHandleByBigMask -> GetMaskProtrusions;边缘上的凸起(把手等)不会把边缘带偏), 拟合不可用/无效时回退 bigmask 最大连通域外接矩形 rp(近似矩形,四周可能有凸起) + 3.1、对 edge_select 选中的边缘再结合原图(detImg 灰度)精细化:沿边缘按步长采样,从边缘向产品内侧 + 找第一个 255 像素作为新边缘点(最多向内 edge_refine_search 像素,找不到沿用原边缘点), + 有效点足够时稳健拟合新的边缘线;采样步长 edge_refine_step(像素) 4、按 edge_select 指定方向(left/right/up/down)计算 rs 中心到产品对应边缘的距离 5、计算值与标准值(x_standard/y_standard)做差取平均,平均差超过 offset(x_offset) → 偏移 6、旋转偏移:支架最小外接旋转矩形的长轴(对应左/右边缘)与产品左/右边缘夹角超过 r_offset(度) → 偏移 */ @@ -1164,7 +1261,8 @@ int ImgCheckAnalysisy::CheckRun() { // 支架缺失 NG:ROI 取支架区域(有轮廓时)或整个产品区域(无轮廓时),映射到检测图(detImg)坐标 cv::Rect missRect = (rsRect.width > 0 && rsRect.height > 0) ? rsRect : bigRect; - cv::Rect roi = MatAffineRect(m_matSrc2Det, missRect); + // cv::Rect roi = MatAffineRect(m_matSrc2Det, missRect); + cv::Rect roi = missRect; roi &= cv::Rect(0, 0, m_pImageAllResult->detImg.cols, m_pImageAllResult->detImg.rows); QX_ERROR_INFO_ temerror; @@ -1289,6 +1387,242 @@ int ImgCheckAnalysisy::CheckRun() ptSegBArr[3] = cv::Point2f((float)(rpRect.x + rpRect.width), (float)(rpRect.y + rpRect.height)); } + // 3.2、结合原图精细化检测边缘(只处理 edge_select 选中的方向): + // 在"所计算边缘"(拟合四边形边/回退外接矩形边)上按步长采样,从边缘向产品内侧逐像素扫描原图 + // (detImg 灰度,未做其它处理;产品区域为饱和白),找到的第一个 255 像素作为该采样点的新边缘点; + // 最多向内搜索 edge_refine_search 像素(JSON,默认见 EDGE_REFINE_SEARCH_DEFAULT), + // 找不到的采样点没有新边缘信息,不参与拟合(相当于沿用原边缘点); + // edge_refine_step(JSON,默认见 EDGE_REFINE_STEP_DEFAULT)为沿边采样步长,不需要每个点都找; + // 有效点足够时稳健拟合新的边缘直线,更新测距点(中心行/列)与绘制线段。 + { + const cv::Mat &grayEdgeImg = m_pImageAllResult->detImg; + int nRefineSearch = EDGE_REFINE_SEARCH_DEFAULT; + int nRefineStep = EDGE_REFINE_STEP_DEFAULT; + if (supportDet.edge_refine_search > 0) + { + nRefineSearch = (int)(supportDet.edge_refine_search + 0.5f); + } + if (supportDet.edge_refine_step > 0) + { + nRefineStep = (int)(supportDet.edge_refine_step + 0.5f); + } + nRefineSearch = std::max(1, nRefineSearch); + nRefineStep = std::max(4, nRefineStep); + + bool bEdgeRefined[4] = {false, false, false, false}; // edge_select 配重复时只处理一次 + if (grayEdgeImg.type() == CV_8UC1 && grayEdgeImg.cols > 0 && grayEdgeImg.rows > 0) + { + for (size_t iselect = 0; iselect < supportDet.edge_select.size(); iselect++) + { + const std::string &strEdge = supportDet.edge_select[iselect]; + int gi = -1; // 方向索引:0 left 1 right 2 up 3 down + if (strEdge == "left") + { + gi = 0; + } + else if (strEdge == "right") + { + gi = 1; + } + else if (strEdge == "up") + { + gi = 2; + } + else if (strEdge == "down") + { + gi = 3; + } + if (gi < 0 || bEdgeRefined[gi]) + { + continue; + } + bEdgeRefined[gi] = true; + + // 当前边缘直线:左右边 x=k*y+b,上下边 y=k*x+b(与拟合四边形约定一致) + const bool bVertEdge = (gi == 0 || gi == 1); + const cv::Point2f ptSegA = ptSegAArr[gi]; + const cv::Point2f ptSegB = ptSegBArr[gi]; + const double fDelta = bVertEdge ? ((double)ptSegB.y - ptSegA.y) : ((double)ptSegB.x - ptSegA.x); + if (std::fabs(fDelta) < 4.0) + { + continue; // 边太短/退化,保持原边缘 + } + const double fKOld = bVertEdge ? ((double)ptSegB.x - ptSegA.x) / fDelta + : ((double)ptSegB.y - ptSegA.y) / fDelta; + const double fBOld = bVertEdge ? (ptSegA.x - fKOld * ptSegA.y) + : (ptSegA.y - fKOld * ptSegA.x); + + // 沿边采样区间:两端各去掉 5%(至少 4px),避开圆角过渡段 + const double fT0 = bVertEdge ? std::min(ptSegA.y, ptSegB.y) : std::min(ptSegA.x, ptSegB.x); + const double fT1 = bVertEdge ? std::max(ptSegA.y, ptSegB.y) : std::max(ptSegA.x, ptSegB.x); + const double fTrim = std::max(4.0, (fT1 - fT0) * 0.05); + const double fTStart = fT0 + fTrim; + const double fTEnd = fT1 - fTrim; + if (fTEnd - fTStart < 8.0) + { + continue; + } + + std::vector vecRefinePts; // 有效的新边缘点(t, v):左右 t=y/v=x,上下 t=x/v=y + int nSampleNum = 0; + for (double fT = fTStart; fT <= fTEnd; fT += nRefineStep) + { + nSampleNum++; + const double fEdgePos = fKOld * fT + fBOld; + const cv::Point2f ptSrc = bVertEdge ? cv::Point2f((float)fEdgePos, (float)fT) + : cv::Point2f((float)fT, (float)fEdgePos); + // 原图坐标 -> 检测图(detImg)坐标(纯平移);在检测图灰度上找第一个 255 + const cv::Point2f ptDet = MatAffinePoint(m_matSrc2Det, ptSrc); + const int nFix = bVertEdge ? cvRound(ptDet.y) : cvRound(ptDet.x); // 固定坐标(行/列) + if ((bVertEdge && (nFix < 0 || nFix >= grayEdgeImg.rows)) || + (!bVertEdge && (nFix < 0 || nFix >= grayEdgeImg.cols))) + { + continue; // 固定坐标越界,该采样点无法搜索 + } + + bool bFound = false; + double fNewPos = fEdgePos; // 找到的新边缘位置(原图坐标) + if (gi == 0) // 左边:向产品内侧(+x)找 + { + const int nX0 = (int)std::ceil(ptDet.x); + const int nXEnd = std::min(grayEdgeImg.cols - 1, nX0 + nRefineSearch); + for (int x = std::max(0, nX0); x <= nXEnd; x++) + { + if (grayEdgeImg.at(nFix, x) == 255) + { + const cv::Point2f ptNew = MatAffinePoint(m_matDet2Src, cv::Point2f((float)x, ptDet.y)); + fNewPos = ptNew.x; + bFound = true; + break; + } + } + } + else if (gi == 1) // 右边:向产品内侧(-x)找 + { + const int nX0 = (int)std::floor(ptDet.x); + const int nXEnd = std::max(0, nX0 - nRefineSearch); + for (int x = std::min(grayEdgeImg.cols - 1, nX0); x >= nXEnd && x >= 0; x--) + { + if (grayEdgeImg.at(nFix, x) == 255) + { + const cv::Point2f ptNew = MatAffinePoint(m_matDet2Src, cv::Point2f((float)x, ptDet.y)); + fNewPos = ptNew.x; + bFound = true; + break; + } + } + } + else if (gi == 2) // 上边:向产品内侧(+y)找 + { + const int nY0 = (int)std::ceil(ptDet.y); + const int nYEnd = std::min(grayEdgeImg.rows - 1, nY0 + nRefineSearch); + for (int y = std::max(0, nY0); y <= nYEnd; y++) + { + if (grayEdgeImg.at(y, nFix) == 255) + { + const cv::Point2f ptNew = MatAffinePoint(m_matDet2Src, cv::Point2f(ptDet.x, (float)y)); + fNewPos = ptNew.y; + bFound = true; + break; + } + } + } + else // 下边:向产品内侧(-y)找 + { + const int nY0 = (int)std::floor(ptDet.y); + const int nYEnd = std::max(0, nY0 - nRefineSearch); + for (int y = std::min(grayEdgeImg.rows - 1, nY0); y >= nYEnd && y >= 0; y--) + { + if (grayEdgeImg.at(y, nFix) == 255) + { + const cv::Point2f ptNew = MatAffinePoint(m_matDet2Src, cv::Point2f(ptDet.x, (float)y)); + fNewPos = ptNew.y; + bFound = true; + break; + } + } + } + if (bFound) + { + vecRefinePts.push_back(cv::Point2f((float)fT, (float)fNewPos)); + } + // 找不到:该采样点没有新边缘信息,不参与拟合(相当于沿用原边缘点) + } + + // 有效采样点足够时重新拟合边缘线;否则保留原边缘 + if (vecRefinePts.size() < 4) + { + m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "支架检测", + "edge refine %s skip: sample %d found %ld (need 4), keep old", + strEdge.c_str(), nSampleNum, (long)vecRefinePts.size()); + continue; + } + double fKNew = 0, fBNew = 0; + if (FitLineRobustTV(vecRefinePts, fKNew, fBNew) < 4) + { + m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "支架检测", + "edge refine %s skip: fit failed, keep old", strEdge.c_str()); + continue; + } + + // 中心行/列上的新边缘位置 + 合理性检查(仍需在中心外侧,相对原边缘偏移不超过搜索范围) + const double fOldCenterPos = bVertEdge ? ptEdgeArr[gi].x : ptEdgeArr[gi].y; + const double fNewCenterPos = bVertEdge ? (fKNew * fCy + fBNew) : (fKNew * fCx + fBNew); + const bool bCenterSideOK = (gi == 0) ? (fNewCenterPos < fCx) + : (gi == 1) ? (fNewCenterPos > fCx) + : (gi == 2) ? (fNewCenterPos < fCy) + : (fNewCenterPos > fCy); + if (!bCenterSideOK || std::fabs(fNewCenterPos - fOldCenterPos) > nRefineSearch + 2.0) + { + m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "支架检测", + "edge refine %s reject: center %.1f -> %.1f (limit %d), keep old", + strEdge.c_str(), fOldCenterPos, fNewCenterPos, nRefineSearch); + continue; + } + + // 应用新边缘线:更新测距点(中心行/列)与绘制线段两端(沿边坐标不变,位置取新线) + if (bVertEdge) + { + ptEdgeArr[gi].x = (float)fNewCenterPos; + ptSegAArr[gi].x = (float)(fKNew * ptSegAArr[gi].y + fBNew); + ptSegBArr[gi].x = (float)(fKNew * ptSegBArr[gi].y + fBNew); + if (gi == 0) + { + fDL = fCx - ptEdgeArr[0].x; + } + else + { + fDR = ptEdgeArr[1].x - fCx; + } + } + else + { + ptEdgeArr[gi].y = (float)fNewCenterPos; + ptSegAArr[gi].y = (float)(fKNew * ptSegAArr[gi].x + fBNew); + ptSegBArr[gi].y = (float)(fKNew * ptSegBArr[gi].x + fBNew); + if (gi == 2) + { + fDT = fCy - ptEdgeArr[2].y; + } + else + { + fDB = ptEdgeArr[3].y - fCy; + } + } + + m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "支架检测", + "edge refine %s: sample %d found %ld center %.1f -> %.1f shift %.1f", + strEdge.c_str(), nSampleNum, (long)vecRefinePts.size(), + fOldCenterPos, fNewCenterPos, fNewCenterPos - fOldCenterPos); + } + } + else if (!supportDet.edge_select.empty()) + { + m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "支架检测", + "edge refine skip: detImg not CV_8UC1 (type %d)", grayEdgeImg.type()); + } + } + // 3.5、旋转偏移:支架最小外接旋转矩形(长轴对应左/右边缘、短轴对应上/下边缘) // 长轴与产品左/右边缘的夹角 > r_offset(度) → 偏移;r_offset<=0 不判定(兼容旧参数) float fSupportAngle = 0; // 支架长轴相对产品左/右边缘的夹角(度,带符号;正=支架长轴相对产品边缘向右倾) @@ -1446,7 +1780,8 @@ int ImgCheckAnalysisy::CheckRun() temerror.Idx = m_pDetResult->pQx_ErrorList->size(); // roi 在原图坐标系,按坐标映射转换到检测图(detImg)坐标系 - cv::Rect roi = MatAffineRect(m_matSrc2Det, rsRect); + // cv::Rect roi = MatAffineRect(m_matSrc2Det, rsRect); + cv::Rect roi = rsRect; roi &= cv::Rect(0, 0, m_pImageAllResult->detImg.cols, m_pImageAllResult->detImg.rows); temerror.roi = roi; temerror.area = roi.width * roi.height; @@ -1499,7 +1834,8 @@ int ImgCheckAnalysisy::CheckRun() } // 上报该把手区域的位置:参数(模板)坐标 -> 检测图(detImg)坐标 - cv::Rect roi = MatAffineRect(m_matParam2Det, regionResult.boxRegion); + // cv::Rect roi = MatAffineRect(m_matParam2Det, regionResult.boxRegion); + cv::Rect roi = regionResult.boxRegion; roi &= cv::Rect(0, 0, m_pImageAllResult->detImg.cols, m_pImageAllResult->detImg.rows); if (roi.width <= 0 || roi.height <= 0) { diff --git a/ConfigModule/include/CheckConfigDefine.h b/ConfigModule/include/CheckConfigDefine.h index b66fae6..01e332a 100644 --- a/ConfigModule/include/CheckConfigDefine.h +++ b/ConfigModule/include/CheckConfigDefine.h @@ -924,6 +924,8 @@ struct Function_Support_Det // 支架参数(Support_Detect) bool bDetSupport; // 支架偏位检测开关(Support_Detect.isOpen) bool bDrawSupport; // 支架绘制开关(Support_Detect.form.support_param.bDrawSupport):是否绘制支架中心十字/距离线 + bool bUseTraditionEdge; // 传统算法搜边开关(Support_Detect.form.support_param.bUseTraditionEdge): + // true=产品边缘用裁剪图(detImg)转灰度、二值化后搜边(不依赖定位模型 bigmask);false=用定位模型 bigmask float x_standard; // 水平方向标准距离(left/right 用) float y_standard; // 垂直方向标准距离(up/down 用) std::vector edge_select; // 参与计算的方向:up/down/left/right @@ -931,6 +933,10 @@ struct Function_Support_Det float y_offset; float r_offset; // 支架旋转偏移阈值(度):支架旋转矩形长轴(对应左/右边缘)与产品左/右边缘夹角超过该值判偏移;<=0 不判定 float support_min_area; // 支架缺失判定:支架面积阈值(单位 mm²)。支架由 Align_Inner 模型(smallmask)检出,支架面积 < 该值判缺失;<=0 不判定 + // 支架边缘原图精细化(Support_Detect.form.support_param,均可选;仅对 edge_select 选中的边缘生效): + // 沿边缘按步长采样,从边缘向产品内侧逐像素找第一个 255 像素作为新边缘点,再重新拟合边缘线 + float edge_refine_search; // edge_refine_search:最多向内搜索的像素数;<=0=未配置(默认 80) + float edge_refine_step; // edge_refine_step:沿边采样步长(像素,不需要每个点都找);<=0=未配置(默认 40) // 把手参数(Handle_Detect) bool bDetHandle; // 把手缺失检测开关(Handle_Detect.isOpen) // 把手区域(最多 HANDLE_REGION_MAX_NUM 个,只保存非空的;区域宽高用于把手卡控) @@ -961,6 +967,7 @@ struct Function_Support_Det { bDetSupport = false; bDrawSupport = false; + bUseTraditionEdge = false; x_standard = 0; y_standard = 0; edge_select.clear(); @@ -968,6 +975,8 @@ struct Function_Support_Det y_offset = 0; r_offset = 0; support_min_area = 0; + edge_refine_search = 0; + edge_refine_step = 0; bDetHandle = false; handleRegions.clear(); handleBoxes.clear(); @@ -989,6 +998,7 @@ struct Function_Support_Det { this->bDetSupport = tem.bDetSupport; this->bDrawSupport = tem.bDrawSupport; + this->bUseTraditionEdge = tem.bUseTraditionEdge; this->x_standard = tem.x_standard; this->y_standard = tem.y_standard; this->edge_select.assign(tem.edge_select.begin(), tem.edge_select.end()); @@ -996,6 +1006,8 @@ struct Function_Support_Det this->y_offset = tem.y_offset; this->r_offset = tem.r_offset; this->support_min_area = tem.support_min_area; + this->edge_refine_search = tem.edge_refine_search; + this->edge_refine_step = tem.edge_refine_step; this->bDetHandle = tem.bDetHandle; this->handleRegions.assign(tem.handleRegions.begin(), tem.handleRegions.end()); this->handleBoxes.assign(tem.handleBoxes.begin(), tem.handleBoxes.end()); @@ -1014,16 +1026,16 @@ struct Function_Support_Det } void print(std::string str) { - printf("%s>>bDetSupport %d bDrawSupport %d bDetHandle %d bDetTag %d x_standard %f y_standard %f x_offset %f y_offset %f r_offset %f support_min_area %f edge num %ld handleRegion num %ld handle_diff %f handleRange[size %.2f~%.2f search %.1f depth %.1f area %.1f margin %.1f(0=自动,<0=默认)] BQ[area %f energy %f len %f hj %f]\n", - str.c_str(), bDetSupport, bDrawSupport, bDetHandle, bDetTag, x_standard, y_standard, x_offset, y_offset, r_offset, support_min_area, edge_select.size(), handleRegions.size(), handle_diff, + printf("%s>>bDetSupport %d bDrawSupport %d bUseTraditionEdge %d bDetHandle %d bDetTag %d x_standard %f y_standard %f x_offset %f y_offset %f r_offset %f support_min_area %f edgeRefine[search %.0f step %.0f] edge num %ld handleRegion num %ld handle_diff %f handleRange[size %.2f~%.2f search %.1f depth %.1f area %.1f margin %.1f(0=自动,<0=默认)] BQ[area %f energy %f len %f hj %f]\n", + str.c_str(), bDetSupport, bDrawSupport, bUseTraditionEdge, bDetHandle, bDetTag, x_standard, y_standard, x_offset, y_offset, r_offset, support_min_area, edge_refine_search, edge_refine_step, edge_select.size(), handleRegions.size(), handle_diff, handle_size_min_ratio, handle_size_max_ratio, handle_search_ratio, handle_min_depth_coef, handle_min_area_coef, handle_edge_margin_coef, BQ_area, BQ_energy, BQ_len, BQ_hj); } std::string GetInfo(std::string str) { char buffer[1024]; - sprintf(buffer, "%s>>bDetSupport %d bDrawSupport %d bDetHandle %d bDetTag %d x_standard %f y_standard %f x_offset %f y_offset %f r_offset %f support_min_area %f edge num %ld handleRegion num %ld handle_diff %f handleRange[size %.2f~%.2f search %.1f depth %.1f area %.1f margin %.1f(0=自动,<0=默认)] BQ[area %f energy %f len %f hj %f]\n", - str.c_str(), bDetSupport, bDrawSupport, bDetHandle, bDetTag, x_standard, y_standard, x_offset, y_offset, r_offset, support_min_area, edge_select.size(), handleRegions.size(), handle_diff, + sprintf(buffer, "%s>>bDetSupport %d bDrawSupport %d bUseTraditionEdge %d bDetHandle %d bDetTag %d x_standard %f y_standard %f x_offset %f y_offset %f r_offset %f support_min_area %f edgeRefine[search %.0f step %.0f] edge num %ld handleRegion num %ld handle_diff %f handleRange[size %.2f~%.2f search %.1f depth %.1f area %.1f margin %.1f(0=自动,<0=默认)] BQ[area %f energy %f len %f hj %f]\n", + str.c_str(), bDetSupport, bDrawSupport, bUseTraditionEdge, bDetHandle, bDetTag, x_standard, y_standard, x_offset, y_offset, r_offset, support_min_area, edge_refine_search, edge_refine_step, edge_select.size(), handleRegions.size(), handle_diff, handle_size_min_ratio, handle_size_max_ratio, handle_search_ratio, handle_min_depth_coef, handle_min_area_coef, handle_edge_margin_coef, BQ_area, BQ_energy, BQ_len, BQ_hj); std::string str123 = buffer; diff --git a/ConfigModule/src/JsonConfig.cpp b/ConfigModule/src/JsonConfig.cpp index e3a7a9e..4877c21 100644 --- a/ConfigModule/src/JsonConfig.cpp +++ b/ConfigModule/src/JsonConfig.cpp @@ -930,6 +930,11 @@ int BaseFuntonConfigJson::GetFunction(Json::Value value) { _config.supportDet.bDrawSupport = value_param["bDrawSupport"].asBool(); } + // 传统算法搜边开关 + if (value_param["bUseTraditionEdge"].isBool()) + { + _config.supportDet.bUseTraditionEdge = value_param["bUseTraditionEdge"].asBool(); + } if (value_param["x_standard"]) { @@ -952,12 +957,23 @@ int BaseFuntonConfigJson::GetFunction(Json::Value value) _config.supportDet.r_offset = value_param["r_offset"].asFloat(); } - // 支架缺失判定:支架(Align_Inner 模型)面积 < support_min_area(单位 mm²)→ 支架缺失;<=0 不判定(兼容旧参数) - if (value_param["support_min_area"].isNumeric()) + if (value_param["support_min_area"]) { _config.supportDet.support_min_area = value_param["support_min_area"].asFloat(); } + // 支架边缘原图精细化(可选):沿边缘采样,从边缘向内找第一个 255 像素作为新边缘点, + // edge_refine_search:最多向内搜索像素数(未配置默认 80) + // edge_refine_step :沿边采样步长(像素)(未配置默认 40,不需要每个点都找) + if (value_param["edge_refine_search"]) + { + _config.supportDet.edge_refine_search = value_param["edge_refine_search"].asFloat(); + } + if (value_param["edge_refine_step"]) + { + _config.supportDet.edge_refine_step = value_param["edge_refine_step"].asFloat(); + } + auto value_qx = value_param["edge_select"]; if (value_qx.isArray()) {