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都已提前返回false

		cv::Rect roi(ROI_tl.x, ROI_tl.y, ROI_br.x - ROI_tl.x, ROI_br.y - ROI_tl.y);
		imgOriginal = img(roi);	//裁剪出的ROI区域放于imgOriginal
		ROI_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都已提前返回false

		cv::Rect roi(ROI_tl.x, ROI_tl.y, ROI_br.x - ROI_tl.x, ROI_br.y - ROI_tl.y);
		imgOriginal = img(roi);	//裁剪出的ROI区域放于imgOriginal
		ROI_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);//第一次线性变换100
	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区域

	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]));
}

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

	/*
	//圆弧+直线  求内角
	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都已提前返回false

		cv::Rect roi(ROI_tl.x, ROI_tl.y, ROI_br.x - ROI_tl.x, ROI_br.y - ROI_tl.y);
		imgOriginal = img(roi);	//裁剪出的ROI区域放于imgOriginal
		ROI_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都已提前返回false

		cv::Rect roi(ROI_tl.x, ROI_tl.y, ROI_br.x - ROI_tl.x, ROI_br.y - ROI_tl.y);
		imgOriginal = img(roi);	//裁剪出的ROI区域放于imgOriginal
		ROI_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都已提前返回false

		cv::Rect roi(ROI_tl.x, ROI_tl.y, ROI_br.x - ROI_tl.x, ROI_br.y - ROI_tl.y);
		imgOriginal = img(roi);	//裁剪出的ROI区域放于imgOriginal
		ROI_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);//第一次线性变换100
	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;
		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都已提前返回false

		cv::Rect roi(ROI_tl.x, ROI_tl.y, ROI_br.x - ROI_tl.x, ROI_br.y - ROI_tl.y);
		imgOriginal = img(roi);	//裁剪出的ROI区域放于imgOriginal
		ROI_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都已提前返回false

		cv::Rect roi(ROI_tl.x, ROI_tl.y, ROI_br.x - ROI_tl.x, ROI_br.y - ROI_tl.y);
		imgOriginal = img(roi);	//裁剪出的ROI区域放于imgOriginal
		ROI_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都已提前返回false

		cv::Rect roi(ROI_tl.x, ROI_tl.y, ROI_br.x - ROI_tl.x, ROI_br.y - ROI_tl.y);
		imgOriginal = img(roi);	//裁剪出的ROI区域放于imgOriginal
		ROI_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偏差过大时返回的两点无效,则返回圆弧区域的中心y
	cv::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都已提前返回false

		cv::Rect roi(ROI_tl.x, ROI_tl.y, ROI_br.x - ROI_tl.x, ROI_br.y - ROI_tl.y);
		imgOriginal = img(roi);	//裁剪出的ROI区域放于imgOriginal
		ROI_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都已提前返回false

		cv::Rect roi(ROI_tl.x, ROI_tl.y, ROI_br.x - ROI_tl.x, ROI_br.y - ROI_tl.y);
		imgOriginal = img(roi);	//裁剪出的ROI区域放于imgOriginal
		ROI_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都已提前返回false

		cv::Rect roi(ROI_tl.x, ROI_tl.y, ROI_br.x - ROI_tl.x, ROI_br.y - ROI_tl.y);
		imgOriginal = img(roi);	//裁剪出的ROI区域放于imgOriginal
		ROI_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);//第一次线性变换100
	if (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都已提前返回false

		cv::Rect roi(ROI_tl.x, ROI_tl.y, ROI_br.x - ROI_tl.x, ROI_br.y - ROI_tl.y);
		imgOriginal = img(roi);	//裁剪出的ROI区域放于imgOriginal
		ROI_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;
}

相关推荐

  1. ROI 接口便捷修改

    2024-07-11 07:02:04       8 阅读
  2. ros2--服务接口

    2024-07-11 07:02:04       3 阅读
  3. 如何编辑和修改ROM,快速上手

    2024-07-11 07:02:04       15 阅读
  4. ROS2】实现自定义服务接口

    2024-07-11 07:02:04       34 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-11 07:02:04       7 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-11 07:02:04       7 阅读
  3. 在Django里面运行非项目文件

    2024-07-11 07:02:04       6 阅读
  4. Python语言-面向对象

    2024-07-11 07:02:04       9 阅读

热门阅读

  1. rknn部署rk3588

    2024-07-11 07:02:04       9 阅读
  2. 深入探索Apache Flink:流处理的艺术与实践

    2024-07-11 07:02:04       9 阅读
  3. python 之修改host配置

    2024-07-11 07:02:04       9 阅读
  4. 使用Python + Scrapy + Django构建企业级爬虫平台

    2024-07-11 07:02:04       12 阅读
  5. Elasticsearch 自定义评分和脚本评分

    2024-07-11 07:02:04       9 阅读
  6. CentOS 7 编译安装 sqlite3

    2024-07-11 07:02:04       7 阅读