#include "AI_Edge_Algin.h" #include "CheckErrorCodeDefine.hpp" #define EDGE_GPU 0 AI_Edge_Algin::AI_Edge_Algin() { m_bInitialized = false; m_bModelSucc = false; m_str_curCamName = ""; AI_Factory = AIFactory::GetInstance(); CheckUtil::CreateDir("/home/aidlux/BOE/FOG/Edge/Error/"); CheckUtil::CreateDir("/home/aidlux/BOE/FOG/Edge/Result/"); CheckUtil::CreateDir("/home/aidlux/BOE/FOG/Edge/Smasll/"); CheckUtil::CreateDir("/home/aidlux/BOE/FOG/Edge/Big/"); runner = std::make_shared(); runner->Start(); } AI_Edge_Algin::~AI_Edge_Algin() { } int AI_Edge_Algin::Detect(const cv::Mat &img, DetConfig *pDetConfig, std::shared_ptr &pCheckResult_Aling) { m_pDetConfig = pDetConfig; m_str_curCamName = pDetConfig->strCamName; // printf("save type saveProcessImg %d bSaveResultImg %d cam %s\n", // pDetConfig->saveProcessImg, m_pDetConfig->bDebugSaveImg, m_str_curCamName.c_str()); static int erridx = 0; std::string str_error = ""; // 保存过程图片 if (m_pDetConfig->IsSaveProcessImg()) { erridx++; if (erridx > 9999999) { erridx = 0; } str_error = "/home/aidlux/BOE/FOG/Edge/Error/" + std::to_string(erridx) + "_src.png"; } cv::Mat showimg; // 保存结果图片 if (m_pDetConfig->bDebugSaveImg) { cv::cvtColor(img, showimg, cv::COLOR_GRAY2BGR); } pCheckResult_Aling = std::make_shared(); if (img.empty()) { return 1; } long t1 = CheckUtil::getcurTime(); // 1、初步定位 找到产品大致区域 int re = 0; vector rois; cv::Rect Big_roi; cv::Mat mask; cv::Mat big_mask; re = Det_big(img, rois, pCheckResult_Aling->edge_RoiList, Big_roi, big_mask); if (re != 0) { // printf("AICheck_Edge_Big----error %d \n", re); if (m_pDetConfig->IsSaveProcessImg()) { cv::imwrite(str_error, img); } return re; } long t2 = CheckUtil::getcurTime(); if (m_pDetConfig->bDebugSaveImg) { for (const auto &roi : rois) { cv::rectangle(showimg, roi, cv::Scalar(0, 0, 255)); } cv::rectangle(showimg, Big_roi, cv::Scalar(255, 255, 255), 2); cv::imwrite(pDetConfig->strCamName + "_0_edge_Small_Det_ROI.png", showimg); } cv::Mat Src_Mask; re = Dtet_small(img, rois, Src_Mask); if (re != 0) { // printf("AICheck_Edge_Small----error %d \n", re); if (m_pDetConfig->IsSaveProcessImg()) { cv::imwrite(str_error, img); } return re; } long t3 = CheckUtil::getcurTime(); cv::Mat Src_Masksss; if (m_pDetConfig->bDebugSaveImg) { cv::imwrite(pDetConfig->strCamName + "_1_edge_Small_Out_Mask.png", Src_Mask); } cv::Rect result_roi; Mat resultMask = Mat::zeros(img.size(), CV_8UC1); { vector> contours; findContours(Src_Mask, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE); // 找到最大轮廓 double max_area = 0; int max_contour_index = 0; for (int i = 0; i < contours.size(); i++) { double area = contourArea(contours[i]); if (area > max_area) { max_area = area; max_contour_index = i; } } if (max_contour_index < 0) { cerr << "No contours found!" << endl; return 7; } if (max_contour_index >= 0) { result_roi = boundingRect(contours[max_contour_index]); } drawContours(resultMask, contours, max_contour_index, Scalar(255), FILLED); // -1表示填充所有轮廓 } long t4 = CheckUtil::getcurTime(); // 和原始big模型做比对 { double widthDiff = std::abs(result_roi.width - Big_roi.width) * 1.0f / std::min(result_roi.width, Big_roi.width); double heightDiff = std::abs(result_roi.height - Big_roi.height) * 1.0f / std::min(result_roi.height, Big_roi.height); // printf("big roi %s det %swidthDiff %f heightDiff %f\n", CheckUtil::GetRectString(Big_roi).c_str(), CheckUtil::GetRectString(result_roi).c_str(), widthDiff, heightDiff); // 如果差异超过10%,抛出异常 if (widthDiff > 0.10) { return 51; } if (heightDiff > 0.10) { return 52; } } if (m_pDetConfig->bUseDrawRoi_Check) { double widthDiff = std::abs(result_roi.width - m_pDetConfig->drawRoi.width) * 1.0f / std::min(result_roi.width, m_pDetConfig->drawRoi.width); double heightDiff = std::abs(result_roi.height - m_pDetConfig->drawRoi.height) * 1.0f / std::min(result_roi.height, m_pDetConfig->drawRoi.height); //printf("draw roi %s det %s widthDiff %f heightDiff %f\n", CheckUtil::GetRectString(m_pDetConfig->drawRoi).c_str(), CheckUtil::GetRectString(result_roi).c_str(), widthDiff, heightDiff); // 如果差异超过10%,抛出异常 if (widthDiff > 0.10) { return 53; } if (heightDiff > 0.10) { return 54; } } long t5 = CheckUtil::getcurTime(); // 用big 的来测试 if (false) { cv::Size sz_big; sz_big.width = big_mask.cols; sz_big.height = big_mask.rows; cv::Mat size_prodct; cv::resize(resultMask, size_prodct, sz_big, 0, 0, cv::INTER_AREA); int va_big = countNonZero(big_mask); int va_small = countNonZero(size_prodct); if (va_big > 0) { int diff = std::abs(va_big - va_small); // 面积的差异值。 float fs = diff * 1.0f / va_big; // printf("va_big %d va_small %d dff %d diffscale %f \n", va_big, va_small, diff, fs); if (fs > 0.1) { // if (true) // { // cv::imwrite("big_mask.png",big_mask); // cv::imwrite("size_prodct.png",size_prodct); // getchar(); // } return 55; } } /* code */ } if (m_pDetConfig->bUseDrawRoi_Check && !m_pDetConfig->drawMask.empty()) { cv::Size sz_big; sz_big.width = big_mask.cols; sz_big.height = big_mask.rows; cv::Mat size_prodct; cv::resize(resultMask, size_prodct, sz_big, 0, 0, cv::INTER_AREA); cv::Mat size_drawmask; cv::resize(m_pDetConfig->drawMask, size_drawmask, sz_big, 0, 0, cv::INTER_AREA); int va_draw = countNonZero(size_drawmask); int va_small = countNonZero(size_prodct); if (va_draw > 0) { int diff = std::abs(va_draw - va_small); // 面积的差异值。 float fs = diff * 1.0f / va_draw; // printf("va_draw %d va_small %d dff %d diffscale %f \n", va_draw, va_small, diff, fs); if (fs > 0.1) { return 56; } } } long t6 = CheckUtil::getcurTime(); if (m_pDetConfig->bDebugSaveImg) { cv::imwrite(pDetConfig->strCamName + "_3_edge_product_det_mask.png", resultMask); if (!m_pDetConfig->drawMask.empty()) { cv::imwrite(pDetConfig->strCamName + "_4_edge_product_draw_mask.png", m_pDetConfig->drawMask); } } pCheckResult_Aling->DetMask_src = resultMask; cv::Mat resultMask_erode_small; // 膨胀腐蚀处理 { // printf("m_pDetConfig->nAIErodesize %d\n", m_pDetConfig->nAIErodesize); if (m_pDetConfig->nAIErodesize <= 0) { resultMask_erode_small = resultMask(result_roi).clone(); } else { // 定义膨胀核 int dilation_size = 7; // 膨胀核的大小 if (m_pDetConfig->nAIErodesize > 0 && m_pDetConfig->nAIErodesize < 101) { dilation_size = 2 * m_pDetConfig->nAIErodesize; } cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(dilation_size, dilation_size)); // 进行膨胀操作 cv::erode(resultMask(result_roi), resultMask_erode_small, kernel); } pCheckResult_Aling->mask = ~resultMask_erode_small; } if (m_pDetConfig->bDebugSaveImg) { // cv::imwrite("edge_result_src_roi_thresholdvalue.png", temimg); cv::imwrite(pDetConfig->strCamName + "_5_edge_result_src.png", img(result_roi)); cv::imwrite(pDetConfig->strCamName + "_6_edge_result_mask.png", pCheckResult_Aling->mask); cv::Mat temAdd = img(result_roi).clone(); temAdd += pCheckResult_Aling->mask * 0.25; { // 查找轮廓 std::vector> contours; std::vector hierarchy; cv::findContours(resultMask_erode_small.clone(), contours, hierarchy, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE); // 创建一个空白图像用于绘制轮廓 // 绘制轮廓 cv::drawContours(temAdd, contours, -1, cv::Scalar(128, 255, 0), 2); // 绿色,线宽2 } cv::imwrite(pDetConfig->strCamName + "_7_edge_result_Merge.png", temAdd); } long t7 = CheckUtil::getcurTime(); // 存在中间结果 if (m_pDetConfig->saveProcessImg != Save_Close) { static int svidx = 0; svidx++; if (svidx > 9999999) { svidx = 0; /* code */ } std::string str1 = "/home/aidlux/BOE/FOG/Edge/Result/" + std::to_string(svidx) + "_mask.png"; std::string str2 = "/home/aidlux/BOE/FOG/Edge/Result/" + std::to_string(svidx) + "_show.png"; int newWidth = 1280; float aspectRatio = static_cast(resultMask_erode_small.rows) / resultMask_erode_small.cols; int newHeight = static_cast(newWidth * aspectRatio); // 缩放图像 cv::Mat resizedImage; cv::resize(resultMask_erode_small, resizedImage, cv::Size(newWidth, newHeight)); cv::Mat temAdd = img(result_roi).clone(); cv::resize(temAdd, temAdd, cv::Size(newWidth, newHeight)); { // 查找轮廓 std::vector> contours; std::vector hierarchy; cv::findContours(resizedImage.clone(), contours, hierarchy, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE); // 创建一个空白图像用于绘制轮廓 // 绘制轮廓 cv::drawContours(temAdd, contours, -1, cv::Scalar(255, 255, 0), 1); // 绿色,线宽2 } cv::imwrite(str1, resizedImage); cv::imwrite(str2, temAdd); } long t8 = CheckUtil::getcurTime(); // printf("use time %ld %ld %ld %ld %ld %ld %ld %ld \n", t8 - t1, t2 - t1, t3 - t2, t4 - t3, t5 - t4, t6 - t5, t7 - t6, t8 - t7); pCheckResult_Aling->roi = result_roi; return 0; } int AI_Edge_Algin::SaveSmallImg(const cv::Mat &img, const cv::Mat &mask, cv::Rect roi) { // 是否要保存中间过程的小图 if (m_pDetConfig->IsSaveProcessImg()) { static int svsmallidx = 0; svsmallidx++; if (svsmallidx > 9999999) { svsmallidx = 0; /* code */ } bool bssss = false; if (m_pDetConfig->saveProcessImg == Save_Filter) { // 4. 查找轮廓 vector> contours; vector hierarchy; findContours(mask.clone(), contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE); if (contours.size() > 1) { bssss = true; } else if (contours.size() == 1) { int pointNum = 0; for (int i = 0; i < contours.size(); i++) { pointNum += contours[i].size(); } // printf("pointNum============== %d\n", pointNum); if (pointNum > 30) { bssss = true; } } } else if (m_pDetConfig->saveProcessImg == Save_ALL) { bssss = true; } if (bssss) { std::string str1 = "/home/aidlux/BOE/FOG/Edge/Smasll/" + std::to_string(svsmallidx) + "_in.png"; std::string str2 = "/home/aidlux/BOE/FOG/Edge/Smasll/" + std::to_string(svsmallidx) + "_in_mask.png"; // std::string st3 = "/home/aidlux/BOE/Edge/Smasll/" + std::to_string(svsmallidx) + "_in_show.png"; cv::imwrite(str1, img); cv::imwrite(str2, mask); // cv::Mat showsss = temDet + smask * 0.4; // cv::imwrite(st3, showsss); } } return 0; } int AI_Edge_Algin::InitModel_ALL() { m_bModelSucc = false; int re = InitModel_Big(); if (re != 0) { // printf("AI_Edge_Algin InitModel_Big Error \n"); return re; } re = InitModel_Small(); if (re != 0) { // printf("AI_Edge_Algin InitModel_Small Error \n"); return re; } m_bModelSucc = true; return 0; } int AI_Edge_Algin::InitModel_Big() { return 0; } int AI_Edge_Algin::InitModel_Small() { return 0; } int AI_Edge_Algin::Det_big(const cv::Mat &img, vector &smallRoiList, std::shared_ptr> edgeRoiList, cv::Rect &bigRoi, cv::Mat &big_mask) { std::shared_ptr pAI_Model = AI_Factory->AI_defect_Edge_Big; cv::Size sz; sz.width = pAI_Model->input_0.width; sz.height = pAI_Model->input_0.height; cv::Mat detImg; cv::resize(img, detImg, sz); int re = 0; cv::Mat mask; // printf("sz %d %d \n", sz.width, sz.height); re = pAI_Model->AIDet(detImg, mask); big_mask = mask; if (re != 0) { // printf("AICheck_Edge_Big----error \n"); int re123 = 100 + re; return re123; } if (m_pDetConfig->bDebugSaveImg) { std::string str1 = m_str_curCamName + "_edge_big_in.png"; cv::imwrite(str1, detImg); std::string str2 = m_str_curCamName + "_edge_big_out_mask.png"; cv::imwrite(str2, mask); } if (m_pDetConfig->IsSaveProcessImg()) { static int bigidx = 0; bigidx++; if (bigidx > 9999999) { bigidx = 0; /* code */ } std::string str1 = "/home/aidlux/BOE/FOG/Edge/Big/" + std::to_string(bigidx) + "_in.png"; std::string str2 = "/home/aidlux/BOE/FOG/Edge/Big/" + std::to_string(bigidx) + "_in_mask.png"; cv::imwrite(str1, detImg); cv::imwrite(str2, mask); } // 找到最大轮廓 bool found; cv::Rect boundingBox = CheckUtil::getLargestContourROI(mask, found); if (!found) { cerr << "No contours found!" << endl; return 4; } // 形成 小图分割的检测区域 float fresize_x = img.cols * 1.0f / sz.width; float fresize_y = img.rows * 1.0f / sz.height; bigRoi.x = boundingBox.x * fresize_x; bigRoi.y = boundingBox.y * fresize_y; bigRoi.width = boundingBox.width * fresize_x; bigRoi.height = boundingBox.height * fresize_y; // 使用手动绘制的roi进行校验 if (m_pDetConfig->bUseDrawRoi_Check) { double widthDiff = std::abs(bigRoi.width - m_pDetConfig->drawRoi.width) * 1.0f / std::min(bigRoi.width, m_pDetConfig->drawRoi.width); double heightDiff = std::abs(bigRoi.height - m_pDetConfig->drawRoi.height) * 1.0f / std::min(bigRoi.height, m_pDetConfig->drawRoi.height); // printf("draw roi %s bigRoi %s widthDiff %f heightDiff %f\n", CheckUtil::GetRectString(m_pDetConfig->drawRoi).c_str(), CheckUtil::GetRectString(bigRoi).c_str(), widthDiff, heightDiff); // 如果差异超过10%,抛出异常 if (widthDiff > 0.10) { return 5; } if (heightDiff > 0.10) { return 5; } } float fresize_x_1 = sz.width * 1.0f / img.cols; float fresize_y_1 = sz.height * 1.0f / img.rows; int resize_Small_Roi_width = 320 * fresize_x_1; int resize_Small_Roi_height = 320 * fresize_y_1; int haf_w = resize_Small_Roi_width / 2; int haf_h = resize_Small_Roi_height / 2; int step_w = resize_Small_Roi_width * 0.85; int step_h = resize_Small_Roi_height * 0.85; smallRoiList.clear(); int sizeare = resize_Small_Roi_width * resize_Small_Roi_height; for (int y = boundingBox.y; y < boundingBox.y + boundingBox.height + haf_h; y += step_h) { int roiY = y - haf_h; for (int x = boundingBox.x; x < boundingBox.x + boundingBox.width + haf_w; x += step_w) { int roiX = x - haf_w; if (roiX < 0) roiX = 0; if (roiY < 0) roiY = 0; if (roiX + resize_Small_Roi_width >= mask.cols) roiX = mask.cols - resize_Small_Roi_width; if (roiY + resize_Small_Roi_height > mask.rows) roiY = mask.rows - resize_Small_Roi_height; Rect rect(roiX, roiY, resize_Small_Roi_width, resize_Small_Roi_height); if (!CheckUtil::RoiInImg(rect, mask)) { continue; } if (roiX >= 0 && roiY >= 0) { if (roiX == 0 || roiX + resize_Small_Roi_width == mask.cols) { cv::Rect src_Roi; src_Roi.x = rect.x * fresize_x; src_Roi.y = rect.y * fresize_y; src_Roi.width = 320; src_Roi.height = 320; smallRoiList.push_back(src_Roi); // 存储ROI的矩形框 // printf("\n\n\n\n\n\n\n=================%d===============\n\n\n\n\n\n\n", smallRoiList.size()); } else { int va = countNonZero(mask(rect)); if (va > 0 && va < sizeare) { cv::Rect src_Roi; src_Roi.x = rect.x * fresize_x; src_Roi.y = rect.y * fresize_y; src_Roi.width = 320; src_Roi.height = 320; smallRoiList.push_back(src_Roi); // 存储ROI的矩形框 } } } } } for (int i = 0; i < smallRoiList.size(); i++) { cv::Rect src_Roi = smallRoiList.at(i); if (src_Roi.x < 0) { src_Roi.x = 0; } if (src_Roi.y < 0) { src_Roi.y = 0; } if (src_Roi.x + src_Roi.width > img.cols) { src_Roi.x = img.cols - src_Roi.width; } if (src_Roi.y + src_Roi.height > img.rows) { src_Roi.y = img.rows - src_Roi.height; } smallRoiList.at(i) = src_Roi; } { // ------------------------- // 2. 查找轮廓 // ------------------------- std::vector> contours; cv::findContours(mask, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE); if (contours.empty()) { std::cout << "No contours found" << std::endl; return -1; } // ------------------------- // 3. 找最大面积轮廓 // ------------------------- int max_idx = 0; double max_area = 0; for (size_t i = 0; i < contours.size(); i++) { double area = cv::contourArea(contours[i]); if (area > max_area) { max_area = area; max_idx = i; } } std::vector max_contour = contours[max_idx]; float fresize_x_1 = mask.cols * 1.0f / img.cols; float fresize_y_1 = mask.rows * 1.0f / img.rows; int resize_Small_Roi_width = 320 * fresize_x_1; int resize_Small_Roi_height = 320 * fresize_y_1; int roi_size_X = resize_Small_Roi_width; int roi_size_Y = resize_Small_Roi_height; double overlap_ratio = 0.2; // ROI 重叠比例,可调 double step_len_X = roi_size_X * (1.0 - overlap_ratio); double step_len_Y = roi_size_Y * (1.0 - overlap_ratio); std::vector rois; std::set> roi_set; double accumulated_len = 0.0; for (size_t i = 0; i < max_contour.size(); i++) { cv::Point p1 = max_contour[i]; cv::Point p2 = max_contour[(i + 1) % max_contour.size()]; // 下一个点,闭合轮廓 double segment_len = cv::norm(p2 - p1); if (segment_len <= 0) { continue; } double dx = p2.x - p1.x; double dy = p2.y - p1.y; while (accumulated_len + 1e-6 < segment_len) { // 沿线段放置 ROI double t = accumulated_len / segment_len; cv::Point center = p1 + t * (p2 - p1); int x = center.x - roi_size_X / 2; int y = center.y - roi_size_Y / 2; // 边界裁剪 if (x < 0) x = 0; if (y < 0) y = 0; if (x + roi_size_X > mask.cols) x = mask.cols - roi_size_X; if (y + roi_size_Y > mask.rows) y = mask.rows - roi_size_Y; auto key = std::make_pair(x, y); if (roi_set.find(key) == roi_set.end()) { roi_set.insert(key); rois.push_back(cv::Rect(x, y, roi_size_X, roi_size_Y)); } double step = (std::abs(dx) > std::abs(dy)) ? step_len_X : step_len_Y; accumulated_len += step; } accumulated_len -= segment_len; // 移动到下一个线段 if (accumulated_len < 0) accumulated_len = 0; } edgeRoiList->clear(); for (const auto &r : rois) { cv::Rect roi; roi.x = r.x / fresize_x_1; roi.y = r.y / fresize_y_1; roi.width = 320; roi.height = 320; if (roi.x < 0) { roi.x = 0; } if (roi.y < 0) { roi.y = 0; } if (roi.x + roi.width > img.cols) { roi.x = img.cols - roi.width; } if (roi.y + roi.height > img.rows) { roi.y = img.rows - roi.height; } edgeRoiList->push_back(roi); } if (m_pDetConfig->bDebugSaveImg) { // ------------------------- // 5. 可视化 // ------------------------- cv::Mat vis; cv::cvtColor(mask, vis, cv::COLOR_GRAY2BGR); cv::Mat vis22; cv::cvtColor(img, vis22, cv::COLOR_GRAY2BGR); for (auto &r : rois) { cv::rectangle(vis, r, cv::Scalar(0, 0, 255), 2); } for (auto &r : rois) { cv::Rect roi; roi.x = r.x / fresize_x_1; roi.y = r.y / fresize_y_1; roi.width = 320; roi.height = 320; cv::rectangle(vis22, roi, cv::Scalar(0, 0, 255), 2); } cv::drawContours(vis, std::vector>{max_contour}, -1, cv::Scalar(0, 255, 0), 1); cv::imwrite("edge_det_roi_small.png", vis); cv::imwrite("edge_det_roi_big.png", vis22); // getchar(); } } return 0; } int AI_Edge_Algin::Dtet_small(const cv::Mat &img, vector &smallRoiList, cv::Mat &Src_Mask) { std::shared_ptr pAIDet = AI_Factory->AI_defect_Edge_Samll; // 2、对每个小区域进行处理 Src_Mask = cv::Mat(img.rows, img.cols, CV_8U, cv::Scalar(0)); const int totalTasks = smallRoiList.size(); int submitted = 0; int completed = 0; while (completed < totalTasks) { // 如果任务还没提交完,且当前处理任务数 < 2,提交新任务 if (submitted < totalTasks && runner->GetProcessingCount() < 10) { std::shared_ptr task = std::make_shared(); task->id = completed; task->roi = smallRoiList.at(submitted); if (!CheckUtil::RoiInImg(task->roi, img)) { CheckUtil::printROI(task->roi, "small roi 1 "); // printf("img %d %d \n", img.cols, img.rows); } task->input = img(smallRoiList.at(submitted)).clone(); task->output = std::make_shared(); task->engine = pAIDet; runner->SubmitTask(task); submitted++; } // 尝试取结果 std::shared_ptr result; if (runner->PopResult(result)) { cv::Mat &outimg = *(result->output); if (!outimg.empty()) { outimg.copyTo(Src_Mask(result->roi), outimg); } // 保存过程小图 SaveSmallImg(result->input, outimg, result->roi); completed++; } else { std::this_thread::sleep_for(std::chrono::milliseconds(0)); } } return 0; } Image_Feature_Algin::Image_Feature_Algin() { } Image_Feature_Algin::~Image_Feature_Algin() { } int Image_Feature_Algin::Detect(DetConfig *pDetConfig, Align_Result *pResult, std::vector &LogList) { // 检测目标:找到 参数模版图到 检测图的 映射关系。包括 缩放和移动。 // 先缩放 在 移动 std::string strlog = ""; if (!pDetConfig) { return 1; } if (pDetConfig->TemplateImg.empty()) { strlog = m_PrintLog.printstr(Print_Level_Error, "Image_Align", "TemplateImg is empty "); LogList.push_back(strlog); return 1; } // 裁切位置; pResult->Crop_Roi_DetImg = pDetConfig->DetImg_CropROi; // 1、缩放尺度 float fx = 1; float fy = 1; // 裁切尺寸 存在 并合理 if (pDetConfig->param_CropRoi.width > 0 && pDetConfig->param_CropRoi.height > 0 && pDetConfig->DetImg_CropROi.width > 0 && pDetConfig->DetImg_CropROi.height > 0) { fx = pDetConfig->DetImg_CropROi.width * 1.0f / pDetConfig->param_CropRoi.width; fy = pDetConfig->DetImg_CropROi.height * 1.0f / pDetConfig->param_CropRoi.height; if (fx > 0.5 && fx < 2 && fy > 0.5 && fy < 2) { pResult->fCropROI_Scale_ParmToDet_X = fx; pResult->fCropROI_Scale_ParmToDet_Y = fy; } else { strlog = m_PrintLog.printstr(Print_Level_Error, "Image_Align", "Scale out 0.5--2"); LogList.push_back(strlog); return 1; } } else { strlog = m_PrintLog.printstr(Print_Level_Error, "Image_Align", "crop ROI Error"); LogList.push_back(strlog); return 1; } // strlog = m_PrintLog.printstr(Print_Level_Info, "Image_Align", "Scale x %f y %f\n", fx, fy); // LogList.push_back(strlog); // 2、定位 // 1)、模版特征图片的 缩放。 cv::Mat TemplateFeature; cv::Size sz; // fx = 1; // fy = 1; sz.width = int(pDetConfig->TemplateImg.cols * fx); sz.height = int(pDetConfig->TemplateImg.rows * fy); cv::resize(pDetConfig->TemplateImg, TemplateFeature, sz); if (!CheckUtil::RoiInImg(pDetConfig->Search_Roi, pDetConfig->DetImg)) { strlog = m_PrintLog.printstr(Print_Level_Error, "Image_Align", "Search_Roi ROI Error Not In img"); LogList.push_back(strlog); return 1; } cv::Mat DetFeature = pDetConfig->DetImg(pDetConfig->Search_Roi).clone(); double confidence = 0; int kernel_size = 128; int search_size = 1024; int det_search_min_size = DetFeature.cols; if (DetFeature.rows < det_search_min_size) { det_search_min_size = DetFeature.rows; } int template_kernel_min_size = TemplateFeature.cols; if (TemplateFeature.rows < template_kernel_min_size) { template_kernel_min_size = TemplateFeature.rows; } float f_search = search_size * 1.0f / det_search_min_size; float f_Kernel = kernel_size * 1.0f / template_kernel_min_size; float falign = f_search; if (f_Kernel > falign) { falign = f_Kernel; } cv::Size Search_sz; Search_sz.width = int(DetFeature.cols * falign); Search_sz.height = int(DetFeature.rows * falign); cv::Mat Search_img; cv::resize(DetFeature, Search_img, Search_sz); cv::Size Kernel_sz; Kernel_sz.width = int(TemplateFeature.cols * falign); Kernel_sz.height = int(TemplateFeature.rows * falign); cv::Mat Kernel_img; cv::resize(TemplateFeature, Kernel_img, Kernel_sz); auto bestMatch = findBestTemplateMatch(Search_img, Kernel_img, confidence); bestMatch.x /= falign; bestMatch.y /= falign; pResult->bestMatch = bestMatch; if (pDetConfig->bSaveImg) { cv::imwrite("Align_template.png", TemplateFeature); cv::imwrite("Align_Det.png", DetFeature); } if (confidence != -1) { std::cout << "最佳匹配位置: (" << bestMatch.x << ", " << bestMatch.y << "), 得分: " << confidence << std::endl; if (confidence > pDetConfig->fscore) { /* code */ int m_x = pDetConfig->feature_Roi.x * fx - pDetConfig->Search_Roi.x; int m_y = pDetConfig->feature_Roi.y * fy - pDetConfig->Search_Roi.y; pResult->offt_x = bestMatch.x - m_x; pResult->offt_y = bestMatch.y - m_y; // printf("m_x %d bestMatch.x %d offt_x %d\n", m_x, bestMatch.x, pResult->offt_x); // printf("m_y %d bestMatch.y %d offt_y %d\n", m_y, bestMatch.y, pResult->offt_y); pResult->bDet = true; pResult->Crop_Roi_ParmImg = pResult->Det_srcToParm_src_Rect(pResult->Crop_Roi_DetImg); strlog = m_PrintLog.printstr(Print_Level_Info, "Image_Align", " -- Succ :Align score %f > %f offt x %d y %d Scale x %f y %f", confidence, pDetConfig->fscore, pResult->offt_x, pResult->offt_y, pResult->fCropROI_Scale_ParmToDet_X, pResult->fCropROI_Scale_ParmToDet_Y); LogList.push_back(strlog); } else { strlog = m_PrintLog.printstr(Print_Level_Error, "Image_Align", " error :Align score %f< 0.9", confidence); pResult->fCropROI_Scale_ParmToDet_X = 1; pResult->fCropROI_Scale_ParmToDet_Y = 1; LogList.push_back(strlog); } } else { pResult->fCropROI_Scale_ParmToDet_X = 1; pResult->fCropROI_Scale_ParmToDet_Y = 1; std::cout << "未找到有效匹配" << std::endl; } return 0; } cv::Point Image_Feature_Algin::findBestTemplateMatch( const cv::Mat &detectionImage, const cv::Mat &templateImage, double &bestScore, int method) { // 输入验证 if (detectionImage.empty() || templateImage.empty()) { throw std::invalid_argument("输入图像不能为空"); } if (detectionImage.channels() != 1 || templateImage.channels() != 1) { throw std::invalid_argument("必须输入灰度图像"); } if (templateImage.rows > detectionImage.rows || templateImage.cols > detectionImage.cols) { throw std::invalid_argument("模板尺寸不能大于被检测图像"); } // cv::imwrite("detectionImage.png", detectionImage); // cv::imwrite("templateImage.png", templateImage); // 执行模板匹配 cv::Mat resultMatrix; cv::matchTemplate(detectionImage, templateImage, resultMatrix, method); // 确定极值搜索方式 const bool findMinima = (method == cv::TM_SQDIFF || method == cv::TM_SQDIFF_NORMED); // 查找极值位置 cv::Point extremaLoc = cv::Point(0, 0); double extremaVal; cv::minMaxLoc(resultMatrix, findMinima ? &extremaVal : nullptr, findMinima ? nullptr : &extremaVal, findMinima ? &extremaLoc : nullptr, findMinima ? nullptr : &extremaLoc); // 设置有效性检查阈值(可根据方法动态调整) double threshold = 0.0; switch (method) { case cv::TM_CCOEFF_NORMED: threshold = 0.6; break; // [-1, 1] case cv::TM_CCORR_NORMED: threshold = 0.7; break; // [0, 1] case cv::TM_SQDIFF_NORMED: threshold = 0.2; break; // [0, 1] default: threshold = 0.0; } // 验证匹配有效性 const bool isValid = findMinima ? (extremaVal <= threshold) : (extremaVal >= threshold); if (isValid) { bestScore = extremaVal; return extremaLoc; } bestScore = -1; // 无效时的默认值 return extremaLoc; }