update 支架边缘精细化

dev_lsy
liusiyang 2 weeks ago
parent a24995500b
commit 5f34acfdce

@ -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<cv::Point2f> &pts, double &fK, double &fB)
{
auto fnFit = [](const std::vector<cv::Point2f> &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<cv::Point2f> vecInlier;
for (int nIter = 0; nIter < 2; nIter++)
{
std::vector<double> 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<double> 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<cv::Point2f> 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<uchar>(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<uchar>(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<uchar>(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<uchar>(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)
{

@ -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<std::string> 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;

@ -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())
{

Loading…
Cancel
Save