diff --git a/AlgorithmModule/include/ImageAllResult.h b/AlgorithmModule/include/ImageAllResult.h index a6e59b2..87195ef 100644 --- a/AlgorithmModule/include/ImageAllResult.h +++ b/AlgorithmModule/include/ImageAllResult.h @@ -70,6 +70,9 @@ public: float fscale_detToresult_x = 0; float fscale_detToresult_y = 0; + // 产品左上角(rot_cur_roi.boundingRect)在检测图 detImg 中的偏移,缺陷坐标转换到产品坐标系时需减去该间隙 + cv::Point ptRoiOffsetInDet = cv::Point(0, 0); + int NG_num = 0; int YS_num = 0; int Ok_num = 0; diff --git a/AlgorithmModule/include/ImgCheckAnalysisy.hpp b/AlgorithmModule/include/ImgCheckAnalysisy.hpp index 7bc29e9..7e49e6b 100644 --- a/AlgorithmModule/include/ImgCheckAnalysisy.hpp +++ b/AlgorithmModule/include/ImgCheckAnalysisy.hpp @@ -241,6 +241,8 @@ private: cv::Rect m_CutRoi; cv::Rect m_Crop_Roi_paramImg; // 裁切在参数模板图上的 位置。 + cv::RotatedRect m_rot_cur_roi; // 产品旋转外接矩形(原图坐标) + bool m_bRotCurRoiValid = false; // m_rot_cur_roi 是否有效 std::string m_strCurDetChannel; // 当前处理的图片通道 diff --git a/AlgorithmModule/src/ImageResultJudge.cpp b/AlgorithmModule/src/ImageResultJudge.cpp index 4d32cb8..b4db803 100644 --- a/AlgorithmModule/src/ImageResultJudge.cpp +++ b/AlgorithmModule/src/ImageResultJudge.cpp @@ -119,7 +119,11 @@ int ImageResultJudge::GetAIDetImg(std::shared_ptr pImageResult, QXImageResult ImageResultJudge::BuildDefectImage(std::shared_ptr pImageResult, QX_ERROR_INFO_ *QX_info, int qxidx, cv::Point pCenter, float fs_resize_x, float fs_resize_y) { - cv::Rect roi = QX_info->roi; + cv::Rect roi = QX_info->roi; // 缺陷坐标(产品坐标系,已减去裁剪框与产品左上角的间隙) + // 还原检测图(detImg)坐标,用于缺陷小图裁剪等内部用途 + cv::Rect roi_det = roi; + roi_det.x += pImageResult->ptRoiOffsetInDet.x; + roi_det.y += pImageResult->ptRoiOffsetInDet.y; float JudgArea = QX_info->JudgArea; float flen = QX_info->flen; float fbreadth = QX_info->fbreadth; @@ -130,7 +134,7 @@ QXImageResult ImageResultJudge::BuildDefectImage(std::shared_ptr QXImageResult tem; tem.idx = qxidx; - cv::Rect CutRoi = GetCutRoi(roi, pImageResult->detImg); + cv::Rect CutRoi = GetCutRoi(roi_det, pImageResult->detImg); cv::Size sz = cv::Size(QX_SAMLLIMG_WIDTH, QX_SAMLLIMG_HEIGHT); if (pImageResult->detImg.channels() == 1) @@ -151,25 +155,26 @@ QXImageResult ImageResultJudge::BuildDefectImage(std::shared_ptr tem.max_v = maxValue; tem.strTypeName = QX_Result_Names[nqx_type]; tem.qx_Code = QX_Result_Code[nqx_type]; - tem.srcImgroi = roi; + tem.srcImgroi = roi_det; tem.len = flen; tem.breadth = fbreadth; tem.qx_type = 0; tem.fScore = 0; tem.density = 0; - tem.resizeImgroi.x = roi.x * fs_resize_x; - tem.resizeImgroi.width = roi.width * fs_resize_x; - tem.resizeImgroi.y = roi.y * fs_resize_y; - tem.resizeImgroi.height = roi.height * fs_resize_y; + tem.resizeImgroi.x = roi_det.x * fs_resize_x; + tem.resizeImgroi.width = roi_det.width * fs_resize_x; + tem.resizeImgroi.y = roi_det.y * fs_resize_y; + tem.resizeImgroi.height = roi_det.height * fs_resize_y; + // 缺陷中心:产品坐标系(像素/物理),相对产品左上角 tem.x_pixel = roi.x + roi.width * 0.5; tem.y_pixel = roi.y + roi.height * 0.5; tem.x_mm = tem.x_pixel * m_fImgage_Scale_X; tem.y_mm = tem.y_pixel * m_fImgage_Scale_Y; - tem.CutImgroi = roi; + tem.CutImgroi = roi_det; tem.CutImgroi.x -= CutRoi.x; tem.CutImgroi.y -= CutRoi.y; diff --git a/AlgorithmModule/src/ImgCheckAnalysisy.cpp b/AlgorithmModule/src/ImgCheckAnalysisy.cpp index c245d26..15716b3 100644 --- a/AlgorithmModule/src/ImgCheckAnalysisy.cpp +++ b/AlgorithmModule/src/ImgCheckAnalysisy.cpp @@ -802,7 +802,16 @@ int ImgCheckAnalysisy::CheckRun() /*自适应更新参数*/ long time_adapt_s = CheckUtil::getcurTime(); cv::RotatedRect rot_cur_roi; - Adapt_Config(m_CheckResult_shareP->in_shareImage->img, m_CutRoi, rot_cur_roi, m_pbaseCheckFunction->markLine.badapt_region); + int nAdaptRe = Adapt_Config(m_CheckResult_shareP->in_shareImage->img, m_CutRoi, rot_cur_roi, m_pbaseCheckFunction->markLine.badapt_region); + if (nAdaptRe == 0) + { + m_rot_cur_roi = rot_cur_roi; + m_bRotCurRoiValid = true; + } + else + { + m_bRotCurRoiValid = false; + } long time_adapt_e = CheckUtil::getcurTime(); m_pdetlog->AddCheckstr(PrintLevel_0, "Adapt_Config", "time = %ld", time_adapt_e - time_adapt_s); @@ -842,6 +851,18 @@ int ImgCheckAnalysisy::CheckRun() m_pdetlog->AddCheckstr(PrintLevel_0, "2、pre detect", "-------------------------AI_Edge------------succ---time %ld----\n", time_edge_e - time_edge_s); m_Crop_Roi_paramImg = m_CutRoi; + // 计算产品左上角在检测图(detImg)中的偏移(间隙),用于缺陷坐标转换到产品坐标系 + if (m_bRotCurRoiValid) + { + // 取旋转矩形实际的左上角顶点(非轴对齐外接框 boundingRect,后者在带旋转角时会偏大) + std::vector rroi_vertices = sort_vertices(m_rot_cur_roi); + m_pImageAllResult->ptRoiOffsetInDet.x = cvRound(rroi_vertices[0].x) - m_CutRoi.x; + m_pImageAllResult->ptRoiOffsetInDet.y = cvRound(rroi_vertices[0].y) - m_CutRoi.y; + } + else + { + m_pImageAllResult->ptRoiOffsetInDet = cv::Point(0, 0); + } m_pImageAllResult->pDetResult->CutRoi = m_CutRoi; m_pImageAllResult->pDetResult->Param_CropRoi = m_Crop_Roi_paramImg; @@ -2532,6 +2553,12 @@ int ImgCheckAnalysisy::Edge_Qx_Det(const cv::Mat &img) // } // } + // 缺陷坐标转换到产品坐标系:减去裁剪框与产品左上角的间隙 + if (m_bRotCurRoiValid) + { + temerror.roi.x -= m_pImageAllResult->ptRoiOffsetInDet.x; + temerror.roi.y -= m_pImageAllResult->ptRoiOffsetInDet.y; + } m_pDetResult->pQx_ErrorList->push_back(temerror); } @@ -2604,6 +2631,12 @@ int ImgCheckAnalysisy::BLobToDetResult() { QX_ERROR_INFO_ temerror; temerror.roi = roi; + // 缺陷坐标转换到产品坐标系:减去裁剪框与产品左上角的间隙 + if (m_bRotCurRoiValid) + { + temerror.roi.x -= m_pImageAllResult->ptRoiOffsetInDet.x; + temerror.roi.y -= m_pImageAllResult->ptRoiOffsetInDet.y; + } temerror.Idx = m_pDetResult->pQx_ErrorList->size(); temerror.area = blobs.blobTab[i].area; temerror.JudgArea = JudgArea; @@ -2695,8 +2728,25 @@ int ImgCheckAnalysisy::AI_Edge(const cv::Mat &img, cv::Rect &cutRoi) int ImgCheckAnalysisy::CalProductSize() { - float fw = m_CutRoi.width * m_fImgage_Scale_X; - float fh = m_CutRoi.height * m_fImgage_Scale_Y; + float fw, fh; + if (m_bRotCurRoiValid) + { + // 产品存在旋转角:用旋转矩形四个顶点的实际边长换算物理尺寸 + // 宽 = (左上-右上 + 左下-右下) / 2,高 = (左上-左下 + 右上-右下) / 2 + std::vector v = sort_vertices(m_rot_cur_roi); + auto edgeLenPhys = [&](const cv::Point2f &a, const cv::Point2f &b) -> double { + double dx = (a.x - b.x) * m_fImgage_Scale_X; + double dy = (a.y - b.y) * m_fImgage_Scale_Y; + return std::sqrt(dx * dx + dy * dy); + }; + fw = (float)((edgeLenPhys(v[0], v[1]) + edgeLenPhys(v[2], v[3])) * 0.5); // 上边+下边平均 + fh = (float)((edgeLenPhys(v[0], v[2]) + edgeLenPhys(v[1], v[3])) * 0.5); // 左边+右边平均 + } + else + { + fw = m_CutRoi.width * m_fImgage_Scale_X; + fh = m_CutRoi.height * m_fImgage_Scale_Y; + } fw = std::ceil(fw * 10) / 10; fh = std::ceil(fh * 10) / 10; m_CheckResult_shareP->productWidht_mm = fw;