|
|
|
@ -2228,19 +2228,13 @@ int ImgCheckAnalysisy::Pin_Qx_Det(const cv::Mat &img)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
std::vector<bool> curUsed(nCur, false);
|
|
|
|
std::vector<bool> curUsed(nCur, false);
|
|
|
|
|
|
|
|
|
|
|
|
// 3、偏移阈值由基础参数 pin_x_offset / pin_y_offset (mm) 换算为像素
|
|
|
|
// 3、偏移阈值直接使用基础参数 pin_x_offset / pin_y_offset (mm),与换算为 mm 的偏移量直接比较
|
|
|
|
float offsetThX = 0.0f;
|
|
|
|
float offsetThX = 0.0f; // mm
|
|
|
|
float offsetThY = 0.0f;
|
|
|
|
float offsetThY = 0.0f; // mm
|
|
|
|
if (m_pbaseCheckFunction != NULL)
|
|
|
|
if (m_pbaseCheckFunction != NULL)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (m_fImgage_Scale_X > 0.0f)
|
|
|
|
offsetThX = m_pbaseCheckFunction->pinDet.pin_x_offset;
|
|
|
|
{
|
|
|
|
offsetThY = m_pbaseCheckFunction->pinDet.pin_y_offset;
|
|
|
|
offsetThX = m_pbaseCheckFunction->pinDet.pin_x_offset / m_fImgage_Scale_X;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_fImgage_Scale_Y > 0.0f)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
offsetThY = m_pbaseCheckFunction->pinDet.pin_y_offset / m_fImgage_Scale_Y;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 上报缺失/偏移缺陷(缺陷类型可按需调整)
|
|
|
|
// 上报缺失/偏移缺陷(缺陷类型可按需调整)
|
|
|
|
@ -2309,19 +2303,21 @@ int ImgCheckAnalysisy::Pin_Qx_Det(const cv::Mat &img)
|
|
|
|
|
|
|
|
|
|
|
|
curUsed[bestIdx] = true;
|
|
|
|
curUsed[bestIdx] = true;
|
|
|
|
|
|
|
|
|
|
|
|
// x 或 y 方向偏移超过配置阈值 -> 偏移
|
|
|
|
// x 或 y 方向偏移超过配置阈值 -> 偏移;偏移量按成像精度换算为 mm (mm = px * 成像精度)
|
|
|
|
float dx = tplCenters[i].x - curCenters[bestIdx].x;
|
|
|
|
float dx_mm = (tplCenters[i].x - curCenters[bestIdx].x) * m_fImgage_Scale_X;
|
|
|
|
float dy = tplCenters[i].y - curCenters[bestIdx].y;
|
|
|
|
float dy_mm = (tplCenters[i].y - curCenters[bestIdx].y) * m_fImgage_Scale_Y;
|
|
|
|
float absDx = std::fabs(dx);
|
|
|
|
float absDx = std::fabs(dx_mm);
|
|
|
|
float absDy = std::fabs(dy);
|
|
|
|
float absDy = std::fabs(dy_mm);
|
|
|
|
if (absDx > offsetThX || absDy > offsetThY)
|
|
|
|
bool bOffset = (absDx > offsetThX || absDy > offsetThY);
|
|
|
|
|
|
|
|
if (bOffset)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
nOffset++;
|
|
|
|
nOffset++;
|
|
|
|
char buf[64];
|
|
|
|
char buf[64];
|
|
|
|
snprintf(buf, sizeof(buf), "offset dx %.1f dy %.1f", absDx, absDy);
|
|
|
|
snprintf(buf, sizeof(buf), "offset dx %.2f dy %.2f mm", absDx, absDy);
|
|
|
|
reportPinError(i, tplCenters[i], buf, CONFIG_QX_NAME_PIN_PianYi);
|
|
|
|
reportPinError(i, tplCenters[i], buf, CONFIG_QX_NAME_PIN_PianYi);
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "Pin Check", "pin %d OFFSET dx %.1f dy %.1f", i, absDx, absDy);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 每个pin脚都打印dx/dy(mm),方便调整 pin_x_offset / pin_y_offset 参数
|
|
|
|
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "Pin Check", "pin %d %s dx %.2f dy %.2f mm", i, bOffset ? "OFFSET" : "OK", absDx, absDy);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "Pin Check", "tpl %d cur %d miss %d offset %d", nTpl, nCur, nMiss, nOffset);
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "Pin Check", "tpl %d cur %d miss %d offset %d", nTpl, nCur, nMiss, nOffset);
|
|
|
|
@ -2639,8 +2635,8 @@ int ImgCheckAnalysisy::Pin_Direct_Match()
|
|
|
|
// 新方案(开关 PIN_USE_DIRECT_MATCH = 1): 不做模板对比, 只针对检测Pin分析
|
|
|
|
// 新方案(开关 PIN_USE_DIRECT_MATCH = 1): 不做模板对比, 只针对检测Pin分析
|
|
|
|
// 1) 方向扫描(0~180°, 步长1°): 取 "两排Pin沿法线投影组内方差之和" 最小的角度作为Pin排方向(对图像旋转不敏感),
|
|
|
|
// 1) 方向扫描(0~180°, 步长1°): 取 "两排Pin沿法线投影组内方差之和" 最小的角度作为Pin排方向(对图像旋转不敏感),
|
|
|
|
// 再沿该法线投影, 在最大间隙处把Pin分成两排(两排插口; Pin不足4个则按一排处理);
|
|
|
|
// 再沿该法线投影, 在最大间隙处把Pin分成两排(两排插口; Pin不足4个则按一排处理);
|
|
|
|
// 2) 每排做最小二乘直线拟合(cv::fitLine): pin中心到直线(沿法线方向)距离超过 pin_y_offset(换算像素) 判 偏移;
|
|
|
|
// 2) 每排做最小二乘直线拟合(cv::fitLine): pin中心到直线(沿法线方向)距离按成像精度换算为 mm, 超过 pin_y_offset(mm) 判 偏移;
|
|
|
|
// 3) 每排内沿排方向排序: 相邻两pin中心连线距离超过 pin_x_offset(换算像素) 判 两pin中间缺失一个pin。
|
|
|
|
// 3) 每排内沿排方向排序: 相邻两pin中心连线距离按成像精度换算为 mm, 超过 pin_x_offset(mm) 判 两pin中间缺失一个pin。
|
|
|
|
int ImgCheckAnalysisy::Pin_Direct_Check()
|
|
|
|
int ImgCheckAnalysisy::Pin_Direct_Check()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
// 计算轮廓中心点(外接矩形中心)
|
|
|
|
// 计算轮廓中心点(外接矩形中心)
|
|
|
|
@ -2672,19 +2668,13 @@ int ImgCheckAnalysisy::Pin_Direct_Check()
|
|
|
|
return 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 阈值(mm 参数换算为像素): pin_x_offset -> 相邻pin间距(缺失)阈值; pin_y_offset -> 到拟合直线距离(偏移)阈值; <=0 时不判该项
|
|
|
|
// 阈值直接使用 mm 参数(判据按 mm 比较): pin_x_offset -> 相邻pin间距(缺失)阈值; pin_y_offset -> 到拟合直线距离(偏移)阈值; <=0 时不判该项
|
|
|
|
float offsetThX = 0.0f;
|
|
|
|
float offsetThX = 0.0f; // mm
|
|
|
|
float offsetThY = 0.0f;
|
|
|
|
float offsetThY = 0.0f; // mm
|
|
|
|
if (m_pbaseCheckFunction != NULL)
|
|
|
|
if (m_pbaseCheckFunction != NULL)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (m_fImgage_Scale_X > 0.0f)
|
|
|
|
offsetThX = m_pbaseCheckFunction->pinDet.pin_x_offset;
|
|
|
|
{
|
|
|
|
offsetThY = m_pbaseCheckFunction->pinDet.pin_y_offset;
|
|
|
|
offsetThX = m_pbaseCheckFunction->pinDet.pin_x_offset / m_fImgage_Scale_X;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_fImgage_Scale_Y > 0.0f)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
offsetThY = m_pbaseCheckFunction->pinDet.pin_y_offset / m_fImgage_Scale_Y;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 沿给定方向投影排序, 在最大间隙处切分成两排(order[0..splitK] 一排, order[splitK+1..] 另一排)
|
|
|
|
// 沿给定方向投影排序, 在最大间隙处切分成两排(order[0..splitK] 一排, order[splitK+1..] 另一排)
|
|
|
|
@ -2801,11 +2791,11 @@ int ImgCheckAnalysisy::Pin_Direct_Check()
|
|
|
|
rows.push_back(order);
|
|
|
|
rows.push_back(order);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "Pin Check",
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "Pin Check",
|
|
|
|
"row dir %.1f deg rows %d th[gap %.1f line %.1f] px",
|
|
|
|
"row dir %.1f deg rows %d th[gap %.2f line %.2f] mm",
|
|
|
|
bestTheta * 180.0f / static_cast<float>(CV_PI),
|
|
|
|
bestTheta * 180.0f / static_cast<float>(CV_PI),
|
|
|
|
static_cast<int>(rows.size()), offsetThX, offsetThY);
|
|
|
|
static_cast<int>(rows.size()), offsetThX, offsetThY);
|
|
|
|
|
|
|
|
|
|
|
|
// 上报缺陷(roi/area 由调用处给出; grayDis 记录对应度量: 到直线距离 / 相邻间距, 单位像素)
|
|
|
|
// 上报缺陷(roi/area 由调用处给出; grayDis 记录对应度量: 到直线距离 / 相邻间距, 单位mm)
|
|
|
|
auto reportPinError = [&](const cv::Rect &roi, int area, double grayDis, int nconfig_qx_type, const std::string &detail)
|
|
|
|
auto reportPinError = [&](const cv::Rect &roi, int area, double grayDis, int nconfig_qx_type, const std::string &detail)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
QX_ERROR_INFO_ pinErr;
|
|
|
|
QX_ERROR_INFO_ pinErr;
|
|
|
|
@ -2870,23 +2860,28 @@ int ImgCheckAnalysisy::Pin_Direct_Check()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
m_pinFitLines.push_back(std::make_pair(lineP0 + lineDir * tMin, lineP0 + lineDir * tMax));
|
|
|
|
m_pinFitLines.push_back(std::make_pair(lineP0 + lineDir * tMin, lineP0 + lineDir * tMax));
|
|
|
|
|
|
|
|
|
|
|
|
// 2、pin中心到直线(沿法线方向)距离超过 pin_y_offset -> 偏移
|
|
|
|
// 2、pin中心到直线(沿法线方向)距离超过 pin_y_offset -> 偏移;距离按成像精度换算为 mm (mm = px * 成像精度)
|
|
|
|
if (offsetThY > 0.0f)
|
|
|
|
if (offsetThY > 0.0f)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
for (int i = 0; i < nRow; i++)
|
|
|
|
for (int i = 0; i < nRow; i++)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
float absDist = std::fabs((rowPts[i] - lineP0).dot(lineNor));
|
|
|
|
// 垂直偏移向量(px)的分量分别换算为 mm 后求模
|
|
|
|
if (absDist > offsetThY)
|
|
|
|
float distPx = (rowPts[i] - lineP0).dot(lineNor);
|
|
|
|
{
|
|
|
|
float dx_mm = lineNor.x * distPx * m_fImgage_Scale_X;
|
|
|
|
|
|
|
|
float dy_mm = lineNor.y * distPx * m_fImgage_Scale_Y;
|
|
|
|
|
|
|
|
float absDist = std::sqrt(dx_mm * dx_mm + dy_mm * dy_mm);
|
|
|
|
int idx = rowIdx[i];
|
|
|
|
int idx = rowIdx[i];
|
|
|
|
|
|
|
|
bool bOffset = (absDist > offsetThY);
|
|
|
|
|
|
|
|
if (bOffset)
|
|
|
|
|
|
|
|
{
|
|
|
|
nOffset++;
|
|
|
|
nOffset++;
|
|
|
|
char buf[96];
|
|
|
|
char buf[96];
|
|
|
|
snprintf(buf, sizeof(buf), "pin %d offset to row line %.1f px > %.1f px", idx, absDist, offsetThY);
|
|
|
|
snprintf(buf, sizeof(buf), "pin %d offset to row line %.2f mm > %.2f mm", idx, absDist, offsetThY);
|
|
|
|
reportPinError(curRects[idx], static_cast<int>(cv::contourArea(m_curPinContours[idx])),
|
|
|
|
reportPinError(curRects[idx], static_cast<int>(cv::contourArea(m_curPinContours[idx])),
|
|
|
|
absDist, CONFIG_QX_NAME_PIN_PianYi, buf);
|
|
|
|
absDist, CONFIG_QX_NAME_PIN_PianYi, buf);
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "Pin Check", "row %d pin %d OFFSET %.1f px > %.1f px",
|
|
|
|
|
|
|
|
static_cast<int>(r), idx, absDist, offsetThY);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 每个pin脚都打印到拟合直线的距离(mm),方便调整 pin_y_offset 参数
|
|
|
|
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "Pin Check", "row %d pin %d %s line %.2f mm", static_cast<int>(r), idx, bOffset ? "OFFSET" : "OK", absDist);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@ -2905,11 +2900,16 @@ int ImgCheckAnalysisy::Pin_Direct_Check()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
int ia = tOrder[i].second;
|
|
|
|
int ia = tOrder[i].second;
|
|
|
|
int ib = tOrder[i + 1].second;
|
|
|
|
int ib = tOrder[i + 1].second;
|
|
|
|
float gap = static_cast<float>(cv::norm(rowPts[ib] - rowPts[ia]));
|
|
|
|
// 相邻pin中心连线距离(px)的分量分别换算为 mm 后求模
|
|
|
|
if (gap > offsetThX)
|
|
|
|
cv::Point2f dv = rowPts[ib] - rowPts[ia];
|
|
|
|
{
|
|
|
|
float dx_mm = dv.x * m_fImgage_Scale_X;
|
|
|
|
|
|
|
|
float dy_mm = dv.y * m_fImgage_Scale_Y;
|
|
|
|
|
|
|
|
float gap = std::sqrt(dx_mm * dx_mm + dy_mm * dy_mm);
|
|
|
|
int idxa = rowIdx[ia];
|
|
|
|
int idxa = rowIdx[ia];
|
|
|
|
int idxb = rowIdx[ib];
|
|
|
|
int idxb = rowIdx[ib];
|
|
|
|
|
|
|
|
bool bMiss = (gap > offsetThX);
|
|
|
|
|
|
|
|
if (bMiss)
|
|
|
|
|
|
|
|
{
|
|
|
|
cv::Point2f mid = (rowPts[ia] + rowPts[ib]) * 0.5f;
|
|
|
|
cv::Point2f mid = (rowPts[ia] + rowPts[ib]) * 0.5f;
|
|
|
|
m_pinMissMarks.push_back(mid);
|
|
|
|
m_pinMissMarks.push_back(mid);
|
|
|
|
|
|
|
|
|
|
|
|
@ -2923,11 +2923,11 @@ int ImgCheckAnalysisy::Pin_Direct_Check()
|
|
|
|
static_cast<int>(cv::contourArea(m_curPinContours[idxb]))) / 2;
|
|
|
|
static_cast<int>(cv::contourArea(m_curPinContours[idxb]))) / 2;
|
|
|
|
nMiss++;
|
|
|
|
nMiss++;
|
|
|
|
char buf[96];
|
|
|
|
char buf[96];
|
|
|
|
snprintf(buf, sizeof(buf), "miss between pin %d-%d gap %.1f px > %.1f px", idxa, idxb, gap, offsetThX);
|
|
|
|
snprintf(buf, sizeof(buf), "miss between pin %d-%d gap %.2f mm > %.2f mm", idxa, idxb, gap, offsetThX);
|
|
|
|
reportPinError(roiMiss, areaAvg, gap, CONFIG_QX_NAME_PIN_QueShi, buf);
|
|
|
|
reportPinError(roiMiss, areaAvg, gap, CONFIG_QX_NAME_PIN_QueShi, buf);
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "Pin Check", "row %d pin %d-%d MISS gap %.1f px > %.1f px",
|
|
|
|
|
|
|
|
static_cast<int>(r), idxa, idxb, gap, offsetThX);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 每对相邻pin都打印间距(mm),方便调整 pin_x_offset 参数
|
|
|
|
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "Pin Check", "row %d pin %d-%d %s gap %.2f mm", static_cast<int>(r), idxa, idxb, bMiss ? "MISS" : "OK", gap);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|