当前位置: 首页 > news >正文

ROI 接口便捷修改

传入的图片截取ROI后再进入识别接口

(识别接口比ROI接口的函数参数少一个传入的ROI)

无点只有点集

 返回双点集

//平直冷侧翅片
bool ImageProcessingTest::straightColdSideFin_ROI(cv::Mat img, cv::Rect ROI, std::vector<cv::Point>& topList, std::vector<cv::Point>& bottomList, cv::Mat & canvas, bool debug)
{int endRes = 0;bool result = false;img.copyTo(canvas);//top = cv::Point(0, 0);//bottom = cv::Point(0, 0);cv::Mat imgOriginal;bool ROI_flag;//是否有给信息区cv::Point ROI_tl = cv::Point2i(ROI.x, ROI.y);cv::Point ROI_br = cv::Point2i(ROI.x + ROI.width, ROI.y + ROI.height);if (ROI_tl == cv::Point(0, 0) && ROI_br == cv::Point(0, 0) || ROI.width == 0 || ROI.height == 0){img.copyTo(imgOriginal);ROI_flag = false;}else{if (ROI_tl.x > ROI_br.x || ROI_tl.y > ROI_br.y)//信息区两点疑似传反{printf("信息区两点疑似传反!");return false;}if (ROI_tl.x < 0 || ROI_br.x > img.cols || ROI_tl.y < 0 || ROI_br.y > img.rows)//信息区的框选超出图像范围{printf("信息区的框选超出图像范围!");return false;}if (abs(ROI_tl.x - ROI_br.x) > img.cols || abs(ROI_tl.y - ROI_br.y) > img.rows)//信息区大小超出图像大小{printf("信息区大小超出图像大小!");return false;}//此时不合法的ROI都已提前返回falsecv::Rect roi(ROI_tl.x, ROI_tl.y, ROI_br.x - ROI_tl.x, ROI_br.y - ROI_tl.y);imgOriginal = img(roi);	//裁剪出的ROI区域放于imgOriginalROI_flag = true;}result = straightColdSideFin(imgOriginal, topList, bottomList, canvas, debug);//调用识别算法if (debug) {for (int i = 0; i < topList.size(); i++) {cv::Point top = topList.at(i);top += ROI_tl;if (debug) printf("-------------------------------------****------ roiF  top=【%d, %d】\n", top.x, top.y);}for (int i = 0; i < bottomList.size(); i++) {cv::Point bottom = bottomList.at(i);bottom += ROI_tl;if (debug) printf("-------------------------------------****------ roiF  bottom=【%d, %d】\n", bottom.x, bottom.y);}}//if (debug) printf("-------------------------------------****------ roiF  top=【%d, %d】, bottom=【%d, %d】\n", top.x, top.y, bottom.x, bottom.y);//img.copyTo(canvas);x值和y值补上ROI左上点x和y//if (ROI_flag) {//	if (Corner != cv::Point(0, 0))//	{//		Corner.x += ROI_tl.x;//		Corner.y += ROI_tl.y;//	}//}img.copyTo(canvas);//调试时注释掉if (result){cv::Point textP(6, 0);//演示用endRes = 1;for (int i = 0; i < topList.size(); i++) {topList.at(i) += ROI_tl;cv::Point top = topList.at(i);circle(canvas, top, 2, cv::Scalar(0, 69, 255), -1);cv::putText(canvas, to_string(i), top + textP, cv::FONT_HERSHEY_COMPLEX, 0.45, cv::Scalar(0, 69, 255), 1);//演示用}for (int i = 0; i < bottomList.size(); i++) {bottomList.at(i) += ROI_tl;cv::Point bottom = bottomList.at(i);circle(canvas, bottom, 2, cv::Scalar(255, 69, 0), -1);cv::putText(canvas, to_string(i), bottom + textP, cv::FONT_HERSHEY_COMPLEX, 0.45, cv::Scalar(255, 69, 0), 1);//演示用}printf("topList.size()=%d , bottomList.size()=%d \n", topList.size(), bottomList.size());cv::putText(canvas, "true", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);}else{cv::putText(canvas, "false", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);}cv::Mat ROIcanvas;img.copyTo(ROIcanvas);if (debug) {if (debug) printf("topList.size()=%d , bottomList.size()=%d \n", topList.size(), bottomList.size());for (int i = 0; i < topList.size(); i++) {cv::Point top = topList.at(i);circle(ROIcanvas, top, 3, cv::Scalar(0, 69, 255), 1);if (debug) printf("-------------------------------------****------ roiF  top=【%d, %d】\n", top.x, top.y);}for (int i = 0; i < bottomList.size(); i++) {cv::Point bottom = bottomList.at(i);circle(ROIcanvas, bottom, 3, cv::Scalar(255, 69, 0), 1);if (debug) printf("-------------------------------------****------ roiF  bottom=【%d, %d】\n", bottom.x, bottom.y);}}//if (debug) circle(ROIcanvas, top, 3, cv::Scalar(0, 69, 255), 1);//if (debug) circle(ROIcanvas, bottom, 3, cv::Scalar(0, 69, 255), 1);if (debug) rectangle(ROIcanvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);rectangle(canvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);//if (debug) printf("-------------------------------------****------ roiF  top=【%d, %d】, bottom=【%d, %d】\n", top.x, top.y, bottom.x, bottom.y);if (debug) imshow("ROI", ROIcanvas);if (debug) imshow("ROI接口_canvas", canvas);//ROIcanvas.copyTo(canvas);return result;
}

调用main:

//平直冷侧翅片:straightColdSideFin_ROI
int main333() {bool flag = false;std::string filePath = "../img/straightColdSideFin/0616img";string resPath = "/output";//string resPath = filePath + "./output";cv::Point tlP = cv::Point(200, 0);cv::Point brP = cv::Point(950, 1024);std::vector<cv::Point> topList;std::vector<cv::Point> bottomList;cv::Mat canvas;ImageProcessingTest m_ImageProcessing;ofstream ofs("log.txt", ios::out);if (ofs){ofs.clear();ofs << "日志启动" << endl;}vector<string> path_name;bool   lianxu = false; //循环测试if (lianxu){string path = filePath + cv::format("\\Image_20230614160744823.png");//string path = filePath + cv::format("\\Image_20230609111800152.png");//string path = filePath + cv::format("\\Image_20230601143638388.png");//string path = filePath + cv::format("\\Image_20230601143505168.png");//string path = filePath + cv::format("\\Image_20230609113049539.png");cv::Mat src = cv::imread(path);src.copyTo(canvas);cv::namedWindow("main_OriginalIMG", cv::RECURS_FILTER);cvSetMouseCallback("main_OriginalIMG", on_mouse_singleClick, 0);cv::imshow("main_OriginalIMG", src);//cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);bool flag = m_ImageProcessing.straightColdSideFin_ROI(src, ROI, topList, bottomList, canvas, true);cout << "\nmain ==== flag " << flag << endl;if (flag) {for (int i = 0; i < topList.size(); i++) {cv::Point top = topList.at(i);cout << "top = " << top.x << " " << top.y << endl;circle(canvas, top, 6, cv::Scalar(0, 69, 255), 1);}for (int i = 0; i < bottomList.size(); i++) {cv::Point bottom = bottomList.at(i);cout << "bottom = " << bottom.x << " " << bottom.y << endl;circle(canvas, bottom, 6, cv::Scalar(255, 69, 0), 1);}printf("topList.size()=%d , bottomList.size()=%d \n", topList.size(), bottomList.size());}canvas.copyTo(src);//cout << "\nmain ==== i " << endl;//cv::putText(src, to_string(flag), cv::Point(src.cols / 2 - 20, src.rows / 2 - 65), cv::FONT_HERSHEY_COMPLEX, 1.75, cv::Scalar(255, 135, 160), 3);cv::namedWindow("main-结果图src", cv::RECURS_FILTER);cvSetMouseCallback("main-结果图src", on_mouse_singleClick, 0);cv::imshow("main-结果图src", src);}else{vector<string> path_name;getAllFiles(filePath, path_name);cout << "path_name.size()=" << path_name.size() << endl;int number = 1;for (auto i : path_name){cv::Mat src = cv::imread(filePath + "\\" + i);cout << endl << "number【" << number << "】src path=" << i << " ;" << endl;src.copyTo(canvas);cv::imshow("main_OriginalIMG", src);//将结果图写入文件方便查看结果int len = filePath.length();//i = i.substr(i.find_last_of('\\') + 1, len);cout << "i=" << i << endl;int time_start = clock();int time_end = clock();//cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);bool flag = m_ImageProcessing.straightColdSideFin_ROI(src, ROI, topList, bottomList, canvas);time_end = clock();printf("\n耗时 %d ms \n", time_end - time_start);cout << "\nmain ==== flag " << flag << endl;if (flag) {for (int i = 0; i < topList.size(); i++) {cv::Point top = topList.at(i);cout << "top = " << top.x << " " << top.y << endl;}for (int i = 0; i < bottomList.size(); i++) {cv::Point bottom = bottomList.at(i);cout << "bottom = " << bottom.x << " " << bottom.y << endl;}printf("topList.size()=%d , bottomList.size()=%d \n", topList.size(), bottomList.size());}canvas.copyTo(src);//cv::putText(src, to_string(flag), cv::Point(src.cols / 2 - 20, src.rows / 2 - 65), cv::FONT_HERSHEY_COMPLEX, 1.75, cv::Scalar(255, 135, 160), 3);cv::imshow("main-结果图src", src);cv::waitKey(10);//将结果图写入文件方便查看结果char*  filePath_ = new char[len + 1];strcpy(filePath_, filePath.c_str());len = filePath.length();char*  resPath_ = new char[len + 1];strcpy(resPath_, resPath.c_str());//i.erase(0, strlen(filePath_) - strlen(resPath_) - 2);string out = filePath + resPath;cout << "\nmain ==== i " << i << endl;out.append("\\").append(i);cout << "number【" << number << "】res path=" << out << endl;cv::imwrite(out, src);number++;cout << "path_name.size() = " << path_name.size() << endl;cout << "*********************************************************************************************************************" << endl;if (number == path_name.size()) break;}}cout << "main 循环结束!!!" << endl;ofs.close();cv::waitKey(0);system("Pause");return 0;
}

单点

返回只有单点 

bool ImageProcess::arcPlusLine_ROI(cv::Mat img, cv::Rect ROI, cv::Point & top, cv::Mat & canvas, bool debug)
{int endRes = 0;bool result = false;img.copyTo(canvas);top = cv::Point(0, 0);cv::Mat imgOriginal;bool ROI_flag;//是否有给信息区cv::Point ROI_tl = cv::Point2i(ROI.x, ROI.y);cv::Point ROI_br = cv::Point2i(ROI.x + ROI.width, ROI.y + ROI.height);if (ROI_tl == cv::Point(0, 0) && ROI_br == cv::Point(0, 0) || ROI.width == 0 || ROI.height == 0){img.copyTo(imgOriginal);ROI_flag = false;}else{if (ROI_tl.x > ROI_br.x || ROI_tl.y > ROI_br.y)//信息区两点疑似传反{printf("信息区两点疑似传反!");return false;}if (ROI_tl.x < 0 || ROI_br.x > img.cols || ROI_tl.y < 0 || ROI_br.y > img.rows)//信息区的框选超出图像范围{printf("信息区的框选超出图像范围!");return false;}if (abs(ROI_tl.x - ROI_br.x) > img.cols || abs(ROI_tl.y - ROI_br.y) > img.rows)//信息区大小超出图像大小{printf("信息区大小超出图像大小!");return false;}//此时不合法的ROI都已提前返回falsecv::Rect roi(ROI_tl.x, ROI_tl.y, ROI_br.x - ROI_tl.x, ROI_br.y - ROI_tl.y);imgOriginal = img(roi);	//裁剪出的ROI区域放于imgOriginalROI_flag = true;}result = arcPlusLine(imgOriginal, top, canvas, debug);//调用识别算法if (debug) printf("-------------------------------------****------ roiF  top=【%d, %d】\n", top.x, top.y);//img.copyTo(canvas);//img.copyTo(canvas);//调试时注释掉cv::Mat t1;//canvas.convertTo(t1, -1, 900 / 100.0, 200 - 100);//第一次线性变换100canvas.convertTo(t1, -1, 900 / 100.0, 200 - 100);//第一次线性变换100if (debug)cv::imshow("线性变换ROI", t1);t1.copyTo(canvas);if (result){endRes = 1;top += ROI_tl;cv::putText(canvas, "true", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);int w = 38;int thickness = 4;cv::Point curPoint = top;cv::line(canvas, curPoint, cv::Point(curPoint.x - w, curPoint.y), cv::Scalar(235, 135, 40), thickness);circle(canvas, top, 2, cv::Scalar(0, 69, 255), -1);circle(canvas, top, 63, cv::Scalar(0, 169, 255), 1);}else{cv::putText(canvas, "false", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);}cv::Mat ROIcanvas;img.copyTo(ROIcanvas);if (debug) circle(ROIcanvas, top, 3, cv::Scalar(0, 69, 255), 1);if (debug) circle(ROIcanvas, top, 63, cv::Scalar(0, 169, 255), 1);if (debug) rectangle(ROIcanvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);rectangle(canvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);if (debug) printf("-------------------------------------****------ roiF  top=【%d, %d】 \n", top.x, top.y);if (debug) imshow("ROI", ROIcanvas);if (debug) imshow("ROI_canvas", canvas);//ROIcanvas.copyTo(canvas);//cv::Rect roi_(ROI_tl.x, ROI_tl.y, ROI_br.x - ROI_tl.x, ROI_br.y - ROI_tl.y);//if(!ROI_flag) canvas.copyTo(canvas);//else canvas = canvas(roi_);	//裁剪出的ROI区域return result;
}

调用main:

//圆弧+直线 内角:arcPlusLine_ROI
int main/*arcl*/() {bool flag = false;//std::string filePath = "E://vsproject//WeldingLine//1219img//in//宁波金波";//std::string filePath = "E://vsproject//WeldingLine//1219img//in//宁波金波//down";std::string filePath = "E://vsproject//WeldingLine//1219img//in//宁波金波//LogImg";//std::string filePath = "../img/ThreadedRoundPipe/0530img";string resPath = "/output";//string resPath = filePath + "./output";cv::Point tlP = cv::Point(200, 340);cv::Point brP = cv::Point(950, 999);cv::Point top(90, 90);cv::Mat canvas;VisualInterface m_ImageProcessing;//ImageProcess m_ImageProcessing;ofstream ofs("log.txt", ios::out);if (ofs){ofs.clear();ofs << "日志启动" << endl;}vector<string> path_name;bool lineOnTop = true;bool   getROI = !true;bool   lianxu = false; //循环测试if (!lianxu){string name = cv::format("\\Img_2024_03_12_15_01_57_350_TYPE_12_ROI_486_64_257_474_src.png");string path = filePath + name;//string path = filePath + cv::format("\\Image_20240228115544906.bmp");cv::Mat src = cv::imread(path);src.copyTo(canvas);cv::namedWindow("main_OriginalIMG", cv::RECURS_FILTER);cvSetMouseCallback("main_OriginalIMG", on_mouse_singleClick, 0);cv::imshow("main_OriginalIMG", src);cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);//cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);if (getROI) ROI = getROIFromString(name);bool flag = m_ImageProcessing.arcPlusLine_ROI(src, ROI, top, canvas, lineOnTop, true);cout << "\nmain ==== flag " << flag << endl;if (flag) {cout << "top = " << top.x << " " << top.y << endl;}canvas.copyTo(src);//cout << "\nmain ==== i " << endl;circle(canvas, top, 63, cv::Scalar(0, 69, 255), 1);cv::putText(src, to_string(flag), cv::Point(src.cols / 2 - 20, src.rows / 2 - 165), cv::FONT_HERSHEY_COMPLEX, 1.75, cv::Scalar(255, 135, 160), 3);cv::namedWindow("main-结果图src", cv::RECURS_FILTER);cvSetMouseCallback("main-结果图src", on_mouse_singleClick, 0);cv::imshow("main-结果图src", src);}else{vector<string> path_name;getAllFiles(filePath, path_name);cout << "path_name.size()=" << path_name.size() << endl;int number = 1;for (auto i : path_name){if (i.find("_res") != std::string::npos ) continue;if (i.find("png") == std::string::npos && i.find("bmp") == std::string::npos && i.find("jpg") == std::string::npos) continue;cv::Mat src = cv::imread(filePath + "\\" + i);cout << endl << "number【" << number << "】src path=" << i << " ;" << endl;src.copyTo(canvas);cv::imshow("main_OriginalIMG", src);//将结果图写入文件方便查看结果int len = filePath.length();//i = i.substr(i.find_last_of('\\') + 1, len);cout << "i=" << i << endl;int time_start = clock();int time_end = clock();cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);//cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);if (getROI) ROI = getROIFromString(i);bool flag = m_ImageProcessing.arcPlusLine_ROI(src, ROI, top, canvas, lineOnTop, false);time_end = clock();printf("\n耗时 %d ms \n", time_end - time_start);cout << "\nmain ==== flag " << flag << endl;if (flag) {cout << "top = " << top.x << " " << top.y << endl;}canvas.copyTo(src);cv::putText(src, to_string(flag), cv::Point(src.cols / 2 - 20, src.rows / 2 - 65), cv::FONT_HERSHEY_COMPLEX, 1.75, cv::Scalar(255, 135, 160), 3);cv::imshow("main-结果图src", src);cv::waitKey(10);//将结果图写入文件方便查看结果char*  filePath_ = new char[len + 1];strcpy(filePath_, filePath.c_str());len = filePath.length();char*  resPath_ = new char[len + 1];strcpy(resPath_, resPath.c_str());//i.erase(0, strlen(filePath_) - strlen(resPath_) - 2);string out = filePath + resPath;cout << "\nmain ==== i " << i << endl;out.append("\\").append(i);cout << "number【" << number << "】res path=" << out << endl;cv::imwrite(out, src);number++;cout << "path_name.size() = " << path_name.size() << endl;cout << "*********************************************************************************************************************" << endl;if (number == path_name.size()) break;}}cout << "main 循环结束!!!" << endl;ofs.close();cv::waitKey(0);system("Pause");return 0;
}
cv::Rect getROIFromString(std::string str) {//图像名字格式:“SrcImg_2023_10_11_11_39_19_002_ROI_600_396_137_218_src.png”if (str.empty()) return cv::Rect(0, 0, 0, 0);using namespace std;const char *split = "_";char *p = strtok((char*)str.c_str(), split);std::vector<char*>data;while (p != NULL) {cout << p << endl;data.push_back(p);p = strtok(NULL, split);}//9 12;if (data.size() < 12)return cv::Rect();return cv::Rect(atoi(data[data.size() - 5]),atoi(data[data.size() - 4]),atoi(data[data.size() - 3]),atoi(data[data.size() - 2]));//return cv::Rect(//	atoi(data[9]),//	atoi(data[10]),//	atoi(data[11]),//	atoi(data[12]));
}

 返回只有单点,传入(高/低曝光图)两张原图,返回单点(高曝光图和激光图结合时使用)

int ImageProcess::getPnt_2Dwith3D_MaiSi(cv::Mat imgHE, cv::Mat imgLE, cv::Mat & canvas, cv::Point & resPoint, bool &MaiSi_isTopPnt, cv::Rect ROI, bool debug)
{int endRes = 0;bool result = false;imgHE.copyTo(canvas);cv::addWeighted(imgHE, 0.5, imgLE, 0.5, 0, canvas);ImageProcess pd;cv::Mat imgHE_roi;cv::Mat imgOriginal;bool ROI_flag;//是否有给信息区cv::Point ROI_tl = cv::Point2i(ROI.x, ROI.y);cv::Point ROI_br = cv::Point2i(ROI.x + ROI.width, ROI.y + ROI.height);cv::Mat img;imgLE.copyTo(img);if (ROI_tl == cv::Point(0, 0) && ROI_br == cv::Point(0, 0)){img.copyTo(imgOriginal);imgHE.copyTo(imgHE_roi);ROI_flag = false;}else{if (ROI_tl.x > ROI_br.x || ROI_tl.y > ROI_br.y)//信息区两点疑似传反{printf("信息区两点疑似传反!");return false;}if (ROI_tl.x < 0 || ROI_br.x > img.cols || ROI_tl.y < 0 || ROI_br.y > img.rows)//信息区的框选超出图像范围{printf("信息区的框选超出图像范围!");return false;}if (abs(ROI_tl.x - ROI_br.x) > img.cols || abs(ROI_tl.y - ROI_br.y) > img.rows)//信息区大小超出图像大小{printf("信息区大小超出图像大小!");return false;}//此时不合法的ROI都已提前返回falsecv::Rect roi(ROI_tl.x, ROI_tl.y, ROI_br.x - ROI_tl.x, ROI_br.y - ROI_tl.y);imgOriginal = img(roi);	//裁剪出的ROI区域放于imgOriginalimgHE_roi = imgHE(roi);ROI_flag = true;if (debug) {cv::Mat tmp;img.copyTo(tmp);rectangle(tmp, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);if (debug) cv::imshow("根据roi裁剪后进入识别的图", tmp);}}result = getPnt_2Dwith3D_MaiSi(imgHE_roi, imgOriginal, canvas, resPoint, MaiSi_isTopPnt, debug);cv::addWeighted(imgHE, 0.5, imgLE, 0.5, 0, canvas);//x值和y值补上ROI左上点x和yif (ROI_flag){if (resPoint != cv::Point(0, 0)){resPoint.x += ROI_tl.x;resPoint.y += ROI_tl.y;}}if (debug) std::cout << img.size() << imgOriginal.size() << std::endl;if (result){endRes = 1;cv::circle(canvas, resPoint, 3, cv::Scalar(0, 0, 255), -1, 8, 0);putText(canvas, "true", { cv::Point(250, 250) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);//putText(canvas, "EmbWare_Leg", { cv::Point(250, 350) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);if (MaiSi_isTopPnt) {putText(canvas, "isTopPnt", { resPoint + cv::Point(15, 5) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(195, 165, 255), 1);}else {putText(canvas, "isBotPnt", { resPoint + cv::Point(15, 5) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(155, 155, 255), 1);}Mark(canvas);}else{putText(canvas, "false", { cv::Point(250, 250) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);Mark(canvas);}rectangle(canvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);return endRes;
}

返回单点+上下翻转再进入识别

	/*//圆弧+直线  求内角cv::Mat img, 原图cv::Rect ROI,cv::Point& Corner, 输出角点cv::Mat &canvas,效果图可视化bool lineOnTop = true,直线部分是否为较上端的角边,true则为是,false反之*/bool arcPlusLine(cv::Mat imgOriginal, cv::Point& Corner, cv::Mat &canvas, bool debug = false);bool arcPlusLine_ROI(cv::Mat img, cv::Rect ROI, cv::Point& Corner, cv::Mat &canvas, bool lineOnTop = true, bool debug = false);
bool ImageProcess::arcPlusLine_ROI(cv::Mat img, cv::Rect ROI, cv::Point & top, cv::Mat & canvas, bool lineOnTop, bool debug)
{int endRes = 0;bool result = false;img.copyTo(canvas);top = cv::Point(0, 0);cv::Mat imgOriginal;bool ROI_flag;//是否有给信息区cv::Point ROI_tl = cv::Point2i(ROI.x, ROI.y);cv::Point ROI_br = cv::Point2i(ROI.x + ROI.width, ROI.y + ROI.height);if (ROI_tl == cv::Point(0, 0) && ROI_br == cv::Point(0, 0) || ROI.width == 0 || ROI.height == 0){img.copyTo(imgOriginal);ROI_flag = false;}else{if (ROI_tl.x > ROI_br.x || ROI_tl.y > ROI_br.y)//信息区两点疑似传反{printf("信息区两点疑似传反!");return false;}if (ROI_tl.x < 0 || ROI_br.x > img.cols || ROI_tl.y < 0 || ROI_br.y > img.rows)//信息区的框选超出图像范围{printf("信息区的框选超出图像范围!");return false;}if (abs(ROI_tl.x - ROI_br.x) > img.cols || abs(ROI_tl.y - ROI_br.y) > img.rows)//信息区大小超出图像大小{printf("信息区大小超出图像大小!");return false;}//此时不合法的ROI都已提前返回falsecv::Rect roi(ROI_tl.x, ROI_tl.y, ROI_br.x - ROI_tl.x, ROI_br.y - ROI_tl.y);imgOriginal = img(roi);	//裁剪出的ROI区域放于imgOriginalROI_flag = true;}if (lineOnTop) {result = arcPlusLine(imgOriginal, top, canvas, debug);//调用识别算法}else {cv::Mat fpMt;cv::flip(imgOriginal, fpMt, 0);		// 上下翻转 x对称result = arcPlusLine(fpMt, top, canvas, debug);//调用识别算法if (result) {top.y = fpMt.rows - top.y - 1;}}cv::Mat lockCanvas = canvas.clone();if (debug) printf("-------------------------------------****------ roiF  top=【%d, %d】\n", top.x, top.y);//img.copyTo(canvas);//img.copyTo(canvas);//调试时注释掉//cv::Mat t1;//canvas.convertTo(t1, -1, 900 / 100.0, 200 - 100);//第一次线性变换100//if (debug)cv::imshow("线性变换ROI", t1);//t1.copyTo(canvas);if (result){endRes = 1;top += ROI_tl;cv::putText(canvas, "true", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);int w = 38;int thickness = 4;cv::Point curPoint = top;cv::line(canvas, curPoint, cv::Point(curPoint.x - w, curPoint.y), cv::Scalar(235, 135, 40), thickness);circle(canvas, top, 2, cv::Scalar(0, 69, 255), -1);circle(canvas, top, 63, cv::Scalar(0, 169, 255), 1);}else{cv::putText(canvas, "false", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);}cv::Mat ROIcanvas;img.copyTo(ROIcanvas);if (debug) circle(ROIcanvas, top, 3, cv::Scalar(0, 69, 255), 1);if (debug) circle(ROIcanvas, top, 63, cv::Scalar(0, 169, 255), 1);if (debug) rectangle(ROIcanvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);rectangle(canvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);if (debug) printf("-------------------------------------****------ roiF  top=【%d, %d】 \n", top.x, top.y);if (debug) imshow("ROI", ROIcanvas);if (debug) imshow("ROI_canvas", canvas);//ROIcanvas.copyTo(canvas);//cv::Rect roi_(ROI_tl.x, ROI_tl.y, ROI_br.x - ROI_tl.x, ROI_br.y - ROI_tl.y);//if(!ROI_flag) canvas.copyTo(canvas);//else canvas = canvas(roi_);	//裁剪出的ROI区域lockCanvas.copyTo(canvas);return result;
}

调用main:

// 内角:arcPlusLine_ROI
int main/*arcl*/() {bool flag = false;std::string filePath = "E://vsproject//WeldingLine//1219img//in//宁波金波";//std::string filePath = "E://vsproject//WeldingLine//1219img//in//宁波金波//down";//std::string filePath = "../img/ThreadedRoundPipe/0530img";string resPath = "/output";//string resPath = filePath + "./output";cv::Point tlP = cv::Point(200, 340);cv::Point brP = cv::Point(950, 999);cv::Point top(90, 90);cv::Mat canvas;//VisualInterface m_ImageProcessing;ImageProcess m_ImageProcessing;ofstream ofs("log.txt", ios::out);if (ofs){ofs.clear();ofs << "日志启动" << endl;}vector<string> path_name;bool lineOnTop = true;bool   lianxu = false; //循环测试if (lianxu){string path = filePath + cv::format("\\Image_20240304155500627.png");//string path = filePath + cv::format("\\Image_20240228115544906.bmp");cv::Mat src = cv::imread(path);src.copyTo(canvas);cv::namedWindow("main_OriginalIMG", cv::RECURS_FILTER);cvSetMouseCallback("main_OriginalIMG", on_mouse_singleClick, 0);cv::imshow("main_OriginalIMG", src);cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);//cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);bool flag = m_ImageProcessing.arcPlusLine_ROI(src, ROI, top, canvas, lineOnTop, true);cout << "\nmain ==== flag " << flag << endl;if (flag) {cout << "top = " << top.x << " " << top.y << endl;}canvas.copyTo(src);//cout << "\nmain ==== i " << endl;circle(canvas, top, 63, cv::Scalar(0, 69, 255), 1);cv::putText(src, to_string(flag), cv::Point(src.cols / 2 - 20, src.rows / 2 - 165), cv::FONT_HERSHEY_COMPLEX, 1.75, cv::Scalar(255, 135, 160), 3);cv::namedWindow("main-结果图src", cv::RECURS_FILTER);cvSetMouseCallback("main-结果图src", on_mouse_singleClick, 0);cv::imshow("main-结果图src", src);}else{vector<string> path_name;getAllFiles(filePath, path_name);cout << "path_name.size()=" << path_name.size() << endl;int number = 1;for (auto i : path_name){if (i.find("png") == std::string::npos && i.find("bmp") == std::string::npos && i.find("jpg") == std::string::npos) continue;cv::Mat src = cv::imread(filePath + "\\" + i);cout << endl << "number【" << number << "】src path=" << i << " ;" << endl;src.copyTo(canvas);cv::imshow("main_OriginalIMG", src);//将结果图写入文件方便查看结果int len = filePath.length();//i = i.substr(i.find_last_of('\\') + 1, len);cout << "i=" << i << endl;int time_start = clock();int time_end = clock();cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);//cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);bool flag = m_ImageProcessing.arcPlusLine_ROI(src, ROI, top, canvas, lineOnTop, false);time_end = clock();printf("\n耗时 %d ms \n", time_end - time_start);cout << "\nmain ==== flag " << flag << endl;if (flag) {cout << "top = " << top.x << " " << top.y << endl;}canvas.copyTo(src);cv::putText(src, to_string(flag), cv::Point(src.cols / 2 - 20, src.rows / 2 - 65), cv::FONT_HERSHEY_COMPLEX, 1.75, cv::Scalar(255, 135, 160), 3);cv::imshow("main-结果图src", src);cv::waitKey(10);//将结果图写入文件方便查看结果char*  filePath_ = new char[len + 1];strcpy(filePath_, filePath.c_str());len = filePath.length();char*  resPath_ = new char[len + 1];strcpy(resPath_, resPath.c_str());//i.erase(0, strlen(filePath_) - strlen(resPath_) - 2);string out = filePath + resPath;cout << "\nmain ==== i " << i << endl;out.append("\\").append(i);cout << "number【" << number << "】res path=" << out << endl;cv::imwrite(out, src);number++;cout << "path_name.size() = " << path_name.size() << endl;cout << "*********************************************************************************************************************" << endl;if (number == path_name.size()) break;}}cout << "main 循环结束!!!" << endl;ofs.close();cv::waitKey(0);system("Pause");return 0;
}

返回单点+1个点集+上下翻转再进入识别 

bool PTank_imgProcess::arcPlusLine_ROI(cv::Mat img, cv::Rect ROI, cv::Point & top, std::vector<cv::Point>& allPntList, cv::Mat & canvas, bool lineOnTop, bool debug)
{int endRes = 0;bool result = false;img.copyTo(canvas);top = cv::Point(0, 0);cv::Mat imgOriginal;bool ROI_flag;//是否有给信息区cv::Point ROI_tl = cv::Point2i(ROI.x, ROI.y);cv::Point ROI_br = cv::Point2i(ROI.x + ROI.width, ROI.y + ROI.height);if (ROI_tl == cv::Point(0, 0) && ROI_br == cv::Point(0, 0) || ROI.width == 0 || ROI.height == 0){img.copyTo(imgOriginal);ROI_flag = false;}else{if (ROI_tl.x > ROI_br.x || ROI_tl.y > ROI_br.y)//信息区两点疑似传反{printf("信息区两点疑似传反!");return false;}if (ROI_tl.x < 0 || ROI_br.x > img.cols || ROI_tl.y < 0 || ROI_br.y > img.rows)//信息区的框选超出图像范围{printf("信息区的框选超出图像范围!");return false;}if (abs(ROI_tl.x - ROI_br.x) > img.cols || abs(ROI_tl.y - ROI_br.y) > img.rows)//信息区大小超出图像大小{printf("信息区大小超出图像大小!");return false;}//此时不合法的ROI都已提前返回falsecv::Rect roi(ROI_tl.x, ROI_tl.y, ROI_br.x - ROI_tl.x, ROI_br.y - ROI_tl.y);imgOriginal = img(roi);	//裁剪出的ROI区域放于imgOriginalROI_flag = true;}cv::Mat lockCanvas;if (lineOnTop) {result = arcPlusLine(imgOriginal, top, allPntList, canvas, debug);//调用识别算法canvas.copyTo(lockCanvas);//for (int i = 0; i < allPntList.size(); i++) {//	cv::line(lockCanvas, allPntList.at(i), cv::Point(allPntList.at(i).x - 3, allPntList.at(i).y), cv::Scalar(55, 195, 40), 1);//}}else {cv::Mat fpMt;cv::flip(imgOriginal, fpMt, 0);		// 上下翻转 x对称result = arcPlusLine(fpMt, top, allPntList, canvas, debug);//调用识别算法canvas.copyTo(lockCanvas);if (result) {top.y = fpMt.rows - top.y - 1;for (int i = 0; i < allPntList.size(); i++) {//cv::line(lockCanvas, allPntList.at(i), cv::Point(allPntList.at(i).x - 3, allPntList.at(i).y), cv::Scalar(55, 195, 40), 1);allPntList.at(i).y = fpMt.rows - allPntList.at(i).y - 1;}}}if (debug) printf("-------------------------------------****------ roiF  top=【%d, %d】\n", top.x, top.y);//img.copyTo(canvas);//img.copyTo(canvas);//调试时注释掉//cv::Mat t1;//canvas.convertTo(t1, -1, 900 / 100.0, 200 - 100);//第一次线性变换100//if (debug)cv::imshow("线性变换ROI", t1);//t1.copyTo(canvas);if (result){img.copyTo(canvas);endRes = 1;top += ROI_tl;for (int i = 0; i < allPntList.size(); i++) {allPntList.at(i) += ROI_tl;}cv::putText(canvas, "true", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);int w = 38;int thickness = 4;cv::Point curPoint = top;cv::line(canvas, curPoint, cv::Point(curPoint.x - w, curPoint.y), cv::Scalar(235, 135, 40), thickness);circle(canvas, top, 2, cv::Scalar(0, 69, 255), -1);circle(canvas, top, 63, cv::Scalar(0, 169, 255), 1);w = 3;for (int i = 0; i < allPntList.size(); i++) {cv::Point curPoint = allPntList.at(i);cv::line(canvas, curPoint, cv::Point(curPoint.x - w, curPoint.y), cv::Scalar(55, 195, 40), 1);}}else{cv::putText(canvas, "false", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);}cv::Mat ROIcanvas;img.copyTo(ROIcanvas);if (debug) circle(ROIcanvas, top, 3, cv::Scalar(0, 69, 255), 1);if (debug) circle(ROIcanvas, top, 63, cv::Scalar(0, 169, 255), 1);if (debug) rectangle(ROIcanvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);rectangle(canvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);if (debug) printf("-------------------------------------****------ roiF  top=【%d, %d】 \n", top.x, top.y);if (debug) imshow("ROI", ROIcanvas);if (debug) imshow("ROI_canvas", canvas);//ROIcanvas.copyTo(canvas);//cv::Rect roi_(ROI_tl.x, ROI_tl.y, ROI_br.x - ROI_tl.x, ROI_br.y - ROI_tl.y);//if(!ROI_flag) canvas.copyTo(canvas);//else canvas = canvas(roi_);	//裁剪出的ROI区域if (result) lockCanvas.copyTo(canvas);cv::putText(canvas, to_string(result), cv::Point(30, 65), cv::FONT_HERSHEY_COMPLEX, 1.75, cv::Scalar(255, 135, 160), 3);return result;
}

调用main:

// 内角:arcPlusLine_ROI 类似金波(金波优化版)
int main/*arcl*/() {bool flag = false;//std::string filePath = "E://vsproject//压力罐\\img\\类金波/top";std::string filePath = "E://vsproject//压力罐\\img\\类金波";//std::string filePath = "E://vsproject//压力罐\\img\\叶子";//std::string filePath = "../img/ThreadedRoundPipe/0530img";string resPath = "/output";//string resPath = filePath + "./output";cv::Point tlP = cv::Point(200, 340);cv::Point brP = cv::Point(950, 999);cv::Point top(90, 90);std::vector<cv::Point> allPntList;cv::Mat canvas;PTank_imgProcess m_ImageProcessing;//ImageProcess m_ImageProcessing;ofstream ofs("log.txt", ios::out);if (ofs){ofs.clear();ofs << "日志启动" << endl;}vector<string> path_name;bool lineOnTop = !true;bool   getROI = true;bool   lianxu = false; //循环测试if (!lianxu){string name = cv::format("\\Image_20240627151014832.png");string path = filePath + name;cv::Mat src = cv::imread(path);src.copyTo(canvas);cv::namedWindow("main_OriginalIMG", cv::RECURS_FILTER);cvSetMouseCallback("main_OriginalIMG", on_mouse_singleClick, 0);cv::imshow("main_OriginalIMG", src);cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);//cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);if (getROI) ROI = getROIFromString(name);bool flag = m_ImageProcessing.arcPlusLine_ROI(src, ROI, top, allPntList, canvas, lineOnTop, true);cout << "\nmain ==== flag " << flag << endl;if (flag) {cout << "top = " << top.x << " " << top.y << endl;}canvas.copyTo(src);//cout << "\nmain ==== i " << endl;circle(canvas, top, 63, cv::Scalar(0, 69, 255), 1);cv::putText(src, to_string(flag), cv::Point(src.cols / 2 - 20, src.rows / 2 - 165), cv::FONT_HERSHEY_COMPLEX, 1.75, cv::Scalar(255, 135, 160), 3);cv::namedWindow("main-结果图src", cv::RECURS_FILTER);cvSetMouseCallback("main-结果图src", on_mouse_singleClick, 0);cv::imshow("main-结果图src", src);}else{vector<string> path_name;getAllFiles(filePath, path_name);cout << "path_name.size()=" << path_name.size() << endl;int number = 1;for (auto i : path_name){if (i.find("_res") != std::string::npos) continue;if (i.find("png") == std::string::npos && i.find("bmp") == std::string::npos && i.find("jpg") == std::string::npos) continue;cv::Mat src = cv::imread(filePath + "\\" + i);cout << endl << "number【" << number << "】src path=" << i << " ;" << endl;src.copyTo(canvas);cv::imshow("main_OriginalIMG", src);//将结果图写入文件方便查看结果int len = filePath.length();//i = i.substr(i.find_last_of('\\') + 1, len);cout << "i=" << i << endl;int time_start = clock();int time_end = clock();cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);//cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);if (getROI) ROI = getROIFromString(i);bool flag = m_ImageProcessing.arcPlusLine_ROI(src, ROI, top, allPntList, canvas, lineOnTop, false);time_end = clock();printf("\n耗时 %d ms \n", time_end - time_start);cout << "\nmain ==== flag " << flag << endl;if (flag) {cout << "top = " << top.x << " " << top.y << endl;}canvas.copyTo(src);cv::putText(src, to_string(flag), cv::Point(src.cols / 2 - 20, src.rows / 2 - 65), cv::FONT_HERSHEY_COMPLEX, 1.75, cv::Scalar(255, 135, 160), 3);cv::imshow("main-结果图src", src);cv::waitKey(10);//将结果图写入文件方便查看结果char*  filePath_ = new char[len + 1];strcpy(filePath_, filePath.c_str());len = filePath.length();char*  resPath_ = new char[len + 1];strcpy(resPath_, resPath.c_str());//i.erase(0, strlen(filePath_) - strlen(resPath_) - 2);string out = filePath + resPath;cout << "\nmain ==== i " << i << endl;out.append("\\").append(i);cout << "number【" << number << "】res path=" << out << endl;cv::imwrite(out, src);number++;cout << "path_name.size() = " << path_name.size() << endl;cout << "*********************************************************************************************************************" << endl;if (number == path_name.size()) break;}}cout << "main 循环结束!!!" << endl;ofs.close();cv::waitKey(0);system("Pause");return 0;
}

双点

返回只有双点 

bool ImageProcessingTest::ThreadedRoundPipe_ROI(cv::Mat img, cv::Rect ROI, cv::Point& top, cv::Point& bottom, cv::Mat & canvas, bool debug)
{int endRes = 0;bool result = false;img.copyTo(canvas);top = cv::Point(0, 0);bottom = cv::Point(0, 0);cv::Mat imgOriginal;bool ROI_flag;//是否有给信息区cv::Point ROI_tl = cv::Point2i(ROI.x, ROI.y);cv::Point ROI_br = cv::Point2i(ROI.x + ROI.width, ROI.y + ROI.height);if (ROI_tl == cv::Point(0, 0) && ROI_br == cv::Point(0, 0) || ROI.width == 0 || ROI.height == 0){img.copyTo(imgOriginal);ROI_flag = false;}else{if (ROI_tl.x > ROI_br.x || ROI_tl.y > ROI_br.y)//信息区两点疑似传反{printf("信息区两点疑似传反!");return false;}if (ROI_tl.x < 0 || ROI_br.x > img.cols || ROI_tl.y < 0 || ROI_br.y > img.rows)//信息区的框选超出图像范围{printf("信息区的框选超出图像范围!");return false;}if (abs(ROI_tl.x - ROI_br.x) > img.cols || abs(ROI_tl.y - ROI_br.y) > img.rows)//信息区大小超出图像大小{printf("信息区大小超出图像大小!");return false;}//此时不合法的ROI都已提前返回falsecv::Rect roi(ROI_tl.x, ROI_tl.y, ROI_br.x - ROI_tl.x, ROI_br.y - ROI_tl.y);imgOriginal = img(roi);	//裁剪出的ROI区域放于imgOriginalROI_flag = true;}result = ThreadedRoundPipe(imgOriginal, top, bottom, canvas, debug);//调用识别算法if (debug) printf("-------------------------------------****------ roiF  top=【%d, %d】, bottom=【%d, %d】\n", top.x, top.y, bottom.x, bottom.y);//img.copyTo(canvas);x值和y值补上ROI左上点x和y//if (ROI_flag) {//	if (Corner != cv::Point(0, 0))//	{//		Corner.x += ROI_tl.x;//		Corner.y += ROI_tl.y;//	}//}img.copyTo(canvas);//调试时注释掉cv::Mat t1;//canvas.convertTo(t1, -1, 900 / 100.0, 200 - 100);//第一次线性变换100canvas.convertTo(t1, -1, 900 / 100.0, 200 - 100);//第一次线性变换100if (debug)cv::imshow("线性变换ROI", t1);t1.copyTo(canvas);if (result){endRes = 1;top += ROI_tl;bottom += ROI_tl;cv::putText(canvas, "true", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);int w = 38;int thickness = 4;cv::Point curPoint = top;cv::line(canvas, curPoint, cv::Point(curPoint.x - w, curPoint.y), cv::Scalar(235, 135, 40), thickness);curPoint = bottom;cv::line(canvas, curPoint, cv::Point(curPoint.x - w, curPoint.y), cv::Scalar(235, 135, 40), thickness);circle(canvas, top, 2, cv::Scalar(0, 69, 255), -1);circle(canvas, top, 63, cv::Scalar(0, 169, 255), 1);circle(canvas, bottom, 2, cv::Scalar(0, 69, 255), -1);circle(canvas, bottom, 43, cv::Scalar(255, 169, 0), 1);}else{cv::putText(canvas, "false", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);}cv::Mat ROIcanvas;img.copyTo(ROIcanvas);if (debug) circle(ROIcanvas, top, 3, cv::Scalar(0, 69, 255), 1);if (debug) circle(ROIcanvas, top, 63, cv::Scalar(0, 169, 255), 1);if (debug) circle(ROIcanvas, bottom, 3, cv::Scalar(0, 69, 255), 1);if (debug) circle(ROIcanvas, bottom, 63, cv::Scalar(0, 169, 255), 1);if (debug) rectangle(ROIcanvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);rectangle(canvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);if (debug) printf("-------------------------------------****------ roiF  top=【%d, %d】, bottom=【%d, %d】\n", top.x, top.y, bottom.x, bottom.y);if (debug) imshow("ROI", ROIcanvas);if (debug) imshow("ROI_canvas", canvas);//ROIcanvas.copyTo(canvas);//cv::Rect roi_(ROI_tl.x, ROI_tl.y, ROI_br.x - ROI_tl.x, ROI_br.y - ROI_tl.y);//if(!ROI_flag) canvas.copyTo(canvas);//else canvas = canvas(roi_);	//裁剪出的ROI区域return result;
}

调用main:

//螺纹圆管:ThreadedRoundPipe_ROI
int main222() {bool flag = false;//std::string filePath = "E:\\vsproject\\勋仪交接\\标克艾芬达暖水管/0529img";//std::string filePath = "../img/ThreadedRoundPipe/0530img";std::string filePath = "../img/ThreadedRoundPipe/0606img";string resPath = "/output";//string resPath = filePath + "./output";cv::Point tlP = cv::Point(200, 340);cv::Point brP = cv::Point(950, 999);cv::Point top(90, 90);cv::Point bottom(90, 90);cv::Mat canvas;ImageProcessingTest m_ImageProcessing;ofstream ofs("log.txt", ios::out);if (ofs){ofs.clear();ofs << "日志启动" << endl;}vector<string> path_name;bool   lianxu = false; //循环测试if (!lianxu){//string path = filePath + cv::format("\\Image_20230606135229441.png");string path = filePath + cv::format("\\Image_20230606135308519.png");//string path = filePath + cv::format("\\Image_20230601143638388.png");//string path = filePath + cv::format("\\Image_20230601143505168.png");//string path = filePath + cv::format("\\Image_20230529095011455.png");cv::Mat src = cv::imread(path);src.copyTo(canvas);cv::namedWindow("main_OriginalIMG", cv::RECURS_FILTER);cvSetMouseCallback("main_OriginalIMG", on_mouse_singleClick, 0);cv::imshow("main_OriginalIMG", src);//cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);bool flag = m_ImageProcessing.ThreadedRoundPipe_ROI(src, ROI, top, bottom, canvas, true);cout << "\nmain ==== flag " << flag << endl;if (flag) {cout << "top = " << top.x << " " << top.y << endl;cout << "bottom = " << bottom.x << " " << bottom.y << endl;}canvas.copyTo(src);//cout << "\nmain ==== i " << endl;circle(canvas, top, 63, cv::Scalar(0, 69, 255), 1);circle(canvas, bottom, 63, cv::Scalar(0, 69, 255), 1);cv::putText(src, to_string(flag), cv::Point(src.cols / 2 - 20, src.rows / 2 - 65), cv::FONT_HERSHEY_COMPLEX, 1.75, cv::Scalar(255, 135, 160), 3);cv::namedWindow("main-结果图src", cv::RECURS_FILTER);cvSetMouseCallback("main-结果图src", on_mouse_singleClick, 0);cv::imshow("main-结果图src", src);}else{vector<string> path_name;getAllFiles(filePath, path_name);cout << "path_name.size()=" << path_name.size() << endl;int number = 1;for (auto i : path_name){cv::Mat src = cv::imread(filePath + "\\" + i);cout << endl << "number【" << number << "】src path=" << i << " ;" << endl;src.copyTo(canvas);cv::imshow("main_OriginalIMG", src);//将结果图写入文件方便查看结果int len = filePath.length();//i = i.substr(i.find_last_of('\\') + 1, len);cout << "i=" << i << endl;int time_start = clock();int time_end = clock();//cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);bool flag = m_ImageProcessing.ThreadedRoundPipe_ROI(src, ROI, top, bottom, canvas, false);time_end = clock();printf("\n耗时 %d ms \n", time_end - time_start);cout << "\nmain ==== flag " << flag << endl;if (flag) {cout << "top = " << top.x << " " << top.y << endl;cout << "bottom = " << bottom.x << " " << bottom.y << endl;}canvas.copyTo(src);cv::putText(src, to_string(flag), cv::Point(src.cols / 2 - 20, src.rows / 2 - 65), cv::FONT_HERSHEY_COMPLEX, 1.75, cv::Scalar(255, 135, 160), 3);cv::imshow("main-结果图src", src);cv::waitKey(10);//将结果图写入文件方便查看结果char*  filePath_ = new char[len + 1];strcpy(filePath_, filePath.c_str());len = filePath.length();char*  resPath_ = new char[len + 1];strcpy(resPath_, resPath.c_str());//i.erase(0, strlen(filePath_) - strlen(resPath_) - 2);string out = filePath + resPath;cout << "\nmain ==== i " << i << endl;out.append("\\").append(i);cout << "number【" << number << "】res path=" << out << endl;cv::imwrite(out, src);number++;cout << "path_name.size() = " << path_name.size() << endl;cout << "*********************************************************************************************************************" << endl;if (number == path_name.size()) break;}}cout << "main 循环结束!!!" << endl;ofs.close();cv::waitKey(0);system("Pause");return 0;
}

返回双点+1个点集

	/*//矩形位置  返回双点+骨干点集cv::Mat img, 原图cv::Rect ROI, cv::Point& top, 输出焊点(图像上位于较上方的点)cv::Point& bottom, 输出焊点(图像上位于较下方的点)std::vector<cv::Point>& allPntList:直线部分非弧线的点集cv::Mat &canvas,效果图可视化*/bool rectangle2Pnt(cv::Mat imgOriginal, cv::Point& top, cv::Point& bottom, std::vector<cv::Point>& allPntList, cv::Mat &canvas, bool debug = false);bool rectangle2Pnt_ROI(cv::Mat img, cv::Rect ROI, cv::Point& top, cv::Point& bottom, std::vector<cv::Point>& allPntList, cv::Mat &canvas, bool debug = false);
bool PTank_imgProcess::rectangle2Pnt_ROI(cv::Mat img, cv::Rect ROI, cv::Point & top, cv::Point & bottom, std::vector<cv::Point>& allPntList, cv::Mat & canvas, bool debug)
{int endRes = 0;bool result = false;img.copyTo(canvas);top = cv::Point(0, 0);bottom = cv::Point(0, 0);allPntList.clear();cv::Mat imgOriginal;bool ROI_flag;//是否有给信息区cv::Point ROI_tl = cv::Point2i(ROI.x, ROI.y);cv::Point ROI_br = cv::Point2i(ROI.x + ROI.width, ROI.y + ROI.height);if (ROI_tl == cv::Point(0, 0) && ROI_br == cv::Point(0, 0) || ROI.width == 0 || ROI.height == 0){img.copyTo(imgOriginal);ROI_flag = false;}else{if (ROI_tl.x > ROI_br.x || ROI_tl.y > ROI_br.y)//信息区两点疑似传反{printf("信息区两点疑似传反!");return false;}if (ROI_tl.x < 0 || ROI_br.x > img.cols || ROI_tl.y < 0 || ROI_br.y > img.rows)//信息区的框选超出图像范围{printf("信息区的框选超出图像范围!");return false;}if (abs(ROI_tl.x - ROI_br.x) > img.cols || abs(ROI_tl.y - ROI_br.y) > img.rows)//信息区大小超出图像大小{printf("信息区大小超出图像大小!");return false;}//此时不合法的ROI都已提前返回falsecv::Rect roi(ROI_tl.x, ROI_tl.y, ROI_br.x - ROI_tl.x, ROI_br.y - ROI_tl.y);imgOriginal = img(roi);	//裁剪出的ROI区域放于imgOriginalROI_flag = true;}result = rectangle2Pnt(imgOriginal, top, bottom, allPntList, canvas, debug);//调用识别算法if (debug) printf("-------------------------------------****------ roiF  top=【%d, %d】, bottom=【%d, %d】\n", top.x, top.y, bottom.x, bottom.y);//img.copyTo(canvas);img.copyTo(canvas);//调试时注释掉if (result){endRes = 1;top += ROI_tl;bottom += ROI_tl;for (int i = 0; i < allPntList.size(); i++) {allPntList.at(i) += ROI_tl;}int w = 5;for (int i = 0; i < allPntList.size(); i++) {cv::Point curPoint = allPntList.at(i);cv::line(canvas, curPoint, cv::Point(curPoint.x - w, curPoint.y), cv::Scalar(55, 195, 40), 1);}cv::putText(canvas, "true", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);circle(canvas, top, 3, cv::Scalar(0, 69, 255), 1);circle(canvas, top, 63, cv::Scalar(0, 169, 255), 1);circle(canvas, bottom, 3, cv::Scalar(0, 69, 255), 1);circle(canvas, bottom, 43, cv::Scalar(255, 169, 0), 1);}else{cv::putText(canvas, "false", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);}cv::Mat ROIcanvas;img.copyTo(ROIcanvas);if (debug) circle(ROIcanvas, top, 3, cv::Scalar(0, 69, 255), 1);if (debug) circle(ROIcanvas, top, 63, cv::Scalar(0, 169, 255), 1);if (debug) circle(ROIcanvas, bottom, 3, cv::Scalar(0, 69, 255), 1);if (debug) circle(ROIcanvas, bottom, 63, cv::Scalar(0, 169, 255), 1);if (debug) rectangle(ROIcanvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);rectangle(canvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);if (debug) printf("-------------------------------------****------ roiF  top=【%d, %d】, bottom=【%d, %d】\n", top.x, top.y, bottom.x, bottom.y);if (debug) imshow("ROI", ROIcanvas);if (debug) imshow("ROI_canvas", canvas);//ROIcanvas.copyTo(canvas);return result;
}

调用main:

//矩形位置  返回双点+骨干点集
int main/*Rectangle2Pnt_ROI*/() {bool flag;//std::string filePath = "../../../../Log08141641/TestImg/src";std::string filePath = "E://vsproject//压力罐\\img\\矩形";string resPath = "/output";//string resPath = filePath + "./output";cv::Point tlP = cv::Point(500, 292);cv::Point brP = cv::Point(750, 677);//cv::Rect ROI = cv::Rect(0, 0, 0, 0);//cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);//cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);//cv::Rect ROI = cv::Rect(539, 218, 113, 513);cv::Point top(90, 90);cv::Point bottom(90, 90);int outMidY;cv::Mat canvas;PTank_imgProcess m_ImageProcessing;ofstream ofs("log.txt", ios::out);if (ofs){ofs.clear();ofs << "日志启动" << endl;}std::vector<cv::Point> allPntList;vector<string> path_name;bool   getROI = true;bool   lianxu = false; //循环测试if (!lianxu){string name = cv::format("\\Image_20240627144421072.png");string path = filePath + name;cv::Mat src = cv::imread(path);src.copyTo(canvas);cv::namedWindow("main_OriginalIMG", cv::RECURS_FILTER);cvSetMouseCallback("main_OriginalIMG", on_mouse_singleClick, 0);cv::imshow("main_OriginalIMG", src);cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);//cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);if (getROI) ROI = getROIFromString(name);bool flag = m_ImageProcessing.rectangle2Pnt_ROI(src, ROI, top, bottom, allPntList, canvas, true);cout << "\nmain ==== flag " << flag << endl;if (flag) {cout << "top = " << top.x << " " << top.y << endl;cout << "bottom = " << bottom.x << " " << bottom.y << endl;}canvas.copyTo(src);//cout << "\nmain ==== i " << endl;circle(canvas, top, 63, cv::Scalar(0, 69, 255), 1);circle(canvas, bottom, 63, cv::Scalar(0, 69, 255), 1);cv::putText(src, to_string(flag), cv::Point(src.cols / 2 - 20, src.rows / 2 - 65), cv::FONT_HERSHEY_COMPLEX, 1.75, cv::Scalar(255, 135, 160), 3);cv::namedWindow("main-结果图src", cv::RECURS_FILTER);cvSetMouseCallback("main-结果图src", on_mouse_singleClick, 0);cv::imshow("main-结果图src", src);cv::namedWindow("main-canvas", cv::RECURS_FILTER);cvSetMouseCallback("main-canvas", on_mouse_singleClick, 0);cv::imshow("main-canvas", canvas);}else{vector<string> path_name;getAllFiles(filePath, path_name);cout << "path_name.size()=" << path_name.size() << endl;int number = 1;for (auto i : path_name){//cout << i.size() << endl;if (i.size() == 7) continue;if (i.find(".log") != std::string::npos) continue;std::string path11 = filePath + "\\" + i;cv::Mat src = cv::imread(path11);//cv::Mat src = cv::imread(filePath + "\\" + i);cout << endl << "number【" << number << "】src path=" << i << " ;" << endl;src.copyTo(canvas);cv::imshow("main_OriginalIMG", src);//将结果图写入文件方便查看结果int len = filePath.length();//i = i.substr(i.find_last_of('\\') + 1, len);cout << "i=" << i << ", path11=" << path11 << endl;int time_start = clock();int time_end = clock();cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);//cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);if (getROI) ROI = getROIFromString(i);bool flag = m_ImageProcessing.rectangle2Pnt_ROI(src, ROI, top, bottom, allPntList, canvas, false);time_end = clock();printf("\n耗时 %d ms \n", time_end - time_start);cout << "\nmain ==== flag " << flag << endl;if (flag) {cout << "top = " << top.x << " " << top.y << endl;cout << "bottom = " << bottom.x << " " << bottom.y << endl;}canvas.copyTo(src);cv::putText(src, to_string(flag), cv::Point(src.cols / 2 - 20, src.rows / 2 - 65), cv::FONT_HERSHEY_COMPLEX, 1.75, cv::Scalar(255, 135, 160), 3);cv::imshow("main-结果图src", src);cv::imshow("main-canvas", canvas);//将结果图写入文件方便查看结果char*  filePath_ = new char[len + 1];strcpy(filePath_, filePath.c_str());len = filePath.length();char*  resPath_ = new char[len + 1];strcpy(resPath_, resPath.c_str());//i.erase(0, strlen(filePath_) - strlen(resPath_) - 2);string out = filePath + resPath;cout << "\nmain ==== i " << i << endl;out.append("\\").append(i);cout << "number【" << number << "】res path=" << out << endl;cv::imwrite(out, src);number++;cout << "path_name.size() = " << path_name.size() << endl;cout << "*********************************************************************************************************************" << endl;cv::waitKey(10);}cout << "循环结束!!! main " << endl;}ofs.close();cv::waitKey(0);system("Pause");return 0;
}

返回双点+三点集+左右/上下翻转再进入识别

注:该接口中 bottom, linearPntB无效!!!

根据传入参数判断是否左右翻转,判断识别的是上半部分还是下半部分,下半部分则需再做上下翻转再进入识别。

	/*//D型主管,方形支管 只处理上半部分或下半部分cv::Mat img, 原图cv::Rect ROI, 可以让右边的干扰直反光落进去,上下不用截,左右可适当截小一下减少识别时的计算时间std::vector<cv::Point>& linearPnt:直线部分非弧线的点集cv::Point& top, 输出焊点(图像上位于较上方的点)倒角弧形边边上的激光最边边点cv::Point& bottom, 输出焊点(图像上位于较下方的点)倒角弧形边边上的激光最边边点cv::Mat &canvas,效果图可视化bool arcTop_right = true;//圆弧顶点是否朝右的标志量,默认为true(true为朝右,false为朝左)bool isTopHalf = true;//识别区域是否为上半部分,上半部分为true,下半部分反之注:该接口中 bottom, linearPntB无效!!!*/bool OneSideSquare(cv::Mat imgOriginal, std::vector<cv::Point>& linearPntT, std::vector<cv::Point>& linearPntB, std::vector<cv::Point>& linearPntM, cv::Point& top, cv::Point& bottom, cv::Mat &canvas, bool debug = false);bool OneSideSquare_ROI(cv::Mat img, cv::Rect ROI, std::vector<cv::Point>& linearPntT, std::vector<cv::Point>& linearPntB, std::vector<cv::Point>& linearPntM, cv::Point& top, cv::Point& bottom, cv::Mat &canvas, bool arcTop_right = true, bool isTopHalf = true, bool debug = false);
bool ImageProcessing::OneSideSquare_ROI(cv::Mat img, cv::Rect ROI, std::vector<cv::Point>& linearPntT, std::vector<cv::Point>& linearPntB, std::vector<cv::Point>& linearPntM, cv::Point & top, cv::Point & bottom, cv::Mat & canvas, bool arcTop_right, bool isTopHalf, bool debug)
{int endRes = 0;bool result = false;img.copyTo(canvas);top = cv::Point(0, 0);bottom = cv::Point(0, 0);linearPntT.clear();linearPntB.clear();linearPntM.clear();cv::Mat imgOriginal;bool ROI_flag;//是否有给信息区cv::Point ROI_tl = cv::Point2i(ROI.x, ROI.y);cv::Point ROI_br = cv::Point2i(ROI.x + ROI.width, ROI.y + ROI.height);if (ROI_tl == cv::Point(0, 0) && ROI_br == cv::Point(0, 0) || ROI.width == 0 || ROI.height == 0){img.copyTo(imgOriginal);ROI_flag = false;}else{if (ROI_tl.x > ROI_br.x || ROI_tl.y > ROI_br.y)//信息区两点疑似传反{printf("信息区两点疑似传反!");return false;}if (ROI_tl.x < 0 || ROI_br.x > img.cols || ROI_tl.y < 0 || ROI_br.y > img.rows)//信息区的框选超出图像范围{printf("信息区的框选超出图像范围!");return false;}if (abs(ROI_tl.x - ROI_br.x) > img.cols || abs(ROI_tl.y - ROI_br.y) > img.rows)//信息区大小超出图像大小{printf("信息区大小超出图像大小!");return false;}//此时不合法的ROI都已提前返回falsecv::Rect roi(ROI_tl.x, ROI_tl.y, ROI_br.x - ROI_tl.x, ROI_br.y - ROI_tl.y);imgOriginal = img(roi);	//裁剪出的ROI区域放于imgOriginalROI_flag = true;}if (arcTop_right) {//圆弧顶点朝右的情况if (isTopHalf) {result = OneSideSquare(imgOriginal, linearPntT, linearPntB, linearPntM, top, bottom, canvas, debug);//调用识别算法}else {cv::Mat fpMt;cv::flip(imgOriginal, fpMt, 0);		// 上下翻转 x对称result = OneSideSquare(fpMt, linearPntT, linearPntB, linearPntM, top, bottom, canvas, debug);//调用识别算法if (result) {top.y = fpMt.rows - top.y - 1;for (int i = 0; i < linearPntT.size(); i++) {linearPntT.at(i).y = fpMt.rows - linearPntT.at(i).y - 1;}for (int i = 0; i < linearPntM.size(); i++) {linearPntM.at(i).y = fpMt.rows - linearPntM.at(i).y - 1;}}}}else {//圆弧顶点朝左的情况cv::Mat flipMat;cv::flip(imgOriginal, flipMat, 1);			// 左右翻转 y对称if (debug) imshow("图像左右翻转", flipMat);if (isTopHalf) {result = OneSideSquare(flipMat, linearPntT, linearPntB, linearPntM, top, bottom, canvas, debug);//调用识别算法}else {cv::Mat fpMt;cv::flip(flipMat, fpMt, 0);		// 上下翻转 x对称result = OneSideSquare(fpMt, linearPntT, linearPntB, linearPntM, top, bottom, canvas, debug);//调用识别算法if (result) {top.y = fpMt.rows - top.y - 1;for (int i = 0; i < linearPntT.size(); i++) {linearPntT.at(i).y = fpMt.rows - linearPntT.at(i).y - 1;}for (int i = 0; i < linearPntM.size(); i++) {linearPntM.at(i).y = fpMt.rows - linearPntM.at(i).y - 1;}}}if (result) {top.x = flipMat.cols - top.x - 1;//bottom.x = flipMat.cols - bottom.x - 1;for (int i = 0; i < linearPntT.size(); i++) {linearPntT.at(i).x = flipMat.cols - linearPntT.at(i).x - 1;}for (int i = 0; i < linearPntB.size(); i++) {linearPntB.at(i).x = flipMat.cols - linearPntB.at(i).x - 1;}for (int i = 0; i < linearPntM.size(); i++) {linearPntM.at(i).x = flipMat.cols - linearPntM.at(i).x - 1;}}}if (debug) printf("-------------------------------------****------ roiF  top=【%d, %d】, bottom=【%d, %d】\n", top.x, top.y, bottom.x, bottom.y);//img.copyTo(canvas);x值和y值补上ROI左上点x和y//if (ROI_flag) {//	if (Corner != cv::Point(0, 0))//	{//		Corner.x += ROI_tl.x;//		Corner.y += ROI_tl.y;//	}//}img.copyTo(canvas);//调试时注释掉if (result){endRes = 1;top += ROI_tl;//bottom += ROI_tl;for (int i = 0; i < linearPntT.size(); i++) {linearPntT.at(i) += ROI_tl;}for (int i = 0; i < linearPntB.size(); i++) {linearPntB.at(i) += ROI_tl;}for (int i = 0; i < linearPntM.size(); i++) {linearPntM.at(i) += ROI_tl;}for (int i = 0; i < linearPntT.size(); i++) {cv::Point curPoint = linearPntT.at(i);cv::line(canvas, curPoint, cv::Point(curPoint.x - 5, curPoint.y), cv::Scalar(55, 195, 40), 1);}for (int i = 0; i < linearPntB.size(); i++) {cv::Point curPoint = linearPntB.at(i);cv::line(canvas, curPoint, cv::Point(curPoint.x - 5, curPoint.y), cv::Scalar(55, 195, 40), 1);}for (int i = 0; i < linearPntM.size(); i++) {cv::Point curPoint = linearPntM.at(i);cv::line(canvas, curPoint, cv::Point(curPoint.x - 5, curPoint.y), cv::Scalar(145, 175, 40), 1);}cv::putText(canvas, "true", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);circle(canvas, top, 3, cv::Scalar(0, 69, 255), 1);circle(canvas, top, 63, cv::Scalar(0, 169, 255), 1);//circle(canvas, bottom, 3, cv::Scalar(0, 69, 255), 1);//circle(canvas, bottom, 43, cv::Scalar(255, 169, 0), 1);}else{cv::putText(canvas, "false", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);}cv::Mat ROIcanvas;img.copyTo(ROIcanvas);if (debug) circle(ROIcanvas, top, 3, cv::Scalar(0, 69, 255), 1);if (debug) circle(ROIcanvas, top, 63, cv::Scalar(0, 169, 255), 1);//if (debug) circle(ROIcanvas, bottom, 3, cv::Scalar(0, 69, 255), 1);//if (debug) circle(ROIcanvas, bottom, 63, cv::Scalar(0, 169, 255), 1);if (debug) rectangle(ROIcanvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);rectangle(canvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);if (debug) printf("-------------------------------------****------ roiF  top=【%d, %d】, bottom=【%d, %d】\n", top.x, top.y, bottom.x, bottom.y);if (debug) imshow("ROI", ROIcanvas);if (debug) imshow("ROI_canvas", canvas);//ROIcanvas.copyTo(canvas);return result;
}

调用main:

//D型主管,方形支管 上或下单侧  OneSideSquare_ROI
int main() {bool flag;//std::string filePath = "../../../../0方管支管/1023img";std::string filePath = "../../../../0方管支管/left";//std::string filePath = "../../../../0方管支管/right";string resPath = "/output";//string resPath = filePath + "./output";//cv::Point tlP = cv::Point(500, 40);//cv::Point brP = cv::Point(750, 777);cv::Point tlP = cv::Point(584, 236);cv::Point brP = cv::Point(660, 820);//cv::Rect ROI = cv::Rect(0, 0, 0, 0);//cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);//cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);//cv::Rect ROI = cv::Rect(639, 188, 125, 569);cv::Point top(90, 90);cv::Point bottom(90, 90);cv::Point2f midP(90, 90);int outMidY;cv::Mat canvas;ImageProcessing m_ImageProcessing;ofstream ofs("log.txt", ios::out);if (ofs){ofs.clear();ofs << "日志启动" << endl;}std::vector<cv::Point> linearPntT;std::vector<cv::Point> linearPntB;std::vector<cv::Point> linearPntM;vector<Picture_set> img_buf;vector<string> path_name;bool arcTop_right = !true;bool isTopHalf = true;int midyTolerant = 4;bool   getROI = true;bool   lianxu = false; //循环测试if (lianxu){//string path = filePath + cv::format("\\Image_20231023105829348.png");//std::string name = cv::format("\\ImgD_2023_10_26_10_48_12_135_567_196_153_603_Src.png");std::string name = cv::format("\\ImgD_2023_10_25_18_16_24_519_569_200_166_559_Src.png");string path = filePath + name;cv::Mat src = cv::imread(path);src.copyTo(canvas);cv::namedWindow("main_OriginalIMG", cv::NORMCONV_FILTER);cvSetMouseCallback("main_OriginalIMG", on_mouse_singleClick, 0);cv::imshow("main_OriginalIMG", src);//cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);if (getROI) {ROI = getROIFromString(name);ROI.height /= 2;if (!isTopHalf) {ROI.y += ROI.height;}}//鼠标点击的坐标【691, 319】//	鼠标点击的坐标【692, 632】//cout << src.size() << endl;//rotateImage(src);//cout << src.size() << endl;//鼠标点击的坐标【707, 691】//	鼠标点击的坐标【395, 691】//trueX=outY;//trueY=oriSrc.rows-outX;//circle(src, cv::Point(622, 424), 5, cv::Scalar(255, 255, 255), -1);//cv::Mat flipMat;//cv::flip(src, flipMat, 1);//cv::Point q = cv::Point(flipMat.cols - 622 - 1, 424)/* - cv::Point(546, 228)*/;//circle(flipMat, q, 3, cv::Scalar(0, 0, 0), -1);//cv::imshow("flipMat", flipMat);//cv::waitKey();//cv::flip(src, src, 0);bool flag = m_ImageProcessing.OneSideSquare_ROI(src, ROI, linearPntT, linearPntB, linearPntM, top, bottom, canvas, arcTop_right, isTopHalf, true);cout << "\nmain ==== flag " << flag << endl;if (flag) {cout << "top = " << top.x << " " << top.y << endl;cout << "bottom = " << bottom.x << " " << bottom.y << endl;}canvas.copyTo(src);//cout << "\nmain ==== i " << endl;circle(canvas, top, 63, cv::Scalar(0, 69, 255), 1);circle(canvas, bottom, 63, cv::Scalar(0, 69, 255), 1);cv::putText(src, to_string(flag), cv::Point(src.cols / 2 - 20, src.rows / 2 - 65), cv::FONT_HERSHEY_COMPLEX, 1.75, cv::Scalar(255, 135, 160), 3);cv::namedWindow("main-结果图src", cv::RECURS_FILTER);cvSetMouseCallback("main-结果图src", on_mouse_singleClick, 0);cv::imshow("main-结果图src", src);cv::namedWindow("main-canvas", cv::RECURS_FILTER);cvSetMouseCallback("main-canvas", on_mouse_singleClick, 0);cv::imshow("main-canvas", canvas);}else{vector<string> path_name;getAllFiles(filePath, path_name);cout << "path_name.size()=" << path_name.size() << endl;int number = 1;for (auto i : path_name){//cout << i.size() << endl;if (i.size() == 7) continue;if (i.find(".log") != std::string::npos) continue;if (i.find(".txt") != std::string::npos) continue;std::string name = i;std::string path11 = filePath + "\\" + i;cv::Mat src = cv::imread(path11);//cv::Mat src = cv::imread(filePath + "\\" + i);cout << endl << "number【" << number << "】src path=" << i << " ;" << endl;src.copyTo(canvas);cv::imshow("main_OriginalIMG", src);//将结果图写入文件方便查看结果int len = filePath.length();//i = i.substr(i.find_last_of('\\') + 1, len);cout << "i=" << i << ", path11=" << path11 << endl;int time_start = clock();int time_end = clock();cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);if (getROI) {ROI = getROIFromString(name);ROI.height /= 2;if (!isTopHalf) {ROI.y += ROI.height;}}bool flag = m_ImageProcessing.OneSideSquare_ROI(src, ROI, linearPntT, linearPntB, linearPntM, top, bottom, canvas, arcTop_right, isTopHalf, false);time_end = clock();printf("\n耗时 %d ms \n", time_end - time_start);cout << "\nmain ==== flag " << flag << endl;if (flag) {cout << "top = " << top.x << " " << top.y << endl;cout << "bottom = " << bottom.x << " " << bottom.y << endl;}canvas.copyTo(src);cv::putText(src, to_string(flag), cv::Point(src.cols / 2 - 20, src.rows / 2 - 65), cv::FONT_HERSHEY_COMPLEX, 1.75, cv::Scalar(255, 135, 160), 3);cv::imshow("main-结果图src", src);cv::imshow("main-canvas", canvas);//将结果图写入文件方便查看结果char*  filePath_ = new char[len + 1];strcpy(filePath_, filePath.c_str());len = filePath.length();char*  resPath_ = new char[len + 1];strcpy(resPath_, resPath.c_str());//i.erase(0, strlen(filePath_) - strlen(resPath_) - 2);string out = filePath + resPath;cout << "\nmain ==== i " << i << endl;out.append("\\").append(i);cout << "number【" << number << "】res path=" << out << endl;cv::imwrite(out, src);number++;cout << "path_name.size() = " << path_name.size() << endl;cout << "*********************************************************************************************************************" << endl;cv::waitKey(10);}cout << "循环结束!!! main " << endl;}ofs.close();cv::waitKey(0);system("Pause");return 0;
}

三点

返回三点+1个点集  

	/*//两弧线夹圆弧  返回三点+骨干点集cv::Mat img, 原图cv::Rect ROI,cv::Point& top, 输出焊点(图像上位于较上方的点)cv::Point& bottom, 输出焊点(图像上位于较下方的点)cv::Point2f& midP, 圆弧中点std::vector<cv::Point>& allPntList:直线部分非弧线的点集cv::Mat &canvas,效果图可视化*/bool twoArcsClipTheArc(cv::Mat imgOriginal, cv::Point& top, cv::Point& bottom, cv::Point2f& midP, std::vector<cv::Point>& allPntList, cv::Mat &canvas, bool debug = false);bool twoArcsClipTheArc_ROI(cv::Mat img, cv::Rect ROI, cv::Point& top, cv::Point& bottom, cv::Point2f& midP, std::vector<cv::Point>& allPntList, cv::Mat &canvas, bool arcTop_right = true, bool debug = false);
bool PTank_imgProcess::twoArcsClipTheArc_ROI(cv::Mat img, cv::Rect ROI, cv::Point & top, cv::Point & bottom, cv::Point2f & midP, std::vector<cv::Point>& allPntList, cv::Mat & canvas, bool arcTop_right, bool debug)
{int endRes = 0;bool result = false;img.copyTo(canvas);top = cv::Point(0, 0);bottom = cv::Point(0, 0);midP = cv::Point2f(0, 0);allPntList.clear();cv::Mat imgOriginal;bool ROI_flag;//是否有给信息区cv::Point ROI_tl = cv::Point2i(ROI.x, ROI.y);cv::Point ROI_br = cv::Point2i(ROI.x + ROI.width, ROI.y + ROI.height);if (ROI_tl == cv::Point(0, 0) && ROI_br == cv::Point(0, 0) || ROI.width == 0 || ROI.height == 0){img.copyTo(imgOriginal);ROI_flag = false;}else{if (ROI_tl.x > ROI_br.x || ROI_tl.y > ROI_br.y)//信息区两点疑似传反{printf("信息区两点疑似传反!");return false;}if (ROI_tl.x < 0 || ROI_br.x > img.cols || ROI_tl.y < 0 || ROI_br.y > img.rows)//信息区的框选超出图像范围{printf("信息区的框选超出图像范围!");return false;}if (abs(ROI_tl.x - ROI_br.x) > img.cols || abs(ROI_tl.y - ROI_br.y) > img.rows)//信息区大小超出图像大小{printf("信息区大小超出图像大小!");return false;}//此时不合法的ROI都已提前返回falsecv::Rect roi(ROI_tl.x, ROI_tl.y, ROI_br.x - ROI_tl.x, ROI_br.y - ROI_tl.y);imgOriginal = img(roi);	//裁剪出的ROI区域放于imgOriginalROI_flag = true;}if (arcTop_right) {//圆弧顶点朝右的情况result = twoArcsClipTheArc(imgOriginal, top, bottom, midP, allPntList, canvas, debug);//调用识别算法}else {//圆弧顶点朝左的情况cv::Mat flipMat;cv::flip(imgOriginal, flipMat, 1);			// 左右翻转 y对称if (debug) imshow("图像左右翻转", flipMat);result = twoArcsClipTheArc(flipMat, top, bottom, midP, allPntList, canvas, debug);//调用识别算法if (result) {top.x = flipMat.cols - top.x - 1;bottom.x = flipMat.cols - bottom.x - 1;for (int i = 0; i < allPntList.size(); i++) {allPntList.at(i).x = flipMat.cols - allPntList.at(i).x - 1;}if (midP != cv::Point2f(0, 0)) midP.x = flipMat.cols - midP.x - 1;}}if (debug) printf("-------------------------------------****------ roiF  top=【%d, %d】, bottom=【%d, %d】\n", top.x, top.y, bottom.x, bottom.y);if (debug) printf("                                                roiF  midP=【%f, %f】\n", midP.x, midP.y);//img.copyTo(canvas);//img.copyTo(canvas);//调试时注释掉if (result){endRes = 1;for (int i = 0; i < allPntList.size(); i++) {allPntList.at(i) += ROI_tl;}for (int i = 0; i < allPntList.size(); i++) {cv::Point curPoint = allPntList.at(i);cv::line(canvas, curPoint, cv::Point(curPoint.x - 5, curPoint.y), cv::Scalar(55, 195, 40), 1);}top += ROI_tl;bottom += ROI_tl;midP += cv::Point2f(ROI_tl);//if (midP != cv::Point2f(0, 0)) {//	midP.x = midP.x + ROI_tl.x;//	midP.y = midP.y + ROI_tl.y;//}circle(canvas, midP, 3, cv::Scalar(0, 69, 255), 1);circle(canvas, midP, 43, cv::Scalar(0, 169, 255), 1);cv::line(canvas, midP, cv::Point2f(5, midP.y), cv::Scalar(155, 195, 40), 1);cv::line(canvas, cv::Point2f(midP.x, midP.y - 5), cv::Point2f(midP.x, midP.y + 5), cv::Scalar(155, 195, 40), 1);cv::putText(canvas, "true", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);circle(canvas, top, 3, cv::Scalar(0, 69, 255), 1);circle(canvas, top, 63, cv::Scalar(0, 169, 255), 1);circle(canvas, bottom, 3, cv::Scalar(0, 69, 255), 1);circle(canvas, bottom, 43, cv::Scalar(255, 169, 0), 1);}else{cv::putText(canvas, "false", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);}cv::Mat ROIcanvas;img.copyTo(ROIcanvas);if (debug) circle(ROIcanvas, top, 3, cv::Scalar(0, 69, 255), 1);if (debug) circle(ROIcanvas, top, 63, cv::Scalar(0, 169, 255), 1);if (debug) circle(ROIcanvas, bottom, 3, cv::Scalar(0, 69, 255), 1);if (debug) circle(ROIcanvas, bottom, 63, cv::Scalar(0, 169, 255), 1);if (debug) rectangle(ROIcanvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);rectangle(canvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);if (debug) printf("-------------------------------------****------ roiF  top=【%d, %d】, bottom=【%d, %d】\n", top.x, top.y, bottom.x, bottom.y);if (debug) printf("                                                roiF  midP=【%f, %f】\n", midP.x, midP.y);if (debug) imshow("ROI", ROIcanvas);if (debug) imshow("ROI_canvas", canvas);//ROIcanvas.copyTo(canvas);return result;
}

 调用main:

//两弧线夹圆弧  返回三点+骨干点集
int main/*TwoArcsClipTheArc*/() {bool flag;std::string filePath = "../../img/圆弧夹圆弧";string resPath = "/output";//string resPath = filePath + "./output";cv::Point tlP = cv::Point(500, 292);cv::Point brP = cv::Point(750, 677);//cv::Rect ROI = cv::Rect(0, 0, 0, 0);//cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);//cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);//cv::Rect ROI = cv::Rect(539, 218, 113, 513);cv::Rect ROI = cv::Rect(546, 228, 101, 520);cv::Point top(90, 90);cv::Point bottom(90, 90);cv::Point2f midP(90, 90);int outMidY;cv::Mat canvas;PTank_imgProcess m_ImageProcessing;ofstream ofs("log.txt", ios::out);if (ofs){ofs.clear();ofs << "日志启动" << endl;}std::vector<cv::Point> allPntList;vector<string> path_name;bool arcTop_right = true;bool   getROI = true;bool   lianxu = false; //循环测试if (!lianxu){string name = cv::format("\\Image_20240702114054217.png");//string name = cv::format("\\Image_20240702170558613.png");//斜//string name = cv::format("\\Image_20240702170644641.png");//斜string path = filePath + name;//string path = filePath + cv::format("\\ImgD_2023_08_17_15_06_45_412_639_188_125_569_Src.png");cv::Mat src = cv::imread(path);src.copyTo(canvas);cv::namedWindow("main_OriginalIMG", cv::NORMCONV_FILTER);cvSetMouseCallback("main_OriginalIMG", on_mouse_singleClick, 0);cv::imshow("main_OriginalIMG", src);//cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);//cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);if (getROI) ROI = getROIFromString(name);bool flag = m_ImageProcessing.twoArcsClipTheArc_ROI(src, ROI, top, bottom, midP, allPntList, canvas, arcTop_right, true);cout << "\nmain ==== flag " << flag << endl;if (flag) {cout << "top = " << top.x << " " << top.y << endl;cout << "bottom = " << bottom.x << " " << bottom.y << endl;cout << "midP = " << midP.x << " " << midP.y << endl;}canvas.copyTo(src);//cout << "\nmain ==== i " << endl;circle(canvas, top, 63, cv::Scalar(0, 69, 255), 1);circle(canvas, bottom, 63, cv::Scalar(0, 69, 255), 1);cv::putText(src, to_string(flag), cv::Point(src.cols / 2 - 20, src.rows / 2 - 65), cv::FONT_HERSHEY_COMPLEX, 1.75, cv::Scalar(255, 135, 160), 3);cv::namedWindow("main-结果图src", cv::RECURS_FILTER);cvSetMouseCallback("main-结果图src", on_mouse_singleClick, 0);cv::imshow("main-结果图src", src);cv::namedWindow("main-canvas", cv::RECURS_FILTER);cvSetMouseCallback("main-canvas", on_mouse_singleClick, 0);cv::imshow("main-canvas", canvas);}else{vector<string> path_name;getAllFiles(filePath, path_name);cout << "path_name.size()=" << path_name.size() << endl;int number = 1;for (auto i : path_name){//cout << i.size() << endl;if (i.size() == 7) continue;if (i.find(".log") != std::string::npos) continue;if (i.find(".txt") != std::string::npos) continue;if (i.find("_result") != std::string::npos) continue;if (i.find("png") == std::string::npos && i.find("bmp") == std::string::npos && i.find("jpg") == std::string::npos) continue;std::string path11 = filePath + "\\" + i;cv::Mat src = cv::imread(path11);//cv::Mat src = cv::imread(filePath + "\\" + i);cout << endl << "number【" << number << "】src path=" << i << " ;" << endl;src.copyTo(canvas);cv::imshow("main_OriginalIMG", src);//将结果图写入文件方便查看结果int len = filePath.length();//i = i.substr(i.find_last_of('\\') + 1, len);cout << "i=" << i << ", path11=" << path11 << endl;int time_start = clock();int time_end = clock();cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);//cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);if (getROI) ROI = getROIFromString(i);bool flag = m_ImageProcessing.twoArcsClipTheArc_ROI(src, ROI, top, bottom, midP, allPntList, canvas, arcTop_right, false);time_end = clock();printf("\n耗时 %d ms \n", time_end - time_start);cout << "\nmain ==== flag " << flag << endl;if (flag) {cout << "top = " << top.x << " " << top.y << endl;cout << "bottom = " << bottom.x << " " << bottom.y << endl;}canvas.copyTo(src);cv::putText(src, to_string(flag), cv::Point(src.cols / 2 - 20, src.rows / 2 - 65), cv::FONT_HERSHEY_COMPLEX, 1.75, cv::Scalar(255, 135, 160), 3);cv::imshow("main-结果图src", src);cv::imshow("main-canvas", canvas);//将结果图写入文件方便查看结果char*  filePath_ = new char[len + 1];strcpy(filePath_, filePath.c_str());len = filePath.length();char*  resPath_ = new char[len + 1];strcpy(resPath_, resPath.c_str());//i.erase(0, strlen(filePath_) - strlen(resPath_) - 2);string out = filePath + resPath;cout << "\nmain ==== i " << i << endl;out.append("\\").append(i);cout << "number【" << number << "】res path=" << out << endl;cv::imwrite(out, src);number++;cout << "path_name.size() = " << path_name.size() << endl;cout << "*********************************************************************************************************************" << endl;cv::waitKey(10);}cout << "循环结束!!! main " << endl;}ofs.close();cv::waitKey(0);system("Pause");return 0;
}

返回三点+双点集+左右翻转再进入识别

左右翻转变回来后必须要x-1,不然会与原来基于原图上的坐标对应不上。

	/*//D型管的两直线夹圆弧//周六新策略:两边直线中间圆弧,激光平行于主管 (__O__两端直线中间半圆弧找圆弧的两端拐点)---圆轨迹cv::Mat img, 原图cv::Rect ROI, 可以让右边的干扰直反光落进去,上下不用截,左右可适当截小一下减少识别时的计算时间int outMidY,因y偏差过大时返回的两点无效,则返回圆弧区域的中心ycv::Point& midP, outMidY对应的圆弧上的骨干点(midP为(0,0)时,该值无效)std::vector<cv::Point>& linearPnt:直线部分非弧线的点集cv::Point& top, 输出焊点(图像上位于较上方的点)cv::Point& bottom, 输出焊点(图像上位于较下方的点)cv::Mat &canvas,效果图可视化int midyTolerant = 2;//outMidY的容差范围bool arcTop_right = true;//圆弧顶点是否朝右的标志量,默认为true(true为朝右,false为朝左)*/bool LaserParallelToTheMainD(cv::Mat imgOriginal, int &outMidY, cv::Point2f& midP, std::vector<cv::Point>& linearPntT, std::vector<cv::Point>& linearPntB, cv::Point& top, cv::Point& bottom, cv::Mat &canvas, int midyTolerant, bool debug = false);bool LaserParallelToTheMainD_ROI(cv::Mat img, cv::Rect ROI, int &outMidY, cv::Point2f& midP, std::vector<cv::Point>& linearPntT, std::vector<cv::Point>& linearPntB, cv::Point& top, cv::Point& bottom, cv::Mat &canvas, int midyTolerant = 2, bool arcTop_right = true, bool debug = false);
bool ImageProcessing::LaserParallelToTheMainD_ROI(cv::Mat img, cv::Rect ROI, int &outMidY, cv::Point2f& midP, std::vector<cv::Point>& linearPntT, std::vector<cv::Point>& linearPntB, cv::Point & top, cv::Point & bottom, cv::Mat & canvas, int midyTolerant, bool arcTop_right, bool debug)
{int endRes = 0;bool result = false;img.copyTo(canvas);top = cv::Point(0, 0);bottom = cv::Point(0, 0);midP = cv::Point2f(0, 0);linearPntT.clear();linearPntB.clear();outMidY = 0;cv::Mat imgOriginal;bool ROI_flag;//是否有给信息区cv::Point ROI_tl = cv::Point2i(ROI.x, ROI.y);cv::Point ROI_br = cv::Point2i(ROI.x + ROI.width, ROI.y + ROI.height);if (ROI_tl == cv::Point(0, 0) && ROI_br == cv::Point(0, 0) || ROI.width == 0 || ROI.height == 0){img.copyTo(imgOriginal);ROI_flag = false;}else{if (ROI_tl.x > ROI_br.x || ROI_tl.y > ROI_br.y)//信息区两点疑似传反{printf("信息区两点疑似传反!");return false;}if (ROI_tl.x < 0 || ROI_br.x > img.cols || ROI_tl.y < 0 || ROI_br.y > img.rows)//信息区的框选超出图像范围{printf("信息区的框选超出图像范围!");return false;}if (abs(ROI_tl.x - ROI_br.x) > img.cols || abs(ROI_tl.y - ROI_br.y) > img.rows)//信息区大小超出图像大小{printf("信息区大小超出图像大小!");return false;}//此时不合法的ROI都已提前返回falsecv::Rect roi(ROI_tl.x, ROI_tl.y, ROI_br.x - ROI_tl.x, ROI_br.y - ROI_tl.y);imgOriginal = img(roi);	//裁剪出的ROI区域放于imgOriginalROI_flag = true;}if (arcTop_right) {//圆弧顶点朝右的情况result = LaserParallelToTheMainD(imgOriginal, outMidY, midP, linearPntT, linearPntB, top, bottom, canvas, midyTolerant, debug);//调用识别算法}else {//圆弧顶点朝左的情况cv::Mat flipMat;cv::flip(imgOriginal, flipMat, 1);			// 左右翻转 y对称if (debug) imshow("图像左右翻转", flipMat);result = LaserParallelToTheMainD(flipMat, outMidY, midP, linearPntT, linearPntB, top, bottom, canvas, midyTolerant, debug);//调用识别算法if (result) {top.x = flipMat.cols - top.x - 1;bottom.x = flipMat.cols - bottom.x - 1;for (int i = 0; i < linearPntT.size(); i++) {linearPntT.at(i).x = flipMat.cols - linearPntT.at(i).x - 1;}for (int i = 0; i < linearPntB.size(); i++) {linearPntB.at(i).x = flipMat.cols - linearPntB.at(i).x - 1;}if (midP != cv::Point2f(0, 0)) midP.x = flipMat.cols - midP.x - 1;}}if (debug) printf("-------------------------------------****------ roiF  top=【%d, %d】, bottom=【%d, %d】\n", top.x, top.y, bottom.x, bottom.y);if (debug) printf("                                                roiF  midP=【%f, %f】\n", midP.x, midP.y);//img.copyTo(canvas);x值和y值补上ROI左上点x和y//if (ROI_flag) {//	if (Corner != cv::Point(0, 0))//	{//		Corner.x += ROI_tl.x;//		Corner.y += ROI_tl.y;//	}//}img.copyTo(canvas);//调试时注释掉if (result){endRes = 1;top += ROI_tl;bottom += ROI_tl;if (midP != cv::Point2f(0, 0)) {midP.x = midP.x + ROI_tl.x;midP.y = midP.y + ROI_tl.y;}cv::line(canvas, midP, cv::Point2f(5, midP.y), cv::Scalar(55, 195, 40), 1);cv::line(canvas, cv::Point2f(midP.x, midP.y - 5), cv::Point2f(midP.x, midP.y + 5), cv::Scalar(55, 195, 40), 1);for (int i = 0; i < linearPntT.size(); i++) {linearPntT.at(i) += ROI_tl;}for (int i = 0; i < linearPntB.size(); i++) {linearPntB.at(i) += ROI_tl;}for (int i = 0; i < linearPntT.size(); i++) {cv::Point curPoint = linearPntT.at(i);cv::line(canvas, curPoint, cv::Point(curPoint.x - 5, curPoint.y), cv::Scalar(55, 195, 40), 1);}for (int i = 0; i < linearPntB.size(); i++) {cv::Point curPoint = linearPntB.at(i);cv::line(canvas, curPoint, cv::Point(curPoint.x - 5, curPoint.y), cv::Scalar(55, 195, 40), 1);}cv::putText(canvas, "true", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);circle(canvas, top, 3, cv::Scalar(0, 69, 255), 1);circle(canvas, top, 63, cv::Scalar(0, 169, 255), 1);circle(canvas, bottom, 3, cv::Scalar(0, 69, 255), 1);circle(canvas, bottom, 43, cv::Scalar(255, 169, 0), 1);}else{cv::putText(canvas, "false", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);}cv::Mat ROIcanvas;img.copyTo(ROIcanvas);if (debug) circle(ROIcanvas, top, 3, cv::Scalar(0, 69, 255), 1);if (debug) circle(ROIcanvas, top, 63, cv::Scalar(0, 169, 255), 1);if (debug) circle(ROIcanvas, bottom, 3, cv::Scalar(0, 69, 255), 1);if (debug) circle(ROIcanvas, bottom, 63, cv::Scalar(0, 169, 255), 1);if (debug) rectangle(ROIcanvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);rectangle(canvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);if (debug) printf("-------------------------------------****------ roiF  top=【%d, %d】, bottom=【%d, %d】\n", top.x, top.y, bottom.x, bottom.y);if (debug) printf("                                                roiF  midP=【%f, %f】\n", midP.x, midP.y);if (debug) imshow("ROI", ROIcanvas);if (debug) imshow("ROI_canvas", canvas);//ROIcanvas.copyTo(canvas);return result;
}

调用main:

//CXL 两边直线中间圆弧,激光平行于主管 DDDDDDDDDDDDDDDDD 圆轨迹  增加直线部分点集 的重载
int main() {bool flag;std::string filePath = "../../../../Log08141641/TestImg/src";string resPath = "/output";//string resPath = filePath + "./output";cv::Point tlP = cv::Point(500, 292);cv::Point brP = cv::Point(750, 677);//cv::Rect ROI = cv::Rect(0, 0, 0, 0);//cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);//cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);//cv::Rect ROI = cv::Rect(539, 218, 113, 513);cv::Point top(90, 90);cv::Point bottom(90, 90);cv::Point2f midP(90, 90);int outMidY;cv::Mat canvas;ImageProcessing m_ImageProcessing;ofstream ofs("log.txt", ios::out);if (ofs){ofs.clear();ofs << "日志启动" << endl;}std::vector<cv::Point> linearPntT;std::vector<cv::Point> linearPntB;vector<string> path_name;bool arcTop_right = !true;int midyTolerant = 4;bool   getROI = true;bool   lianxu = false; //循环测试if (!lianxu){string name = cv::format("\\ImgD_2024_06_04_09_14_48_111_565_82_86_851_Src.png");string path = filePath + name;//string path = filePath + cv::format("\\ImgD_2023_08_17_15_06_45_412_639_188_125_569_Src.png");cv::Mat src = cv::imread(path);src.copyTo(canvas);cv::namedWindow("main_OriginalIMG", cv::NORMCONV_FILTER);cvSetMouseCallback("main_OriginalIMG", on_mouse_singleClick, 0);cv::imshow("main_OriginalIMG", src);//cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);//cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);if (getROI) ROI = getROIFromString(name);//trueX=outY;//trueY=oriSrc.rows-outX;//circle(src, cv::Point(622, 424), 5, cv::Scalar(255, 255, 255), -1);//cv::Mat flipMat;//cv::flip(src, flipMat, 1);//cv::Point q = cv::Point(flipMat.cols - 622 - 1, 424)/* - cv::Point(546, 228)*/;//circle(flipMat, q, 3, cv::Scalar(0, 0, 0), -1);//cv::imshow("flipMat", flipMat);//cv::waitKey();bool flag = m_ImageProcessing.LaserParallelToTheMainD_ROI(src, ROI, outMidY, midP, linearPntT, linearPntB, top, bottom, canvas, midyTolerant, arcTop_right, true);cout << "\nmain ==== flag " << flag << endl;if (flag) {cout << "top = " << top.x << " " << top.y << endl;cout << "bottom = " << bottom.x << " " << bottom.y << endl;}canvas.copyTo(src);//cout << "\nmain ==== i " << endl;circle(canvas, top, 63, cv::Scalar(0, 69, 255), 1);circle(canvas, bottom, 63, cv::Scalar(0, 69, 255), 1);cv::putText(src, to_string(flag), cv::Point(src.cols / 2 - 20, src.rows / 2 - 65), cv::FONT_HERSHEY_COMPLEX, 1.75, cv::Scalar(255, 135, 160), 3);cv::namedWindow("main-结果图src", cv::RECURS_FILTER);cvSetMouseCallback("main-结果图src", on_mouse_singleClick, 0);cv::imshow("main-结果图src", src);cv::namedWindow("main-canvas", cv::RECURS_FILTER);cvSetMouseCallback("main-canvas", on_mouse_singleClick, 0);cv::imshow("main-canvas", canvas);}else{vector<string> path_name;getAllFiles(filePath, path_name);cout << "path_name.size()=" << path_name.size() << endl;int number = 1;for (auto i : path_name){//cout << i.size() << endl;if (i.size() == 7) continue;if (i.find(".log") != std::string::npos) continue;if (i.find(".txt") != std::string::npos) continue;if (i.find("_result") != std::string::npos) continue;if (i.find("png") == std::string::npos && i.find("bmp") == std::string::npos && i.find("jpg") == std::string::npos) continue;std::string path11 = filePath + "\\" + i;cv::Mat src = cv::imread(path11);//cv::Mat src = cv::imread(filePath + "\\" + i);cout << endl << "number【" << number << "】src path=" << i << " ;" << endl;src.copyTo(canvas);cv::imshow("main_OriginalIMG", src);//将结果图写入文件方便查看结果int len = filePath.length();//i = i.substr(i.find_last_of('\\') + 1, len);cout << "i=" << i << ", path11=" << path11 << endl;int time_start = clock();int time_end = clock();cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);//cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);if (getROI) ROI = getROIFromString(i);bool flag = m_ImageProcessing.LaserParallelToTheMainD_ROI(src, ROI, outMidY, midP, linearPntT, linearPntB, top, bottom, canvas, midyTolerant, arcTop_right, false);time_end = clock();printf("\n耗时 %d ms \n", time_end - time_start);cout << "\nmain ==== flag " << flag << endl;if (flag) {cout << "top = " << top.x << " " << top.y << endl;cout << "bottom = " << bottom.x << " " << bottom.y << endl;}canvas.copyTo(src);cv::putText(src, to_string(flag), cv::Point(src.cols / 2 - 20, src.rows / 2 - 65), cv::FONT_HERSHEY_COMPLEX, 1.75, cv::Scalar(255, 135, 160), 3);cv::imshow("main-结果图src", src);cv::imshow("main-canvas", canvas);//将结果图写入文件方便查看结果char*  filePath_ = new char[len + 1];strcpy(filePath_, filePath.c_str());len = filePath.length();char*  resPath_ = new char[len + 1];strcpy(resPath_, resPath.c_str());//i.erase(0, strlen(filePath_) - strlen(resPath_) - 2);string out = filePath + resPath;cout << "\nmain ==== i " << i << endl;out.append("\\").append(i);cout << "number【" << number << "】res path=" << out << endl;cv::imwrite(out, src);number++;cout << "path_name.size() = " << path_name.size() << endl;cout << "*********************************************************************************************************************" << endl;cv::waitKey(10);}cout << "循环结束!!! main " << endl;}ofs.close();cv::waitKey(0);system("Pause");return 0;
}

四点

返回四点+1个点集 

	/*//矩形位置  返回四点+骨干点集cv::Mat img, 原图cv::Rect ROI,cv::Point & p1, 图像较上方的主管底部点cv::Point & p2, 图像较上方的矩形顶部边缘点cv::Point & p3, 图像较下方的主管底部点cv::Point & p4,图像较下方的矩形顶部边缘点std::vector<cv::Point>& allPntList:直线部分非弧线的点集cv::Mat &canvas,效果图可视化*/bool rectangle4Pnt(cv::Mat imgOriginal, cv::Point & p1, cv::Point& p2, cv::Point & p3, cv::Point& p4, std::vector<cv::Point>& allPntList, cv::Mat &canvas, bool debug = false);bool rectangle4Pnt_ROI(cv::Mat img, cv::Rect ROI, cv::Point & p1, cv::Point& p2, cv::Point & p3, cv::Point& p4, std::vector<cv::Point>& allPntList, cv::Mat &canvas, bool debug = false);
bool PTank_imgProcess::rectangle4Pnt_ROI(cv::Mat img, cv::Rect ROI, cv::Point & p1, cv::Point& p2, cv::Point & p3, cv::Point& p4, std::vector<cv::Point>& allPntList, cv::Mat & canvas, bool debug)
{int endRes = 0;bool result = false;img.copyTo(canvas);p1 = cv::Point(0, 0);p2 = cv::Point(0, 0);p3 = cv::Point(0, 0);p4 = cv::Point(0, 0);allPntList.clear();cv::Mat imgOriginal;bool ROI_flag;//是否有给信息区cv::Point ROI_tl = cv::Point2i(ROI.x, ROI.y);cv::Point ROI_br = cv::Point2i(ROI.x + ROI.width, ROI.y + ROI.height);if (ROI_tl == cv::Point(0, 0) && ROI_br == cv::Point(0, 0) || ROI.width == 0 || ROI.height == 0){img.copyTo(imgOriginal);ROI_flag = false;}else{if (ROI_tl.x > ROI_br.x || ROI_tl.y > ROI_br.y)//信息区两点疑似传反{printf("信息区两点疑似传反!");return false;}if (ROI_tl.x < 0 || ROI_br.x > img.cols || ROI_tl.y < 0 || ROI_br.y > img.rows)//信息区的框选超出图像范围{printf("信息区的框选超出图像范围!");return false;}if (abs(ROI_tl.x - ROI_br.x) > img.cols || abs(ROI_tl.y - ROI_br.y) > img.rows)//信息区大小超出图像大小{printf("信息区大小超出图像大小!");return false;}//此时不合法的ROI都已提前返回falsecv::Rect roi(ROI_tl.x, ROI_tl.y, ROI_br.x - ROI_tl.x, ROI_br.y - ROI_tl.y);imgOriginal = img(roi);	//裁剪出的ROI区域放于imgOriginalROI_flag = true;}result = rectangle4Pnt(imgOriginal, p1, p2, p3, p4, allPntList, canvas, debug);//调用识别算法if (debug) printf("-------------------------------------****------ roiF  p1=【%d, %d】, p2=【%d, %d】\n", p1.x, p1.y, p2.x, p2.y);if (debug) printf("-------------------------------------****------ roiF  p3=【%d, %d】, p4=【%d, %d】\n", p3.x, p3.y, p4.x, p4.y);//img.copyTo(canvas);img.copyTo(canvas);//调试时注释掉if (result){endRes = 1;p1 += ROI_tl;p2 += ROI_tl;p3 += ROI_tl;p4 += ROI_tl;for (int i = 0; i < allPntList.size(); i++) {allPntList.at(i) += ROI_tl;}int w = 5;for (int i = 0; i < allPntList.size(); i++) {cv::Point curPoint = allPntList.at(i);cv::line(canvas, curPoint, cv::Point(curPoint.x - w, curPoint.y), cv::Scalar(55, 195, 40), 1);}cv::putText(canvas, "true", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);circle(canvas, p1, 3, cv::Scalar(0, 69, 255), 1);circle(canvas, p1, 63, cv::Scalar(0, 169, 255), 1);circle(canvas, p2, 3, cv::Scalar(0, 69, 255), 1);circle(canvas, p2, 43, cv::Scalar(255, 169, 0), 1);circle(canvas, p3, 3, cv::Scalar(0, 69, 255), 1);circle(canvas, p3, 63, cv::Scalar(0, 169, 255), 1);circle(canvas, p4, 3, cv::Scalar(0, 69, 255), 1);circle(canvas, p4, 43, cv::Scalar(255, 169, 0), 1);}else{cv::putText(canvas, "false", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);}cv::Mat ROIcanvas;img.copyTo(ROIcanvas);if (debug) circle(ROIcanvas, p1, 3, cv::Scalar(0, 69, 255), 1);if (debug) circle(ROIcanvas, p1, 63, cv::Scalar(0, 169, 255), 1);if (debug) circle(ROIcanvas, p2, 3, cv::Scalar(0, 69, 255), 1);if (debug) circle(ROIcanvas, p2, 63, cv::Scalar(0, 169, 255), 1);if (debug) circle(ROIcanvas, p3, 3, cv::Scalar(0, 69, 255), 1);if (debug) circle(ROIcanvas, p3, 63, cv::Scalar(0, 169, 255), 1);if (debug) circle(ROIcanvas, p4, 3, cv::Scalar(0, 69, 255), 1);if (debug) circle(ROIcanvas, p4, 63, cv::Scalar(0, 169, 255), 1);if (debug) rectangle(ROIcanvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);rectangle(canvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);if (debug) printf("---------------****------ roiF  p1=【%d, %d】, p2=【%d, %d】\n", p1.x, p1.y, p2.x, p2.y);if (debug) printf("---------------****------ roiF  p3=【%d, %d】, p4=【%d, %d】\n", p3.x, p3.y, p4.x, p4.y);if (debug) imshow("ROI", ROIcanvas);if (debug) imshow("ROI_canvas", canvas);//ROIcanvas.copyTo(canvas);return result;
}

调用main:

//矩形位置  返回四点+骨干点集
int main/*Rectangle4Pnt_ROI*/() {bool flag;//std::string filePath = "../../../../Log08141641/TestImg/src";std::string filePath = "E://vsproject//压力罐\\img\\矩形";string resPath = "/output";//string resPath = filePath + "./output";cv::Point tlP = cv::Point(500, 292);cv::Point brP = cv::Point(750, 677);//cv::Rect ROI = cv::Rect(0, 0, 0, 0);//cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);//cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);//cv::Rect ROI = cv::Rect(539, 218, 113, 513);cv::Point top(90, 90);cv::Point bottom(90, 90);cv::Point p3(90, 90);cv::Point p4(90, 90);int outMidY;cv::Mat canvas;PTank_imgProcess m_ImageProcessing;ofstream ofs("log.txt", ios::out);if (ofs){ofs.clear();ofs << "日志启动" << endl;}std::vector<cv::Point> allPntList;vector<string> path_name;bool   getROI = true;bool   lianxu = false; //循环测试if (lianxu){string name = cv::format("\\Image_20240627144521008.png");string path = filePath + name;cv::Mat src = cv::imread(path);src.copyTo(canvas);cv::namedWindow("main_OriginalIMG", cv::RECURS_FILTER);cvSetMouseCallback("main_OriginalIMG", on_mouse_singleClick, 0);cv::imshow("main_OriginalIMG", src);//cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);if (getROI) ROI = getROIFromString(name);bool flag = m_ImageProcessing.rectangle4Pnt_ROI(src, ROI, top, bottom, p3, p4, allPntList, canvas, true);cout << "\nmain ==== flag " << flag << endl;if (flag) {cout << "top = " << top.x << " " << top.y << endl;cout << "bottom = " << bottom.x << " " << bottom.y << endl;}canvas.copyTo(src);//cout << "\nmain ==== i " << endl;circle(canvas, top, 63, cv::Scalar(0, 69, 255), 1);circle(canvas, bottom, 63, cv::Scalar(0, 69, 255), 1);cv::putText(src, to_string(flag), cv::Point(src.cols / 2 - 20, src.rows / 2 - 65), cv::FONT_HERSHEY_COMPLEX, 1.75, cv::Scalar(255, 135, 160), 3);cv::namedWindow("main-结果图src", cv::RECURS_FILTER);cvSetMouseCallback("main-结果图src", on_mouse_singleClick, 0);cv::imshow("main-结果图src", src);cv::namedWindow("main-canvas", cv::RECURS_FILTER);cvSetMouseCallback("main-canvas", on_mouse_singleClick, 0);cv::imshow("main-canvas", canvas);}else{vector<string> path_name;getAllFiles(filePath, path_name);cout << "path_name.size()=" << path_name.size() << endl;int number = 1;for (auto i : path_name){//cout << i.size() << endl;if (i.size() == 7) continue;if (i.find(".log") != std::string::npos) continue;	if (i.find("png") == std::string::npos && i.find("bmp") == std::string::npos && i.find("jpg") == std::string::npos) continue;std::string path11 = filePath + "\\" + i;cv::Mat src = cv::imread(path11);//cv::Mat src = cv::imread(filePath + "\\" + i);cout << endl << "number【" << number << "】src path=" << i << " ;" << endl;src.copyTo(canvas);cv::imshow("main_OriginalIMG", src);//将结果图写入文件方便查看结果int len = filePath.length();//i = i.substr(i.find_last_of('\\') + 1, len);cout << "i=" << i << ", path11=" << path11 << endl;int time_start = clock();int time_end = clock();cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);//cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);if (getROI) ROI = getROIFromString(i);bool flag = m_ImageProcessing.rectangle4Pnt_ROI(src, ROI, top, bottom, p3, p4, allPntList, canvas, false);time_end = clock();printf("\n耗时 %d ms \n", time_end - time_start);cout << "\nmain ==== flag " << flag << endl;if (flag) {cout << "top = " << top.x << " " << top.y << endl;cout << "bottom = " << bottom.x << " " << bottom.y << endl;}canvas.copyTo(src);cv::putText(src, to_string(flag), cv::Point(src.cols / 2 - 20, src.rows / 2 - 65), cv::FONT_HERSHEY_COMPLEX, 1.75, cv::Scalar(255, 135, 160), 3);cv::imshow("main-结果图src", src);cv::imshow("main-canvas", canvas);//将结果图写入文件方便查看结果char*  filePath_ = new char[len + 1];strcpy(filePath_, filePath.c_str());len = filePath.length();char*  resPath_ = new char[len + 1];strcpy(resPath_, resPath.c_str());//i.erase(0, strlen(filePath_) - strlen(resPath_) - 2);string out = filePath + resPath;cout << "\nmain ==== i " << i << endl;out.append("\\").append(i);cout << "number【" << number << "】res path=" << out << endl;cv::imwrite(out, src);number++;cout << "path_name.size() = " << path_name.size() << endl;cout << "*********************************************************************************************************************" << endl;cv::waitKey(10);}cout << "循环结束!!! main " << endl;}ofs.close();cv::waitKey(0);system("Pause");return 0;
}

返回四点+双点集

	/*//多层多道焊  圆管表面 & 四边形坡口拼接cv::Mat img, 原图cv::Point& top, 输出焊点(图像上位于较上方的点)cv::Point& bottom, 输出焊点(图像上位于较下方的点)std::vector<cv::Point>& groovePnt:坡口部分包括内侧面的点集cv::Point& valleyT, 位于焊道底部的焊点(图像上位于较上方的点)cv::Point& valleyB, 位于焊道底部的焊点(图像上位于较下方的点)std::vector<cv::Point>& valleyPnt,位于焊道底部的,焊道底部两点之间的点集cv::Mat &canvas,效果图可视化cv::Rect ROI,*/bool multilayerMultichannel4(cv::Mat imgOriginal, cv::Point& top, cv::Point& bottom, std::vector<cv::Point>& groovePnt, cv::Point& valleyT, cv::Point& valleyB, std::vector<cv::Point>& valleyPnt, cv::Mat &canvas, bool debug = false);bool multilayerMultichannel4_ROI(cv::Mat img, cv::Point& top, cv::Point& bottom, std::vector<cv::Point>& groovePnt, cv::Point& valleyT, cv::Point& valleyB, std::vector<cv::Point>& valleyPnt, cv::Mat &canvas, cv::Rect ROI = cv::Rect(540, 540, 200, 200), bool debug = false);
bool ImageProcess::multilayerMultichannel4_ROI(cv::Mat img, cv::Point & top, cv::Point & bottom, std::vector<cv::Point>& groovePnt, cv::Point & valleyT, cv::Point & valleyB, std::vector<cv::Point>& valleyPnt, cv::Mat & canvas, cv::Rect ROI, bool debug)
{int endRes = 0;bool result = false;img.copyTo(canvas);top = cv::Point(0, 0);bottom = cv::Point(0, 0);groovePnt.clear();valleyT = cv::Point(0, 0);valleyB = cv::Point(0, 0);valleyPnt.clear();cv::Mat imgOriginal;bool ROI_flag;//是否有给信息区cv::Point ROI_tl = cv::Point2i(ROI.x, ROI.y);cv::Point ROI_br = cv::Point2i(ROI.x + ROI.width, ROI.y + ROI.height);if (ROI_tl == cv::Point(0, 0) && ROI_br == cv::Point(0, 0) || ROI.width == 0 || ROI.height == 0){img.copyTo(imgOriginal);ROI_flag = false;}else{if (ROI_tl.x > ROI_br.x || ROI_tl.y > ROI_br.y)//信息区两点疑似传反{printf("信息区两点疑似传反!");return false;}if (ROI_tl.x < 0 || ROI_br.x > img.cols || ROI_tl.y < 0 || ROI_br.y > img.rows)//信息区的框选超出图像范围{printf("信息区的框选超出图像范围!");return false;}if (abs(ROI_tl.x - ROI_br.x) > img.cols || abs(ROI_tl.y - ROI_br.y) > img.rows)//信息区大小超出图像大小{printf("信息区大小超出图像大小!");return false;}//此时不合法的ROI都已提前返回falsecv::Rect roi(ROI_tl.x, ROI_tl.y, ROI_br.x - ROI_tl.x, ROI_br.y - ROI_tl.y);imgOriginal = img(roi);	//裁剪出的ROI区域放于imgOriginalROI_flag = true;}result = multilayerMultichannel4(imgOriginal, top, bottom, groovePnt, valleyT, valleyB, valleyPnt, canvas, debug);//调用识别算法if (debug) printf("-------------------------------------****------ roiF  top=【%d, %d】, bottom=【%d, %d】\n", top.x, top.y, bottom.x, bottom.y);if (debug) printf("----- roiF valleyT=【%d, %d】, valleyB=【%d, %d】\n", valleyT.x, valleyT.y, valleyB.x, valleyB.y);//img.copyTo(canvas);x值和y值补上ROI左上点x和y//if (ROI_flag) {//	if (Corner != cv::Point(0, 0))//	{//		Corner.x += ROI_tl.x;//		Corner.y += ROI_tl.y;//	}//}img.copyTo(canvas);//调试时注释掉cv::Mat t1;canvas.convertTo(t1, -1, 1900 / 100.0, 100 - 100);//第一次线性变换100if (debug)cv::imshow("线性变换ROI", t1);t1.copyTo(canvas);if (result){endRes = 1;top += ROI_tl;bottom += ROI_tl;valleyT += ROI_tl;valleyB += ROI_tl;for (int i = 0; i < groovePnt.size(); i++) {groovePnt.at(i) += ROI_tl;}for (int i = 0; i < valleyPnt.size(); i++) {valleyPnt.at(i) += ROI_tl;}int w = 9;for (int i = 0; i < groovePnt.size(); i++) {cv::Point curPoint = groovePnt.at(i);cv::line(canvas, curPoint, cv::Point(curPoint.x + w, curPoint.y), cv::Scalar(55, 195, 40), 1);}cv::putText(canvas, "true", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);circle(canvas, top, 3, cv::Scalar(0, 69, 255), 1);circle(canvas, top, 63, cv::Scalar(0, 169, 255), 1);circle(canvas, bottom, 3, cv::Scalar(0, 69, 255), 1);circle(canvas, bottom, 43, cv::Scalar(255, 169, 0), 1);circle(canvas, valleyT, 3, cv::Scalar(0, 69, 255), 1);circle(canvas, valleyT, 43, cv::Scalar(0, 169, 255), 1);circle(canvas, valleyB, 3, cv::Scalar(0, 69, 255), 1);circle(canvas, valleyB, 23, cv::Scalar(255, 169, 0), 1);for (int i = 0; i < valleyPnt.size(); i++) {cv::Point curPoint = valleyPnt.at(i);cv::line(canvas, curPoint, cv::Point(curPoint.x - w, curPoint.y), cv::Scalar(75, 155, 40), 1);}}else{cv::putText(canvas, "false", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);}cv::Mat ROIcanvas;img.copyTo(ROIcanvas);if (debug) circle(ROIcanvas, top, 3, cv::Scalar(0, 69, 255), 1);if (debug) circle(ROIcanvas, top, 63, cv::Scalar(0, 169, 255), 1);if (debug) circle(ROIcanvas, bottom, 3, cv::Scalar(0, 69, 255), 1);if (debug) circle(ROIcanvas, bottom, 63, cv::Scalar(0, 169, 255), 1);if (debug) rectangle(ROIcanvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);rectangle(canvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);if (debug) printf("-------------------------------------****------ roiF  top=【%d, %d】, bottom=【%d, %d】\n", top.x, top.y, bottom.x, bottom.y);if (debug) printf("----- roiF valleyT=【%d, %d】, valleyB=【%d, %d】\n", valleyT.x, valleyT.y, valleyB.x, valleyB.y);if (debug) imshow("ROI", ROIcanvas);if (debug) imshow("ROI_canvas", canvas);//ROIcanvas.copyTo(canvas);return result;
}

调用main:

//multilayerMultichannel4_ROI  多层多道焊  圆管表面 & 四边形坡口拼接
int main() {bool flag;//std::string filePath = "E:\\vsproject\\WeldingLine\\多层多道4";std::string filePath = "E:\\vsproject\\WeldingLine\\多层多道4\\TestImgAAA";std::string resPath = "/output";//string resPath = filePath + "./output";//cv::Point tlP = cv::Point(500, 40);//cv::Point brP = cv::Point(750, 777);cv::Point tlP = cv::Point(345, 108);cv::Point brP = cv::Point(859, 951);cv::Rect ROI = cv::Rect(0, 0, 0, 0);//cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);//cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);//cv::Rect ROI = cv::Rect(544,208,107,545);//cv::Rect ROI = cv::Rect(639, 188, 125, 569);cv::Point top(90, 90);cv::Point bottom(90, 90);cv::Point valleyT(90, 90);cv::Point valleyB(90, 90);int outMidY;cv::Mat canvas;VisualInterface m_ImageProcessing;//ImageProcess m_ImageProcessing;std::vector<cv::Point> groovePnt;std::vector<cv::Point> valleyPnt;vector<string> path_name;bool arcTop_right = true;int midyTolerant = 4;bool   getROI = !true;bool   lianxu = false; //循环测试if (!lianxu){string name = cv::format("\\SrcImg_2023_12_28_14_57_17_133_ROI_1132_999_401_126_src.png");//中间底部较高的情况string path = filePath + name;cv::Mat src = cv::imread(path);src.copyTo(canvas);cv::namedWindow("main_OriginalIMG", cv::NORMCONV_FILTER);cvSetMouseCallback("main_OriginalIMG", on_mouse_singleClick, 0);cv::imshow("main_OriginalIMG", src);cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);//ROI = cv::Rect(400, 0, 400, src.rows);//cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);if (getROI) ROI = getROIFromString(name);bool flag = m_ImageProcessing.multilayerMultichannel4_ROI(src, top, bottom, groovePnt, valleyT, valleyB, valleyPnt, canvas, ROI, true);cout << "\nmain ==== flag " << flag << endl;if (flag) {cout << "top = " << top.x << " " << top.y << endl;cout << "bottom = " << bottom.x << " " << bottom.y << endl;}canvas.copyTo(src);//cout << "\nmain ==== i " << endl;circle(canvas, top, 63, cv::Scalar(0, 69, 255), 1);circle(canvas, bottom, 63, cv::Scalar(0, 69, 255), 1);cv::putText(src, to_string(flag), cv::Point(src.cols / 2 - 20, src.rows / 2 - 65), cv::FONT_HERSHEY_COMPLEX, 1.75, cv::Scalar(255, 135, 160), 3);cv::namedWindow("main-结果图src", cv::RECURS_FILTER);cvSetMouseCallback("main-结果图src", on_mouse_singleClick, 0);cv::imshow("main-结果图src", src);cv::namedWindow("main-canvas", cv::RECURS_FILTER);cvSetMouseCallback("main-canvas", on_mouse_singleClick, 0);cv::imshow("main-canvas", canvas);}else{vector<string> path_name;getAllFiles(filePath, path_name);cout << "path_name.size()=" << path_name.size() << endl;int number = 1;for (auto i : path_name){//cout << i.size() << endl;if (i.size() == 7) continue;if (i.find(".log") != std::string::npos) continue;if (i.find(".txt") != std::string::npos) continue;if (i.find("_result") != std::string::npos) continue;if (i.find("png") == std::string::npos && i.find("bmp") == std::string::npos && i.find("jpg") == std::string::npos) continue;std::string path11 = filePath + "\\" + i;cv::Mat src = cv::imread(path11);//cv::Mat src = cv::imread(filePath + "\\" + i);cout << endl << "number【" << number << "】src path=" << i << " ;" << endl;src.copyTo(canvas);cv::imshow("main_OriginalIMG", src);//将结果图写入文件方便查看结果int len = filePath.length();//i = i.substr(i.find_last_of('\\') + 1, len);cout << "i=" << i << ", path11=" << path11 << endl;int time_start = clock();int time_end = clock();cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);//ROI = cv::Rect(400, 0, 400, src.rows);cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);if (getROI) ROI = getROIFromString(i);bool flag = m_ImageProcessing.multilayerMultichannel4_ROI(src, top, bottom, groovePnt, valleyT, valleyB, valleyPnt, canvas, ROI, false);time_end = clock();printf("\n耗时 %d ms \n", time_end - time_start);cout << "\nmain ==== flag " << flag << endl;if (flag) {cout << "top = " << top.x << " " << top.y << endl;cout << "bottom = " << bottom.x << " " << bottom.y << endl;}canvas.copyTo(src);cv::putText(src, to_string(flag), cv::Point(src.cols / 2 - 20, src.rows / 2 - 65), cv::FONT_HERSHEY_COMPLEX, 1.75, cv::Scalar(255, 135, 160), 3);cv::imshow("main-结果图src", src);cv::imshow("main-canvas", canvas);//将结果图写入文件方便查看结果char*  filePath_ = new char[len + 1];strcpy(filePath_, filePath.c_str());len = filePath.length();char*  resPath_ = new char[len + 1];strcpy(resPath_, resPath.c_str());//i.erase(0, strlen(filePath_) - strlen(resPath_) - 2);string out = filePath + resPath;cout << "\nmain ==== i " << i << endl;out.append("\\").append(i);cout << "number【" << number << "】res path=" << out << endl;cv::imwrite(out, src);number++;cout << "path_name.size() = " << path_name.size() << endl;cout << "*********************************************************************************************************************" << endl;cv::waitKey(10);}cout << "循环结束!!! main " << endl;}cv::waitKey(0);system("Pause");return 0;
}

五点

返回五点+1个点集

	/*//两弧线夹悬空的圆弧  返回五点+骨干点集   定"L"型管相贯线水平用cv::Mat img, 原图cv::Rect ROI,cv::Point & p1, 图像较上方的主管底部点cv::Point & p2, 图像较上方的弧形激光边缘点cv::Point2f & midP, 圆弧中点cv::Point & p3, 图像较下方的弧形激光边缘点cv::Point & p4,图像较下方的主管底部点std::vector<cv::Point>& allPntList:直线部分非弧线的点集cv::Mat &canvas,效果图可视化*/bool twoArcsClipTheHangingArc(cv::Mat imgOriginal, cv::Point & p1, cv::Point& p2, cv::Point2f& midP, cv::Point& p3, cv::Point& p4, std::vector<cv::Point>& allPntList, cv::Mat &canvas, bool debug = false);bool twoArcsClipTheHangingArc_ROI(cv::Mat img, cv::Rect ROI, cv::Point& p1, cv::Point& p2, cv::Point2f& midP, cv::Point& p3, cv::Point& p4, std::vector<cv::Point>& allPntList, cv::Mat &canvas, bool debug = false);
bool PTank_imgProcess::twoArcsClipTheHangingArc_ROI(cv::Mat img, cv::Rect ROI, cv::Point & p1, cv::Point & p2, cv::Point2f & midP, cv::Point & p3, cv::Point & p4, std::vector<cv::Point>& allPntList, cv::Mat & canvas, bool debug)
{int endRes = 0;bool result = false;img.copyTo(canvas);p1 = cv::Point(0, 0);p2 = cv::Point(0, 0);p3 = cv::Point(0, 0);p4 = cv::Point(0, 0);midP = cv::Point2f(0, 0);allPntList.clear();cv::Mat imgOriginal;bool ROI_flag;//是否有给信息区cv::Point ROI_tl = cv::Point2i(ROI.x, ROI.y);cv::Point ROI_br = cv::Point2i(ROI.x + ROI.width, ROI.y + ROI.height);if (ROI_tl == cv::Point(0, 0) && ROI_br == cv::Point(0, 0) || ROI.width == 0 || ROI.height == 0){img.copyTo(imgOriginal);ROI_flag = false;}else{if (ROI_tl.x > ROI_br.x || ROI_tl.y > ROI_br.y)//信息区两点疑似传反{printf("信息区两点疑似传反!");return false;}if (ROI_tl.x < 0 || ROI_br.x > img.cols || ROI_tl.y < 0 || ROI_br.y > img.rows)//信息区的框选超出图像范围{printf("信息区的框选超出图像范围!");return false;}if (abs(ROI_tl.x - ROI_br.x) > img.cols || abs(ROI_tl.y - ROI_br.y) > img.rows)//信息区大小超出图像大小{printf("信息区大小超出图像大小!");return false;}//此时不合法的ROI都已提前返回falsecv::Rect roi(ROI_tl.x, ROI_tl.y, ROI_br.x - ROI_tl.x, ROI_br.y - ROI_tl.y);imgOriginal = img(roi);	//裁剪出的ROI区域放于imgOriginalROI_flag = true;}result = twoArcsClipTheHangingArc(imgOriginal, p1, p2, midP, p3, p4, allPntList, canvas, debug);//调用识别算法if (debug) printf("-------------------------------------****------ roiF  p1=【%d, %d】, p2=【%d, %d】\n", p1.x, p1.y, p2.x, p2.y);if (debug) printf("-------------------------------------****------ roiF  p3=【%d, %d】, p4=【%d, %d】\n", p3.x, p3.y, p4.x, p4.y);if (debug) printf("                                                roiF  midP=【%f, %f】\n", midP.x, midP.y);//img.copyTo(canvas);img.copyTo(canvas);//调试时注释掉if (result){endRes = 1;p1 += ROI_tl;p2 += ROI_tl;p3 += ROI_tl;p4 += ROI_tl;midP += cv::Point2f(ROI_tl);for (int i = 0; i < allPntList.size(); i++) {allPntList.at(i) += ROI_tl;}int w = 5;for (int i = 0; i < allPntList.size(); i++) {cv::Point curPoint = allPntList.at(i);cv::line(canvas, curPoint, cv::Point(curPoint.x - w, curPoint.y), cv::Scalar(55, 195, 40), 1);}cv::putText(canvas, "true", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);circle(canvas, midP, 3, cv::Scalar(0, 69, 255), 1);circle(canvas, midP, 43, cv::Scalar(0, 169, 255), 1);cv::line(canvas, midP, cv::Point2f(5, midP.y), cv::Scalar(155, 195, 40), 1);cv::line(canvas, cv::Point2f(midP.x, midP.y - 5), cv::Point2f(midP.x, midP.y + 5), cv::Scalar(155, 195, 40), 1);circle(canvas, p1, 3, cv::Scalar(0, 69, 255), 1);circle(canvas, p1, 63, cv::Scalar(0, 169, 255), 1);circle(canvas, p2, 3, cv::Scalar(0, 69, 255), 1);circle(canvas, p2, 43, cv::Scalar(255, 169, 0), 1);circle(canvas, p3, 3, cv::Scalar(0, 69, 255), 1);circle(canvas, p3, 63, cv::Scalar(0, 169, 255), 1);circle(canvas, p4, 3, cv::Scalar(0, 69, 255), 1);circle(canvas, p4, 43, cv::Scalar(255, 169, 0), 1);}else{cv::putText(canvas, "false", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);}cv::Mat ROIcanvas;img.copyTo(ROIcanvas);if (debug) circle(ROIcanvas, p1, 3, cv::Scalar(0, 69, 255), 1);if (debug) circle(ROIcanvas, p1, 63, cv::Scalar(0, 169, 255), 1);if (debug) circle(ROIcanvas, p2, 3, cv::Scalar(0, 69, 255), 1);if (debug) circle(ROIcanvas, p2, 63, cv::Scalar(0, 169, 255), 1);if (debug) circle(ROIcanvas, p3, 3, cv::Scalar(0, 69, 255), 1);if (debug) circle(ROIcanvas, p3, 63, cv::Scalar(0, 169, 255), 1);if (debug) circle(ROIcanvas, p4, 3, cv::Scalar(0, 69, 255), 1);if (debug) circle(ROIcanvas, p4, 63, cv::Scalar(0, 169, 255), 1);if (debug) rectangle(ROIcanvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);rectangle(canvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);if (debug) printf("---------------****------ roiF  p1=【%d, %d】, p2=【%d, %d】\n", p1.x, p1.y, p2.x, p2.y);if (debug) printf("---------------****------ roiF  p3=【%d, %d】, p4=【%d, %d】\n", p3.x, p3.y, p4.x, p4.y);if (debug) printf("---------------****------ roiF  midP=【%f, %f】\n", midP.x, midP.y);if (debug) imshow("ROI", ROIcanvas);if (debug) imshow("ROI_canvas", canvas);//ROIcanvas.copyTo(canvas);return result;
}

 调用main:

//两弧线夹悬空的圆弧  返回五点+骨干点集   定"L"型管相贯线水平用
int mainTwoArcsClipTheHangingArc() {bool flag;//std::string filePath = "../../../../Log08141641/TestImg/src";std::string filePath = "E://vsproject//压力罐\\img\\L型管定水平";string resPath = "/output";//string resPath = filePath + "./output";cv::Point tlP = cv::Point(500, 292);cv::Point brP = cv::Point(750, 677);//cv::Rect ROI = cv::Rect(0, 0, 0, 0);//cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);//cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);//cv::Rect ROI = cv::Rect(539, 218, 113, 513);cv::Point top(90, 90);cv::Point bottom(90, 90);cv::Point p3(90, 90);cv::Point p4(90, 90);cv::Point2f midP(90, 90);int outMidY;cv::Mat canvas;PTank_imgProcess m_ImageProcessing;ofstream ofs("log.txt", ios::out);if (ofs){ofs.clear();ofs << "日志启动" << endl;}std::vector<cv::Point> allPntList;std::vector<cv::Point> tPntList;std::vector<cv::Point> bPntList;std::vector<cv::Point> mPntList;vector<string> path_name;bool   getROI = true;bool   lianxu = false; //循环测试if (!lianxu){string name = cv::format("\\Image_20240627151133378.png");string path = filePath + name;cv::Mat src = cv::imread(path);src.copyTo(canvas);cv::namedWindow("main_OriginalIMG", cv::RECURS_FILTER);cvSetMouseCallback("main_OriginalIMG", on_mouse_singleClick, 0);cv::imshow("main_OriginalIMG", src);//cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);if (getROI) ROI = getROIFromString(name);bool flag = m_ImageProcessing.twoArcsClipTheHangingArc_ROI(src, ROI, top, bottom, midP, p3, p4, allPntList, canvas, true);m_ImageProcessing.By4Pnt_SplitPLst_1to3(canvas, top, bottom, p3, p4, allPntList, tPntList, bPntList, mPntList, canvas, true);cout << "\nmain ==== flag " << flag << endl;if (flag) {cout << "top = " << top.x << " " << top.y << endl;cout << "bottom = " << bottom.x << " " << bottom.y << endl;cout << "midP = " << midP.x << " " << midP.y << endl;}canvas.copyTo(src);//cout << "\nmain ==== i " << endl;circle(canvas, top, 63, cv::Scalar(0, 69, 255), 1);circle(canvas, bottom, 63, cv::Scalar(0, 69, 255), 1);cv::putText(src, to_string(flag), cv::Point(src.cols / 2 - 20, src.rows / 2 - 65), cv::FONT_HERSHEY_COMPLEX, 1.75, cv::Scalar(255, 135, 160), 3);cv::namedWindow("main-结果图src", cv::RECURS_FILTER);cvSetMouseCallback("main-结果图src", on_mouse_singleClick, 0);cv::imshow("main-结果图src", src);cv::namedWindow("main-canvas", cv::RECURS_FILTER);cvSetMouseCallback("main-canvas", on_mouse_singleClick, 0);cv::imshow("main-canvas", canvas);}else{vector<string> path_name;getAllFiles(filePath, path_name);cout << "path_name.size()=" << path_name.size() << endl;int number = 1;for (auto i : path_name){//cout << i.size() << endl;if (i.size() == 7) continue;if (i.find(".log") != std::string::npos) continue;if (i.find("png") == std::string::npos && i.find("bmp") == std::string::npos && i.find("jpg") == std::string::npos) continue;std::string path11 = filePath + "\\" + i;cv::Mat src = cv::imread(path11);//cv::Mat src = cv::imread(filePath + "\\" + i);cout << endl << "number【" << number << "】src path=" << i << " ;" << endl;src.copyTo(canvas);cv::imshow("main_OriginalIMG", src);//将结果图写入文件方便查看结果int len = filePath.length();//i = i.substr(i.find_last_of('\\') + 1, len);cout << "i=" << i << ", path11=" << path11 << endl;int time_start = clock();int time_end = clock();cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);//cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);if (getROI) ROI = getROIFromString(i);bool flag = m_ImageProcessing.twoArcsClipTheHangingArc_ROI(src, ROI, top, bottom, midP, p3, p4, allPntList, canvas, false);m_ImageProcessing.By4Pnt_SplitPLst_1to3(canvas, top, bottom, p3, p4, allPntList, tPntList, bPntList, mPntList, canvas, false);time_end = clock();printf("\n耗时 %d ms \n", time_end - time_start);cout << "\nmain ==== flag " << flag << endl;if (flag) {cout << "top = " << top.x << " " << top.y << endl;cout << "bottom = " << bottom.x << " " << bottom.y << endl;cout << "midP = " << midP.x << " " << midP.y << endl;}canvas.copyTo(src);cv::putText(src, to_string(flag), cv::Point(src.cols / 2 - 20, src.rows / 2 - 65), cv::FONT_HERSHEY_COMPLEX, 1.75, cv::Scalar(255, 135, 160), 3);cv::imshow("main-结果图src", src);cv::imshow("main-canvas", canvas);//将结果图写入文件方便查看结果char*  filePath_ = new char[len + 1];strcpy(filePath_, filePath.c_str());len = filePath.length();char*  resPath_ = new char[len + 1];strcpy(resPath_, resPath.c_str());//i.erase(0, strlen(filePath_) - strlen(resPath_) - 2);string out = filePath + resPath;cout << "\nmain ==== i " << i << endl;out.append("\\").append(i);cout << "number【" << number << "】res path=" << out << endl;cv::imwrite(out, src);number++;cout << "path_name.size() = " << path_name.size() << endl;cout << "*********************************************************************************************************************" << endl;cv::waitKey(10);}cout << "循环结束!!! main " << endl;}ofs.close();cv::waitKey(0);system("Pause");return 0;
}

传入原图和模板图,返回vector

	/*//泡泡cv::Mat img, 原图cv::Rect ROI, cv::Mat imgTemplate:模板图片(无泡泡的图)cv::Mat &canvas,效果图可视化*/bool DetectingBubble(const cv::Mat imgOriginal, cv::Mat imgTemplate, std::vector<cv::Rect> &bubbles, cv::Mat &canvas, bool debug = false);bool DetectingBubble_ROI(cv::Mat img, cv::Mat imgTemplate, std::vector<cv::Rect> &bubbles, cv::Rect ROI, cv::Mat &canvas, bool debug = false);
bool ImageProcessing::DetectingBubble_ROI(cv::Mat img, cv::Mat imgTemplate, std::vector<cv::Rect> &bubbles, cv::Rect ROI, cv::Mat & canvas, bool debug)
{cout << __FUNCTION__ << endl;int endRes = 0;bool result = false;img.copyTo(canvas);bubbles.clear();cv::Mat imgOriginal;bool ROI_flag;//是否有给信息区cv::Point ROI_tl = cv::Point2i(ROI.x, ROI.y);cv::Point ROI_br = cv::Point2i(ROI.x + ROI.width, ROI.y + ROI.height);if (ROI_tl == cv::Point(0, 0) && ROI_br == cv::Point(0, 0) || ROI.width == 0 || ROI.height == 0){img.copyTo(imgOriginal);ROI_flag = false;}else{if (ROI_tl.x > ROI_br.x || ROI_tl.y > ROI_br.y)//信息区两点疑似传反{printf("信息区两点疑似传反!");return false;}if (ROI_tl.x < 0 || ROI_br.x > img.cols || ROI_tl.y < 0 || ROI_br.y > img.rows)//信息区的框选超出图像范围{printf("信息区的框选超出图像范围!");return false;}if (abs(ROI_tl.x - ROI_br.x) > img.cols || abs(ROI_tl.y - ROI_br.y) > img.rows)//信息区大小超出图像大小{printf("信息区大小超出图像大小!");return false;}//此时不合法的ROI都已提前返回falsecv::Rect roi(ROI_tl.x, ROI_tl.y, ROI_br.x - ROI_tl.x, ROI_br.y - ROI_tl.y);imgOriginal = img(roi);	//裁剪出的ROI区域放于imgOriginalimgTemplate = imgTemplate(roi);ROI_flag = true;}result = DetectingBubble(imgOriginal, imgTemplate, bubbles, canvas, debug);//调用识别算法//if (debug) printf("-------------------------------------****------ roiF  top=【%d, %d】, bottom=【%d, %d】\n", top.x, top.y, bottom.x, bottom.y);img.copyTo(canvas);//调试时注释掉cv::Mat t1;canvas.convertTo(t1, -1, 200 / 100.0, 0 + 55);//if (debug) cv::imshow("线性变换0", t1);t1.copyTo(canvas);if (result){endRes = 1;cv::putText(canvas, "true", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);//for (int i = 0; i < bubbles.size(); i++) {//	//bubbles.at(i).tl.x = bubbles.at(i).tl.x + ROI_tl.x;//	//bubbles.at(i).tl.y = bubbles.at(i).tl.y + ROI_tl.y;//	//bubbles.at(i).br.x = bubbles.at(i).br.x + ROI_tl.x;//	//bubbles.at(i).br.y = bubbles.at(i).br.y + ROI_tl.y;//	cv::Rect curBR = bubbles.at(i);//	bubbles.at(i).x = bubbles.at(i).x + ROI_tl.x;//	bubbles.at(i).y = bubbles.at(i).y + ROI_tl.y;//	//curBR.tl.x = bubbles.at(i).tl.x + ROI_tl.x;//	//curBR.tl.y = bubbles.at(i).tl.y + ROI_tl.y;//	//curBR.br.x = bubbles.at(i).br.x + ROI_tl.x;//	//curBR.br.y = bubbles.at(i).br.y + ROI_tl.y;//}for (int i = 0; i < bubbles.size(); i++) {//可视化bubbles.at(i).x = bubbles.at(i).x + ROI_tl.x;bubbles.at(i).y = bubbles.at(i).y + ROI_tl.y;cv::Rect curBR = bubbles.at(i);cv::rectangle(canvas, curBR.tl(), curBR.br(), cv::Scalar(0, 255, 0), 1);cv::putText(canvas, to_string(i), curBR.br(), cv::FONT_HERSHEY_COMPLEX, 0.45, cv::Scalar(55, 35, 160), 1);}}else{cv::putText(canvas, "false", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);}cv::Mat ROIcanvas;img.copyTo(ROIcanvas);if (debug) rectangle(ROIcanvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);rectangle(canvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);if (debug) imshow("ROI", ROIcanvas);if (debug) imshow("ROI_canvas", canvas);//ROIcanvas.copyTo(canvas);return result;
}

 调用main:

//泡泡  OneSideSquare_ROI
int main/*pp*/() {bool flag;std::string filePath = "../../../../泡泡/0708/6000";//std::string filePath = "../../../../泡泡/0708/20000";string resPath = "/output";//string resPath = filePath + "./output";cv::Point tlP = cv::Point(491, 50);cv::Point brP = cv::Point(1596, 760);tlP = cv::Point(1, 296);brP = cv::Point(1160, 2278);tlP = cv::Point(190, 0);brP = cv::Point(840, 1024);//cv::Rect ROI = cv::Rect(0, 0, 0, 0);//cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);//cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);//cv::Rect ROI = cv::Rect(639, 188, 125, 569);cv::Point top(90, 90);cv::Point bottom(90, 90);cv::Point2f midP(90, 90);int outMidY;cv::Mat canvas;ImageProcessing m_ImageProcessing;ofstream ofs("log.txt", ios::out);if (ofs){ofs.clear();ofs << "日志启动" << endl;}std::vector<cv::Rect> bubbles;//泡泡集合vector<Picture_set> img_buf;vector<string> path_name;//cv::Mat templ = cv::imread(filePath + cv::format("\\屏幕截图(13).png"));//模板图的灰度图cv::Mat templ = cv::imread(filePath + cv::format("\\Image_20240708175744959.png"));//6000bool   getROI = !true;bool   lianxu = false; //循环测试if (lianxu){std::string name = cv::format("\\Image_20240708175747311.png");string path = filePath + name;cv::Mat src = cv::imread(path);src.copyTo(canvas);cv::namedWindow("main_OriginalIMG", cv::NORMCONV_FILTER);cvSetMouseCallback("main_OriginalIMG", on_mouse_singleClick, 0);cv::imshow("main_OriginalIMG", src);cv::imshow("templ", templ);//cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);if (getROI) {ROI = getROIFromString(name);}//cv::Mat imgCur = src - templ;imgCur = imgOriginal - imgTemplate;//if (1) cv::imshow("减去模板图后", imgCur);bool flag = m_ImageProcessing.DetectingBubble_ROI(src, templ, bubbles, ROI, canvas, true);cout << "\nmain ==== flag " << flag << endl;if (flag) {cout << "top = " << top.x << " " << top.y << endl;cout << "bottom = " << bottom.x << " " << bottom.y << endl;}canvas.copyTo(src);//cout << "\nmain ==== i " << endl;circle(canvas, top, 63, cv::Scalar(0, 69, 255), 1);circle(canvas, bottom, 63, cv::Scalar(0, 69, 255), 1);cv::putText(src, to_string(flag), cv::Point(src.cols / 2 - 20, src.rows / 2 - 65), cv::FONT_HERSHEY_COMPLEX, 1.75, cv::Scalar(255, 135, 160), 3);cv::namedWindow("main-结果图src", cv::NORMCONV_FILTER);cvSetMouseCallback("main-结果图src", on_mouse_singleClick, 0);cv::imshow("main-结果图src", src);cv::namedWindow("main-canvas", cv::NORMCONV_FILTER);cvSetMouseCallback("main-canvas", on_mouse_singleClick, 0);cv::imshow("main-canvas", canvas);}else{vector<string> path_name;getAllFiles(filePath, path_name);cout << "path_name.size()=" << path_name.size() << endl;int number = 1;for (auto i : path_name){//cout << i.size() << endl;if (i.size() == 7) continue;if (i.find("output") != std::string::npos) continue;if (i.find(".log") != std::string::npos) continue;if (i.find(".txt") != std::string::npos) continue;if (i.find("png") == std::string::npos && i.find("bmp") == std::string::npos && i.find("jpg") == std::string::npos) continue;//if (i.find("_202404220930171") == std::string::npos) continue;std::string name = i;std::string path11 = filePath + "\\" + i;cv::Mat src = cv::imread(path11);//cv::Mat src = cv::imread(filePath + "\\" + i);cout << endl << "number【" << number << "】src path=" << i << " ;" << endl;src.copyTo(canvas);cv::imshow("main_OriginalIMG", src);//将结果图写入文件方便查看结果int len = filePath.length();//i = i.substr(i.find_last_of('\\') + 1, len);cout << "i=" << i << ", path11=" << path11 << endl;int time_start = clock();int time_end = clock();cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);if (getROI) {ROI = getROIFromString(name);}bool flag = m_ImageProcessing.DetectingBubble_ROI(src, templ, bubbles, ROI, canvas, false);time_end = clock();printf("\n耗时 %d ms \n", time_end - time_start);cout << "\nmain ==== flag " << flag << endl;if (flag) {cout << "top = " << top.x << " " << top.y << endl;cout << "bottom = " << bottom.x << " " << bottom.y << endl;}canvas.copyTo(src);//cv::putText(src, to_string(number - 1), { cv::Point(250, 250) }, cv::FONT_HERSHEY_COMPLEX, 8, cv::Scalar(255, 255, 255), 5);cv::putText(src, to_string(flag), cv::Point(src.cols / 2 - 20, src.rows / 2 - 65), cv::FONT_HERSHEY_COMPLEX, 1.75, cv::Scalar(255, 135, 160), 3);cv::namedWindow("main-结果图src", cv::NORMCONV_FILTER);cv::imshow("main-结果图src", src);cv::namedWindow("main-canvas", cv::NORMCONV_FILTER);cv::imshow("main-canvas", canvas);//将结果图写入文件方便查看结果char*  filePath_ = new char[len + 1];strcpy(filePath_, filePath.c_str());len = filePath.length();char*  resPath_ = new char[len + 1];strcpy(resPath_, resPath.c_str());//i.erase(0, strlen(filePath_) - strlen(resPath_) - 2);string out = filePath + resPath;cout << "\nmain ==== i " << i << endl;out.append("\\").append(i);cout << "number【" << number << "】res path=" << out << endl;cv::imwrite(out, src);number++;cout << "path_name.size() = " << path_name.size() << endl;cout << "*********************************************************************************************************************" << endl;cv::waitKey(1);}cout << "循环结束!!! main " << endl;}ofs.close();cv::waitKey(0);system("Pause");return 0;
}

***识别接口开头模板***

{bool result = false;if (imgOriginal.empty()) {printf("传入图像为空,直接返回false!!!! \n");return false;}imgOriginal.copyTo(canvas);top = cv::Point(0, 0);bottom = cv::Point(0, 0);midP = cv::Point(0, 0);cv::Mat imgGray;if (imgOriginal.type() != CV_8UC1)cv::cvtColor(imgOriginal, imgGray, cv::COLOR_BGR2GRAY);else imgOriginal.copyTo(imgGray);//if (1) {//	cv::Mat imgMedianBlur;//	cv::medianBlur(imgGray, imgMedianBlur, 3);//	if (debug) cv::imshow("imgMedianBlur", imgMedianBlur);//	imgMedianBlur.copyTo(imgGray);//}cv::Mat close;cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(7, 5));cv::morphologyEx(imgGray, close, cv::MORPH_CLOSE, kernel);if (debug) cv::imshow("闭运算", close);cv::Mat thresholdMat;cv::adaptiveThreshold(close, thresholdMat, 255, cv::ADAPTIVE_THRESH_GAUSSIAN_C, cv::THRESH_BINARY, 85, -15);if (debug) cv::imshow("threshold", thresholdMat);//一个不为0的像素都没有,即全黑时,直接返回falseint iVal255 = cv::countNonZero(thresholdMat);if (!iVal255) return false;std::vector<std::vector<cv::Point>> contours;std::vector<cv::Vec4i> hierarchy;std::vector<std::vector<cv::Point>>::iterator k;cv::findContours(thresholdMat, contours, hierarchy, cv::RETR_EXTERNAL, CV_RETR_LIST);if (contours.size() <= 0)//图为全黑时{std::cout << "contours.size() <= 0";return false;}if (debug) printf("图像处理后 检测到的轮廓数 contours.size() = %d  \n", contours.size());int remainNum = 0;//剩余的轮廓数cv::Mat  tmpMat = cv::Mat(thresholdMat.rows, thresholdMat.cols, CV_8UC1, cv::Scalar(0, 0, 0));//画出轮廓;int  count = 0;for (k = contours.begin(); k != contours.end(); ++k, count++) //删除小连通域的{std::vector<cv::Point> curContours = *k;if (curContours.size() < 40) continue;remainNum++;cv::drawContours(tmpMat, contours, count, cv::Scalar(255, 255, 255), -1, CV_AA, hierarchy); //用全黑色填充}if (debug) cv::imshow("tmpMat", tmpMat);if (debug) printf("删减后 剩余的轮廓数 remainNum = %d \n", remainNum);if (remainNum == 0)//图为全黑时{std::cout << "contours.size() <= 0";return false;}//------------------------------------------------------------------------------------------------------------------------------------//提取骨干点集std::vector<cv::Point> bright_point;//max点std::vector<int> bright_value;//max像素值//bright_point = extrectBackbone(tmpMat, bright_value);if (1) {if (debug) cout << "tmpMat.size() =" << tmpMat.size() << std::endl;int splitRow = tmpMat.rows / 2 - 5;cv::Mat tmpMatU, tmpMatD;tmpMat.rowRange(0, splitRow).copyTo(tmpMatU);tmpMat.rowRange(splitRow, tmpMat.rows).copyTo(tmpMatD);cv::flip(tmpMatU, tmpMatU, 0);std::vector<cv::Point> bright_pointU;//max点std::vector<cv::Point> bright_pointD;//max点std::vector<int> bright_valueU;//max像素值std::vector<int> bright_valueD;//max像素值bright_pointU = extrectBackbone(tmpMatU, bright_valueU, 0);bright_pointD = extrectBackbone(tmpMatD, bright_valueD, 0);std::reverse(bright_pointU.begin(), bright_pointU.end());for (int i = 0; i < bright_pointU.size(); i++) {//把上半部分的骨干上下翻转回cv::Point curPoint = bright_pointU.at(i);if (curPoint.x != 0) curPoint.y = tmpMatU.rows - curPoint.y - 1;//if(debug) printf("将上半截骨干排序反转:第%d 行, 【%d, %d】 =============  \n", i, curPoint.x, curPoint.y);//curPoint.x = tmpMat.cols - curPoint.x;bright_point.push_back(curPoint);}std::vector<cv::Point> bright_pointD_new;for (int i = 0; i < bright_pointD.size(); i++) {cv::Point curPoint = bright_pointD.at(i);if (curPoint.x != 0) curPoint.y = splitRow + curPoint.y;bright_pointD_new.push_back(curPoint);}bright_pointD = bright_pointD_new;bright_point.insert(bright_point.end(), bright_pointD.begin(), bright_pointD.end());std::reverse(bright_valueU.begin(), bright_valueU.end());bright_value = bright_valueU;bright_value.insert(bright_value.end(), bright_valueD.begin(), bright_valueD.end());}//有效骨干个数过少,直接返回 false !!!!int vaildBackbone = 0;//有效骨干个数for (int i = 0; i < bright_point.size(); i++){cv::Point P = bright_point.at(i);if (P != cv::Point(0, 0)) vaildBackbone++;}if (debug) printf("有效骨干个数 vaildBackbone = %d \n", vaildBackbone);if (vaildBackbone <= 30){printf("有效骨干个数过少!!!!\n");return false;}if (debug) {printf("骨干点集更新前:\n");for (int i = 0; i < bright_point.size(); i++){cv::Point curPoint = bright_point.at(i);int curGray = bright_value.at(i);//printf("骨干点集更新前:第%d 行, 【%d, %d】 灰度值:%d \n", i, curPoint.x, curPoint.y, curGray);}}std::vector<cv::Point> tmpPoint;std::vector<int> tmpValue;for (int i = 0; i < bright_point.size(); i++) {cv::Point curPoint = bright_point.at(i);if (curPoint.x == 0 || curPoint.y == 0) continue;if (tmpMat.at<uchar>(curPoint) < 185) continue;//if (imgGray.at<uchar>(curPoint) < 185) continue;tmpPoint.push_back(curPoint);}bright_point = tmpPoint;//把无效点删掉if (0) {std::vector<cv::Point> rightmost;//激光最右点集//for (int row = 0; row < tmpMat.rows; row++)//for (int row = bright_point.at(0).y; row < bright_point.at(bright_point.size() - 1).y; row++)for (int i = 0; i < bright_point.size(); i++){int row = bright_point[i].y;//for (int col = bright_point.at(row).x; col < tmpMat.cols - 1; col++)//-1是为了防崩溃for (int col = bright_point.at(i).x; col < tmpMat.cols - 1 && col < bright_point.at(i).x + 70; col++)//-1是为了防崩溃{int pv = tmpMat.at<uchar>(row, col);//int pv = tmpMat.at<uchar>(row, col);if (pv != 0 && tmpMat.at<uchar>(row, col + 1) == 0)//激光最右点入列{if (!rightmost.empty() && rightmost.back().y == row) rightmost.pop_back();rightmost.push_back(cv::Point(col - 1, row));//break;}}}bright_point = rightmost;}if (debug) {printf("骨干点集更新后:\n");for (int i = 0; i < bright_point.size(); i++) {cv::Point curPoint = bright_point.at(i);printf("骨干点集更新后:第%d 行, 【%d, %d】 \n", i, curPoint.x, curPoint.y);}}if (debug) printf("有效骨干个数 bright_point.size() = %d \n", bright_point.size());if (bright_point.size() <= 30){printf("有效骨干个数过少!!!!\n");return false;}allPntList = bright_point;//可视化骨干点集cv::Mat newArcMat = cv::Mat::zeros(tmpMat.size(), CV_8UC1);for (int i = 0; i < bright_point.size(); i++){cv::Point P = cv::Point(bright_point.at(i).x, bright_point.at(i).y);newArcMat.at<uchar>(cv::Point(bright_point.at(i).x, bright_point.at(i).y)) = 255;}cv::Mat BowCurveMat;cv::Mat imgRGB_Begin;if (newArcMat.type() != CV_8UC1)cvtColor(newArcMat, imgRGB_Begin, cv::COLOR_RGB2GRAY);else newArcMat.copyTo(imgRGB_Begin);//重叠看效果cv::addWeighted(tmpMat, 0.5, imgRGB_Begin, 0.5, 0, BowCurveMat);//if (debug) cv::namedWindow("BowCurveMat", cv::WINDOW_NORMAL);if (debug) cv::imshow("BowCurveMat", BowCurveMat);result = true;// TODOreturn result;
}

相关文章:

ROI 接口便捷修改

传入的图片截取ROI后再进入识别接口 &#xff08;识别接口比ROI接口的函数参数少一个传入的ROI&#xff09; 无点只有点集 返回双点集 //平直冷侧翅片 bool ImageProcessingTest::straightColdSideFin_ROI(cv::Mat img, cv::Rect ROI, std::vector<cv::Point>& topL…...

jenkins打包java项目报错Error: Unable to access jarfile tlm-admin.jar

jenkins打包boot项目 自动重启脚本失败 查看了一下项目日志报错&#xff1a; Error: Unable to access jarfile tlm-admin.jar我检查了一下这个配置&#xff0c;感觉没有问题&#xff0c;包可以正常打&#xff0c; cd 到项目目录下面&#xff0c;手动执行这个sh脚本也是能正常…...

SQL Server设置端口:跨平台指南

在使用SQL Server时&#xff0c;设置或修改其监听的端口是确保数据库服务安全访问和高效管理的重要步骤。由于SQL Server可以部署在多种操作系统上&#xff0c;包括Windows、Linux和Docker容器等&#xff0c;因此设置端口的步骤和方法也会因平台而异。本文将为您提供一个跨平台…...

ActiveMQ-CVE-2023-46604

Apache ActiveMQ OpenWire 协议反序列化命令执行漏洞 OpenWire协议在ActiveMQ中被用于多语言客户端与服务端通信。在Apache ActvieMQ5.18.2版本以及以前&#xff0c;OpenWire协议通信过程中存在一处反序列化漏洞&#xff0c;该漏洞可以允许具有网络访问权限的远程攻击者通过操作…...

TensorBoard ,PIL 和 OpenCV 在深度学习中的应用

重要工具介绍 TensorBoard&#xff1a; 是一个TensorFlow提供的强大工具&#xff0c;用于可视化和理解深度学习模型的训练过程和结果。下面我将介绍TensorBoard的相关知识和使用方法。 TensorBoard 简介 TensorBoard是TensorFlow提供的一个可视化工具&#xff0c;用于&#x…...

【超音速 专利 CN117576413A】基于全连接网络分类模型的AI涂布抓边处理方法及系统

申请号CN202311568976.4公开号&#xff08;公开&#xff09;CN117576413A申请日2023.11.22申请人&#xff08;公开&#xff09;超音速人工智能科技股份有限公司发明人&#xff08;公开&#xff09;张俊峰&#xff08;总&#xff09;; 杨培文&#xff08;总&#xff09;; 沈俊羽…...

iPhone数据恢复篇:iPhone 数据恢复软件有哪些

问题&#xff1a;iPhone 15 最好的免费恢复软件是什么&#xff1f;我一直在寻找一个恢复程序来恢复从iPhone中意外删除的照片&#xff0c;联系人和消息&#xff0c;但是我有很多选择。 谷歌一下&#xff0c;你会发现许多付费或免费的iPhone数据恢复工具&#xff0c;声称它们可…...

Html5+Css3学习笔记

Html5 CSS3 一、概念 1.什么是html5 html: Hyper Text Markup Language ( 超文本标记语言) 文本&#xff1a;记事本 超文本&#xff1a; 文字、图片、音频、视频、动画等等&#xff08;网页&#xff09; html语言经过浏览器的编译显示成超文本 开发者使用5种浏览器&#xf…...

WPF学习(2) -- 样式基础

一、代码 <Window x:Class"学习.MainWindow"xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x"http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d"http://schemas.microsoft.com/expression/blend/2008&…...

独家揭秘!五大内网穿透神器,访问你的私有服务

本文精心筛选了五款炙手可热的内网穿透工具&#xff0c;它们各怀绝技&#xff0c;无论您是企业用户、独立开发者&#xff0c;还是技术探索者&#xff0c;这篇文章都物有所值&#xff0c;废话不多说&#xff0c;主角们即将上场。 目录 1. 巴比达 - 安全至上的企业护航者 2. 花…...

Ubuntu 编译和运行ZLMediaKit

摘要 本文描述了如何在Ubuntu上构建ZLMediaKIt项目源码&#xff0c;以及如何体验其WebRTC推流和播放功能。 实验环境 操作系统版本&#xff1a;Ubuntu 22.04.3 LTS gcc版本&#xff1a;11.4.0 g版本&#xff1a;11.4.0 依赖库安装 #让ZLMediaKit媒体服务器具备WebRTC流转发…...

基于JavaSpringBoot+Vue+uniapp微信小程序校园宿舍管理系统设计与实现

基于JavaSpringBootVueuniapp微信小程序实现校园宿舍管理系统设计与实现 目录 第一章 绪论 1.1 研究背景 1.2 研究现状 1.3 研究内容 第二章 相关技术介绍 2.1 Java语言 2.2 HTML网页技术 2.3 MySQL数据库 2.4 Springboot 框架介绍 2.5 VueJS介绍 2.6 ElementUI介绍…...

Hive的基本操作(创建与修改)

必备知识 数据类型 基本类型 类型写法字符char, varchar, string✔整数tinyint, smallint, int✔, bigint✔小数float, double, numeric(m,n), decimal(m,n)✔布尔值boolean✔时间date✔, timestamp✔ 复杂类型(集合类型) 1、数组&#xff1a;array<T> 面向用户提供…...

Linux开发讲课37--- ARM的22个常用概念

1. ARM中一些常见英文缩写解释 MSB&#xff1a;最高有效位&#xff1b; LSB&#xff1a;最低有效位&#xff1b; AHB&#xff1a;先进的高性能总线&#xff1b; VPB&#xff1a;连接片内外设功能的VLSI外设总线&#xff1b; EMC&#xff1a;外部存储器…...

7-1、2、3 IPFS介绍使用及浏览器交互(react+区块链实战)

7-1、2、3 IPFS介绍使用及浏览器交互&#xff08;react区块链实战&#xff09; 7-1 ipfs介绍7-2 IPFS-desktop使用7-3 reactipfs-api浏览器和ipfs交互 7-1 ipfs介绍 IPFS区块链上的文件系统 https://ipfs.io/ 这个网站本身是需要科学上网的 Ipfs是点对点的分布式系统 无限…...

CentOS 7 中出现 cannot open Packages database in /var/lib/rpm 错误

转载自:https://www.jianshu.com/p/423306f43e72 # 进入 rpmdb 所在目录 [roothostbase ~]# cd /var/lib/rpm [roothostbase rpm]# ls Basenames __db.001 __db.003 Group Name Packages Requirename Sigmd5 Conflictname __db.002 Dirnames Ins…...

【java深入学习第6章】深入解析Spring事件监听机制

在Spring框架中&#xff0c;事件监听机制是一个强大且灵活的功能&#xff0c;允许我们在应用程序中发布和监听事件。这种机制可以帮助我们实现松耦合的设计&#xff0c;使得不同模块之间的通信更加灵活和可维护。本文将详细介绍Spring的事件监听机制&#xff0c;并通过代码示例…...

Flask与Celery实现Python调度服务

文章目录 Flask与Celery实现Python调度服务一、前言1.组件2.场景说明3.环境 二、安装依赖1.安装Anaconda3.安装redis2.安装依赖包 三、具体实现1.目录结构2.业务流程3.配置文件4.Celery程序5.Flask程序6.测试脚本7.程序启动1&#xff09;Windows开发调试2&#xff09;Linux服务…...

Eureka应用场景和优势

Eureka是一款由Netflix开源的服务注册与发现框架&#xff0c;在微服务架构中扮演着至关重要的角色。以下是Eureka的应用场景和优势&#xff1a; Eureka的应用场景 Eureka主要应用于微服务架构中&#xff0c;特别是在大型、复杂的分布式系统中&#xff0c;用于管理和发现服务。…...

prompt第三讲-PromptTemplate

文章目录 前提回顾PromptTemplateprompt 模板定义以f-string渲染格式以mustache渲染格式以jinja2渲染格式直接实例化PromptTemplatePromptTemplate核心变量 prompt value生成invokeformat_prompt(不建议使用)format(不建议使用) batchstreamainvoke PromptTemplate核心方法part…...

《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》

在注意力分散、内容高度同质化的时代&#xff0c;情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现&#xff0c;消费者对内容的“有感”程度&#xff0c;正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中&#xff0…...

Linux云原生安全:零信任架构与机密计算

Linux云原生安全&#xff1a;零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言&#xff1a;云原生安全的范式革命 随着云原生技术的普及&#xff0c;安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测&#xff0c;到2025年&#xff0c;零信任架构将成为超…...

论文浅尝 | 基于判别指令微调生成式大语言模型的知识图谱补全方法(ISWC2024)

笔记整理&#xff1a;刘治强&#xff0c;浙江大学硕士生&#xff0c;研究方向为知识图谱表示学习&#xff0c;大语言模型 论文链接&#xff1a;http://arxiv.org/abs/2407.16127 发表会议&#xff1a;ISWC 2024 1. 动机 传统的知识图谱补全&#xff08;KGC&#xff09;模型通过…...

Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)

引言&#xff1a;为什么 Eureka 依然是存量系统的核心&#xff1f; 尽管 Nacos 等新注册中心崛起&#xff0c;但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制&#xff0c;是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...

C++中string流知识详解和示例

一、概览与类体系 C 提供三种基于内存字符串的流&#xff0c;定义在 <sstream> 中&#xff1a; std::istringstream&#xff1a;输入流&#xff0c;从已有字符串中读取并解析。std::ostringstream&#xff1a;输出流&#xff0c;向内部缓冲区写入内容&#xff0c;最终取…...

Web后端基础(基础知识)

BS架构&#xff1a;Browser/Server&#xff0c;浏览器/服务器架构模式。客户端只需要浏览器&#xff0c;应用程序的逻辑和数据都存储在服务端。 优点&#xff1a;维护方便缺点&#xff1a;体验一般 CS架构&#xff1a;Client/Server&#xff0c;客户端/服务器架构模式。需要单独…...

日常一水C

多态 言简意赅&#xff1a;就是一个对象面对同一事件时做出的不同反应 而之前的继承中说过&#xff0c;当子类和父类的函数名相同时&#xff0c;会隐藏父类的同名函数转而调用子类的同名函数&#xff0c;如果要调用父类的同名函数&#xff0c;那么就需要对父类进行引用&#…...

DeepSeek源码深度解析 × 华为仓颉语言编程精粹——从MoE架构到全场景开发生态

前言 在人工智能技术飞速发展的今天&#xff0c;深度学习与大模型技术已成为推动行业变革的核心驱动力&#xff0c;而高效、灵活的开发工具与编程语言则为技术创新提供了重要支撑。本书以两大前沿技术领域为核心&#xff0c;系统性地呈现了两部深度技术著作的精华&#xff1a;…...

Modbus RTU与Modbus TCP详解指南

目录 1. Modbus协议基础 1.1 什么是Modbus? 1.2 Modbus协议历史 1.3 Modbus协议族 1.4 Modbus通信模型 🎭 主从架构 🔄 请求响应模式 2. Modbus RTU详解 2.1 RTU是什么? 2.2 RTU物理层 🔌 连接方式 ⚡ 通信参数 2.3 RTU数据帧格式 📦 帧结构详解 🔍…...

高考志愿填报管理系统---开发介绍

高考志愿填报管理系统是一款专为教育机构、学校和教师设计的学生信息管理和志愿填报辅助平台。系统基于Django框架开发&#xff0c;采用现代化的Web技术&#xff0c;为教育工作者提供高效、安全、便捷的学生管理解决方案。 ## &#x1f4cb; 系统概述 ### &#x1f3af; 系统定…...