#include #include #include #include #include #include #include #include #include #include #include #include #include . #include enum ngTypeEnum { OK, huaHeng, aoKeng, zangWu }; //简单的图像相关算法 class simpleAlgo { public: //融合两张图片白色区域 static cv::Mat mergeBinaryMats(const cv::Mat& mat1, const cv::Mat& mat2) { // 确保两个输入图像具有相同的尺寸 if (mat1.size() != mat2.size()) { std::cerr << "Error: Input images must have the same size." << std::endl; return cv::Mat(); } // 创建一个输出图像,初始化为全黑 cv::Mat merged = cv::Mat::zeros(mat1.size(), CV_8U); // 将两个输入图像中的白色部分合并到输出图像 cv::bitwise_or(mat1, mat2, merged); return merged; } //Rect相加 cv::Rect rectPlusRect(cv::Rect world, cv::Rect rect) { return cv::Rect(rect.x + world.x, rect.y + world.y, rect.width, rect.height); } static cv::Rect findMaxAreaContour(cv::Mat src) { int maxIndex = 0, maxArea = 0; vector>contours; cv::findContours(src, contours, cv::noArray(), cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE); if (contours.size() == 0) return cv::Rect(0, 0, 0, 0); for (int i = 0; i < contours.size(); i++) { int Area = contourArea(contours[i]); if (Area > maxArea) { maxArea = Area; maxIndex = i; } } if (contours.size() != 0) return boundingRect(contours[maxIndex]); return cv::Rect(0, 0, 0, 0); } static cv::Rect findMaxAreaContour(cv::Mat src, int& indexReturn) { int maxIndex = 0, maxArea = 0; vector>contours; cv::findContours(src, contours, cv::noArray(), cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE); if (contours.size() == 0) return cv::Rect(0, 0, 0, 0); for (int i = 0; i < contours.size(); i++) { int Area = contourArea(contours[i]); if (Area > maxArea) { maxArea = Area; maxIndex = i; } } if (contours.size() != 0) { indexReturn = maxIndex; return boundingRect(contours[maxIndex]); } } static cv::Mat cutImg2Cls(vectorcontour, cv::Mat imgInput, cv::Size targetSize = cv::Size(128, 128)) { if (contour.empty() || imgInput.empty()) { std::cerr << "Empty contour or input image." << std::endl; return cv::Mat(); } cv::Rect boundingBox = cv::boundingRect(contour); cv::Point mid(boundingBox.x + boundingBox.width / 2, boundingBox.y + boundingBox.height / 2); int sideLength = std::max(std::max(boundingBox.width, boundingBox.height), 128); cv::Mat squareImage(sideLength, sideLength, imgInput.type(), cv::Scalar(0, 0, 0)); cv::Rect expectRect(mid.x - sideLength / 2, mid.y - sideLength / 2, sideLength, sideLength); int xOffset = 0; int yOffset = 0;// (sideLength - boundingBox.height) / 2; //越界判断 { if (expectRect.x < 0) { expectRect.width += expectRect.x; xOffset -= expectRect.x; expectRect.x = 0; } if (expectRect.y < 0) { expectRect.height += expectRect.y; yOffset -= expectRect.y; expectRect.y = 0; } if (expectRect.x + expectRect.width > imgInput.cols) expectRect.width = imgInput.cols - expectRect.x; if (expectRect.y + expectRect.height > imgInput.rows) expectRect.height = imgInput.rows - expectRect.y; } imgInput(expectRect).copyTo(squareImage(cv::Rect(xOffset, yOffset, expectRect.width, expectRect.height))); resize(squareImage, squareImage, targetSize); return squareImage; } static cv::Mat cutImg2Cls(cv::Rect boundingBox, cv::Mat imgInput, cv::Size targetSize = cv::Size(128, 128)) { if (boundingBox.empty() || imgInput.empty()) { std::cerr << "Empty contour or input image." << std::endl; return cv::Mat(); } cv::Point mid(boundingBox.x + boundingBox.width / 2, boundingBox.y + boundingBox.height / 2); int sideLength = std::max(std::max(boundingBox.width, boundingBox.height), 128); cv::Mat squareImage(sideLength, sideLength, imgInput.type(), cv::Scalar(0, 0, 0)); cv::Rect expectRect(mid.x - sideLength / 2, mid.y - sideLength / 2, sideLength, sideLength); int xOffset = 0; int yOffset = 0;// (sideLength - boundingBox.height) / 2; //越界判断 { if (expectRect.x < 0) { expectRect.width += expectRect.x; xOffset -= expectRect.x; expectRect.x = 0; } if (expectRect.y < 0) { expectRect.height += expectRect.y; yOffset -= expectRect.y; expectRect.y = 0; } if (expectRect.x + expectRect.width > imgInput.cols) expectRect.width = imgInput.cols - expectRect.x; if (expectRect.y + expectRect.height > imgInput.rows) expectRect.height = imgInput.rows - expectRect.y; } imgInput(expectRect).copyTo(squareImage(cv::Rect(xOffset, yOffset, expectRect.width, expectRect.height))); resize(squareImage, squareImage, targetSize); return squareImage; } static cv::Mat HObject2Mat(HObject Hobj) //HObject类型转Mat类型 { HTuple htCh; HString cType; cv::Mat Image; ConvertImageType(Hobj, &Hobj, "byte"); CountChannels(Hobj, &htCh); Hlong wid = 0; Hlong hgt = 0; if (htCh[0].I() == 1) { HImage hImg(Hobj); void* ptr = hImg.GetImagePointer1(&cType, &wid, &hgt);//GetImagePointer1(Hobj, &ptr, &cType, &wid, &hgt); int W = wid; int H = hgt; Image.create(H, W, CV_8UC1); unsigned char* pdata = static_cast(ptr); memcpy(Image.data, pdata, W * H); } else if (htCh[0].I() == 3) { void* Rptr; void* Gptr; void* Bptr; HImage hImg(Hobj); hImg.GetImagePointer3(&Rptr, &Gptr, &Bptr, &cType, &wid, &hgt); int W = wid; int H = hgt; Image.create(H, W, CV_8UC3); std::vector VecM(3); VecM[0].create(H, W, CV_8UC1); VecM[1].create(H, W, CV_8UC1); VecM[2].create(H, W, CV_8UC1); unsigned char* R2 = (unsigned char*)Rptr; unsigned char* G = (unsigned char*)Gptr; unsigned char* B = (unsigned char*)Bptr; memcpy(VecM[2].data, R2, W * H); memcpy(VecM[1].data, G, W * H); memcpy(VecM[0].data, B, W * H); cv::merge(VecM, Image); } return Image; } static HalconCpp::HObject MatToHObject(cv::Mat& image) { HalconCpp::HObject Hobj = HalconCpp::HObject(); int hgt = image.rows; int wid = image.cols; int i; if (image.type() == CV_8UC3) { HalconCpp::HImage himage = HalconCpp::HImage(); std::vector imgchannel; split(image, imgchannel); cv::Mat imgB = imgchannel[0]; cv::Mat imgG = imgchannel[1]; cv::Mat imgR = imgchannel[2]; uchar* dataR = new uchar[hgt * wid]; uchar* dataG = new uchar[hgt * wid]; uchar* dataB = new uchar[hgt * wid]; for (i = 0; i < hgt; i++) { memcpy(dataR + wid * i, imgR.data + imgR.step * i, wid); memcpy(dataG + wid * i, imgG.data + imgG.step * i, wid); memcpy(dataB + wid * i, imgB.data + imgB.step * i, wid); } himage.GenImage3("byte", wid, hgt, dataR, dataG, dataB); HalconCpp::HString tmpType; Hlong tmpW, tmpH; void* hImgPtR, * hImgPtG, * hImgPtB; himage.GetImagePointer3(&hImgPtR, &hImgPtG, &hImgPtB, &tmpType, &tmpW, &tmpH); GenImage3(&Hobj, "byte", wid, hgt, (Hlong)hImgPtR, (Hlong)hImgPtG, (Hlong)hImgPtB); delete[]dataR; delete[]dataG; delete[]dataB; dataR = NULL; dataG = NULL; dataB = NULL; } else if (image.type() == CV_8UC1) { HalconCpp::HImage himage = HalconCpp::HImage(); uchar* data = new uchar[hgt * wid]; for (i = 0; i < hgt; i++) { memcpy(data + wid * i, image.data + image.step * i, wid); } himage.GenImage1("byte", wid, hgt, data); HalconCpp::HString tmpType; Hlong tmpW, tmpH; void* hImgPt; hImgPt = himage.GetImagePointer1(&tmpType, &tmpW, &tmpH); GenImage1(&Hobj, "byte", wid, hgt, (Hlong)hImgPt); delete[] data; data = NULL; } else if (image.type() == CV_16UC1) { HalconCpp::HImage himage = HalconCpp::HImage(); ushort* data = new ushort[hgt * wid * 2]; memcpy(data, image.data, hgt * wid * 2); himage.GenImage1("uint2", wid, hgt, data); HalconCpp::HString tmpType; Hlong tmpW, tmpH; void* hImgPt; hImgPt = himage.GetImagePointer1(&tmpType, &tmpW, &tmpH); GenImage1(&Hobj, "uint2", wid, hgt, (Hlong)hImgPt); delete[] data; data = NULL; } else if (image.type() == CV_16SC1) { HalconCpp::HImage himage = HalconCpp::HImage(); short* data = new short[hgt * wid * 2]; memcpy(data, image.data, hgt * wid * 2); himage.GenImage1("int2", wid, hgt, data); HalconCpp::HString tmpType; Hlong tmpW, tmpH; void* hImgPt; hImgPt = himage.GetImagePointer1(&tmpType, &tmpW, &tmpH); GenImage1(&Hobj, "int2", wid, hgt, (Hlong)hImgPt); delete[] data; data = NULL; } return Hobj; } //获取两点之间的直线距离 static double getDistance(cv::Point pointO, cv::Point pointA) { double distance; distance = powf((pointO.x - pointA.x), 2) + powf((pointO.y - pointA.y), 2); distance = sqrtf(distance); return distance; } //计算角度,pt2为顶点 static double calculateAngle(cv::Point pt1, cv::Point pt2, cv::Point pt3) { // 计算两个向量 cv::Point vector1 = pt1 - pt2; cv::Point vector2 = pt3 - pt2; // 计算两个向量的长度 double length1 = norm(vector1); double length2 = norm(vector2); // 计算两个向量的点积 double dotProduct = vector1.dot(vector2); // 计算夹角的余弦值 double cosAngle = dotProduct / (length1 * length2); // 计算夹角的弧度 double angleRadians = acos(cosAngle); // 将弧度转换为度数 double angleDegrees = angleRadians * 180 / CV_PI; return angleDegrees; } //计算角度偏移量,pt1,pt2为第一条线段,pt3,pt4为第二条线段 static double calculateAngleOffset(cv::Point pt11, cv::Point pt12, cv::Point pt21, cv::Point pt22) { // 计算第一条线段的向量 cv::Point vec1(pt12.x - pt11.x, pt12.y - pt11.y); // 计算第二条线段的向量 cv::Point vec2(pt22.x - pt21.x, pt22.y - pt21.y); // 计算向量的叉乘 double crossProduct = vec1.x * vec2.y - vec1.y * vec2.x; // 计算角度偏移量 double angleOffset = atan2(crossProduct, vec1.dot(vec2)); // 将弧度转换为度数 angleOffset = angleOffset * 180 / CV_PI; return angleOffset; } //通过角度计算圆上点的位置 cv::Point calculatePointOnCircle(cv::Point center, double radius, double angleDegrees) { // 将角度转换为弧度 double angleRadians = angleDegrees * CV_PI / 180.0; // 计算点的坐标 int x = static_cast(center.x + radius * cos(angleRadians)); int y = static_cast(center.y + radius * sin(angleRadians)); return cv::Point(x, y); } /// /// 模板匹配,以MatchResult返回 /// /// 图像 /// 模板图像 /// static MatchResult templateMatching(const cv::Mat& originalImage, const cv::Mat& templateImage) { MatchResult result; // 创建结果图像 int resultCols = originalImage.cols - templateImage.cols + 1; int resultRows = originalImage.rows - templateImage.rows + 1; cv::Mat resultImg(resultRows, resultCols, CV_32FC1); // 进行模板匹配 cv::matchTemplate(originalImage, templateImage, resultImg, cv::TM_CCOEFF_NORMED); // 归一化结果图像 cv::normalize(resultImg, resultImg, 0, 1, cv::NORM_MINMAX, -1, cv::Mat()); // 寻找最佳匹配位置 double minVal, maxVal; cv::Point minLoc, maxLoc; cv::minMaxLoc(resultImg, &minVal, &maxVal, &minLoc, &maxLoc); // 设置矩形框和可信度 result.boundingRect = cv::Rect(maxLoc.x, maxLoc.y, templateImage.cols, templateImage.rows); result.confidence = maxVal; return result; } /// /// 模板匹配,返回Rect以及分数 /// /// 模板图像 /// 匹配图像 /// 分数 /// static cv::Rect doMatchTemplate(const cv::Mat& templateImg, const cv::Mat& srcImg, double* sorce) { cv::Mat resultImage; matchTemplate(srcImg, templateImg, resultImage, cv::TM_CCOEFF_NORMED); double minVal = 0, maxVal = 0; cv::Point minLoc(0, 0), maxLoc(0, 0); minMaxLoc(resultImage, &minVal, &maxVal, &minLoc, &maxLoc); *sorce = maxVal; cv::Rect rect(maxLoc.x, maxLoc.y, templateImg.cols, templateImg.rows); return rect; } //计算contour是否重叠 static bool isContoursOverlap(const vector& contour1, const vector& contour2, double thresholdPercent = 0) { cv::Rect rect1 = cv::boundingRect(contour1); cv::Rect rect2 = cv::boundingRect(contour2); cv::Size tempImgSize(max(rect1.x + rect1.width, rect2.x + rect2.width), max(rect1.y + rect1.height, rect2.y + rect2.height)); cv::Mat binaryImage = cv::Mat::zeros(tempImgSize,CV_8U); // 画出目标轮廓 drawContours(binaryImage, vector>{contour2}, 0, cv::Scalar(255), -1); double totalOverlap = 0.0; // 创建一个临时的二值图像 cv::Mat tempBinaryImage = cv::Mat::zeros(tempImgSize, CV_8U); // 画出当前轮廓 drawContours(tempBinaryImage, vector>{contour1}, 0, cv::Scalar(255), -1); // 计算重叠的像素数 cv::Mat intersection = binaryImage & tempBinaryImage; int overlapPixelCount = countNonZero(intersection); // 计算当前轮廓的重叠百分比 double overlapPercentage = static_cast(overlapPixelCount) / countNonZero(tempBinaryImage); return overlapPercentage * 100.0> thresholdPercent; // 将结果转换为百分比 } //计算rect是否重叠 static bool isRectOverlap(const cv::Rect& rect1, const cv::Rect& rect2,double thresholdPercent=0) { // 计算两个矩形的重叠区域 cv::Rect intersection = rect1 & rect2; if (thresholdPercent != 0)//如果有阈值 { int maxCnotourArea = max(rect1.area(), rect2.area()); if (intersection.area() / maxCnotourArea < thresholdPercent) return false; } // 如果重叠区域的面积大于0,则说明两个矩形重叠 return intersection.area() > 0; } //将两个contour的区域合并 static vector contourPlusContour(const vector& contour1, const vector& contour2) { vectorres; res.insert(res.end(), contour1.begin(), contour1.end()); res.insert(res.end(), contour2.begin(), contour2.end()); return res; } }; struct rectAndData { cv::Rect rect; double defectHeight; double defectWidth; int badType=0; bool result; ngTypeEnum ngType; vector contour; rectAndData(cv::Rect rectInput, double defectHeightInput, double defectWidthInput,bool resultInput) { rect = rectInput; defectHeight = defectHeightInput; defectWidth = defectWidthInput; result = resultInput; } rectAndData(cv::Rect rectInput, double defectHeightInput, double defectWidthInput, int n, bool resultInput) { rect = rectInput; defectHeight = defectHeightInput; defectWidth = defectWidthInput; badType = n; result = resultInput; } rectAndData(cv::Rect rectInput, double defectHeightInput, double defectWidthInput, int n, bool resultInput, vector& contourInput) { rect = rectInput; defectHeight = defectHeightInput; defectWidth = defectWidthInput; badType = n; result = resultInput; contour = contourInput; } rectAndData(cv::Rect rectInput, double defectHeightInput, double defectWidthInput, int n, bool resultInput, vector&contourInput, ngTypeEnum inputNgType) { rect = rectInput; defectHeight = defectHeightInput; defectWidth = defectWidthInput; badType = n; result = resultInput; contour = contourInput; ngType = inputNgType; } }; //计算主线程 class algoThread : public QThread { Q_OBJECT public: bool m_runFlag = true; QString threadName; handleAiModel* modelPtr; sqlController* sql; threadConroller* tController; subThread* oriSaveThread; subThread* resSaveThread; sncodeCls* snDatas; cameraImages* cameraImgs; QMutex detQueueMutex; QQueue detQueue; QMutex currentMutex, nextMutex, globalMutex; string snErrorsnError = string("snErrNoSn"); QMutex* snAndHashMutex; int Index = 1; int areaIndex = 0; void run(); bool waitForImg(detData* data,int); void getAllFiles(string path, vector& files, string format); void Init(threadConroller* threadConroller) { tController = threadConroller; modelPtr = &threadConroller->models; sql = threadConroller->sql; oriSaveThread = threadConroller->oriSaveThread; resSaveThread = threadConroller->resSaveThread; snDatas = &threadConroller->snDatas; cameraImgs = &threadConroller->cameraImgs; } bool addDetTask(detData*);//添加任务 //算法 void _25D_1_Algo(detData*); void _25D_2_Algo(detData*); signals: void subThreadStart(); }; //用于记录写入csv的缺陷数据 class ngNoteCls { public: struct defectStruct { QString Name; vectorValue; defectStruct(QString nameInput) { Name = nameInput; } }; unordered_mapngDefectMap; unordered_mapokDefectMap; unordered_map::iterator it; /// /// 数据存在返回true,不存在返回false /// /// 数据名 /// bool checkExisted(QString name, unordered_map* map) { it = map->find(name); if (it == map->end()) { return false; } return true; } void insertNgData(QString name) { if (checkExisted(name, &ngDefectMap) == false) { defectStruct defect(name); ngDefectMap.insert({ name,defect }); } } void insertNgData(QString name, double width, double height) { if (checkExisted(name, &ngDefectMap) == false) { defectStruct defect(name); defect.Value.push_back(width); defect.Value.push_back(height); ngDefectMap.insert({ name,defect }); } else//负数缺陷大小设0 { defectStruct* defect = &it->second; for (auto& data : defect->Value) data = 0; } } void insertNgData(QString name, double width, double height, double depth) { if (checkExisted(name, &ngDefectMap) == false) { defectStruct defect(name); defect.Value.push_back(width); defect.Value.push_back(height); defect.Value.push_back(depth); ngDefectMap.insert({ name,defect }); } else//负数缺陷大小设0 { defectStruct* defect = &it->second; for (auto& data : defect->Value) data = 0; } } QString getNgSummaryStr() { QString str; for (auto it : ngDefectMap) { str += "&MAX-" + it.second.Name + "_("; if (it.second.Value.size() > 0) { for (auto data : it.second.Value) str += QString::number(data) + "*"; str.left(str.size() - 1); } str += ")"; } return str; } void insertOkData(QString name) { if (checkExisted(name, &okDefectMap) == false) { defectStruct defect(name); okDefectMap.insert({ name,defect }); } } void insertOkData(QString name, double width, double height) { if (checkExisted(name, &okDefectMap) == false) { defectStruct defect(name); defect.Value.push_back(width); defect.Value.push_back(height); okDefectMap.insert({ name,defect }); } else//负数缺陷大小设0 { defectStruct* defect = &it->second; for (auto& data : defect->Value) data = 0; } } void insertOkData(QString name, double width, double height, double depth) { if (checkExisted(name, &okDefectMap) == false) { defectStruct defect(name); defect.Value.push_back(width); defect.Value.push_back(height); defect.Value.push_back(depth); okDefectMap.insert({ name,defect }); } else//负数缺陷大小设0 { defectStruct* defect = &it->second; for (auto& data : defect->Value) data = 0; } } QString getOkSummaryStr() { QString str; for (auto it : okDefectMap) { str += "&OK-" + it.second.Name + "_("; if (it.second.Value.size() > 0) { for (auto data : it.second.Value) str += QString::number(data) + "*"; str.left(str.size() - 1); } str += ")"; } return str; } private: }; //用于储存以及计算需要在图片上屏蔽的区域 class avoidArea { public: std::vector>avoidContours; bool addArea(cv::Mat& detImg, pSegmentation* segPtr)//只取最大的 { cv::Mat resMat = ~segPtr->Evaluate(detImg); int maxIndex = 0, maxArea = 0; vector>contours; cv::findContours(resMat, contours, cv::noArray(), cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE); if (contours.size() == 0) return false; for (int i = 0; i < contours.size(); i++) { int Area = contourArea(contours[i]); if (Area > maxArea) { maxArea = Area; maxIndex = i; } } if (contours.size() != 0) { avoidContours.push_back(contours[maxIndex]); return true; } return false; } bool checkOverLap(cv::Point input)//检测与中心点是否重叠 { for (auto& contour : avoidContours) { if (cv::pointPolygonTest(contour, input, true) >= 0) { return true; } } return false; } bool checkOverLap(std::vector contourInput) { for (auto& contour : avoidContours) { if (simpleAlgo::isContoursOverlap(contour, contourInput)==true) return true; } return false; } }; //用法:先将contour用insertContours插入,然后调用fusionContourToMat生成Mat class contour2Mat { public: enum type { jiZhuPoSun, aoKeng, huaHeng, max = huaHeng }; struct _strcut { vector contours; cv::Point offset; }; contour2Mat(cv::Size sizeInput) { contoursVec.resize(max+1); offsets.resize(max + 1); imgSize = sizeInput; } contour2Mat() { contoursVec.resize(max + 1); offsets.resize(max + 1); } void insertContours(vector contours, type t,cv::Point offset=cv::Point(0,0)) { if (contours.size() == 0) return; contoursVec[t].push_back({ contours,offset }); } cv::Mat fusionContourToMat(type t) { cv::Mat res; res = cv::Mat( cv::Size( imgSize.width,imgSize.height ), CV_8UC1, cv::Scalar(0)); if (contoursVec[t].size() == 0) { cv::copyMakeBorder(res, res, offsets[t].x, 0, offsets[t].y, 0, 1, cv::Scalar(0)); return res; } for (auto& data : contoursVec[t]) { cv::Rect rect = cv::boundingRect(data.contours); if (res.cols < rect.x + rect.width) cv::copyMakeBorder(res, res, 0, 0, 0, rect.x + rect.width - res.cols, cv::BORDER_CONSTANT, cv::Scalar(0)); if (res.rows < rect.y + rect.height) cv::copyMakeBorder(res, res, 0, rect.y + rect.height - res.rows, 0, 0, cv::BORDER_CONSTANT, cv::Scalar(0)); } for (auto& data : contoursVec[t]) { cv::drawContours(res(cv::Rect(data.offset.x,data.offset.y,imgSize.width-data.offset.x,imgSize.height-data.offset.y)), vector >(1,data.contours), -1, cv::Scalar(255), -1); } return res; } void setImgSize(cv::Size sizeInput) { imgSize = sizeInput; } void setOffSet(cv::Point offsetInput, type t) { offsets[t] = offsetInput; } private: cv::Size imgSize; std::vectoroffsets; std::vector>contoursVec; }; //用于储存检测结果,以及防止重复画图 //尚不启用 class rectAndDataCls { public: vectorrectAndDatas; void insert(vector& input) { if (rectAndDatas.size() == 0)//第一次插入 { rectAndDatas = input; return; } else//第2+次插入 需要进行重合判定 { for (auto& data : input) { bool flag = false; for (auto& data2 : rectAndDatas)//检查是否重合 { if (simpleAlgo::isContoursOverlap(data.contour, data2.contour, 50) == true)//重合部分超过30% { flag = true; data2.contour = simpleAlgo::contourPlusContour(data.contour, data2.contour);//融合 data2.ngType = std::max(data.ngType, data2.ngType); } } if (flag == false)// 否 rectAndDatas.push_back(data); } } } void insert(vector input) { if (rectAndDatas.size() == 0)//第一次插入 { rectAndDatas = input; return; } else//第2+次插入 需要进行重合判定 { for (auto& data : input) { bool flag = false; for (auto& data2 : rectAndDatas)//检查是否重合 { if (simpleAlgo::isContoursOverlap(data.contour, data2.contour, 50) == true)//重合部分超过30% { flag = true; data2.contour = simpleAlgo::contourPlusContour(data.contour, data2.contour);//融合 data2.ngType = std::max(data.ngType, data2.ngType); } } if (flag == false)// 否 rectAndDatas.push_back(data); } } } void clear() { rectAndDatas.clear(); } private: }; #pragma once