update 优化传统检测

dev_lsy
liusiyang 2 weeks ago
parent ae6cfc95c1
commit 7aca87a0bf

@ -108,7 +108,7 @@ private:
cv::Mat m_matLoad;
cv::Mat m_matBlob;
cv::Mat m_matBlur; // 模糊图,供 TraditionalClassify 使用
cv::Mat m_matBlur;
cv::Mat m_matDraw;
cv::Size m_sizeImage;

@ -225,9 +225,9 @@ void CTcsCheck::ClassifyBlobs(const cv::Mat& blurCrop, const cv::Mat& imgBlob)
const int w = stats.at<int>(label, cv::CC_STAT_WIDTH);
const int h = stats.at<int>(label, cv::CC_STAT_HEIGHT);
// blob 区域均值
cv::Mat blobMask = (labels == label);
double blobMean = cv::mean(blurCrop, blobMask)[0];
// blob 区域均值:仅在 bounding rect 局部计算,避免全图 mask
cv::Mat blobMask = (labels(cv::Rect(x, y, w, h)) == label);
double blobMean = cv::mean(blurCrop(cv::Rect(x, y, w, h)), blobMask)[0];
// 所属局部块均值
const double cx = centroids.at<double>(label, 0);
@ -338,6 +338,16 @@ int CTcsCheck::TraditionalDetect(const cv::Mat& img, cv::Rect detRoi, cv::Mat& b
return -1;
}
// 分步计时记录每个步骤的耗时ms
auto tStart = std::chrono::high_resolution_clock::now();
auto tPrev = tStart;
auto logStep = [&](const std::string& step) {
auto tNow = std::chrono::high_resolution_clock::now();
double elapsedMs = std::chrono::duration_cast<std::chrono::milliseconds>(tNow - tPrev).count();
std::cout << "[TraditionalDetect] " << step << " 耗时(ms): " << elapsedMs << std::endl;
tPrev = tNow;
};
// getchar();
// cv::Mat showImg = img.clone();
// cv::rectangle(showImg, detRoi, cv::Scalar(255), 2);
@ -352,6 +362,7 @@ int CTcsCheck::TraditionalDetect(const cv::Mat& img, cv::Rect detRoi, cv::Mat& b
// 1. 全局阈值 → 产品区域定位
cv::Mat matBinary;
cv::threshold(m_matLoad, matBinary, m_cpCfg.nAreaLowFilter, 255, cv::THRESH_BINARY);
// logStep("1.全局阈值");
// 2. 获取最大连通域外接矩形
cv::Rect rtValid = GetBoundingRect(matBinary);
@ -360,9 +371,11 @@ int CTcsCheck::TraditionalDetect(const cv::Mat& img, cv::Rect detRoi, cv::Mat& b
blobImg = cv::Mat();
return -1;
}
// logStep("2.最大连通域外接矩形");
// 3. 裁剪边缘
rtCrop = GetCropArea(rtValid);
// logStep("3.裁剪边缘");
}
// 安全裁剪: 确保 rtCrop 不超出 m_matLoad 边界
@ -375,53 +388,46 @@ int CTcsCheck::TraditionalDetect(const cv::Mat& img, cv::Rect detRoi, cv::Mat& b
return -1;
}
}
// logStep("4.安全裁剪");
cv::Mat matCrop = m_matLoad(rtCrop).clone();
cv::Mat matCrop = m_matLoad(rtCrop);
// logStep("5.ROI裁剪");
// 4. 缩放
// 6. 缩放
const int outW = std::max(1, static_cast<int>(matCrop.cols * m_cpCfg.fZoomRatio));
const int outH = std::max(1, static_cast<int>(matCrop.rows * m_cpCfg.fZoomRatio));
cv::Mat matResized;
cv::resize(matCrop, matResized, cv::Size(outW, outH), 0, 0, cv::INTER_AREA);
// logStep("6.缩放");
// 5. 高斯模糊 — 缓存到 m_matBlur
// 7. 高斯模糊 — 缓存到 m_matBlur
cv::GaussianBlur(matResized, m_matBlur, cv::Size(5, 5), 0);
// cv::imwrite("matResized.png", matResized);
// cv::imwrite("m_matBlur.png", m_matBlur);
// 6. 自适应二值化检测
// logStep("7.高斯模糊");
// 8. 自适应二值化检测
m_matBlob = AdaptiveBinary(m_matBlur);
blobImg = m_matBlob.clone();
blobImg = m_matBlob;
// logStep("8.自适应二值化");
// 7. 反向映射:将 crop+resize 后的残点图恢复为原始输入图尺寸
// 调用方拿到的是与输入 img 同尺寸的 mask坐标体系一致
// 9. 反向映射:只生成下游需要的全尺寸残点 maskresultMaskImg / Blob 计算)。
// 直接 resize 到 ROI 上,省去中间 matCropSize 缓冲与 copyTo
// m_matBlob 保持小图即可,全尺寸副本无任何消费者,已移除。
if (m_cpCfg.fZoomRatio > 0)
{
// 7a. 反向映射 blobImg二值 mask用 INTER_NEAREST
{
cv::Mat matCropSize;
cv::resize(blobImg, matCropSize, cv::Size(rtCrop.width, rtCrop.height), 0, 0, cv::INTER_NEAREST);
cv::Mat fullMask = cv::Mat::zeros(m_matLoad.size(), CV_8UC1);
matCropSize.copyTo(fullMask(rtCrop));
blobImg = fullMask;
}
cv::Mat fullMask = cv::Mat::zeros(m_matLoad.size(), CV_8UC1);
cv::resize(m_matBlob, fullMask(rtCrop), cv::Size(rtCrop.width, rtCrop.height), 0, 0, cv::INTER_NEAREST);
blobImg = fullMask;
// 7b. 同步反向映射 m_matBlur灰度图供 TraditionalClassify 使用,用 INTER_LINEAR
{
cv::Mat matCropSize;
cv::resize(m_matBlur, matCropSize, cv::Size(rtCrop.width, rtCrop.height), 0, 0, cv::INTER_LINEAR);
cv::Mat fullBlur = cv::Mat::zeros(m_matLoad.size(), m_matBlur.type());
matCropSize.copyTo(fullBlur(rtCrop));
m_matBlur = fullBlur;
}
// logStep("9.反向映射(mask)");
}
// 7c. 同步反向映射 m_matBlob二值 mask用 INTER_NEAREST
{
cv::Mat matCropSize;
cv::resize(m_matBlob, matCropSize, cv::Size(rtCrop.width, rtCrop.height), 0, 0, cv::INTER_NEAREST);
cv::Mat fullBlob = cv::Mat::zeros(m_matLoad.size(), CV_8UC1);
matCropSize.copyTo(fullBlob(rtCrop));
m_matBlob = fullBlob;
}
// 总耗时
{
auto tEnd = std::chrono::high_resolution_clock::now();
double totalMs = std::chrono::duration_cast<std::chrono::milliseconds>(tEnd - tStart).count();
// std::cout << "[TraditionalDetect] 总耗时(ms): " << totalMs << std::endl;
}
return 0;
@ -430,15 +436,16 @@ int CTcsCheck::TraditionalDetect(const cv::Mat& img, cv::Rect detRoi, cv::Mat& b
// ============================================================
// TraditionalClassify — 独立分类接口
// 对残点二值图做连通域分析+缺陷分类决策树
// 前提: 已调用 TraditionalDetectm_matBlur 已缓存)
// 前提: 已调用 TraditionalDetectblobImg 已与 m_matLoad 同尺寸)
// 使用没有任何处理的原图 m_matLoad 计算灰阶差
// 返回: 分类到的缺陷数量,<0 表示异常
// ============================================================
int CTcsCheck::TraditionalClassify(const cv::Mat& blobImg)
{
if (m_matBlur.empty() || blobImg.empty()) return -1;
if (m_matLoad.empty() || blobImg.empty()) return -1;
m_matBlob = blobImg.clone();
ClassifyBlobs(m_matBlur, blobImg);
// 不再为全尺寸 mask 做一次 clone直接使用 blobImg 分类
ClassifyBlobs(m_matLoad, blobImg);
return static_cast<int>(m_vecDefectInfo.size());
}

Loading…
Cancel
Save