update 仿射变换使用内定位

dev_lsy
liusiyang 3 weeks ago
parent e23c3df9d5
commit ba394569ec

@ -67,6 +67,8 @@ public:
// 获取模板外接矩形 // 获取模板外接矩形
const cv::RotatedRect &GetTplOuterRect() const { return m_tplOuterRect; } const cv::RotatedRect &GetTplOuterRect() const { return m_tplOuterRect; }
// 获取模板内边缘矩形
const cv::RotatedRect &GetTplInnerRect() const { return m_tplInnerRect; }
// 获取模板 pin blob 轮廓点集 // 获取模板 pin blob 轮廓点集
const std::vector<std::vector<cv::Point>> &GetTplPinContours() const { return m_tplPinContours; } const std::vector<std::vector<cv::Point>> &GetTplPinContours() const { return m_tplPinContours; }
@ -180,6 +182,7 @@ private:
// 模板信息 // 模板信息
cv::RotatedRect m_tplOuterRect; // 模板外接矩形 cv::RotatedRect m_tplOuterRect; // 模板外接矩形
cv::RotatedRect m_tplInnerRect; // 模板内边缘矩形
std::vector<std::vector<cv::Point>> m_tplPinContours; // 模板 pin blob 轮廓点集 std::vector<std::vector<cv::Point>> m_tplPinContours; // 模板 pin blob 轮廓点集
}; };

@ -135,6 +135,7 @@ public:
// 设置模板信息并转发给各个检测核心 // 设置模板信息并转发给各个检测核心
void SetTplInfo(const cv::RotatedRect &outerRect, void SetTplInfo(const cv::RotatedRect &outerRect,
const cv::RotatedRect &innerRect,
const std::vector<std::vector<cv::Point>> &pinContours); const std::vector<std::vector<cv::Point>> &pinContours);
private: private:

@ -80,8 +80,9 @@ public:
int creatsavedir(); int creatsavedir();
// 设置模板信息(模板外接矩形 + 模板 pin blob 轮廓点集) // 设置模板信息(模板外接矩形 + 模板内边缘矩形 + 模板 pin blob 轮廓点集)
void SetTplInfo(const cv::RotatedRect &outerRect, void SetTplInfo(const cv::RotatedRect &outerRect,
const cv::RotatedRect &innerRect,
const std::vector<std::vector<cv::Point>> &pinContours); const std::vector<std::vector<cv::Point>> &pinContours);
private: private:
@ -201,8 +202,8 @@ private:
// 获取指定 残点(blob) 是由哪个(哪些)检测模型检出的 // 获取指定 残点(blob) 是由哪个(哪些)检测模型检出的
std::string GetBlobModelName(const cv::Rect &roi); std::string GetBlobModelName(const cv::Rect &roi);
//自适应参数区域更新 //自适应参数区域更新:仿射变换到模板坐标系(基准矩形可为内定位/外定位)
int Adapt_Config(cv::RotatedRect tplOuterRect, cv::RotatedRect curOuterRect, cv::Mat& det_img); int Adapt_Config(cv::RotatedRect tplRefRect, cv::RotatedRect curRefRect, cv::Mat& det_img);
std::shared_ptr<AIFactory> AI_Factory; std::shared_ptr<AIFactory> AI_Factory;
@ -299,6 +300,7 @@ private:
cv::RotatedRect m_tplOuterRect; // 模板外接矩形 cv::RotatedRect m_tplOuterRect; // 模板外接矩形
cv::RotatedRect m_outer_rroi; cv::RotatedRect m_outer_rroi;
cv::RotatedRect m_inner_rroi; cv::RotatedRect m_inner_rroi;
cv::RotatedRect m_tplInnerRect; // 模板内边缘矩形
std::vector<std::vector<cv::Point>> m_tplPinContours; // 模板 pin blob 轮廓点集 std::vector<std::vector<cv::Point>> m_tplPinContours; // 模板 pin blob 轮廓点集
std::vector<std::vector<cv::Point>> m_curPinContours; // 当前 pin blob 轮廓点集 std::vector<std::vector<cv::Point>> m_curPinContours; // 当前 pin blob 轮廓点集
}; };

@ -246,7 +246,8 @@ int AI_Edge_Algin::Detect(const cv::Mat &img, DetConfig *pDetConfig, std::shared
} }
return re; return re;
} }
cv::Mat Big_outimg_src = img(Big_roi.boundingRect()).clone(); cv::Rect Big_out_roi = Big_roi.boundingRect() & cv::Rect(0, 0, img.cols, img.rows);
cv::Mat Big_outimg_src = img(Big_out_roi).clone();
re = Get_Edge(1, Big_outimg_src, pDetConfig, m_pDetConfig->strChannel, Small_roi); re = Get_Edge(1, Big_outimg_src, pDetConfig, m_pDetConfig->strChannel, Small_roi);
if (re != 0) if (re != 0)
{ {

@ -101,7 +101,7 @@ int ALLImgCheckAnalysisy::RunStart(void *pconfig1)
{ {
if (item.second) if (item.second)
{ {
item.second->SetTplInfo(m_tplOuterRect, m_tplPinContours); item.second->SetTplInfo(m_tplOuterRect, m_tplInnerRect, m_tplPinContours);
} }
} }
m_nErrorCode = CHECK_OK; m_nErrorCode = CHECK_OK;
@ -172,7 +172,7 @@ int ALLImgCheckAnalysisy::UpdateConfig(void *pconfig, int nConfigType)
{ {
if (item.second) if (item.second)
{ {
item.second->SetTplInfo(m_tplOuterRect, m_tplPinContours); item.second->SetTplInfo(m_tplOuterRect, m_tplInnerRect, m_tplPinContours);
} }
} }
} }
@ -249,7 +249,7 @@ int ALLImgCheckAnalysisy::InitAIFactory()
int ALLImgCheckAnalysisy::InitTemplateMask() int ALLImgCheckAnalysisy::InitTemplateMask()
{ {
std::shared_ptr<AIFactory> AI_Factory = AIFactory::GetInstance(); std::shared_ptr<AIFactory> AI_Factory = AIFactory::GetInstance();
if (!AI_Factory || !AI_Factory->Align_Outer || !AI_Factory->Pin_Loc) if (!AI_Factory || !AI_Factory->Align_Outer || !AI_Factory->Align_Inner || !AI_Factory->Pin_Loc)
{ {
return -1; return -1;
} }
@ -322,6 +322,78 @@ int ALLImgCheckAnalysisy::InitTemplateMask()
} }
tplOuterRect = cv::minAreaRect(srcContour); tplOuterRect = cv::minAreaRect(srcContour);
// 模板内边缘矩形,通过模型Align_Inner得到
// 与 AI_Edge_Algin::Detect 的内定位流程保持一致:按外接矩形裁剪模板图 -> Align_Inner 推理 -> 轮廓还原并把裁剪偏移加回,得到模板图坐标系下的内边缘矩形
// PIN 偏移/缺失检测的仿射变换以内定位为基准,模板侧需先准备好该矩形;计算失败时保持空值,运行时自动回退外定位
cv::RotatedRect tplInnerRect;
bool bTplInnerOk = false;
std::shared_ptr<AIModel_Base> pSocket_AlignInner = AI_Factory->Align_Inner;
cv::Rect tplOuterBound = tplOuterRect.boundingRect() & cv::Rect(0, 0, tplImg.cols, tplImg.rows);
if (pSocket_AlignInner && tplOuterBound.width > 0 && tplOuterBound.height > 0)
{
cv::Mat innerCropImg = tplImg(tplOuterBound).clone();
cv::Size innerSz;
innerSz.width = pSocket_AlignInner->input_0.width;
innerSz.height = pSocket_AlignInner->input_0.height;
cv::Mat innerDetImg;
cv::resize(innerCropImg, innerDetImg, innerSz);
if (innerDetImg.channels() != 1)
{
// 与运行时 AI_Edge_Algin::Get_Edge 内定位的灰度化保持一致(BGR 顺序)
cv::cvtColor(innerDetImg, innerDetImg, cv::COLOR_BGR2GRAY);
}
cv::Mat innerMask;
int reInner = pSocket_AlignInner->AIDet(innerDetImg, innerMask);
if (reInner != 0)
{
m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_1, "Init Tpl", "AICheck_Inner----error %d ", reInner);
}
else
{
// 找到最大轮廓
bool innerFound = false;
std::vector<cv::Point> innerBoundingBox = CheckUtil::getLargestContourROI(innerMask, innerFound);
if (!innerFound || innerBoundingBox.size() < 3)
{
m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_1, "Init Tpl", "Inner align: No contours found!----error ");
}
else
{
// 内定位小图 到 裁剪图 的缩放比例
const float inner_scale_x = static_cast<float>(innerCropImg.cols) / innerSz.width;
const float inner_scale_y = static_cast<float>(innerCropImg.rows) / innerSz.height;
std::vector<cv::Point2f> innerContour;
innerContour.reserve(innerBoundingBox.size());
for (const auto &pt : innerBoundingBox)
{
innerContour.emplace_back(pt.x * inner_scale_x, pt.y * inner_scale_y);
}
tplInnerRect = cv::minAreaRect(innerContour);
// 裁剪图坐标 -> 模板图坐标(与 AI_Edge_Algin::Detect 中 smallroi 偏移加回一致)
tplInnerRect.center.x += static_cast<float>(tplOuterBound.x);
tplInnerRect.center.y += static_cast<float>(tplOuterBound.y);
bTplInnerOk = true;
}
}
}
else
{
m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_1, "Init Tpl", "Inner align: model null or outer bound invalid!----error ");
}
if (bTplInnerOk)
{
m_tplInnerRect = tplInnerRect;
m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_1, "Init Tpl",
"tplInnerRect center(%.1f %.1f) size(%.1f %.1f) angle %.1f",
tplInnerRect.center.x, tplInnerRect.center.y,
tplInnerRect.size.width, tplInnerRect.size.height, tplInnerRect.angle);
}
else
{
m_tplInnerRect = cv::RotatedRect();
m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_1, "Init Tpl", "Tpl Inner align invalid, runtime fallback to Outer align!");
}
// 模板Pinmask,通过模型Pin_Loc得到 // 模板Pinmask,通过模型Pin_Loc得到
Mat tplPinMask; // 模板mask Mat tplPinMask; // 模板mask
std::shared_ptr<AIModel_Base> pSocket_Pin; std::shared_ptr<AIModel_Base> pSocket_Pin;

@ -629,6 +629,7 @@ int CameraCheckAnalysisy::Init(std::string strcameraName)
} }
void CameraCheckAnalysisy::SetTplInfo(const cv::RotatedRect &outerRect, void CameraCheckAnalysisy::SetTplInfo(const cv::RotatedRect &outerRect,
const cv::RotatedRect &innerRect,
const std::vector<std::vector<cv::Point>> &pinContours) const std::vector<std::vector<cv::Point>> &pinContours)
{ {
for (int i = 0; i < IMGCHECKANALYSISY_NUM; i++) for (int i = 0; i < IMGCHECKANALYSISY_NUM; i++)
@ -636,7 +637,7 @@ void CameraCheckAnalysisy::SetTplInfo(const cv::RotatedRect &outerRect,
auto *p = static_cast<ImgCheckAnalysisy *>(m_pImgCheckAnalysisy[i]); auto *p = static_cast<ImgCheckAnalysisy *>(m_pImgCheckAnalysisy[i]);
if (p) if (p)
{ {
p->SetTplInfo(outerRect, pinContours); p->SetTplInfo(outerRect, innerRect, pinContours);
} }
} }
} }

@ -211,9 +211,11 @@ int ImgCheckAnalysisy::creatsavedir()
} }
void ImgCheckAnalysisy::SetTplInfo(const cv::RotatedRect &outerRect, void ImgCheckAnalysisy::SetTplInfo(const cv::RotatedRect &outerRect,
const cv::RotatedRect &innerRect,
const std::vector<std::vector<cv::Point>> &pinContours) const std::vector<std::vector<cv::Point>> &pinContours)
{ {
m_tplOuterRect = outerRect; m_tplOuterRect = outerRect;
m_tplInnerRect = innerRect;
m_tplPinContours = pinContours; m_tplPinContours = pinContours;
} }
@ -370,9 +372,10 @@ cv::Scalar ImgCheckAnalysisy::calc_blob_info_withstats(cv::Mat &img, const cv::M
return cv::Scalar(worb, energy, hj); return cv::Scalar(worb, energy, hj);
} }
int ImgCheckAnalysisy::Adapt_Config(RotatedRect tplOuterRect, RotatedRect curOuterRect, Mat& det_img){ // 仿射变换到模板坐标系:把当前基准矩形(内定位/外定位)的顶点映射到模板对应基准矩形上
vector<cv::Point2f> cur_vertices = CheckUtil::sort_vertices(curOuterRect); int ImgCheckAnalysisy::Adapt_Config(RotatedRect tplRefRect, RotatedRect curRefRect, Mat& det_img){
vector<cv::Point2f> tpl_vertices = CheckUtil::sort_vertices(tplOuterRect); vector<cv::Point2f> cur_vertices = CheckUtil::sort_vertices(curRefRect);
vector<cv::Point2f> tpl_vertices = CheckUtil::sort_vertices(tplRefRect);
cv::Point2f src_pts[3] = { cv::Point2f src_pts[3] = {
cur_vertices[0], // 对应左上 cur_vertices[0], // 对应左上
@ -554,7 +557,21 @@ int ImgCheckAnalysisy::CheckRun()
} }
/*投影对齐模板*/ /*投影对齐模板*/
// 检测PIN偏移/缺失对位置基准最敏感:PIN 位置的真实基准是产品内腔(内定位),
// 因此优先用内定位做仿射变换(当前内边缘 -> 模板内边缘);
// 模板内定位/当前内定位缺失或无效时,回退到外定位(与旧行为一致)
bool bUseInnerAlign = (m_tplInnerRect.size.width > 0 && m_tplInnerRect.size.height > 0 &&
m_inner_rroi.size.width > 0 && m_inner_rroi.size.height > 0);
if (bUseInnerAlign)
{
m_pdetlog->AddCheckstr(PrintLevel_0, "2.1、pre detect", "Affine align basis: Inner(inner_rroi -> tplInnerRect)");
Adapt_Config(m_tplInnerRect, m_inner_rroi, m_CheckResult_shareP->in_shareImage->img);
}
else
{
m_pdetlog->AddCheckstr(PrintLevel_0, "2.1、pre detect", "Affine align basis: Outer(outer_rroi -> tplOuterRect)");
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();
m_Crop_Roi_paramImg = m_outer_roi; m_Crop_Roi_paramImg = m_outer_roi;
m_pImageAllResult->pDetResult->CutRoi = m_outer_roi; m_pImageAllResult->pDetResult->CutRoi = m_outer_roi;

Loading…
Cancel
Save