|
|
|
@ -476,6 +476,38 @@ int ImgCheckAnalysisy::CheckRun()
|
|
|
|
float diff_align = std::fabs(aouter - ainner);
|
|
|
|
float diff_align = std::fabs(aouter - ainner);
|
|
|
|
diff_align = std::fmod(diff_align, 180.0f); // 模 180 度
|
|
|
|
diff_align = std::fmod(diff_align, 180.0f); // 模 180 度
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 两条直线的夹角取锐角:min(diff, 180 - diff)
|
|
|
|
|
|
|
|
if (diff_align > 90.0f)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
diff_align = 180.0f - diff_align;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 如果diff_align大于10,则添加到缺陷列表
|
|
|
|
|
|
|
|
if (diff_align > 10.0f)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
QX_ERROR_INFO_ alignErr;
|
|
|
|
|
|
|
|
alignErr.Idx = static_cast<int>(m_pDetResult->pQx_ErrorList->size());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// roi 用整张检测图区域(detImg 坐标系)
|
|
|
|
|
|
|
|
cv::Rect tplRect = m_tplOuterRect.boundingRect();
|
|
|
|
|
|
|
|
alignErr.roi = cv::Rect(0, 0, tplRect.width, tplRect.height);
|
|
|
|
|
|
|
|
alignErr.area = alignErr.roi.width * alignErr.roi.height;
|
|
|
|
|
|
|
|
alignErr.JudgArea = alignErr.area * m_fImgage_Scale_X * m_fImgage_Scale_Y;
|
|
|
|
|
|
|
|
alignErr.flen = tplRect.width * m_fImgage_Scale_X;
|
|
|
|
|
|
|
|
alignErr.fbreadth = tplRect.height * m_fImgage_Scale_Y;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
alignErr.nconfig_qx_type = CONFIG_QX_NAME_cell_zangwu;
|
|
|
|
|
|
|
|
alignErr.qx_name = CONFIG_QX_NAME_Names[CONFIG_QX_NAME_cell_zangwu];
|
|
|
|
|
|
|
|
alignErr.grayDis = diff_align; // 记录内外边缘夹角(度)
|
|
|
|
|
|
|
|
alignErr.detRegionidxList.push_back(0);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
alignErr.detlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "Align Check",
|
|
|
|
|
|
|
|
"outer-inner angle diff %.2f deg", diff_align);
|
|
|
|
|
|
|
|
m_pDetResult->pQx_ErrorList->push_back(alignErr);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "Align Check", "angle diff %.2f deg > 10", diff_align);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*投影对齐模板*/
|
|
|
|
/*投影对齐模板*/
|
|
|
|
Adapt_Config(m_tplOuterRect, m_outer_rroi, m_CheckResult_shareP->in_shareImage->img);
|
|
|
|
Adapt_Config(m_tplOuterRect, m_outer_rroi, m_CheckResult_shareP->in_shareImage->img);
|
|
|
|
m_outer_roi = m_tplOuterRect.boundingRect();
|
|
|
|
m_outer_roi = m_tplOuterRect.boundingRect();
|
|
|
|
@ -1854,6 +1886,7 @@ int ImgCheckAnalysisy::Pin_Qx_Det(const cv::Mat &img)
|
|
|
|
const float pin_scale_x = (pin_mask.cols > 0) ? static_cast<float>(img.cols) / pin_mask.cols : 0.0f;
|
|
|
|
const float pin_scale_x = (pin_mask.cols > 0) ? static_cast<float>(img.cols) / pin_mask.cols : 0.0f;
|
|
|
|
const float pin_scale_y = (pin_mask.rows > 0) ? static_cast<float>(img.rows) / pin_mask.rows : 0.0f;
|
|
|
|
const float pin_scale_y = (pin_mask.rows > 0) ? static_cast<float>(img.rows) / pin_mask.rows : 0.0f;
|
|
|
|
// 将轮廓点从 mask 坐标系 映射回 tplImg 坐标系
|
|
|
|
// 将轮廓点从 mask 坐标系 映射回 tplImg 坐标系
|
|
|
|
|
|
|
|
m_curPinContours.clear();
|
|
|
|
m_curPinContours.reserve(pin_contours.size());
|
|
|
|
m_curPinContours.reserve(pin_contours.size());
|
|
|
|
for (size_t i = 0; i < pin_contours.size(); i++)
|
|
|
|
for (size_t i = 0; i < pin_contours.size(); i++)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
@ -1867,6 +1900,123 @@ int ImgCheckAnalysisy::Pin_Qx_Det(const cv::Mat &img)
|
|
|
|
m_curPinContours.push_back(mapped);
|
|
|
|
m_curPinContours.push_back(mapped);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 根据模板Pin和当前Pin轮廓进行对比,判断当前有无缺失和偏移
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
// 计算轮廓中心点(外接矩形中心)
|
|
|
|
|
|
|
|
auto getCenter = [](const std::vector<cv::Point> &contour) -> cv::Point2f
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
cv::Rect r = cv::boundingRect(contour);
|
|
|
|
|
|
|
|
return cv::Point2f(r.x + r.width * 0.5f, r.y + r.height * 0.5f);
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const int nTpl = static_cast<int>(m_tplPinContours.size());
|
|
|
|
|
|
|
|
const int nCur = static_cast<int>(m_curPinContours.size());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (nTpl > 0)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
// 1、统计模板 pin 中心与平均最小边长,用于自适应阈值
|
|
|
|
|
|
|
|
std::vector<cv::Point2f> tplCenters(nTpl);
|
|
|
|
|
|
|
|
double sumMinDim = 0.0;
|
|
|
|
|
|
|
|
for (int i = 0; i < nTpl; i++)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
tplCenters[i] = getCenter(m_tplPinContours[i]);
|
|
|
|
|
|
|
|
cv::Rect r = cv::boundingRect(m_tplPinContours[i]);
|
|
|
|
|
|
|
|
sumMinDim += (r.width < r.height) ? r.width : r.height;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
const float avgMinDim = static_cast<float>(sumMinDim / nTpl);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 偏移阈值约 1/4 个 pin 尺寸,缺失阈值约 3/4 个 pin 尺寸
|
|
|
|
|
|
|
|
float offsetTh = avgMinDim * 0.5f;
|
|
|
|
|
|
|
|
if (offsetTh < 3.0f)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
offsetTh = 3.0f;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
float missTh = avgMinDim * 0.75f;
|
|
|
|
|
|
|
|
if (missTh < offsetTh + 1.0f)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
missTh = offsetTh + 1.0f;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 2、当前 pin 中心
|
|
|
|
|
|
|
|
std::vector<cv::Point2f> curCenters(nCur);
|
|
|
|
|
|
|
|
for (int i = 0; i < nCur; i++)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
curCenters[i] = getCenter(m_curPinContours[i]);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<bool> curUsed(nCur, false);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 上报缺失/偏移缺陷(缺陷类型可按需调整)
|
|
|
|
|
|
|
|
auto reportPinError = [&](int pinIdx, const cv::Point2f &tplCenter, const std::string &reason)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
QX_ERROR_INFO_ pinErr;
|
|
|
|
|
|
|
|
pinErr.Idx = static_cast<int>(m_pDetResult->pQx_ErrorList->size());
|
|
|
|
|
|
|
|
cv::Rect r = cv::boundingRect(m_tplPinContours[pinIdx]);
|
|
|
|
|
|
|
|
pinErr.roi = r;
|
|
|
|
|
|
|
|
pinErr.area = static_cast<int>(cv::contourArea(m_tplPinContours[pinIdx]));
|
|
|
|
|
|
|
|
pinErr.JudgArea = pinErr.area * m_fImgage_Scale_X * m_fImgage_Scale_Y;
|
|
|
|
|
|
|
|
int longSide = (r.width > r.height) ? r.width : r.height;
|
|
|
|
|
|
|
|
int shortSide = (r.width < r.height) ? r.width : r.height;
|
|
|
|
|
|
|
|
pinErr.flen = longSide * m_fImgage_Scale_X;
|
|
|
|
|
|
|
|
pinErr.fbreadth = shortSide * m_fImgage_Scale_Y;
|
|
|
|
|
|
|
|
pinErr.nconfig_qx_type = CONFIG_QX_NAME_cell_ymhs;
|
|
|
|
|
|
|
|
pinErr.qx_name = CONFIG_QX_NAME_Names[CONFIG_QX_NAME_cell_ymhs];
|
|
|
|
|
|
|
|
pinErr.detRegionidxList.push_back(0);
|
|
|
|
|
|
|
|
pinErr.detlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "Pin Check",
|
|
|
|
|
|
|
|
"pin %d center(%d,%d) %s",
|
|
|
|
|
|
|
|
pinIdx, static_cast<int>(tplCenter.x), static_cast<int>(tplCenter.y),
|
|
|
|
|
|
|
|
reason.c_str());
|
|
|
|
|
|
|
|
m_pDetResult->pQx_ErrorList->push_back(pinErr);
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int nMiss = 0;
|
|
|
|
|
|
|
|
int nOffset = 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 3、逐个模板 pin 找最近且未被占用的当前 pin
|
|
|
|
|
|
|
|
for (int i = 0; i < nTpl; i++)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
int bestIdx = -1;
|
|
|
|
|
|
|
|
double bestDist = 1e12;
|
|
|
|
|
|
|
|
for (int j = 0; j < nCur; j++)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if (curUsed[j])
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
float dx = tplCenters[i].x - curCenters[j].x;
|
|
|
|
|
|
|
|
float dy = tplCenters[i].y - curCenters[j].y;
|
|
|
|
|
|
|
|
double d = std::sqrt(static_cast<double>(dx) * dx + static_cast<double>(dy) * dy);
|
|
|
|
|
|
|
|
if (d < bestDist)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
bestDist = d;
|
|
|
|
|
|
|
|
bestIdx = j;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 无候选或距离过远 -> 缺失
|
|
|
|
|
|
|
|
if (bestIdx < 0 || bestDist > missTh)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
nMiss++;
|
|
|
|
|
|
|
|
reportPinError(i, tplCenters[i], "miss");
|
|
|
|
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "Pin Check", "pin %d MISS", i);
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
curUsed[bestIdx] = true;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 距离超出偏移阈值 -> 偏移
|
|
|
|
|
|
|
|
if (bestDist > offsetTh)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
nOffset++;
|
|
|
|
|
|
|
|
char buf[64];
|
|
|
|
|
|
|
|
snprintf(buf, sizeof(buf), "offset %.1fpx", bestDist);
|
|
|
|
|
|
|
|
reportPinError(i, tplCenters[i], buf);
|
|
|
|
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "Pin Check", "pin %d OFFSET %.1fpx", i, bestDist);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "Pin Check", "tpl %d cur %d miss %d offset %d", nTpl, nCur, nMiss, nOffset);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (m_Edge_DetConfig.bSaveResultImg)
|
|
|
|
if (m_Edge_DetConfig.bSaveResultImg)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
|