You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
BOE_FOG_DETECT/AlgorithmModule/src/AI_Edge_Algin.cpp

1020 lines
33 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#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<AIMulThreadRunBase>();
runner->Start();
}
AI_Edge_Algin::~AI_Edge_Algin()
{
}
int AI_Edge_Algin::Detect(const cv::Mat &img, DetConfig *pDetConfig, std::shared_ptr<Edge_AI_Result> &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<Edge_AI_Result>();
if (img.empty())
{
return 1;
}
long t1 = CheckUtil::getcurTime();
// 1、初步定位 找到产品大致区域
int re = 0;
vector<Rect> 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<vector<Point>> 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<std::vector<cv::Point>> contours;
std::vector<cv::Vec4i> 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<float>(resultMask_erode_small.rows) / resultMask_erode_small.cols;
int newHeight = static_cast<int>(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<std::vector<cv::Point>> contours;
std::vector<cv::Vec4i> 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<vector<Point>> contours;
vector<Vec4i> 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<Rect> &smallRoiList, std::shared_ptr<std::vector<cv::Rect>> edgeRoiList, cv::Rect &bigRoi, cv::Mat &big_mask)
{
std::shared_ptr<AIModel_Base> 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<std::vector<cv::Point>> 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<cv::Point> 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<cv::Rect> rois;
std::set<std::pair<int, int>> 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<std::vector<cv::Point>>{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<Rect> &smallRoiList, cv::Mat &Src_Mask)
{
std::shared_ptr<AIModel_Base> 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<AIMulThreadRunBase::AITask> task = std::make_shared<AIMulThreadRunBase::AITask>();
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<cv::Mat>();
task->engine = pAIDet;
runner->SubmitTask(task);
submitted++;
}
// 尝试取结果
std::shared_ptr<AIMulThreadRunBase::AITask> 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<std::string> &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;
}