ROI 接口便捷修改
传入的图片截取ROI后再进入识别接口
(识别接口比ROI接口的函数参数少一个传入的ROI)
无点只有点集
返回双点集
//平直冷侧翅片
bool ImageProcessingTest::straightColdSideFin_ROI(cv::Mat img, cv::Rect ROI, std::vector<cv::Point>& topList, std::vector<cv::Point>& bottomList, cv::Mat & canvas, bool debug)
{int endRes = 0;bool result = false;img.copyTo(canvas);//top = cv::Point(0, 0);//bottom = cv::Point(0, 0);cv::Mat imgOriginal;bool ROI_flag;//是否有给信息区cv::Point ROI_tl = cv::Point2i(ROI.x, ROI.y);cv::Point ROI_br = cv::Point2i(ROI.x + ROI.width, ROI.y + ROI.height);if (ROI_tl == cv::Point(0, 0) && ROI_br == cv::Point(0, 0) || ROI.width == 0 || ROI.height == 0){img.copyTo(imgOriginal);ROI_flag = false;}else{if (ROI_tl.x > ROI_br.x || ROI_tl.y > ROI_br.y)//信息区两点疑似传反{printf("信息区两点疑似传反!");return false;}if (ROI_tl.x < 0 || ROI_br.x > img.cols || ROI_tl.y < 0 || ROI_br.y > img.rows)//信息区的框选超出图像范围{printf("信息区的框选超出图像范围!");return false;}if (abs(ROI_tl.x - ROI_br.x) > img.cols || abs(ROI_tl.y - ROI_br.y) > img.rows)//信息区大小超出图像大小{printf("信息区大小超出图像大小!");return false;}//此时不合法的ROI都已提前返回falsecv::Rect roi(ROI_tl.x, ROI_tl.y, ROI_br.x - ROI_tl.x, ROI_br.y - ROI_tl.y);imgOriginal = img(roi); //裁剪出的ROI区域放于imgOriginalROI_flag = true;}result = straightColdSideFin(imgOriginal, topList, bottomList, canvas, debug);//调用识别算法if (debug) {for (int i = 0; i < topList.size(); i++) {cv::Point top = topList.at(i);top += ROI_tl;if (debug) printf("-------------------------------------****------ roiF top=【%d, %d】\n", top.x, top.y);}for (int i = 0; i < bottomList.size(); i++) {cv::Point bottom = bottomList.at(i);bottom += ROI_tl;if (debug) printf("-------------------------------------****------ roiF bottom=【%d, %d】\n", bottom.x, bottom.y);}}//if (debug) printf("-------------------------------------****------ roiF top=【%d, %d】, bottom=【%d, %d】\n", top.x, top.y, bottom.x, bottom.y);//img.copyTo(canvas);x值和y值补上ROI左上点x和y//if (ROI_flag) {// if (Corner != cv::Point(0, 0))// {// Corner.x += ROI_tl.x;// Corner.y += ROI_tl.y;// }//}img.copyTo(canvas);//调试时注释掉if (result){cv::Point textP(6, 0);//演示用endRes = 1;for (int i = 0; i < topList.size(); i++) {topList.at(i) += ROI_tl;cv::Point top = topList.at(i);circle(canvas, top, 2, cv::Scalar(0, 69, 255), -1);cv::putText(canvas, to_string(i), top + textP, cv::FONT_HERSHEY_COMPLEX, 0.45, cv::Scalar(0, 69, 255), 1);//演示用}for (int i = 0; i < bottomList.size(); i++) {bottomList.at(i) += ROI_tl;cv::Point bottom = bottomList.at(i);circle(canvas, bottom, 2, cv::Scalar(255, 69, 0), -1);cv::putText(canvas, to_string(i), bottom + textP, cv::FONT_HERSHEY_COMPLEX, 0.45, cv::Scalar(255, 69, 0), 1);//演示用}printf("topList.size()=%d , bottomList.size()=%d \n", topList.size(), bottomList.size());cv::putText(canvas, "true", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);}else{cv::putText(canvas, "false", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);}cv::Mat ROIcanvas;img.copyTo(ROIcanvas);if (debug) {if (debug) printf("topList.size()=%d , bottomList.size()=%d \n", topList.size(), bottomList.size());for (int i = 0; i < topList.size(); i++) {cv::Point top = topList.at(i);circle(ROIcanvas, top, 3, cv::Scalar(0, 69, 255), 1);if (debug) printf("-------------------------------------****------ roiF top=【%d, %d】\n", top.x, top.y);}for (int i = 0; i < bottomList.size(); i++) {cv::Point bottom = bottomList.at(i);circle(ROIcanvas, bottom, 3, cv::Scalar(255, 69, 0), 1);if (debug) printf("-------------------------------------****------ roiF bottom=【%d, %d】\n", bottom.x, bottom.y);}}//if (debug) circle(ROIcanvas, top, 3, cv::Scalar(0, 69, 255), 1);//if (debug) circle(ROIcanvas, bottom, 3, cv::Scalar(0, 69, 255), 1);if (debug) rectangle(ROIcanvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);rectangle(canvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);//if (debug) printf("-------------------------------------****------ roiF top=【%d, %d】, bottom=【%d, %d】\n", top.x, top.y, bottom.x, bottom.y);if (debug) imshow("ROI", ROIcanvas);if (debug) imshow("ROI接口_canvas", canvas);//ROIcanvas.copyTo(canvas);return result;
}
调用main:
//平直冷侧翅片:straightColdSideFin_ROI
int main333() {bool flag = false;std::string filePath = "../img/straightColdSideFin/0616img";string resPath = "/output";//string resPath = filePath + "./output";cv::Point tlP = cv::Point(200, 0);cv::Point brP = cv::Point(950, 1024);std::vector<cv::Point> topList;std::vector<cv::Point> bottomList;cv::Mat canvas;ImageProcessingTest m_ImageProcessing;ofstream ofs("log.txt", ios::out);if (ofs){ofs.clear();ofs << "日志启动" << endl;}vector<string> path_name;bool lianxu = false; //循环测试if (lianxu){string path = filePath + cv::format("\\Image_20230614160744823.png");//string path = filePath + cv::format("\\Image_20230609111800152.png");//string path = filePath + cv::format("\\Image_20230601143638388.png");//string path = filePath + cv::format("\\Image_20230601143505168.png");//string path = filePath + cv::format("\\Image_20230609113049539.png");cv::Mat src = cv::imread(path);src.copyTo(canvas);cv::namedWindow("main_OriginalIMG", cv::RECURS_FILTER);cvSetMouseCallback("main_OriginalIMG", on_mouse_singleClick, 0);cv::imshow("main_OriginalIMG", src);//cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);bool flag = m_ImageProcessing.straightColdSideFin_ROI(src, ROI, topList, bottomList, canvas, true);cout << "\nmain ==== flag " << flag << endl;if (flag) {for (int i = 0; i < topList.size(); i++) {cv::Point top = topList.at(i);cout << "top = " << top.x << " " << top.y << endl;circle(canvas, top, 6, cv::Scalar(0, 69, 255), 1);}for (int i = 0; i < bottomList.size(); i++) {cv::Point bottom = bottomList.at(i);cout << "bottom = " << bottom.x << " " << bottom.y << endl;circle(canvas, bottom, 6, cv::Scalar(255, 69, 0), 1);}printf("topList.size()=%d , bottomList.size()=%d \n", topList.size(), bottomList.size());}canvas.copyTo(src);//cout << "\nmain ==== i " << endl;//cv::putText(src, to_string(flag), cv::Point(src.cols / 2 - 20, src.rows / 2 - 65), cv::FONT_HERSHEY_COMPLEX, 1.75, cv::Scalar(255, 135, 160), 3);cv::namedWindow("main-结果图src", cv::RECURS_FILTER);cvSetMouseCallback("main-结果图src", on_mouse_singleClick, 0);cv::imshow("main-结果图src", src);}else{vector<string> path_name;getAllFiles(filePath, path_name);cout << "path_name.size()=" << path_name.size() << endl;int number = 1;for (auto i : path_name){cv::Mat src = cv::imread(filePath + "\\" + i);cout << endl << "number【" << number << "】src path=" << i << " ;" << endl;src.copyTo(canvas);cv::imshow("main_OriginalIMG", src);//将结果图写入文件方便查看结果int len = filePath.length();//i = i.substr(i.find_last_of('\\') + 1, len);cout << "i=" << i << endl;int time_start = clock();int time_end = clock();//cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);bool flag = m_ImageProcessing.straightColdSideFin_ROI(src, ROI, topList, bottomList, canvas);time_end = clock();printf("\n耗时 %d ms \n", time_end - time_start);cout << "\nmain ==== flag " << flag << endl;if (flag) {for (int i = 0; i < topList.size(); i++) {cv::Point top = topList.at(i);cout << "top = " << top.x << " " << top.y << endl;}for (int i = 0; i < bottomList.size(); i++) {cv::Point bottom = bottomList.at(i);cout << "bottom = " << bottom.x << " " << bottom.y << endl;}printf("topList.size()=%d , bottomList.size()=%d \n", topList.size(), bottomList.size());}canvas.copyTo(src);//cv::putText(src, to_string(flag), cv::Point(src.cols / 2 - 20, src.rows / 2 - 65), cv::FONT_HERSHEY_COMPLEX, 1.75, cv::Scalar(255, 135, 160), 3);cv::imshow("main-结果图src", src);cv::waitKey(10);//将结果图写入文件方便查看结果char* filePath_ = new char[len + 1];strcpy(filePath_, filePath.c_str());len = filePath.length();char* resPath_ = new char[len + 1];strcpy(resPath_, resPath.c_str());//i.erase(0, strlen(filePath_) - strlen(resPath_) - 2);string out = filePath + resPath;cout << "\nmain ==== i " << i << endl;out.append("\\").append(i);cout << "number【" << number << "】res path=" << out << endl;cv::imwrite(out, src);number++;cout << "path_name.size() = " << path_name.size() << endl;cout << "*********************************************************************************************************************" << endl;if (number == path_name.size()) break;}}cout << "main 循环结束!!!" << endl;ofs.close();cv::waitKey(0);system("Pause");return 0;
}
单点
返回只有单点
bool ImageProcess::arcPlusLine_ROI(cv::Mat img, cv::Rect ROI, cv::Point & top, cv::Mat & canvas, bool debug)
{int endRes = 0;bool result = false;img.copyTo(canvas);top = cv::Point(0, 0);cv::Mat imgOriginal;bool ROI_flag;//是否有给信息区cv::Point ROI_tl = cv::Point2i(ROI.x, ROI.y);cv::Point ROI_br = cv::Point2i(ROI.x + ROI.width, ROI.y + ROI.height);if (ROI_tl == cv::Point(0, 0) && ROI_br == cv::Point(0, 0) || ROI.width == 0 || ROI.height == 0){img.copyTo(imgOriginal);ROI_flag = false;}else{if (ROI_tl.x > ROI_br.x || ROI_tl.y > ROI_br.y)//信息区两点疑似传反{printf("信息区两点疑似传反!");return false;}if (ROI_tl.x < 0 || ROI_br.x > img.cols || ROI_tl.y < 0 || ROI_br.y > img.rows)//信息区的框选超出图像范围{printf("信息区的框选超出图像范围!");return false;}if (abs(ROI_tl.x - ROI_br.x) > img.cols || abs(ROI_tl.y - ROI_br.y) > img.rows)//信息区大小超出图像大小{printf("信息区大小超出图像大小!");return false;}//此时不合法的ROI都已提前返回falsecv::Rect roi(ROI_tl.x, ROI_tl.y, ROI_br.x - ROI_tl.x, ROI_br.y - ROI_tl.y);imgOriginal = img(roi); //裁剪出的ROI区域放于imgOriginalROI_flag = true;}result = arcPlusLine(imgOriginal, top, canvas, debug);//调用识别算法if (debug) printf("-------------------------------------****------ roiF top=【%d, %d】\n", top.x, top.y);//img.copyTo(canvas);//img.copyTo(canvas);//调试时注释掉cv::Mat t1;//canvas.convertTo(t1, -1, 900 / 100.0, 200 - 100);//第一次线性变换100canvas.convertTo(t1, -1, 900 / 100.0, 200 - 100);//第一次线性变换100if (debug)cv::imshow("线性变换ROI", t1);t1.copyTo(canvas);if (result){endRes = 1;top += ROI_tl;cv::putText(canvas, "true", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);int w = 38;int thickness = 4;cv::Point curPoint = top;cv::line(canvas, curPoint, cv::Point(curPoint.x - w, curPoint.y), cv::Scalar(235, 135, 40), thickness);circle(canvas, top, 2, cv::Scalar(0, 69, 255), -1);circle(canvas, top, 63, cv::Scalar(0, 169, 255), 1);}else{cv::putText(canvas, "false", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);}cv::Mat ROIcanvas;img.copyTo(ROIcanvas);if (debug) circle(ROIcanvas, top, 3, cv::Scalar(0, 69, 255), 1);if (debug) circle(ROIcanvas, top, 63, cv::Scalar(0, 169, 255), 1);if (debug) rectangle(ROIcanvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);rectangle(canvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);if (debug) printf("-------------------------------------****------ roiF top=【%d, %d】 \n", top.x, top.y);if (debug) imshow("ROI", ROIcanvas);if (debug) imshow("ROI_canvas", canvas);//ROIcanvas.copyTo(canvas);//cv::Rect roi_(ROI_tl.x, ROI_tl.y, ROI_br.x - ROI_tl.x, ROI_br.y - ROI_tl.y);//if(!ROI_flag) canvas.copyTo(canvas);//else canvas = canvas(roi_); //裁剪出的ROI区域return result;
}
调用main:
//圆弧+直线 内角:arcPlusLine_ROI
int main/*arcl*/() {bool flag = false;//std::string filePath = "E://vsproject//WeldingLine//1219img//in//宁波金波";//std::string filePath = "E://vsproject//WeldingLine//1219img//in//宁波金波//down";std::string filePath = "E://vsproject//WeldingLine//1219img//in//宁波金波//LogImg";//std::string filePath = "../img/ThreadedRoundPipe/0530img";string resPath = "/output";//string resPath = filePath + "./output";cv::Point tlP = cv::Point(200, 340);cv::Point brP = cv::Point(950, 999);cv::Point top(90, 90);cv::Mat canvas;VisualInterface m_ImageProcessing;//ImageProcess m_ImageProcessing;ofstream ofs("log.txt", ios::out);if (ofs){ofs.clear();ofs << "日志启动" << endl;}vector<string> path_name;bool lineOnTop = true;bool getROI = !true;bool lianxu = false; //循环测试if (!lianxu){string name = cv::format("\\Img_2024_03_12_15_01_57_350_TYPE_12_ROI_486_64_257_474_src.png");string path = filePath + name;//string path = filePath + cv::format("\\Image_20240228115544906.bmp");cv::Mat src = cv::imread(path);src.copyTo(canvas);cv::namedWindow("main_OriginalIMG", cv::RECURS_FILTER);cvSetMouseCallback("main_OriginalIMG", on_mouse_singleClick, 0);cv::imshow("main_OriginalIMG", src);cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);//cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);if (getROI) ROI = getROIFromString(name);bool flag = m_ImageProcessing.arcPlusLine_ROI(src, ROI, top, canvas, lineOnTop, true);cout << "\nmain ==== flag " << flag << endl;if (flag) {cout << "top = " << top.x << " " << top.y << endl;}canvas.copyTo(src);//cout << "\nmain ==== i " << endl;circle(canvas, top, 63, cv::Scalar(0, 69, 255), 1);cv::putText(src, to_string(flag), cv::Point(src.cols / 2 - 20, src.rows / 2 - 165), cv::FONT_HERSHEY_COMPLEX, 1.75, cv::Scalar(255, 135, 160), 3);cv::namedWindow("main-结果图src", cv::RECURS_FILTER);cvSetMouseCallback("main-结果图src", on_mouse_singleClick, 0);cv::imshow("main-结果图src", src);}else{vector<string> path_name;getAllFiles(filePath, path_name);cout << "path_name.size()=" << path_name.size() << endl;int number = 1;for (auto i : path_name){if (i.find("_res") != std::string::npos ) continue;if (i.find("png") == std::string::npos && i.find("bmp") == std::string::npos && i.find("jpg") == std::string::npos) continue;cv::Mat src = cv::imread(filePath + "\\" + i);cout << endl << "number【" << number << "】src path=" << i << " ;" << endl;src.copyTo(canvas);cv::imshow("main_OriginalIMG", src);//将结果图写入文件方便查看结果int len = filePath.length();//i = i.substr(i.find_last_of('\\') + 1, len);cout << "i=" << i << endl;int time_start = clock();int time_end = clock();cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);//cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);if (getROI) ROI = getROIFromString(i);bool flag = m_ImageProcessing.arcPlusLine_ROI(src, ROI, top, canvas, lineOnTop, false);time_end = clock();printf("\n耗时 %d ms \n", time_end - time_start);cout << "\nmain ==== flag " << flag << endl;if (flag) {cout << "top = " << top.x << " " << top.y << endl;}canvas.copyTo(src);cv::putText(src, to_string(flag), cv::Point(src.cols / 2 - 20, src.rows / 2 - 65), cv::FONT_HERSHEY_COMPLEX, 1.75, cv::Scalar(255, 135, 160), 3);cv::imshow("main-结果图src", src);cv::waitKey(10);//将结果图写入文件方便查看结果char* filePath_ = new char[len + 1];strcpy(filePath_, filePath.c_str());len = filePath.length();char* resPath_ = new char[len + 1];strcpy(resPath_, resPath.c_str());//i.erase(0, strlen(filePath_) - strlen(resPath_) - 2);string out = filePath + resPath;cout << "\nmain ==== i " << i << endl;out.append("\\").append(i);cout << "number【" << number << "】res path=" << out << endl;cv::imwrite(out, src);number++;cout << "path_name.size() = " << path_name.size() << endl;cout << "*********************************************************************************************************************" << endl;if (number == path_name.size()) break;}}cout << "main 循环结束!!!" << endl;ofs.close();cv::waitKey(0);system("Pause");return 0;
}
cv::Rect getROIFromString(std::string str) {//图像名字格式:“SrcImg_2023_10_11_11_39_19_002_ROI_600_396_137_218_src.png”if (str.empty()) return cv::Rect(0, 0, 0, 0);using namespace std;const char *split = "_";char *p = strtok((char*)str.c_str(), split);std::vector<char*>data;while (p != NULL) {cout << p << endl;data.push_back(p);p = strtok(NULL, split);}//9 12;if (data.size() < 12)return cv::Rect();return cv::Rect(atoi(data[data.size() - 5]),atoi(data[data.size() - 4]),atoi(data[data.size() - 3]),atoi(data[data.size() - 2]));//return cv::Rect(// atoi(data[9]),// atoi(data[10]),// atoi(data[11]),// atoi(data[12]));
}
返回只有单点,传入(高/低曝光图)两张原图,返回单点(高曝光图和激光图结合时使用)
int ImageProcess::getPnt_2Dwith3D_MaiSi(cv::Mat imgHE, cv::Mat imgLE, cv::Mat & canvas, cv::Point & resPoint, bool &MaiSi_isTopPnt, cv::Rect ROI, bool debug)
{int endRes = 0;bool result = false;imgHE.copyTo(canvas);cv::addWeighted(imgHE, 0.5, imgLE, 0.5, 0, canvas);ImageProcess pd;cv::Mat imgHE_roi;cv::Mat imgOriginal;bool ROI_flag;//是否有给信息区cv::Point ROI_tl = cv::Point2i(ROI.x, ROI.y);cv::Point ROI_br = cv::Point2i(ROI.x + ROI.width, ROI.y + ROI.height);cv::Mat img;imgLE.copyTo(img);if (ROI_tl == cv::Point(0, 0) && ROI_br == cv::Point(0, 0)){img.copyTo(imgOriginal);imgHE.copyTo(imgHE_roi);ROI_flag = false;}else{if (ROI_tl.x > ROI_br.x || ROI_tl.y > ROI_br.y)//信息区两点疑似传反{printf("信息区两点疑似传反!");return false;}if (ROI_tl.x < 0 || ROI_br.x > img.cols || ROI_tl.y < 0 || ROI_br.y > img.rows)//信息区的框选超出图像范围{printf("信息区的框选超出图像范围!");return false;}if (abs(ROI_tl.x - ROI_br.x) > img.cols || abs(ROI_tl.y - ROI_br.y) > img.rows)//信息区大小超出图像大小{printf("信息区大小超出图像大小!");return false;}//此时不合法的ROI都已提前返回falsecv::Rect roi(ROI_tl.x, ROI_tl.y, ROI_br.x - ROI_tl.x, ROI_br.y - ROI_tl.y);imgOriginal = img(roi); //裁剪出的ROI区域放于imgOriginalimgHE_roi = imgHE(roi);ROI_flag = true;if (debug) {cv::Mat tmp;img.copyTo(tmp);rectangle(tmp, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);if (debug) cv::imshow("根据roi裁剪后进入识别的图", tmp);}}result = getPnt_2Dwith3D_MaiSi(imgHE_roi, imgOriginal, canvas, resPoint, MaiSi_isTopPnt, debug);cv::addWeighted(imgHE, 0.5, imgLE, 0.5, 0, canvas);//x值和y值补上ROI左上点x和yif (ROI_flag){if (resPoint != cv::Point(0, 0)){resPoint.x += ROI_tl.x;resPoint.y += ROI_tl.y;}}if (debug) std::cout << img.size() << imgOriginal.size() << std::endl;if (result){endRes = 1;cv::circle(canvas, resPoint, 3, cv::Scalar(0, 0, 255), -1, 8, 0);putText(canvas, "true", { cv::Point(250, 250) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);//putText(canvas, "EmbWare_Leg", { cv::Point(250, 350) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);if (MaiSi_isTopPnt) {putText(canvas, "isTopPnt", { resPoint + cv::Point(15, 5) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(195, 165, 255), 1);}else {putText(canvas, "isBotPnt", { resPoint + cv::Point(15, 5) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(155, 155, 255), 1);}Mark(canvas);}else{putText(canvas, "false", { cv::Point(250, 250) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);Mark(canvas);}rectangle(canvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);return endRes;
}
返回单点+上下翻转再进入识别
/*//圆弧+直线 求内角cv::Mat img, 原图cv::Rect ROI,cv::Point& Corner, 输出角点cv::Mat &canvas,效果图可视化bool lineOnTop = true,直线部分是否为较上端的角边,true则为是,false反之*/bool arcPlusLine(cv::Mat imgOriginal, cv::Point& Corner, cv::Mat &canvas, bool debug = false);bool arcPlusLine_ROI(cv::Mat img, cv::Rect ROI, cv::Point& Corner, cv::Mat &canvas, bool lineOnTop = true, bool debug = false);
bool ImageProcess::arcPlusLine_ROI(cv::Mat img, cv::Rect ROI, cv::Point & top, cv::Mat & canvas, bool lineOnTop, bool debug)
{int endRes = 0;bool result = false;img.copyTo(canvas);top = cv::Point(0, 0);cv::Mat imgOriginal;bool ROI_flag;//是否有给信息区cv::Point ROI_tl = cv::Point2i(ROI.x, ROI.y);cv::Point ROI_br = cv::Point2i(ROI.x + ROI.width, ROI.y + ROI.height);if (ROI_tl == cv::Point(0, 0) && ROI_br == cv::Point(0, 0) || ROI.width == 0 || ROI.height == 0){img.copyTo(imgOriginal);ROI_flag = false;}else{if (ROI_tl.x > ROI_br.x || ROI_tl.y > ROI_br.y)//信息区两点疑似传反{printf("信息区两点疑似传反!");return false;}if (ROI_tl.x < 0 || ROI_br.x > img.cols || ROI_tl.y < 0 || ROI_br.y > img.rows)//信息区的框选超出图像范围{printf("信息区的框选超出图像范围!");return false;}if (abs(ROI_tl.x - ROI_br.x) > img.cols || abs(ROI_tl.y - ROI_br.y) > img.rows)//信息区大小超出图像大小{printf("信息区大小超出图像大小!");return false;}//此时不合法的ROI都已提前返回falsecv::Rect roi(ROI_tl.x, ROI_tl.y, ROI_br.x - ROI_tl.x, ROI_br.y - ROI_tl.y);imgOriginal = img(roi); //裁剪出的ROI区域放于imgOriginalROI_flag = true;}if (lineOnTop) {result = arcPlusLine(imgOriginal, top, canvas, debug);//调用识别算法}else {cv::Mat fpMt;cv::flip(imgOriginal, fpMt, 0); // 上下翻转 x对称result = arcPlusLine(fpMt, top, canvas, debug);//调用识别算法if (result) {top.y = fpMt.rows - top.y - 1;}}cv::Mat lockCanvas = canvas.clone();if (debug) printf("-------------------------------------****------ roiF top=【%d, %d】\n", top.x, top.y);//img.copyTo(canvas);//img.copyTo(canvas);//调试时注释掉//cv::Mat t1;//canvas.convertTo(t1, -1, 900 / 100.0, 200 - 100);//第一次线性变换100//if (debug)cv::imshow("线性变换ROI", t1);//t1.copyTo(canvas);if (result){endRes = 1;top += ROI_tl;cv::putText(canvas, "true", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);int w = 38;int thickness = 4;cv::Point curPoint = top;cv::line(canvas, curPoint, cv::Point(curPoint.x - w, curPoint.y), cv::Scalar(235, 135, 40), thickness);circle(canvas, top, 2, cv::Scalar(0, 69, 255), -1);circle(canvas, top, 63, cv::Scalar(0, 169, 255), 1);}else{cv::putText(canvas, "false", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);}cv::Mat ROIcanvas;img.copyTo(ROIcanvas);if (debug) circle(ROIcanvas, top, 3, cv::Scalar(0, 69, 255), 1);if (debug) circle(ROIcanvas, top, 63, cv::Scalar(0, 169, 255), 1);if (debug) rectangle(ROIcanvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);rectangle(canvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);if (debug) printf("-------------------------------------****------ roiF top=【%d, %d】 \n", top.x, top.y);if (debug) imshow("ROI", ROIcanvas);if (debug) imshow("ROI_canvas", canvas);//ROIcanvas.copyTo(canvas);//cv::Rect roi_(ROI_tl.x, ROI_tl.y, ROI_br.x - ROI_tl.x, ROI_br.y - ROI_tl.y);//if(!ROI_flag) canvas.copyTo(canvas);//else canvas = canvas(roi_); //裁剪出的ROI区域lockCanvas.copyTo(canvas);return result;
}
调用main:
// 内角:arcPlusLine_ROI
int main/*arcl*/() {bool flag = false;std::string filePath = "E://vsproject//WeldingLine//1219img//in//宁波金波";//std::string filePath = "E://vsproject//WeldingLine//1219img//in//宁波金波//down";//std::string filePath = "../img/ThreadedRoundPipe/0530img";string resPath = "/output";//string resPath = filePath + "./output";cv::Point tlP = cv::Point(200, 340);cv::Point brP = cv::Point(950, 999);cv::Point top(90, 90);cv::Mat canvas;//VisualInterface m_ImageProcessing;ImageProcess m_ImageProcessing;ofstream ofs("log.txt", ios::out);if (ofs){ofs.clear();ofs << "日志启动" << endl;}vector<string> path_name;bool lineOnTop = true;bool lianxu = false; //循环测试if (lianxu){string path = filePath + cv::format("\\Image_20240304155500627.png");//string path = filePath + cv::format("\\Image_20240228115544906.bmp");cv::Mat src = cv::imread(path);src.copyTo(canvas);cv::namedWindow("main_OriginalIMG", cv::RECURS_FILTER);cvSetMouseCallback("main_OriginalIMG", on_mouse_singleClick, 0);cv::imshow("main_OriginalIMG", src);cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);//cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);bool flag = m_ImageProcessing.arcPlusLine_ROI(src, ROI, top, canvas, lineOnTop, true);cout << "\nmain ==== flag " << flag << endl;if (flag) {cout << "top = " << top.x << " " << top.y << endl;}canvas.copyTo(src);//cout << "\nmain ==== i " << endl;circle(canvas, top, 63, cv::Scalar(0, 69, 255), 1);cv::putText(src, to_string(flag), cv::Point(src.cols / 2 - 20, src.rows / 2 - 165), cv::FONT_HERSHEY_COMPLEX, 1.75, cv::Scalar(255, 135, 160), 3);cv::namedWindow("main-结果图src", cv::RECURS_FILTER);cvSetMouseCallback("main-结果图src", on_mouse_singleClick, 0);cv::imshow("main-结果图src", src);}else{vector<string> path_name;getAllFiles(filePath, path_name);cout << "path_name.size()=" << path_name.size() << endl;int number = 1;for (auto i : path_name){if (i.find("png") == std::string::npos && i.find("bmp") == std::string::npos && i.find("jpg") == std::string::npos) continue;cv::Mat src = cv::imread(filePath + "\\" + i);cout << endl << "number【" << number << "】src path=" << i << " ;" << endl;src.copyTo(canvas);cv::imshow("main_OriginalIMG", src);//将结果图写入文件方便查看结果int len = filePath.length();//i = i.substr(i.find_last_of('\\') + 1, len);cout << "i=" << i << endl;int time_start = clock();int time_end = clock();cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);//cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);bool flag = m_ImageProcessing.arcPlusLine_ROI(src, ROI, top, canvas, lineOnTop, false);time_end = clock();printf("\n耗时 %d ms \n", time_end - time_start);cout << "\nmain ==== flag " << flag << endl;if (flag) {cout << "top = " << top.x << " " << top.y << endl;}canvas.copyTo(src);cv::putText(src, to_string(flag), cv::Point(src.cols / 2 - 20, src.rows / 2 - 65), cv::FONT_HERSHEY_COMPLEX, 1.75, cv::Scalar(255, 135, 160), 3);cv::imshow("main-结果图src", src);cv::waitKey(10);//将结果图写入文件方便查看结果char* filePath_ = new char[len + 1];strcpy(filePath_, filePath.c_str());len = filePath.length();char* resPath_ = new char[len + 1];strcpy(resPath_, resPath.c_str());//i.erase(0, strlen(filePath_) - strlen(resPath_) - 2);string out = filePath + resPath;cout << "\nmain ==== i " << i << endl;out.append("\\").append(i);cout << "number【" << number << "】res path=" << out << endl;cv::imwrite(out, src);number++;cout << "path_name.size() = " << path_name.size() << endl;cout << "*********************************************************************************************************************" << endl;if (number == path_name.size()) break;}}cout << "main 循环结束!!!" << endl;ofs.close();cv::waitKey(0);system("Pause");return 0;
}
返回单点+1个点集+上下翻转再进入识别
bool PTank_imgProcess::arcPlusLine_ROI(cv::Mat img, cv::Rect ROI, cv::Point & top, std::vector<cv::Point>& allPntList, cv::Mat & canvas, bool lineOnTop, bool debug)
{int endRes = 0;bool result = false;img.copyTo(canvas);top = cv::Point(0, 0);cv::Mat imgOriginal;bool ROI_flag;//是否有给信息区cv::Point ROI_tl = cv::Point2i(ROI.x, ROI.y);cv::Point ROI_br = cv::Point2i(ROI.x + ROI.width, ROI.y + ROI.height);if (ROI_tl == cv::Point(0, 0) && ROI_br == cv::Point(0, 0) || ROI.width == 0 || ROI.height == 0){img.copyTo(imgOriginal);ROI_flag = false;}else{if (ROI_tl.x > ROI_br.x || ROI_tl.y > ROI_br.y)//信息区两点疑似传反{printf("信息区两点疑似传反!");return false;}if (ROI_tl.x < 0 || ROI_br.x > img.cols || ROI_tl.y < 0 || ROI_br.y > img.rows)//信息区的框选超出图像范围{printf("信息区的框选超出图像范围!");return false;}if (abs(ROI_tl.x - ROI_br.x) > img.cols || abs(ROI_tl.y - ROI_br.y) > img.rows)//信息区大小超出图像大小{printf("信息区大小超出图像大小!");return false;}//此时不合法的ROI都已提前返回falsecv::Rect roi(ROI_tl.x, ROI_tl.y, ROI_br.x - ROI_tl.x, ROI_br.y - ROI_tl.y);imgOriginal = img(roi); //裁剪出的ROI区域放于imgOriginalROI_flag = true;}cv::Mat lockCanvas;if (lineOnTop) {result = arcPlusLine(imgOriginal, top, allPntList, canvas, debug);//调用识别算法canvas.copyTo(lockCanvas);//for (int i = 0; i < allPntList.size(); i++) {// cv::line(lockCanvas, allPntList.at(i), cv::Point(allPntList.at(i).x - 3, allPntList.at(i).y), cv::Scalar(55, 195, 40), 1);//}}else {cv::Mat fpMt;cv::flip(imgOriginal, fpMt, 0); // 上下翻转 x对称result = arcPlusLine(fpMt, top, allPntList, canvas, debug);//调用识别算法canvas.copyTo(lockCanvas);if (result) {top.y = fpMt.rows - top.y - 1;for (int i = 0; i < allPntList.size(); i++) {//cv::line(lockCanvas, allPntList.at(i), cv::Point(allPntList.at(i).x - 3, allPntList.at(i).y), cv::Scalar(55, 195, 40), 1);allPntList.at(i).y = fpMt.rows - allPntList.at(i).y - 1;}}}if (debug) printf("-------------------------------------****------ roiF top=【%d, %d】\n", top.x, top.y);//img.copyTo(canvas);//img.copyTo(canvas);//调试时注释掉//cv::Mat t1;//canvas.convertTo(t1, -1, 900 / 100.0, 200 - 100);//第一次线性变换100//if (debug)cv::imshow("线性变换ROI", t1);//t1.copyTo(canvas);if (result){img.copyTo(canvas);endRes = 1;top += ROI_tl;for (int i = 0; i < allPntList.size(); i++) {allPntList.at(i) += ROI_tl;}cv::putText(canvas, "true", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);int w = 38;int thickness = 4;cv::Point curPoint = top;cv::line(canvas, curPoint, cv::Point(curPoint.x - w, curPoint.y), cv::Scalar(235, 135, 40), thickness);circle(canvas, top, 2, cv::Scalar(0, 69, 255), -1);circle(canvas, top, 63, cv::Scalar(0, 169, 255), 1);w = 3;for (int i = 0; i < allPntList.size(); i++) {cv::Point curPoint = allPntList.at(i);cv::line(canvas, curPoint, cv::Point(curPoint.x - w, curPoint.y), cv::Scalar(55, 195, 40), 1);}}else{cv::putText(canvas, "false", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);}cv::Mat ROIcanvas;img.copyTo(ROIcanvas);if (debug) circle(ROIcanvas, top, 3, cv::Scalar(0, 69, 255), 1);if (debug) circle(ROIcanvas, top, 63, cv::Scalar(0, 169, 255), 1);if (debug) rectangle(ROIcanvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);rectangle(canvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);if (debug) printf("-------------------------------------****------ roiF top=【%d, %d】 \n", top.x, top.y);if (debug) imshow("ROI", ROIcanvas);if (debug) imshow("ROI_canvas", canvas);//ROIcanvas.copyTo(canvas);//cv::Rect roi_(ROI_tl.x, ROI_tl.y, ROI_br.x - ROI_tl.x, ROI_br.y - ROI_tl.y);//if(!ROI_flag) canvas.copyTo(canvas);//else canvas = canvas(roi_); //裁剪出的ROI区域if (result) lockCanvas.copyTo(canvas);cv::putText(canvas, to_string(result), cv::Point(30, 65), cv::FONT_HERSHEY_COMPLEX, 1.75, cv::Scalar(255, 135, 160), 3);return result;
}
调用main:
// 内角:arcPlusLine_ROI 类似金波(金波优化版)
int main/*arcl*/() {bool flag = false;//std::string filePath = "E://vsproject//压力罐\\img\\类金波/top";std::string filePath = "E://vsproject//压力罐\\img\\类金波";//std::string filePath = "E://vsproject//压力罐\\img\\叶子";//std::string filePath = "../img/ThreadedRoundPipe/0530img";string resPath = "/output";//string resPath = filePath + "./output";cv::Point tlP = cv::Point(200, 340);cv::Point brP = cv::Point(950, 999);cv::Point top(90, 90);std::vector<cv::Point> allPntList;cv::Mat canvas;PTank_imgProcess m_ImageProcessing;//ImageProcess m_ImageProcessing;ofstream ofs("log.txt", ios::out);if (ofs){ofs.clear();ofs << "日志启动" << endl;}vector<string> path_name;bool lineOnTop = !true;bool getROI = true;bool lianxu = false; //循环测试if (!lianxu){string name = cv::format("\\Image_20240627151014832.png");string path = filePath + name;cv::Mat src = cv::imread(path);src.copyTo(canvas);cv::namedWindow("main_OriginalIMG", cv::RECURS_FILTER);cvSetMouseCallback("main_OriginalIMG", on_mouse_singleClick, 0);cv::imshow("main_OriginalIMG", src);cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);//cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);if (getROI) ROI = getROIFromString(name);bool flag = m_ImageProcessing.arcPlusLine_ROI(src, ROI, top, allPntList, canvas, lineOnTop, true);cout << "\nmain ==== flag " << flag << endl;if (flag) {cout << "top = " << top.x << " " << top.y << endl;}canvas.copyTo(src);//cout << "\nmain ==== i " << endl;circle(canvas, top, 63, cv::Scalar(0, 69, 255), 1);cv::putText(src, to_string(flag), cv::Point(src.cols / 2 - 20, src.rows / 2 - 165), cv::FONT_HERSHEY_COMPLEX, 1.75, cv::Scalar(255, 135, 160), 3);cv::namedWindow("main-结果图src", cv::RECURS_FILTER);cvSetMouseCallback("main-结果图src", on_mouse_singleClick, 0);cv::imshow("main-结果图src", src);}else{vector<string> path_name;getAllFiles(filePath, path_name);cout << "path_name.size()=" << path_name.size() << endl;int number = 1;for (auto i : path_name){if (i.find("_res") != std::string::npos) continue;if (i.find("png") == std::string::npos && i.find("bmp") == std::string::npos && i.find("jpg") == std::string::npos) continue;cv::Mat src = cv::imread(filePath + "\\" + i);cout << endl << "number【" << number << "】src path=" << i << " ;" << endl;src.copyTo(canvas);cv::imshow("main_OriginalIMG", src);//将结果图写入文件方便查看结果int len = filePath.length();//i = i.substr(i.find_last_of('\\') + 1, len);cout << "i=" << i << endl;int time_start = clock();int time_end = clock();cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);//cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);if (getROI) ROI = getROIFromString(i);bool flag = m_ImageProcessing.arcPlusLine_ROI(src, ROI, top, allPntList, canvas, lineOnTop, false);time_end = clock();printf("\n耗时 %d ms \n", time_end - time_start);cout << "\nmain ==== flag " << flag << endl;if (flag) {cout << "top = " << top.x << " " << top.y << endl;}canvas.copyTo(src);cv::putText(src, to_string(flag), cv::Point(src.cols / 2 - 20, src.rows / 2 - 65), cv::FONT_HERSHEY_COMPLEX, 1.75, cv::Scalar(255, 135, 160), 3);cv::imshow("main-结果图src", src);cv::waitKey(10);//将结果图写入文件方便查看结果char* filePath_ = new char[len + 1];strcpy(filePath_, filePath.c_str());len = filePath.length();char* resPath_ = new char[len + 1];strcpy(resPath_, resPath.c_str());//i.erase(0, strlen(filePath_) - strlen(resPath_) - 2);string out = filePath + resPath;cout << "\nmain ==== i " << i << endl;out.append("\\").append(i);cout << "number【" << number << "】res path=" << out << endl;cv::imwrite(out, src);number++;cout << "path_name.size() = " << path_name.size() << endl;cout << "*********************************************************************************************************************" << endl;if (number == path_name.size()) break;}}cout << "main 循环结束!!!" << endl;ofs.close();cv::waitKey(0);system("Pause");return 0;
}
双点
返回只有双点
bool ImageProcessingTest::ThreadedRoundPipe_ROI(cv::Mat img, cv::Rect ROI, cv::Point& top, cv::Point& bottom, cv::Mat & canvas, bool debug)
{int endRes = 0;bool result = false;img.copyTo(canvas);top = cv::Point(0, 0);bottom = cv::Point(0, 0);cv::Mat imgOriginal;bool ROI_flag;//是否有给信息区cv::Point ROI_tl = cv::Point2i(ROI.x, ROI.y);cv::Point ROI_br = cv::Point2i(ROI.x + ROI.width, ROI.y + ROI.height);if (ROI_tl == cv::Point(0, 0) && ROI_br == cv::Point(0, 0) || ROI.width == 0 || ROI.height == 0){img.copyTo(imgOriginal);ROI_flag = false;}else{if (ROI_tl.x > ROI_br.x || ROI_tl.y > ROI_br.y)//信息区两点疑似传反{printf("信息区两点疑似传反!");return false;}if (ROI_tl.x < 0 || ROI_br.x > img.cols || ROI_tl.y < 0 || ROI_br.y > img.rows)//信息区的框选超出图像范围{printf("信息区的框选超出图像范围!");return false;}if (abs(ROI_tl.x - ROI_br.x) > img.cols || abs(ROI_tl.y - ROI_br.y) > img.rows)//信息区大小超出图像大小{printf("信息区大小超出图像大小!");return false;}//此时不合法的ROI都已提前返回falsecv::Rect roi(ROI_tl.x, ROI_tl.y, ROI_br.x - ROI_tl.x, ROI_br.y - ROI_tl.y);imgOriginal = img(roi); //裁剪出的ROI区域放于imgOriginalROI_flag = true;}result = ThreadedRoundPipe(imgOriginal, top, bottom, canvas, debug);//调用识别算法if (debug) printf("-------------------------------------****------ roiF top=【%d, %d】, bottom=【%d, %d】\n", top.x, top.y, bottom.x, bottom.y);//img.copyTo(canvas);x值和y值补上ROI左上点x和y//if (ROI_flag) {// if (Corner != cv::Point(0, 0))// {// Corner.x += ROI_tl.x;// Corner.y += ROI_tl.y;// }//}img.copyTo(canvas);//调试时注释掉cv::Mat t1;//canvas.convertTo(t1, -1, 900 / 100.0, 200 - 100);//第一次线性变换100canvas.convertTo(t1, -1, 900 / 100.0, 200 - 100);//第一次线性变换100if (debug)cv::imshow("线性变换ROI", t1);t1.copyTo(canvas);if (result){endRes = 1;top += ROI_tl;bottom += ROI_tl;cv::putText(canvas, "true", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);int w = 38;int thickness = 4;cv::Point curPoint = top;cv::line(canvas, curPoint, cv::Point(curPoint.x - w, curPoint.y), cv::Scalar(235, 135, 40), thickness);curPoint = bottom;cv::line(canvas, curPoint, cv::Point(curPoint.x - w, curPoint.y), cv::Scalar(235, 135, 40), thickness);circle(canvas, top, 2, cv::Scalar(0, 69, 255), -1);circle(canvas, top, 63, cv::Scalar(0, 169, 255), 1);circle(canvas, bottom, 2, cv::Scalar(0, 69, 255), -1);circle(canvas, bottom, 43, cv::Scalar(255, 169, 0), 1);}else{cv::putText(canvas, "false", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);}cv::Mat ROIcanvas;img.copyTo(ROIcanvas);if (debug) circle(ROIcanvas, top, 3, cv::Scalar(0, 69, 255), 1);if (debug) circle(ROIcanvas, top, 63, cv::Scalar(0, 169, 255), 1);if (debug) circle(ROIcanvas, bottom, 3, cv::Scalar(0, 69, 255), 1);if (debug) circle(ROIcanvas, bottom, 63, cv::Scalar(0, 169, 255), 1);if (debug) rectangle(ROIcanvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);rectangle(canvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);if (debug) printf("-------------------------------------****------ roiF top=【%d, %d】, bottom=【%d, %d】\n", top.x, top.y, bottom.x, bottom.y);if (debug) imshow("ROI", ROIcanvas);if (debug) imshow("ROI_canvas", canvas);//ROIcanvas.copyTo(canvas);//cv::Rect roi_(ROI_tl.x, ROI_tl.y, ROI_br.x - ROI_tl.x, ROI_br.y - ROI_tl.y);//if(!ROI_flag) canvas.copyTo(canvas);//else canvas = canvas(roi_); //裁剪出的ROI区域return result;
}
调用main:
//螺纹圆管:ThreadedRoundPipe_ROI
int main222() {bool flag = false;//std::string filePath = "E:\\vsproject\\勋仪交接\\标克艾芬达暖水管/0529img";//std::string filePath = "../img/ThreadedRoundPipe/0530img";std::string filePath = "../img/ThreadedRoundPipe/0606img";string resPath = "/output";//string resPath = filePath + "./output";cv::Point tlP = cv::Point(200, 340);cv::Point brP = cv::Point(950, 999);cv::Point top(90, 90);cv::Point bottom(90, 90);cv::Mat canvas;ImageProcessingTest m_ImageProcessing;ofstream ofs("log.txt", ios::out);if (ofs){ofs.clear();ofs << "日志启动" << endl;}vector<string> path_name;bool lianxu = false; //循环测试if (!lianxu){//string path = filePath + cv::format("\\Image_20230606135229441.png");string path = filePath + cv::format("\\Image_20230606135308519.png");//string path = filePath + cv::format("\\Image_20230601143638388.png");//string path = filePath + cv::format("\\Image_20230601143505168.png");//string path = filePath + cv::format("\\Image_20230529095011455.png");cv::Mat src = cv::imread(path);src.copyTo(canvas);cv::namedWindow("main_OriginalIMG", cv::RECURS_FILTER);cvSetMouseCallback("main_OriginalIMG", on_mouse_singleClick, 0);cv::imshow("main_OriginalIMG", src);//cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);bool flag = m_ImageProcessing.ThreadedRoundPipe_ROI(src, ROI, top, bottom, canvas, true);cout << "\nmain ==== flag " << flag << endl;if (flag) {cout << "top = " << top.x << " " << top.y << endl;cout << "bottom = " << bottom.x << " " << bottom.y << endl;}canvas.copyTo(src);//cout << "\nmain ==== i " << endl;circle(canvas, top, 63, cv::Scalar(0, 69, 255), 1);circle(canvas, bottom, 63, cv::Scalar(0, 69, 255), 1);cv::putText(src, to_string(flag), cv::Point(src.cols / 2 - 20, src.rows / 2 - 65), cv::FONT_HERSHEY_COMPLEX, 1.75, cv::Scalar(255, 135, 160), 3);cv::namedWindow("main-结果图src", cv::RECURS_FILTER);cvSetMouseCallback("main-结果图src", on_mouse_singleClick, 0);cv::imshow("main-结果图src", src);}else{vector<string> path_name;getAllFiles(filePath, path_name);cout << "path_name.size()=" << path_name.size() << endl;int number = 1;for (auto i : path_name){cv::Mat src = cv::imread(filePath + "\\" + i);cout << endl << "number【" << number << "】src path=" << i << " ;" << endl;src.copyTo(canvas);cv::imshow("main_OriginalIMG", src);//将结果图写入文件方便查看结果int len = filePath.length();//i = i.substr(i.find_last_of('\\') + 1, len);cout << "i=" << i << endl;int time_start = clock();int time_end = clock();//cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);bool flag = m_ImageProcessing.ThreadedRoundPipe_ROI(src, ROI, top, bottom, canvas, false);time_end = clock();printf("\n耗时 %d ms \n", time_end - time_start);cout << "\nmain ==== flag " << flag << endl;if (flag) {cout << "top = " << top.x << " " << top.y << endl;cout << "bottom = " << bottom.x << " " << bottom.y << endl;}canvas.copyTo(src);cv::putText(src, to_string(flag), cv::Point(src.cols / 2 - 20, src.rows / 2 - 65), cv::FONT_HERSHEY_COMPLEX, 1.75, cv::Scalar(255, 135, 160), 3);cv::imshow("main-结果图src", src);cv::waitKey(10);//将结果图写入文件方便查看结果char* filePath_ = new char[len + 1];strcpy(filePath_, filePath.c_str());len = filePath.length();char* resPath_ = new char[len + 1];strcpy(resPath_, resPath.c_str());//i.erase(0, strlen(filePath_) - strlen(resPath_) - 2);string out = filePath + resPath;cout << "\nmain ==== i " << i << endl;out.append("\\").append(i);cout << "number【" << number << "】res path=" << out << endl;cv::imwrite(out, src);number++;cout << "path_name.size() = " << path_name.size() << endl;cout << "*********************************************************************************************************************" << endl;if (number == path_name.size()) break;}}cout << "main 循环结束!!!" << endl;ofs.close();cv::waitKey(0);system("Pause");return 0;
}
返回双点+1个点集
/*//矩形位置 返回双点+骨干点集cv::Mat img, 原图cv::Rect ROI, cv::Point& top, 输出焊点(图像上位于较上方的点)cv::Point& bottom, 输出焊点(图像上位于较下方的点)std::vector<cv::Point>& allPntList:直线部分非弧线的点集cv::Mat &canvas,效果图可视化*/bool rectangle2Pnt(cv::Mat imgOriginal, cv::Point& top, cv::Point& bottom, std::vector<cv::Point>& allPntList, cv::Mat &canvas, bool debug = false);bool rectangle2Pnt_ROI(cv::Mat img, cv::Rect ROI, cv::Point& top, cv::Point& bottom, std::vector<cv::Point>& allPntList, cv::Mat &canvas, bool debug = false);
bool PTank_imgProcess::rectangle2Pnt_ROI(cv::Mat img, cv::Rect ROI, cv::Point & top, cv::Point & bottom, std::vector<cv::Point>& allPntList, cv::Mat & canvas, bool debug)
{int endRes = 0;bool result = false;img.copyTo(canvas);top = cv::Point(0, 0);bottom = cv::Point(0, 0);allPntList.clear();cv::Mat imgOriginal;bool ROI_flag;//是否有给信息区cv::Point ROI_tl = cv::Point2i(ROI.x, ROI.y);cv::Point ROI_br = cv::Point2i(ROI.x + ROI.width, ROI.y + ROI.height);if (ROI_tl == cv::Point(0, 0) && ROI_br == cv::Point(0, 0) || ROI.width == 0 || ROI.height == 0){img.copyTo(imgOriginal);ROI_flag = false;}else{if (ROI_tl.x > ROI_br.x || ROI_tl.y > ROI_br.y)//信息区两点疑似传反{printf("信息区两点疑似传反!");return false;}if (ROI_tl.x < 0 || ROI_br.x > img.cols || ROI_tl.y < 0 || ROI_br.y > img.rows)//信息区的框选超出图像范围{printf("信息区的框选超出图像范围!");return false;}if (abs(ROI_tl.x - ROI_br.x) > img.cols || abs(ROI_tl.y - ROI_br.y) > img.rows)//信息区大小超出图像大小{printf("信息区大小超出图像大小!");return false;}//此时不合法的ROI都已提前返回falsecv::Rect roi(ROI_tl.x, ROI_tl.y, ROI_br.x - ROI_tl.x, ROI_br.y - ROI_tl.y);imgOriginal = img(roi); //裁剪出的ROI区域放于imgOriginalROI_flag = true;}result = rectangle2Pnt(imgOriginal, top, bottom, allPntList, canvas, debug);//调用识别算法if (debug) printf("-------------------------------------****------ roiF top=【%d, %d】, bottom=【%d, %d】\n", top.x, top.y, bottom.x, bottom.y);//img.copyTo(canvas);img.copyTo(canvas);//调试时注释掉if (result){endRes = 1;top += ROI_tl;bottom += ROI_tl;for (int i = 0; i < allPntList.size(); i++) {allPntList.at(i) += ROI_tl;}int w = 5;for (int i = 0; i < allPntList.size(); i++) {cv::Point curPoint = allPntList.at(i);cv::line(canvas, curPoint, cv::Point(curPoint.x - w, curPoint.y), cv::Scalar(55, 195, 40), 1);}cv::putText(canvas, "true", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);circle(canvas, top, 3, cv::Scalar(0, 69, 255), 1);circle(canvas, top, 63, cv::Scalar(0, 169, 255), 1);circle(canvas, bottom, 3, cv::Scalar(0, 69, 255), 1);circle(canvas, bottom, 43, cv::Scalar(255, 169, 0), 1);}else{cv::putText(canvas, "false", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);}cv::Mat ROIcanvas;img.copyTo(ROIcanvas);if (debug) circle(ROIcanvas, top, 3, cv::Scalar(0, 69, 255), 1);if (debug) circle(ROIcanvas, top, 63, cv::Scalar(0, 169, 255), 1);if (debug) circle(ROIcanvas, bottom, 3, cv::Scalar(0, 69, 255), 1);if (debug) circle(ROIcanvas, bottom, 63, cv::Scalar(0, 169, 255), 1);if (debug) rectangle(ROIcanvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);rectangle(canvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);if (debug) printf("-------------------------------------****------ roiF top=【%d, %d】, bottom=【%d, %d】\n", top.x, top.y, bottom.x, bottom.y);if (debug) imshow("ROI", ROIcanvas);if (debug) imshow("ROI_canvas", canvas);//ROIcanvas.copyTo(canvas);return result;
}
调用main:
//矩形位置 返回双点+骨干点集
int main/*Rectangle2Pnt_ROI*/() {bool flag;//std::string filePath = "../../../../Log08141641/TestImg/src";std::string filePath = "E://vsproject//压力罐\\img\\矩形";string resPath = "/output";//string resPath = filePath + "./output";cv::Point tlP = cv::Point(500, 292);cv::Point brP = cv::Point(750, 677);//cv::Rect ROI = cv::Rect(0, 0, 0, 0);//cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);//cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);//cv::Rect ROI = cv::Rect(539, 218, 113, 513);cv::Point top(90, 90);cv::Point bottom(90, 90);int outMidY;cv::Mat canvas;PTank_imgProcess m_ImageProcessing;ofstream ofs("log.txt", ios::out);if (ofs){ofs.clear();ofs << "日志启动" << endl;}std::vector<cv::Point> allPntList;vector<string> path_name;bool getROI = true;bool lianxu = false; //循环测试if (!lianxu){string name = cv::format("\\Image_20240627144421072.png");string path = filePath + name;cv::Mat src = cv::imread(path);src.copyTo(canvas);cv::namedWindow("main_OriginalIMG", cv::RECURS_FILTER);cvSetMouseCallback("main_OriginalIMG", on_mouse_singleClick, 0);cv::imshow("main_OriginalIMG", src);cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);//cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);if (getROI) ROI = getROIFromString(name);bool flag = m_ImageProcessing.rectangle2Pnt_ROI(src, ROI, top, bottom, allPntList, canvas, true);cout << "\nmain ==== flag " << flag << endl;if (flag) {cout << "top = " << top.x << " " << top.y << endl;cout << "bottom = " << bottom.x << " " << bottom.y << endl;}canvas.copyTo(src);//cout << "\nmain ==== i " << endl;circle(canvas, top, 63, cv::Scalar(0, 69, 255), 1);circle(canvas, bottom, 63, cv::Scalar(0, 69, 255), 1);cv::putText(src, to_string(flag), cv::Point(src.cols / 2 - 20, src.rows / 2 - 65), cv::FONT_HERSHEY_COMPLEX, 1.75, cv::Scalar(255, 135, 160), 3);cv::namedWindow("main-结果图src", cv::RECURS_FILTER);cvSetMouseCallback("main-结果图src", on_mouse_singleClick, 0);cv::imshow("main-结果图src", src);cv::namedWindow("main-canvas", cv::RECURS_FILTER);cvSetMouseCallback("main-canvas", on_mouse_singleClick, 0);cv::imshow("main-canvas", canvas);}else{vector<string> path_name;getAllFiles(filePath, path_name);cout << "path_name.size()=" << path_name.size() << endl;int number = 1;for (auto i : path_name){//cout << i.size() << endl;if (i.size() == 7) continue;if (i.find(".log") != std::string::npos) continue;std::string path11 = filePath + "\\" + i;cv::Mat src = cv::imread(path11);//cv::Mat src = cv::imread(filePath + "\\" + i);cout << endl << "number【" << number << "】src path=" << i << " ;" << endl;src.copyTo(canvas);cv::imshow("main_OriginalIMG", src);//将结果图写入文件方便查看结果int len = filePath.length();//i = i.substr(i.find_last_of('\\') + 1, len);cout << "i=" << i << ", path11=" << path11 << endl;int time_start = clock();int time_end = clock();cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);//cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);if (getROI) ROI = getROIFromString(i);bool flag = m_ImageProcessing.rectangle2Pnt_ROI(src, ROI, top, bottom, allPntList, canvas, false);time_end = clock();printf("\n耗时 %d ms \n", time_end - time_start);cout << "\nmain ==== flag " << flag << endl;if (flag) {cout << "top = " << top.x << " " << top.y << endl;cout << "bottom = " << bottom.x << " " << bottom.y << endl;}canvas.copyTo(src);cv::putText(src, to_string(flag), cv::Point(src.cols / 2 - 20, src.rows / 2 - 65), cv::FONT_HERSHEY_COMPLEX, 1.75, cv::Scalar(255, 135, 160), 3);cv::imshow("main-结果图src", src);cv::imshow("main-canvas", canvas);//将结果图写入文件方便查看结果char* filePath_ = new char[len + 1];strcpy(filePath_, filePath.c_str());len = filePath.length();char* resPath_ = new char[len + 1];strcpy(resPath_, resPath.c_str());//i.erase(0, strlen(filePath_) - strlen(resPath_) - 2);string out = filePath + resPath;cout << "\nmain ==== i " << i << endl;out.append("\\").append(i);cout << "number【" << number << "】res path=" << out << endl;cv::imwrite(out, src);number++;cout << "path_name.size() = " << path_name.size() << endl;cout << "*********************************************************************************************************************" << endl;cv::waitKey(10);}cout << "循环结束!!! main " << endl;}ofs.close();cv::waitKey(0);system("Pause");return 0;
}
返回双点+三点集+左右/上下翻转再进入识别
注:该接口中 bottom, linearPntB无效!!!
根据传入参数判断是否左右翻转,判断识别的是上半部分还是下半部分,下半部分则需再做上下翻转再进入识别。
/*//D型主管,方形支管 只处理上半部分或下半部分cv::Mat img, 原图cv::Rect ROI, 可以让右边的干扰直反光落进去,上下不用截,左右可适当截小一下减少识别时的计算时间std::vector<cv::Point>& linearPnt:直线部分非弧线的点集cv::Point& top, 输出焊点(图像上位于较上方的点)倒角弧形边边上的激光最边边点cv::Point& bottom, 输出焊点(图像上位于较下方的点)倒角弧形边边上的激光最边边点cv::Mat &canvas,效果图可视化bool arcTop_right = true;//圆弧顶点是否朝右的标志量,默认为true(true为朝右,false为朝左)bool isTopHalf = true;//识别区域是否为上半部分,上半部分为true,下半部分反之注:该接口中 bottom, linearPntB无效!!!*/bool OneSideSquare(cv::Mat imgOriginal, std::vector<cv::Point>& linearPntT, std::vector<cv::Point>& linearPntB, std::vector<cv::Point>& linearPntM, cv::Point& top, cv::Point& bottom, cv::Mat &canvas, bool debug = false);bool OneSideSquare_ROI(cv::Mat img, cv::Rect ROI, std::vector<cv::Point>& linearPntT, std::vector<cv::Point>& linearPntB, std::vector<cv::Point>& linearPntM, cv::Point& top, cv::Point& bottom, cv::Mat &canvas, bool arcTop_right = true, bool isTopHalf = true, bool debug = false);
bool ImageProcessing::OneSideSquare_ROI(cv::Mat img, cv::Rect ROI, std::vector<cv::Point>& linearPntT, std::vector<cv::Point>& linearPntB, std::vector<cv::Point>& linearPntM, cv::Point & top, cv::Point & bottom, cv::Mat & canvas, bool arcTop_right, bool isTopHalf, bool debug)
{int endRes = 0;bool result = false;img.copyTo(canvas);top = cv::Point(0, 0);bottom = cv::Point(0, 0);linearPntT.clear();linearPntB.clear();linearPntM.clear();cv::Mat imgOriginal;bool ROI_flag;//是否有给信息区cv::Point ROI_tl = cv::Point2i(ROI.x, ROI.y);cv::Point ROI_br = cv::Point2i(ROI.x + ROI.width, ROI.y + ROI.height);if (ROI_tl == cv::Point(0, 0) && ROI_br == cv::Point(0, 0) || ROI.width == 0 || ROI.height == 0){img.copyTo(imgOriginal);ROI_flag = false;}else{if (ROI_tl.x > ROI_br.x || ROI_tl.y > ROI_br.y)//信息区两点疑似传反{printf("信息区两点疑似传反!");return false;}if (ROI_tl.x < 0 || ROI_br.x > img.cols || ROI_tl.y < 0 || ROI_br.y > img.rows)//信息区的框选超出图像范围{printf("信息区的框选超出图像范围!");return false;}if (abs(ROI_tl.x - ROI_br.x) > img.cols || abs(ROI_tl.y - ROI_br.y) > img.rows)//信息区大小超出图像大小{printf("信息区大小超出图像大小!");return false;}//此时不合法的ROI都已提前返回falsecv::Rect roi(ROI_tl.x, ROI_tl.y, ROI_br.x - ROI_tl.x, ROI_br.y - ROI_tl.y);imgOriginal = img(roi); //裁剪出的ROI区域放于imgOriginalROI_flag = true;}if (arcTop_right) {//圆弧顶点朝右的情况if (isTopHalf) {result = OneSideSquare(imgOriginal, linearPntT, linearPntB, linearPntM, top, bottom, canvas, debug);//调用识别算法}else {cv::Mat fpMt;cv::flip(imgOriginal, fpMt, 0); // 上下翻转 x对称result = OneSideSquare(fpMt, linearPntT, linearPntB, linearPntM, top, bottom, canvas, debug);//调用识别算法if (result) {top.y = fpMt.rows - top.y - 1;for (int i = 0; i < linearPntT.size(); i++) {linearPntT.at(i).y = fpMt.rows - linearPntT.at(i).y - 1;}for (int i = 0; i < linearPntM.size(); i++) {linearPntM.at(i).y = fpMt.rows - linearPntM.at(i).y - 1;}}}}else {//圆弧顶点朝左的情况cv::Mat flipMat;cv::flip(imgOriginal, flipMat, 1); // 左右翻转 y对称if (debug) imshow("图像左右翻转", flipMat);if (isTopHalf) {result = OneSideSquare(flipMat, linearPntT, linearPntB, linearPntM, top, bottom, canvas, debug);//调用识别算法}else {cv::Mat fpMt;cv::flip(flipMat, fpMt, 0); // 上下翻转 x对称result = OneSideSquare(fpMt, linearPntT, linearPntB, linearPntM, top, bottom, canvas, debug);//调用识别算法if (result) {top.y = fpMt.rows - top.y - 1;for (int i = 0; i < linearPntT.size(); i++) {linearPntT.at(i).y = fpMt.rows - linearPntT.at(i).y - 1;}for (int i = 0; i < linearPntM.size(); i++) {linearPntM.at(i).y = fpMt.rows - linearPntM.at(i).y - 1;}}}if (result) {top.x = flipMat.cols - top.x - 1;//bottom.x = flipMat.cols - bottom.x - 1;for (int i = 0; i < linearPntT.size(); i++) {linearPntT.at(i).x = flipMat.cols - linearPntT.at(i).x - 1;}for (int i = 0; i < linearPntB.size(); i++) {linearPntB.at(i).x = flipMat.cols - linearPntB.at(i).x - 1;}for (int i = 0; i < linearPntM.size(); i++) {linearPntM.at(i).x = flipMat.cols - linearPntM.at(i).x - 1;}}}if (debug) printf("-------------------------------------****------ roiF top=【%d, %d】, bottom=【%d, %d】\n", top.x, top.y, bottom.x, bottom.y);//img.copyTo(canvas);x值和y值补上ROI左上点x和y//if (ROI_flag) {// if (Corner != cv::Point(0, 0))// {// Corner.x += ROI_tl.x;// Corner.y += ROI_tl.y;// }//}img.copyTo(canvas);//调试时注释掉if (result){endRes = 1;top += ROI_tl;//bottom += ROI_tl;for (int i = 0; i < linearPntT.size(); i++) {linearPntT.at(i) += ROI_tl;}for (int i = 0; i < linearPntB.size(); i++) {linearPntB.at(i) += ROI_tl;}for (int i = 0; i < linearPntM.size(); i++) {linearPntM.at(i) += ROI_tl;}for (int i = 0; i < linearPntT.size(); i++) {cv::Point curPoint = linearPntT.at(i);cv::line(canvas, curPoint, cv::Point(curPoint.x - 5, curPoint.y), cv::Scalar(55, 195, 40), 1);}for (int i = 0; i < linearPntB.size(); i++) {cv::Point curPoint = linearPntB.at(i);cv::line(canvas, curPoint, cv::Point(curPoint.x - 5, curPoint.y), cv::Scalar(55, 195, 40), 1);}for (int i = 0; i < linearPntM.size(); i++) {cv::Point curPoint = linearPntM.at(i);cv::line(canvas, curPoint, cv::Point(curPoint.x - 5, curPoint.y), cv::Scalar(145, 175, 40), 1);}cv::putText(canvas, "true", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);circle(canvas, top, 3, cv::Scalar(0, 69, 255), 1);circle(canvas, top, 63, cv::Scalar(0, 169, 255), 1);//circle(canvas, bottom, 3, cv::Scalar(0, 69, 255), 1);//circle(canvas, bottom, 43, cv::Scalar(255, 169, 0), 1);}else{cv::putText(canvas, "false", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);}cv::Mat ROIcanvas;img.copyTo(ROIcanvas);if (debug) circle(ROIcanvas, top, 3, cv::Scalar(0, 69, 255), 1);if (debug) circle(ROIcanvas, top, 63, cv::Scalar(0, 169, 255), 1);//if (debug) circle(ROIcanvas, bottom, 3, cv::Scalar(0, 69, 255), 1);//if (debug) circle(ROIcanvas, bottom, 63, cv::Scalar(0, 169, 255), 1);if (debug) rectangle(ROIcanvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);rectangle(canvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);if (debug) printf("-------------------------------------****------ roiF top=【%d, %d】, bottom=【%d, %d】\n", top.x, top.y, bottom.x, bottom.y);if (debug) imshow("ROI", ROIcanvas);if (debug) imshow("ROI_canvas", canvas);//ROIcanvas.copyTo(canvas);return result;
}
调用main:
//D型主管,方形支管 上或下单侧 OneSideSquare_ROI
int main() {bool flag;//std::string filePath = "../../../../0方管支管/1023img";std::string filePath = "../../../../0方管支管/left";//std::string filePath = "../../../../0方管支管/right";string resPath = "/output";//string resPath = filePath + "./output";//cv::Point tlP = cv::Point(500, 40);//cv::Point brP = cv::Point(750, 777);cv::Point tlP = cv::Point(584, 236);cv::Point brP = cv::Point(660, 820);//cv::Rect ROI = cv::Rect(0, 0, 0, 0);//cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);//cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);//cv::Rect ROI = cv::Rect(639, 188, 125, 569);cv::Point top(90, 90);cv::Point bottom(90, 90);cv::Point2f midP(90, 90);int outMidY;cv::Mat canvas;ImageProcessing m_ImageProcessing;ofstream ofs("log.txt", ios::out);if (ofs){ofs.clear();ofs << "日志启动" << endl;}std::vector<cv::Point> linearPntT;std::vector<cv::Point> linearPntB;std::vector<cv::Point> linearPntM;vector<Picture_set> img_buf;vector<string> path_name;bool arcTop_right = !true;bool isTopHalf = true;int midyTolerant = 4;bool getROI = true;bool lianxu = false; //循环测试if (lianxu){//string path = filePath + cv::format("\\Image_20231023105829348.png");//std::string name = cv::format("\\ImgD_2023_10_26_10_48_12_135_567_196_153_603_Src.png");std::string name = cv::format("\\ImgD_2023_10_25_18_16_24_519_569_200_166_559_Src.png");string path = filePath + name;cv::Mat src = cv::imread(path);src.copyTo(canvas);cv::namedWindow("main_OriginalIMG", cv::NORMCONV_FILTER);cvSetMouseCallback("main_OriginalIMG", on_mouse_singleClick, 0);cv::imshow("main_OriginalIMG", src);//cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);if (getROI) {ROI = getROIFromString(name);ROI.height /= 2;if (!isTopHalf) {ROI.y += ROI.height;}}//鼠标点击的坐标【691, 319】// 鼠标点击的坐标【692, 632】//cout << src.size() << endl;//rotateImage(src);//cout << src.size() << endl;//鼠标点击的坐标【707, 691】// 鼠标点击的坐标【395, 691】//trueX=outY;//trueY=oriSrc.rows-outX;//circle(src, cv::Point(622, 424), 5, cv::Scalar(255, 255, 255), -1);//cv::Mat flipMat;//cv::flip(src, flipMat, 1);//cv::Point q = cv::Point(flipMat.cols - 622 - 1, 424)/* - cv::Point(546, 228)*/;//circle(flipMat, q, 3, cv::Scalar(0, 0, 0), -1);//cv::imshow("flipMat", flipMat);//cv::waitKey();//cv::flip(src, src, 0);bool flag = m_ImageProcessing.OneSideSquare_ROI(src, ROI, linearPntT, linearPntB, linearPntM, top, bottom, canvas, arcTop_right, isTopHalf, true);cout << "\nmain ==== flag " << flag << endl;if (flag) {cout << "top = " << top.x << " " << top.y << endl;cout << "bottom = " << bottom.x << " " << bottom.y << endl;}canvas.copyTo(src);//cout << "\nmain ==== i " << endl;circle(canvas, top, 63, cv::Scalar(0, 69, 255), 1);circle(canvas, bottom, 63, cv::Scalar(0, 69, 255), 1);cv::putText(src, to_string(flag), cv::Point(src.cols / 2 - 20, src.rows / 2 - 65), cv::FONT_HERSHEY_COMPLEX, 1.75, cv::Scalar(255, 135, 160), 3);cv::namedWindow("main-结果图src", cv::RECURS_FILTER);cvSetMouseCallback("main-结果图src", on_mouse_singleClick, 0);cv::imshow("main-结果图src", src);cv::namedWindow("main-canvas", cv::RECURS_FILTER);cvSetMouseCallback("main-canvas", on_mouse_singleClick, 0);cv::imshow("main-canvas", canvas);}else{vector<string> path_name;getAllFiles(filePath, path_name);cout << "path_name.size()=" << path_name.size() << endl;int number = 1;for (auto i : path_name){//cout << i.size() << endl;if (i.size() == 7) continue;if (i.find(".log") != std::string::npos) continue;if (i.find(".txt") != std::string::npos) continue;std::string name = i;std::string path11 = filePath + "\\" + i;cv::Mat src = cv::imread(path11);//cv::Mat src = cv::imread(filePath + "\\" + i);cout << endl << "number【" << number << "】src path=" << i << " ;" << endl;src.copyTo(canvas);cv::imshow("main_OriginalIMG", src);//将结果图写入文件方便查看结果int len = filePath.length();//i = i.substr(i.find_last_of('\\') + 1, len);cout << "i=" << i << ", path11=" << path11 << endl;int time_start = clock();int time_end = clock();cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);if (getROI) {ROI = getROIFromString(name);ROI.height /= 2;if (!isTopHalf) {ROI.y += ROI.height;}}bool flag = m_ImageProcessing.OneSideSquare_ROI(src, ROI, linearPntT, linearPntB, linearPntM, top, bottom, canvas, arcTop_right, isTopHalf, false);time_end = clock();printf("\n耗时 %d ms \n", time_end - time_start);cout << "\nmain ==== flag " << flag << endl;if (flag) {cout << "top = " << top.x << " " << top.y << endl;cout << "bottom = " << bottom.x << " " << bottom.y << endl;}canvas.copyTo(src);cv::putText(src, to_string(flag), cv::Point(src.cols / 2 - 20, src.rows / 2 - 65), cv::FONT_HERSHEY_COMPLEX, 1.75, cv::Scalar(255, 135, 160), 3);cv::imshow("main-结果图src", src);cv::imshow("main-canvas", canvas);//将结果图写入文件方便查看结果char* filePath_ = new char[len + 1];strcpy(filePath_, filePath.c_str());len = filePath.length();char* resPath_ = new char[len + 1];strcpy(resPath_, resPath.c_str());//i.erase(0, strlen(filePath_) - strlen(resPath_) - 2);string out = filePath + resPath;cout << "\nmain ==== i " << i << endl;out.append("\\").append(i);cout << "number【" << number << "】res path=" << out << endl;cv::imwrite(out, src);number++;cout << "path_name.size() = " << path_name.size() << endl;cout << "*********************************************************************************************************************" << endl;cv::waitKey(10);}cout << "循环结束!!! main " << endl;}ofs.close();cv::waitKey(0);system("Pause");return 0;
}
三点
返回三点+1个点集
/*//两弧线夹圆弧 返回三点+骨干点集cv::Mat img, 原图cv::Rect ROI,cv::Point& top, 输出焊点(图像上位于较上方的点)cv::Point& bottom, 输出焊点(图像上位于较下方的点)cv::Point2f& midP, 圆弧中点std::vector<cv::Point>& allPntList:直线部分非弧线的点集cv::Mat &canvas,效果图可视化*/bool twoArcsClipTheArc(cv::Mat imgOriginal, cv::Point& top, cv::Point& bottom, cv::Point2f& midP, std::vector<cv::Point>& allPntList, cv::Mat &canvas, bool debug = false);bool twoArcsClipTheArc_ROI(cv::Mat img, cv::Rect ROI, cv::Point& top, cv::Point& bottom, cv::Point2f& midP, std::vector<cv::Point>& allPntList, cv::Mat &canvas, bool arcTop_right = true, bool debug = false);
bool PTank_imgProcess::twoArcsClipTheArc_ROI(cv::Mat img, cv::Rect ROI, cv::Point & top, cv::Point & bottom, cv::Point2f & midP, std::vector<cv::Point>& allPntList, cv::Mat & canvas, bool arcTop_right, bool debug)
{int endRes = 0;bool result = false;img.copyTo(canvas);top = cv::Point(0, 0);bottom = cv::Point(0, 0);midP = cv::Point2f(0, 0);allPntList.clear();cv::Mat imgOriginal;bool ROI_flag;//是否有给信息区cv::Point ROI_tl = cv::Point2i(ROI.x, ROI.y);cv::Point ROI_br = cv::Point2i(ROI.x + ROI.width, ROI.y + ROI.height);if (ROI_tl == cv::Point(0, 0) && ROI_br == cv::Point(0, 0) || ROI.width == 0 || ROI.height == 0){img.copyTo(imgOriginal);ROI_flag = false;}else{if (ROI_tl.x > ROI_br.x || ROI_tl.y > ROI_br.y)//信息区两点疑似传反{printf("信息区两点疑似传反!");return false;}if (ROI_tl.x < 0 || ROI_br.x > img.cols || ROI_tl.y < 0 || ROI_br.y > img.rows)//信息区的框选超出图像范围{printf("信息区的框选超出图像范围!");return false;}if (abs(ROI_tl.x - ROI_br.x) > img.cols || abs(ROI_tl.y - ROI_br.y) > img.rows)//信息区大小超出图像大小{printf("信息区大小超出图像大小!");return false;}//此时不合法的ROI都已提前返回falsecv::Rect roi(ROI_tl.x, ROI_tl.y, ROI_br.x - ROI_tl.x, ROI_br.y - ROI_tl.y);imgOriginal = img(roi); //裁剪出的ROI区域放于imgOriginalROI_flag = true;}if (arcTop_right) {//圆弧顶点朝右的情况result = twoArcsClipTheArc(imgOriginal, top, bottom, midP, allPntList, canvas, debug);//调用识别算法}else {//圆弧顶点朝左的情况cv::Mat flipMat;cv::flip(imgOriginal, flipMat, 1); // 左右翻转 y对称if (debug) imshow("图像左右翻转", flipMat);result = twoArcsClipTheArc(flipMat, top, bottom, midP, allPntList, canvas, debug);//调用识别算法if (result) {top.x = flipMat.cols - top.x - 1;bottom.x = flipMat.cols - bottom.x - 1;for (int i = 0; i < allPntList.size(); i++) {allPntList.at(i).x = flipMat.cols - allPntList.at(i).x - 1;}if (midP != cv::Point2f(0, 0)) midP.x = flipMat.cols - midP.x - 1;}}if (debug) printf("-------------------------------------****------ roiF top=【%d, %d】, bottom=【%d, %d】\n", top.x, top.y, bottom.x, bottom.y);if (debug) printf(" roiF midP=【%f, %f】\n", midP.x, midP.y);//img.copyTo(canvas);//img.copyTo(canvas);//调试时注释掉if (result){endRes = 1;for (int i = 0; i < allPntList.size(); i++) {allPntList.at(i) += ROI_tl;}for (int i = 0; i < allPntList.size(); i++) {cv::Point curPoint = allPntList.at(i);cv::line(canvas, curPoint, cv::Point(curPoint.x - 5, curPoint.y), cv::Scalar(55, 195, 40), 1);}top += ROI_tl;bottom += ROI_tl;midP += cv::Point2f(ROI_tl);//if (midP != cv::Point2f(0, 0)) {// midP.x = midP.x + ROI_tl.x;// midP.y = midP.y + ROI_tl.y;//}circle(canvas, midP, 3, cv::Scalar(0, 69, 255), 1);circle(canvas, midP, 43, cv::Scalar(0, 169, 255), 1);cv::line(canvas, midP, cv::Point2f(5, midP.y), cv::Scalar(155, 195, 40), 1);cv::line(canvas, cv::Point2f(midP.x, midP.y - 5), cv::Point2f(midP.x, midP.y + 5), cv::Scalar(155, 195, 40), 1);cv::putText(canvas, "true", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);circle(canvas, top, 3, cv::Scalar(0, 69, 255), 1);circle(canvas, top, 63, cv::Scalar(0, 169, 255), 1);circle(canvas, bottom, 3, cv::Scalar(0, 69, 255), 1);circle(canvas, bottom, 43, cv::Scalar(255, 169, 0), 1);}else{cv::putText(canvas, "false", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);}cv::Mat ROIcanvas;img.copyTo(ROIcanvas);if (debug) circle(ROIcanvas, top, 3, cv::Scalar(0, 69, 255), 1);if (debug) circle(ROIcanvas, top, 63, cv::Scalar(0, 169, 255), 1);if (debug) circle(ROIcanvas, bottom, 3, cv::Scalar(0, 69, 255), 1);if (debug) circle(ROIcanvas, bottom, 63, cv::Scalar(0, 169, 255), 1);if (debug) rectangle(ROIcanvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);rectangle(canvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);if (debug) printf("-------------------------------------****------ roiF top=【%d, %d】, bottom=【%d, %d】\n", top.x, top.y, bottom.x, bottom.y);if (debug) printf(" roiF midP=【%f, %f】\n", midP.x, midP.y);if (debug) imshow("ROI", ROIcanvas);if (debug) imshow("ROI_canvas", canvas);//ROIcanvas.copyTo(canvas);return result;
}
调用main:
//两弧线夹圆弧 返回三点+骨干点集
int main/*TwoArcsClipTheArc*/() {bool flag;std::string filePath = "../../img/圆弧夹圆弧";string resPath = "/output";//string resPath = filePath + "./output";cv::Point tlP = cv::Point(500, 292);cv::Point brP = cv::Point(750, 677);//cv::Rect ROI = cv::Rect(0, 0, 0, 0);//cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);//cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);//cv::Rect ROI = cv::Rect(539, 218, 113, 513);cv::Rect ROI = cv::Rect(546, 228, 101, 520);cv::Point top(90, 90);cv::Point bottom(90, 90);cv::Point2f midP(90, 90);int outMidY;cv::Mat canvas;PTank_imgProcess m_ImageProcessing;ofstream ofs("log.txt", ios::out);if (ofs){ofs.clear();ofs << "日志启动" << endl;}std::vector<cv::Point> allPntList;vector<string> path_name;bool arcTop_right = true;bool getROI = true;bool lianxu = false; //循环测试if (!lianxu){string name = cv::format("\\Image_20240702114054217.png");//string name = cv::format("\\Image_20240702170558613.png");//斜//string name = cv::format("\\Image_20240702170644641.png");//斜string path = filePath + name;//string path = filePath + cv::format("\\ImgD_2023_08_17_15_06_45_412_639_188_125_569_Src.png");cv::Mat src = cv::imread(path);src.copyTo(canvas);cv::namedWindow("main_OriginalIMG", cv::NORMCONV_FILTER);cvSetMouseCallback("main_OriginalIMG", on_mouse_singleClick, 0);cv::imshow("main_OriginalIMG", src);//cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);//cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);if (getROI) ROI = getROIFromString(name);bool flag = m_ImageProcessing.twoArcsClipTheArc_ROI(src, ROI, top, bottom, midP, allPntList, canvas, arcTop_right, true);cout << "\nmain ==== flag " << flag << endl;if (flag) {cout << "top = " << top.x << " " << top.y << endl;cout << "bottom = " << bottom.x << " " << bottom.y << endl;cout << "midP = " << midP.x << " " << midP.y << endl;}canvas.copyTo(src);//cout << "\nmain ==== i " << endl;circle(canvas, top, 63, cv::Scalar(0, 69, 255), 1);circle(canvas, bottom, 63, cv::Scalar(0, 69, 255), 1);cv::putText(src, to_string(flag), cv::Point(src.cols / 2 - 20, src.rows / 2 - 65), cv::FONT_HERSHEY_COMPLEX, 1.75, cv::Scalar(255, 135, 160), 3);cv::namedWindow("main-结果图src", cv::RECURS_FILTER);cvSetMouseCallback("main-结果图src", on_mouse_singleClick, 0);cv::imshow("main-结果图src", src);cv::namedWindow("main-canvas", cv::RECURS_FILTER);cvSetMouseCallback("main-canvas", on_mouse_singleClick, 0);cv::imshow("main-canvas", canvas);}else{vector<string> path_name;getAllFiles(filePath, path_name);cout << "path_name.size()=" << path_name.size() << endl;int number = 1;for (auto i : path_name){//cout << i.size() << endl;if (i.size() == 7) continue;if (i.find(".log") != std::string::npos) continue;if (i.find(".txt") != std::string::npos) continue;if (i.find("_result") != std::string::npos) continue;if (i.find("png") == std::string::npos && i.find("bmp") == std::string::npos && i.find("jpg") == std::string::npos) continue;std::string path11 = filePath + "\\" + i;cv::Mat src = cv::imread(path11);//cv::Mat src = cv::imread(filePath + "\\" + i);cout << endl << "number【" << number << "】src path=" << i << " ;" << endl;src.copyTo(canvas);cv::imshow("main_OriginalIMG", src);//将结果图写入文件方便查看结果int len = filePath.length();//i = i.substr(i.find_last_of('\\') + 1, len);cout << "i=" << i << ", path11=" << path11 << endl;int time_start = clock();int time_end = clock();cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);//cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);if (getROI) ROI = getROIFromString(i);bool flag = m_ImageProcessing.twoArcsClipTheArc_ROI(src, ROI, top, bottom, midP, allPntList, canvas, arcTop_right, false);time_end = clock();printf("\n耗时 %d ms \n", time_end - time_start);cout << "\nmain ==== flag " << flag << endl;if (flag) {cout << "top = " << top.x << " " << top.y << endl;cout << "bottom = " << bottom.x << " " << bottom.y << endl;}canvas.copyTo(src);cv::putText(src, to_string(flag), cv::Point(src.cols / 2 - 20, src.rows / 2 - 65), cv::FONT_HERSHEY_COMPLEX, 1.75, cv::Scalar(255, 135, 160), 3);cv::imshow("main-结果图src", src);cv::imshow("main-canvas", canvas);//将结果图写入文件方便查看结果char* filePath_ = new char[len + 1];strcpy(filePath_, filePath.c_str());len = filePath.length();char* resPath_ = new char[len + 1];strcpy(resPath_, resPath.c_str());//i.erase(0, strlen(filePath_) - strlen(resPath_) - 2);string out = filePath + resPath;cout << "\nmain ==== i " << i << endl;out.append("\\").append(i);cout << "number【" << number << "】res path=" << out << endl;cv::imwrite(out, src);number++;cout << "path_name.size() = " << path_name.size() << endl;cout << "*********************************************************************************************************************" << endl;cv::waitKey(10);}cout << "循环结束!!! main " << endl;}ofs.close();cv::waitKey(0);system("Pause");return 0;
}
返回三点+双点集+左右翻转再进入识别
左右翻转变回来后必须要x-1,不然会与原来基于原图上的坐标对应不上。
/*//D型管的两直线夹圆弧//周六新策略:两边直线中间圆弧,激光平行于主管 (__O__两端直线中间半圆弧找圆弧的两端拐点)---圆轨迹cv::Mat img, 原图cv::Rect ROI, 可以让右边的干扰直反光落进去,上下不用截,左右可适当截小一下减少识别时的计算时间int outMidY,因y偏差过大时返回的两点无效,则返回圆弧区域的中心ycv::Point& midP, outMidY对应的圆弧上的骨干点(midP为(0,0)时,该值无效)std::vector<cv::Point>& linearPnt:直线部分非弧线的点集cv::Point& top, 输出焊点(图像上位于较上方的点)cv::Point& bottom, 输出焊点(图像上位于较下方的点)cv::Mat &canvas,效果图可视化int midyTolerant = 2;//outMidY的容差范围bool arcTop_right = true;//圆弧顶点是否朝右的标志量,默认为true(true为朝右,false为朝左)*/bool LaserParallelToTheMainD(cv::Mat imgOriginal, int &outMidY, cv::Point2f& midP, std::vector<cv::Point>& linearPntT, std::vector<cv::Point>& linearPntB, cv::Point& top, cv::Point& bottom, cv::Mat &canvas, int midyTolerant, bool debug = false);bool LaserParallelToTheMainD_ROI(cv::Mat img, cv::Rect ROI, int &outMidY, cv::Point2f& midP, std::vector<cv::Point>& linearPntT, std::vector<cv::Point>& linearPntB, cv::Point& top, cv::Point& bottom, cv::Mat &canvas, int midyTolerant = 2, bool arcTop_right = true, bool debug = false);
bool ImageProcessing::LaserParallelToTheMainD_ROI(cv::Mat img, cv::Rect ROI, int &outMidY, cv::Point2f& midP, std::vector<cv::Point>& linearPntT, std::vector<cv::Point>& linearPntB, cv::Point & top, cv::Point & bottom, cv::Mat & canvas, int midyTolerant, bool arcTop_right, bool debug)
{int endRes = 0;bool result = false;img.copyTo(canvas);top = cv::Point(0, 0);bottom = cv::Point(0, 0);midP = cv::Point2f(0, 0);linearPntT.clear();linearPntB.clear();outMidY = 0;cv::Mat imgOriginal;bool ROI_flag;//是否有给信息区cv::Point ROI_tl = cv::Point2i(ROI.x, ROI.y);cv::Point ROI_br = cv::Point2i(ROI.x + ROI.width, ROI.y + ROI.height);if (ROI_tl == cv::Point(0, 0) && ROI_br == cv::Point(0, 0) || ROI.width == 0 || ROI.height == 0){img.copyTo(imgOriginal);ROI_flag = false;}else{if (ROI_tl.x > ROI_br.x || ROI_tl.y > ROI_br.y)//信息区两点疑似传反{printf("信息区两点疑似传反!");return false;}if (ROI_tl.x < 0 || ROI_br.x > img.cols || ROI_tl.y < 0 || ROI_br.y > img.rows)//信息区的框选超出图像范围{printf("信息区的框选超出图像范围!");return false;}if (abs(ROI_tl.x - ROI_br.x) > img.cols || abs(ROI_tl.y - ROI_br.y) > img.rows)//信息区大小超出图像大小{printf("信息区大小超出图像大小!");return false;}//此时不合法的ROI都已提前返回falsecv::Rect roi(ROI_tl.x, ROI_tl.y, ROI_br.x - ROI_tl.x, ROI_br.y - ROI_tl.y);imgOriginal = img(roi); //裁剪出的ROI区域放于imgOriginalROI_flag = true;}if (arcTop_right) {//圆弧顶点朝右的情况result = LaserParallelToTheMainD(imgOriginal, outMidY, midP, linearPntT, linearPntB, top, bottom, canvas, midyTolerant, debug);//调用识别算法}else {//圆弧顶点朝左的情况cv::Mat flipMat;cv::flip(imgOriginal, flipMat, 1); // 左右翻转 y对称if (debug) imshow("图像左右翻转", flipMat);result = LaserParallelToTheMainD(flipMat, outMidY, midP, linearPntT, linearPntB, top, bottom, canvas, midyTolerant, debug);//调用识别算法if (result) {top.x = flipMat.cols - top.x - 1;bottom.x = flipMat.cols - bottom.x - 1;for (int i = 0; i < linearPntT.size(); i++) {linearPntT.at(i).x = flipMat.cols - linearPntT.at(i).x - 1;}for (int i = 0; i < linearPntB.size(); i++) {linearPntB.at(i).x = flipMat.cols - linearPntB.at(i).x - 1;}if (midP != cv::Point2f(0, 0)) midP.x = flipMat.cols - midP.x - 1;}}if (debug) printf("-------------------------------------****------ roiF top=【%d, %d】, bottom=【%d, %d】\n", top.x, top.y, bottom.x, bottom.y);if (debug) printf(" roiF midP=【%f, %f】\n", midP.x, midP.y);//img.copyTo(canvas);x值和y值补上ROI左上点x和y//if (ROI_flag) {// if (Corner != cv::Point(0, 0))// {// Corner.x += ROI_tl.x;// Corner.y += ROI_tl.y;// }//}img.copyTo(canvas);//调试时注释掉if (result){endRes = 1;top += ROI_tl;bottom += ROI_tl;if (midP != cv::Point2f(0, 0)) {midP.x = midP.x + ROI_tl.x;midP.y = midP.y + ROI_tl.y;}cv::line(canvas, midP, cv::Point2f(5, midP.y), cv::Scalar(55, 195, 40), 1);cv::line(canvas, cv::Point2f(midP.x, midP.y - 5), cv::Point2f(midP.x, midP.y + 5), cv::Scalar(55, 195, 40), 1);for (int i = 0; i < linearPntT.size(); i++) {linearPntT.at(i) += ROI_tl;}for (int i = 0; i < linearPntB.size(); i++) {linearPntB.at(i) += ROI_tl;}for (int i = 0; i < linearPntT.size(); i++) {cv::Point curPoint = linearPntT.at(i);cv::line(canvas, curPoint, cv::Point(curPoint.x - 5, curPoint.y), cv::Scalar(55, 195, 40), 1);}for (int i = 0; i < linearPntB.size(); i++) {cv::Point curPoint = linearPntB.at(i);cv::line(canvas, curPoint, cv::Point(curPoint.x - 5, curPoint.y), cv::Scalar(55, 195, 40), 1);}cv::putText(canvas, "true", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);circle(canvas, top, 3, cv::Scalar(0, 69, 255), 1);circle(canvas, top, 63, cv::Scalar(0, 169, 255), 1);circle(canvas, bottom, 3, cv::Scalar(0, 69, 255), 1);circle(canvas, bottom, 43, cv::Scalar(255, 169, 0), 1);}else{cv::putText(canvas, "false", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);}cv::Mat ROIcanvas;img.copyTo(ROIcanvas);if (debug) circle(ROIcanvas, top, 3, cv::Scalar(0, 69, 255), 1);if (debug) circle(ROIcanvas, top, 63, cv::Scalar(0, 169, 255), 1);if (debug) circle(ROIcanvas, bottom, 3, cv::Scalar(0, 69, 255), 1);if (debug) circle(ROIcanvas, bottom, 63, cv::Scalar(0, 169, 255), 1);if (debug) rectangle(ROIcanvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);rectangle(canvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);if (debug) printf("-------------------------------------****------ roiF top=【%d, %d】, bottom=【%d, %d】\n", top.x, top.y, bottom.x, bottom.y);if (debug) printf(" roiF midP=【%f, %f】\n", midP.x, midP.y);if (debug) imshow("ROI", ROIcanvas);if (debug) imshow("ROI_canvas", canvas);//ROIcanvas.copyTo(canvas);return result;
}
调用main:
//CXL 两边直线中间圆弧,激光平行于主管 DDDDDDDDDDDDDDDDD 圆轨迹 增加直线部分点集 的重载
int main() {bool flag;std::string filePath = "../../../../Log08141641/TestImg/src";string resPath = "/output";//string resPath = filePath + "./output";cv::Point tlP = cv::Point(500, 292);cv::Point brP = cv::Point(750, 677);//cv::Rect ROI = cv::Rect(0, 0, 0, 0);//cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);//cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);//cv::Rect ROI = cv::Rect(539, 218, 113, 513);cv::Point top(90, 90);cv::Point bottom(90, 90);cv::Point2f midP(90, 90);int outMidY;cv::Mat canvas;ImageProcessing m_ImageProcessing;ofstream ofs("log.txt", ios::out);if (ofs){ofs.clear();ofs << "日志启动" << endl;}std::vector<cv::Point> linearPntT;std::vector<cv::Point> linearPntB;vector<string> path_name;bool arcTop_right = !true;int midyTolerant = 4;bool getROI = true;bool lianxu = false; //循环测试if (!lianxu){string name = cv::format("\\ImgD_2024_06_04_09_14_48_111_565_82_86_851_Src.png");string path = filePath + name;//string path = filePath + cv::format("\\ImgD_2023_08_17_15_06_45_412_639_188_125_569_Src.png");cv::Mat src = cv::imread(path);src.copyTo(canvas);cv::namedWindow("main_OriginalIMG", cv::NORMCONV_FILTER);cvSetMouseCallback("main_OriginalIMG", on_mouse_singleClick, 0);cv::imshow("main_OriginalIMG", src);//cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);//cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);if (getROI) ROI = getROIFromString(name);//trueX=outY;//trueY=oriSrc.rows-outX;//circle(src, cv::Point(622, 424), 5, cv::Scalar(255, 255, 255), -1);//cv::Mat flipMat;//cv::flip(src, flipMat, 1);//cv::Point q = cv::Point(flipMat.cols - 622 - 1, 424)/* - cv::Point(546, 228)*/;//circle(flipMat, q, 3, cv::Scalar(0, 0, 0), -1);//cv::imshow("flipMat", flipMat);//cv::waitKey();bool flag = m_ImageProcessing.LaserParallelToTheMainD_ROI(src, ROI, outMidY, midP, linearPntT, linearPntB, top, bottom, canvas, midyTolerant, arcTop_right, true);cout << "\nmain ==== flag " << flag << endl;if (flag) {cout << "top = " << top.x << " " << top.y << endl;cout << "bottom = " << bottom.x << " " << bottom.y << endl;}canvas.copyTo(src);//cout << "\nmain ==== i " << endl;circle(canvas, top, 63, cv::Scalar(0, 69, 255), 1);circle(canvas, bottom, 63, cv::Scalar(0, 69, 255), 1);cv::putText(src, to_string(flag), cv::Point(src.cols / 2 - 20, src.rows / 2 - 65), cv::FONT_HERSHEY_COMPLEX, 1.75, cv::Scalar(255, 135, 160), 3);cv::namedWindow("main-结果图src", cv::RECURS_FILTER);cvSetMouseCallback("main-结果图src", on_mouse_singleClick, 0);cv::imshow("main-结果图src", src);cv::namedWindow("main-canvas", cv::RECURS_FILTER);cvSetMouseCallback("main-canvas", on_mouse_singleClick, 0);cv::imshow("main-canvas", canvas);}else{vector<string> path_name;getAllFiles(filePath, path_name);cout << "path_name.size()=" << path_name.size() << endl;int number = 1;for (auto i : path_name){//cout << i.size() << endl;if (i.size() == 7) continue;if (i.find(".log") != std::string::npos) continue;if (i.find(".txt") != std::string::npos) continue;if (i.find("_result") != std::string::npos) continue;if (i.find("png") == std::string::npos && i.find("bmp") == std::string::npos && i.find("jpg") == std::string::npos) continue;std::string path11 = filePath + "\\" + i;cv::Mat src = cv::imread(path11);//cv::Mat src = cv::imread(filePath + "\\" + i);cout << endl << "number【" << number << "】src path=" << i << " ;" << endl;src.copyTo(canvas);cv::imshow("main_OriginalIMG", src);//将结果图写入文件方便查看结果int len = filePath.length();//i = i.substr(i.find_last_of('\\') + 1, len);cout << "i=" << i << ", path11=" << path11 << endl;int time_start = clock();int time_end = clock();cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);//cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);if (getROI) ROI = getROIFromString(i);bool flag = m_ImageProcessing.LaserParallelToTheMainD_ROI(src, ROI, outMidY, midP, linearPntT, linearPntB, top, bottom, canvas, midyTolerant, arcTop_right, false);time_end = clock();printf("\n耗时 %d ms \n", time_end - time_start);cout << "\nmain ==== flag " << flag << endl;if (flag) {cout << "top = " << top.x << " " << top.y << endl;cout << "bottom = " << bottom.x << " " << bottom.y << endl;}canvas.copyTo(src);cv::putText(src, to_string(flag), cv::Point(src.cols / 2 - 20, src.rows / 2 - 65), cv::FONT_HERSHEY_COMPLEX, 1.75, cv::Scalar(255, 135, 160), 3);cv::imshow("main-结果图src", src);cv::imshow("main-canvas", canvas);//将结果图写入文件方便查看结果char* filePath_ = new char[len + 1];strcpy(filePath_, filePath.c_str());len = filePath.length();char* resPath_ = new char[len + 1];strcpy(resPath_, resPath.c_str());//i.erase(0, strlen(filePath_) - strlen(resPath_) - 2);string out = filePath + resPath;cout << "\nmain ==== i " << i << endl;out.append("\\").append(i);cout << "number【" << number << "】res path=" << out << endl;cv::imwrite(out, src);number++;cout << "path_name.size() = " << path_name.size() << endl;cout << "*********************************************************************************************************************" << endl;cv::waitKey(10);}cout << "循环结束!!! main " << endl;}ofs.close();cv::waitKey(0);system("Pause");return 0;
}
四点
返回四点+1个点集
/*//矩形位置 返回四点+骨干点集cv::Mat img, 原图cv::Rect ROI,cv::Point & p1, 图像较上方的主管底部点cv::Point & p2, 图像较上方的矩形顶部边缘点cv::Point & p3, 图像较下方的主管底部点cv::Point & p4,图像较下方的矩形顶部边缘点std::vector<cv::Point>& allPntList:直线部分非弧线的点集cv::Mat &canvas,效果图可视化*/bool rectangle4Pnt(cv::Mat imgOriginal, cv::Point & p1, cv::Point& p2, cv::Point & p3, cv::Point& p4, std::vector<cv::Point>& allPntList, cv::Mat &canvas, bool debug = false);bool rectangle4Pnt_ROI(cv::Mat img, cv::Rect ROI, cv::Point & p1, cv::Point& p2, cv::Point & p3, cv::Point& p4, std::vector<cv::Point>& allPntList, cv::Mat &canvas, bool debug = false);
bool PTank_imgProcess::rectangle4Pnt_ROI(cv::Mat img, cv::Rect ROI, cv::Point & p1, cv::Point& p2, cv::Point & p3, cv::Point& p4, std::vector<cv::Point>& allPntList, cv::Mat & canvas, bool debug)
{int endRes = 0;bool result = false;img.copyTo(canvas);p1 = cv::Point(0, 0);p2 = cv::Point(0, 0);p3 = cv::Point(0, 0);p4 = cv::Point(0, 0);allPntList.clear();cv::Mat imgOriginal;bool ROI_flag;//是否有给信息区cv::Point ROI_tl = cv::Point2i(ROI.x, ROI.y);cv::Point ROI_br = cv::Point2i(ROI.x + ROI.width, ROI.y + ROI.height);if (ROI_tl == cv::Point(0, 0) && ROI_br == cv::Point(0, 0) || ROI.width == 0 || ROI.height == 0){img.copyTo(imgOriginal);ROI_flag = false;}else{if (ROI_tl.x > ROI_br.x || ROI_tl.y > ROI_br.y)//信息区两点疑似传反{printf("信息区两点疑似传反!");return false;}if (ROI_tl.x < 0 || ROI_br.x > img.cols || ROI_tl.y < 0 || ROI_br.y > img.rows)//信息区的框选超出图像范围{printf("信息区的框选超出图像范围!");return false;}if (abs(ROI_tl.x - ROI_br.x) > img.cols || abs(ROI_tl.y - ROI_br.y) > img.rows)//信息区大小超出图像大小{printf("信息区大小超出图像大小!");return false;}//此时不合法的ROI都已提前返回falsecv::Rect roi(ROI_tl.x, ROI_tl.y, ROI_br.x - ROI_tl.x, ROI_br.y - ROI_tl.y);imgOriginal = img(roi); //裁剪出的ROI区域放于imgOriginalROI_flag = true;}result = rectangle4Pnt(imgOriginal, p1, p2, p3, p4, allPntList, canvas, debug);//调用识别算法if (debug) printf("-------------------------------------****------ roiF p1=【%d, %d】, p2=【%d, %d】\n", p1.x, p1.y, p2.x, p2.y);if (debug) printf("-------------------------------------****------ roiF p3=【%d, %d】, p4=【%d, %d】\n", p3.x, p3.y, p4.x, p4.y);//img.copyTo(canvas);img.copyTo(canvas);//调试时注释掉if (result){endRes = 1;p1 += ROI_tl;p2 += ROI_tl;p3 += ROI_tl;p4 += ROI_tl;for (int i = 0; i < allPntList.size(); i++) {allPntList.at(i) += ROI_tl;}int w = 5;for (int i = 0; i < allPntList.size(); i++) {cv::Point curPoint = allPntList.at(i);cv::line(canvas, curPoint, cv::Point(curPoint.x - w, curPoint.y), cv::Scalar(55, 195, 40), 1);}cv::putText(canvas, "true", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);circle(canvas, p1, 3, cv::Scalar(0, 69, 255), 1);circle(canvas, p1, 63, cv::Scalar(0, 169, 255), 1);circle(canvas, p2, 3, cv::Scalar(0, 69, 255), 1);circle(canvas, p2, 43, cv::Scalar(255, 169, 0), 1);circle(canvas, p3, 3, cv::Scalar(0, 69, 255), 1);circle(canvas, p3, 63, cv::Scalar(0, 169, 255), 1);circle(canvas, p4, 3, cv::Scalar(0, 69, 255), 1);circle(canvas, p4, 43, cv::Scalar(255, 169, 0), 1);}else{cv::putText(canvas, "false", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);}cv::Mat ROIcanvas;img.copyTo(ROIcanvas);if (debug) circle(ROIcanvas, p1, 3, cv::Scalar(0, 69, 255), 1);if (debug) circle(ROIcanvas, p1, 63, cv::Scalar(0, 169, 255), 1);if (debug) circle(ROIcanvas, p2, 3, cv::Scalar(0, 69, 255), 1);if (debug) circle(ROIcanvas, p2, 63, cv::Scalar(0, 169, 255), 1);if (debug) circle(ROIcanvas, p3, 3, cv::Scalar(0, 69, 255), 1);if (debug) circle(ROIcanvas, p3, 63, cv::Scalar(0, 169, 255), 1);if (debug) circle(ROIcanvas, p4, 3, cv::Scalar(0, 69, 255), 1);if (debug) circle(ROIcanvas, p4, 63, cv::Scalar(0, 169, 255), 1);if (debug) rectangle(ROIcanvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);rectangle(canvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);if (debug) printf("---------------****------ roiF p1=【%d, %d】, p2=【%d, %d】\n", p1.x, p1.y, p2.x, p2.y);if (debug) printf("---------------****------ roiF p3=【%d, %d】, p4=【%d, %d】\n", p3.x, p3.y, p4.x, p4.y);if (debug) imshow("ROI", ROIcanvas);if (debug) imshow("ROI_canvas", canvas);//ROIcanvas.copyTo(canvas);return result;
}
调用main:
//矩形位置 返回四点+骨干点集
int main/*Rectangle4Pnt_ROI*/() {bool flag;//std::string filePath = "../../../../Log08141641/TestImg/src";std::string filePath = "E://vsproject//压力罐\\img\\矩形";string resPath = "/output";//string resPath = filePath + "./output";cv::Point tlP = cv::Point(500, 292);cv::Point brP = cv::Point(750, 677);//cv::Rect ROI = cv::Rect(0, 0, 0, 0);//cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);//cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);//cv::Rect ROI = cv::Rect(539, 218, 113, 513);cv::Point top(90, 90);cv::Point bottom(90, 90);cv::Point p3(90, 90);cv::Point p4(90, 90);int outMidY;cv::Mat canvas;PTank_imgProcess m_ImageProcessing;ofstream ofs("log.txt", ios::out);if (ofs){ofs.clear();ofs << "日志启动" << endl;}std::vector<cv::Point> allPntList;vector<string> path_name;bool getROI = true;bool lianxu = false; //循环测试if (lianxu){string name = cv::format("\\Image_20240627144521008.png");string path = filePath + name;cv::Mat src = cv::imread(path);src.copyTo(canvas);cv::namedWindow("main_OriginalIMG", cv::RECURS_FILTER);cvSetMouseCallback("main_OriginalIMG", on_mouse_singleClick, 0);cv::imshow("main_OriginalIMG", src);//cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);if (getROI) ROI = getROIFromString(name);bool flag = m_ImageProcessing.rectangle4Pnt_ROI(src, ROI, top, bottom, p3, p4, allPntList, canvas, true);cout << "\nmain ==== flag " << flag << endl;if (flag) {cout << "top = " << top.x << " " << top.y << endl;cout << "bottom = " << bottom.x << " " << bottom.y << endl;}canvas.copyTo(src);//cout << "\nmain ==== i " << endl;circle(canvas, top, 63, cv::Scalar(0, 69, 255), 1);circle(canvas, bottom, 63, cv::Scalar(0, 69, 255), 1);cv::putText(src, to_string(flag), cv::Point(src.cols / 2 - 20, src.rows / 2 - 65), cv::FONT_HERSHEY_COMPLEX, 1.75, cv::Scalar(255, 135, 160), 3);cv::namedWindow("main-结果图src", cv::RECURS_FILTER);cvSetMouseCallback("main-结果图src", on_mouse_singleClick, 0);cv::imshow("main-结果图src", src);cv::namedWindow("main-canvas", cv::RECURS_FILTER);cvSetMouseCallback("main-canvas", on_mouse_singleClick, 0);cv::imshow("main-canvas", canvas);}else{vector<string> path_name;getAllFiles(filePath, path_name);cout << "path_name.size()=" << path_name.size() << endl;int number = 1;for (auto i : path_name){//cout << i.size() << endl;if (i.size() == 7) continue;if (i.find(".log") != std::string::npos) continue; if (i.find("png") == std::string::npos && i.find("bmp") == std::string::npos && i.find("jpg") == std::string::npos) continue;std::string path11 = filePath + "\\" + i;cv::Mat src = cv::imread(path11);//cv::Mat src = cv::imread(filePath + "\\" + i);cout << endl << "number【" << number << "】src path=" << i << " ;" << endl;src.copyTo(canvas);cv::imshow("main_OriginalIMG", src);//将结果图写入文件方便查看结果int len = filePath.length();//i = i.substr(i.find_last_of('\\') + 1, len);cout << "i=" << i << ", path11=" << path11 << endl;int time_start = clock();int time_end = clock();cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);//cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);if (getROI) ROI = getROIFromString(i);bool flag = m_ImageProcessing.rectangle4Pnt_ROI(src, ROI, top, bottom, p3, p4, allPntList, canvas, false);time_end = clock();printf("\n耗时 %d ms \n", time_end - time_start);cout << "\nmain ==== flag " << flag << endl;if (flag) {cout << "top = " << top.x << " " << top.y << endl;cout << "bottom = " << bottom.x << " " << bottom.y << endl;}canvas.copyTo(src);cv::putText(src, to_string(flag), cv::Point(src.cols / 2 - 20, src.rows / 2 - 65), cv::FONT_HERSHEY_COMPLEX, 1.75, cv::Scalar(255, 135, 160), 3);cv::imshow("main-结果图src", src);cv::imshow("main-canvas", canvas);//将结果图写入文件方便查看结果char* filePath_ = new char[len + 1];strcpy(filePath_, filePath.c_str());len = filePath.length();char* resPath_ = new char[len + 1];strcpy(resPath_, resPath.c_str());//i.erase(0, strlen(filePath_) - strlen(resPath_) - 2);string out = filePath + resPath;cout << "\nmain ==== i " << i << endl;out.append("\\").append(i);cout << "number【" << number << "】res path=" << out << endl;cv::imwrite(out, src);number++;cout << "path_name.size() = " << path_name.size() << endl;cout << "*********************************************************************************************************************" << endl;cv::waitKey(10);}cout << "循环结束!!! main " << endl;}ofs.close();cv::waitKey(0);system("Pause");return 0;
}
返回四点+双点集
/*//多层多道焊 圆管表面 & 四边形坡口拼接cv::Mat img, 原图cv::Point& top, 输出焊点(图像上位于较上方的点)cv::Point& bottom, 输出焊点(图像上位于较下方的点)std::vector<cv::Point>& groovePnt:坡口部分包括内侧面的点集cv::Point& valleyT, 位于焊道底部的焊点(图像上位于较上方的点)cv::Point& valleyB, 位于焊道底部的焊点(图像上位于较下方的点)std::vector<cv::Point>& valleyPnt,位于焊道底部的,焊道底部两点之间的点集cv::Mat &canvas,效果图可视化cv::Rect ROI,*/bool multilayerMultichannel4(cv::Mat imgOriginal, cv::Point& top, cv::Point& bottom, std::vector<cv::Point>& groovePnt, cv::Point& valleyT, cv::Point& valleyB, std::vector<cv::Point>& valleyPnt, cv::Mat &canvas, bool debug = false);bool multilayerMultichannel4_ROI(cv::Mat img, cv::Point& top, cv::Point& bottom, std::vector<cv::Point>& groovePnt, cv::Point& valleyT, cv::Point& valleyB, std::vector<cv::Point>& valleyPnt, cv::Mat &canvas, cv::Rect ROI = cv::Rect(540, 540, 200, 200), bool debug = false);
bool ImageProcess::multilayerMultichannel4_ROI(cv::Mat img, cv::Point & top, cv::Point & bottom, std::vector<cv::Point>& groovePnt, cv::Point & valleyT, cv::Point & valleyB, std::vector<cv::Point>& valleyPnt, cv::Mat & canvas, cv::Rect ROI, bool debug)
{int endRes = 0;bool result = false;img.copyTo(canvas);top = cv::Point(0, 0);bottom = cv::Point(0, 0);groovePnt.clear();valleyT = cv::Point(0, 0);valleyB = cv::Point(0, 0);valleyPnt.clear();cv::Mat imgOriginal;bool ROI_flag;//是否有给信息区cv::Point ROI_tl = cv::Point2i(ROI.x, ROI.y);cv::Point ROI_br = cv::Point2i(ROI.x + ROI.width, ROI.y + ROI.height);if (ROI_tl == cv::Point(0, 0) && ROI_br == cv::Point(0, 0) || ROI.width == 0 || ROI.height == 0){img.copyTo(imgOriginal);ROI_flag = false;}else{if (ROI_tl.x > ROI_br.x || ROI_tl.y > ROI_br.y)//信息区两点疑似传反{printf("信息区两点疑似传反!");return false;}if (ROI_tl.x < 0 || ROI_br.x > img.cols || ROI_tl.y < 0 || ROI_br.y > img.rows)//信息区的框选超出图像范围{printf("信息区的框选超出图像范围!");return false;}if (abs(ROI_tl.x - ROI_br.x) > img.cols || abs(ROI_tl.y - ROI_br.y) > img.rows)//信息区大小超出图像大小{printf("信息区大小超出图像大小!");return false;}//此时不合法的ROI都已提前返回falsecv::Rect roi(ROI_tl.x, ROI_tl.y, ROI_br.x - ROI_tl.x, ROI_br.y - ROI_tl.y);imgOriginal = img(roi); //裁剪出的ROI区域放于imgOriginalROI_flag = true;}result = multilayerMultichannel4(imgOriginal, top, bottom, groovePnt, valleyT, valleyB, valleyPnt, canvas, debug);//调用识别算法if (debug) printf("-------------------------------------****------ roiF top=【%d, %d】, bottom=【%d, %d】\n", top.x, top.y, bottom.x, bottom.y);if (debug) printf("----- roiF valleyT=【%d, %d】, valleyB=【%d, %d】\n", valleyT.x, valleyT.y, valleyB.x, valleyB.y);//img.copyTo(canvas);x值和y值补上ROI左上点x和y//if (ROI_flag) {// if (Corner != cv::Point(0, 0))// {// Corner.x += ROI_tl.x;// Corner.y += ROI_tl.y;// }//}img.copyTo(canvas);//调试时注释掉cv::Mat t1;canvas.convertTo(t1, -1, 1900 / 100.0, 100 - 100);//第一次线性变换100if (debug)cv::imshow("线性变换ROI", t1);t1.copyTo(canvas);if (result){endRes = 1;top += ROI_tl;bottom += ROI_tl;valleyT += ROI_tl;valleyB += ROI_tl;for (int i = 0; i < groovePnt.size(); i++) {groovePnt.at(i) += ROI_tl;}for (int i = 0; i < valleyPnt.size(); i++) {valleyPnt.at(i) += ROI_tl;}int w = 9;for (int i = 0; i < groovePnt.size(); i++) {cv::Point curPoint = groovePnt.at(i);cv::line(canvas, curPoint, cv::Point(curPoint.x + w, curPoint.y), cv::Scalar(55, 195, 40), 1);}cv::putText(canvas, "true", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);circle(canvas, top, 3, cv::Scalar(0, 69, 255), 1);circle(canvas, top, 63, cv::Scalar(0, 169, 255), 1);circle(canvas, bottom, 3, cv::Scalar(0, 69, 255), 1);circle(canvas, bottom, 43, cv::Scalar(255, 169, 0), 1);circle(canvas, valleyT, 3, cv::Scalar(0, 69, 255), 1);circle(canvas, valleyT, 43, cv::Scalar(0, 169, 255), 1);circle(canvas, valleyB, 3, cv::Scalar(0, 69, 255), 1);circle(canvas, valleyB, 23, cv::Scalar(255, 169, 0), 1);for (int i = 0; i < valleyPnt.size(); i++) {cv::Point curPoint = valleyPnt.at(i);cv::line(canvas, curPoint, cv::Point(curPoint.x - w, curPoint.y), cv::Scalar(75, 155, 40), 1);}}else{cv::putText(canvas, "false", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);}cv::Mat ROIcanvas;img.copyTo(ROIcanvas);if (debug) circle(ROIcanvas, top, 3, cv::Scalar(0, 69, 255), 1);if (debug) circle(ROIcanvas, top, 63, cv::Scalar(0, 169, 255), 1);if (debug) circle(ROIcanvas, bottom, 3, cv::Scalar(0, 69, 255), 1);if (debug) circle(ROIcanvas, bottom, 63, cv::Scalar(0, 169, 255), 1);if (debug) rectangle(ROIcanvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);rectangle(canvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);if (debug) printf("-------------------------------------****------ roiF top=【%d, %d】, bottom=【%d, %d】\n", top.x, top.y, bottom.x, bottom.y);if (debug) printf("----- roiF valleyT=【%d, %d】, valleyB=【%d, %d】\n", valleyT.x, valleyT.y, valleyB.x, valleyB.y);if (debug) imshow("ROI", ROIcanvas);if (debug) imshow("ROI_canvas", canvas);//ROIcanvas.copyTo(canvas);return result;
}
调用main:
//multilayerMultichannel4_ROI 多层多道焊 圆管表面 & 四边形坡口拼接
int main() {bool flag;//std::string filePath = "E:\\vsproject\\WeldingLine\\多层多道4";std::string filePath = "E:\\vsproject\\WeldingLine\\多层多道4\\TestImgAAA";std::string resPath = "/output";//string resPath = filePath + "./output";//cv::Point tlP = cv::Point(500, 40);//cv::Point brP = cv::Point(750, 777);cv::Point tlP = cv::Point(345, 108);cv::Point brP = cv::Point(859, 951);cv::Rect ROI = cv::Rect(0, 0, 0, 0);//cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);//cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);//cv::Rect ROI = cv::Rect(544,208,107,545);//cv::Rect ROI = cv::Rect(639, 188, 125, 569);cv::Point top(90, 90);cv::Point bottom(90, 90);cv::Point valleyT(90, 90);cv::Point valleyB(90, 90);int outMidY;cv::Mat canvas;VisualInterface m_ImageProcessing;//ImageProcess m_ImageProcessing;std::vector<cv::Point> groovePnt;std::vector<cv::Point> valleyPnt;vector<string> path_name;bool arcTop_right = true;int midyTolerant = 4;bool getROI = !true;bool lianxu = false; //循环测试if (!lianxu){string name = cv::format("\\SrcImg_2023_12_28_14_57_17_133_ROI_1132_999_401_126_src.png");//中间底部较高的情况string path = filePath + name;cv::Mat src = cv::imread(path);src.copyTo(canvas);cv::namedWindow("main_OriginalIMG", cv::NORMCONV_FILTER);cvSetMouseCallback("main_OriginalIMG", on_mouse_singleClick, 0);cv::imshow("main_OriginalIMG", src);cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);//ROI = cv::Rect(400, 0, 400, src.rows);//cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);if (getROI) ROI = getROIFromString(name);bool flag = m_ImageProcessing.multilayerMultichannel4_ROI(src, top, bottom, groovePnt, valleyT, valleyB, valleyPnt, canvas, ROI, true);cout << "\nmain ==== flag " << flag << endl;if (flag) {cout << "top = " << top.x << " " << top.y << endl;cout << "bottom = " << bottom.x << " " << bottom.y << endl;}canvas.copyTo(src);//cout << "\nmain ==== i " << endl;circle(canvas, top, 63, cv::Scalar(0, 69, 255), 1);circle(canvas, bottom, 63, cv::Scalar(0, 69, 255), 1);cv::putText(src, to_string(flag), cv::Point(src.cols / 2 - 20, src.rows / 2 - 65), cv::FONT_HERSHEY_COMPLEX, 1.75, cv::Scalar(255, 135, 160), 3);cv::namedWindow("main-结果图src", cv::RECURS_FILTER);cvSetMouseCallback("main-结果图src", on_mouse_singleClick, 0);cv::imshow("main-结果图src", src);cv::namedWindow("main-canvas", cv::RECURS_FILTER);cvSetMouseCallback("main-canvas", on_mouse_singleClick, 0);cv::imshow("main-canvas", canvas);}else{vector<string> path_name;getAllFiles(filePath, path_name);cout << "path_name.size()=" << path_name.size() << endl;int number = 1;for (auto i : path_name){//cout << i.size() << endl;if (i.size() == 7) continue;if (i.find(".log") != std::string::npos) continue;if (i.find(".txt") != std::string::npos) continue;if (i.find("_result") != std::string::npos) continue;if (i.find("png") == std::string::npos && i.find("bmp") == std::string::npos && i.find("jpg") == std::string::npos) continue;std::string path11 = filePath + "\\" + i;cv::Mat src = cv::imread(path11);//cv::Mat src = cv::imread(filePath + "\\" + i);cout << endl << "number【" << number << "】src path=" << i << " ;" << endl;src.copyTo(canvas);cv::imshow("main_OriginalIMG", src);//将结果图写入文件方便查看结果int len = filePath.length();//i = i.substr(i.find_last_of('\\') + 1, len);cout << "i=" << i << ", path11=" << path11 << endl;int time_start = clock();int time_end = clock();cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);//ROI = cv::Rect(400, 0, 400, src.rows);cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);if (getROI) ROI = getROIFromString(i);bool flag = m_ImageProcessing.multilayerMultichannel4_ROI(src, top, bottom, groovePnt, valleyT, valleyB, valleyPnt, canvas, ROI, false);time_end = clock();printf("\n耗时 %d ms \n", time_end - time_start);cout << "\nmain ==== flag " << flag << endl;if (flag) {cout << "top = " << top.x << " " << top.y << endl;cout << "bottom = " << bottom.x << " " << bottom.y << endl;}canvas.copyTo(src);cv::putText(src, to_string(flag), cv::Point(src.cols / 2 - 20, src.rows / 2 - 65), cv::FONT_HERSHEY_COMPLEX, 1.75, cv::Scalar(255, 135, 160), 3);cv::imshow("main-结果图src", src);cv::imshow("main-canvas", canvas);//将结果图写入文件方便查看结果char* filePath_ = new char[len + 1];strcpy(filePath_, filePath.c_str());len = filePath.length();char* resPath_ = new char[len + 1];strcpy(resPath_, resPath.c_str());//i.erase(0, strlen(filePath_) - strlen(resPath_) - 2);string out = filePath + resPath;cout << "\nmain ==== i " << i << endl;out.append("\\").append(i);cout << "number【" << number << "】res path=" << out << endl;cv::imwrite(out, src);number++;cout << "path_name.size() = " << path_name.size() << endl;cout << "*********************************************************************************************************************" << endl;cv::waitKey(10);}cout << "循环结束!!! main " << endl;}cv::waitKey(0);system("Pause");return 0;
}
五点
返回五点+1个点集
/*//两弧线夹悬空的圆弧 返回五点+骨干点集 定"L"型管相贯线水平用cv::Mat img, 原图cv::Rect ROI,cv::Point & p1, 图像较上方的主管底部点cv::Point & p2, 图像较上方的弧形激光边缘点cv::Point2f & midP, 圆弧中点cv::Point & p3, 图像较下方的弧形激光边缘点cv::Point & p4,图像较下方的主管底部点std::vector<cv::Point>& allPntList:直线部分非弧线的点集cv::Mat &canvas,效果图可视化*/bool twoArcsClipTheHangingArc(cv::Mat imgOriginal, cv::Point & p1, cv::Point& p2, cv::Point2f& midP, cv::Point& p3, cv::Point& p4, std::vector<cv::Point>& allPntList, cv::Mat &canvas, bool debug = false);bool twoArcsClipTheHangingArc_ROI(cv::Mat img, cv::Rect ROI, cv::Point& p1, cv::Point& p2, cv::Point2f& midP, cv::Point& p3, cv::Point& p4, std::vector<cv::Point>& allPntList, cv::Mat &canvas, bool debug = false);
bool PTank_imgProcess::twoArcsClipTheHangingArc_ROI(cv::Mat img, cv::Rect ROI, cv::Point & p1, cv::Point & p2, cv::Point2f & midP, cv::Point & p3, cv::Point & p4, std::vector<cv::Point>& allPntList, cv::Mat & canvas, bool debug)
{int endRes = 0;bool result = false;img.copyTo(canvas);p1 = cv::Point(0, 0);p2 = cv::Point(0, 0);p3 = cv::Point(0, 0);p4 = cv::Point(0, 0);midP = cv::Point2f(0, 0);allPntList.clear();cv::Mat imgOriginal;bool ROI_flag;//是否有给信息区cv::Point ROI_tl = cv::Point2i(ROI.x, ROI.y);cv::Point ROI_br = cv::Point2i(ROI.x + ROI.width, ROI.y + ROI.height);if (ROI_tl == cv::Point(0, 0) && ROI_br == cv::Point(0, 0) || ROI.width == 0 || ROI.height == 0){img.copyTo(imgOriginal);ROI_flag = false;}else{if (ROI_tl.x > ROI_br.x || ROI_tl.y > ROI_br.y)//信息区两点疑似传反{printf("信息区两点疑似传反!");return false;}if (ROI_tl.x < 0 || ROI_br.x > img.cols || ROI_tl.y < 0 || ROI_br.y > img.rows)//信息区的框选超出图像范围{printf("信息区的框选超出图像范围!");return false;}if (abs(ROI_tl.x - ROI_br.x) > img.cols || abs(ROI_tl.y - ROI_br.y) > img.rows)//信息区大小超出图像大小{printf("信息区大小超出图像大小!");return false;}//此时不合法的ROI都已提前返回falsecv::Rect roi(ROI_tl.x, ROI_tl.y, ROI_br.x - ROI_tl.x, ROI_br.y - ROI_tl.y);imgOriginal = img(roi); //裁剪出的ROI区域放于imgOriginalROI_flag = true;}result = twoArcsClipTheHangingArc(imgOriginal, p1, p2, midP, p3, p4, allPntList, canvas, debug);//调用识别算法if (debug) printf("-------------------------------------****------ roiF p1=【%d, %d】, p2=【%d, %d】\n", p1.x, p1.y, p2.x, p2.y);if (debug) printf("-------------------------------------****------ roiF p3=【%d, %d】, p4=【%d, %d】\n", p3.x, p3.y, p4.x, p4.y);if (debug) printf(" roiF midP=【%f, %f】\n", midP.x, midP.y);//img.copyTo(canvas);img.copyTo(canvas);//调试时注释掉if (result){endRes = 1;p1 += ROI_tl;p2 += ROI_tl;p3 += ROI_tl;p4 += ROI_tl;midP += cv::Point2f(ROI_tl);for (int i = 0; i < allPntList.size(); i++) {allPntList.at(i) += ROI_tl;}int w = 5;for (int i = 0; i < allPntList.size(); i++) {cv::Point curPoint = allPntList.at(i);cv::line(canvas, curPoint, cv::Point(curPoint.x - w, curPoint.y), cv::Scalar(55, 195, 40), 1);}cv::putText(canvas, "true", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);circle(canvas, midP, 3, cv::Scalar(0, 69, 255), 1);circle(canvas, midP, 43, cv::Scalar(0, 169, 255), 1);cv::line(canvas, midP, cv::Point2f(5, midP.y), cv::Scalar(155, 195, 40), 1);cv::line(canvas, cv::Point2f(midP.x, midP.y - 5), cv::Point2f(midP.x, midP.y + 5), cv::Scalar(155, 195, 40), 1);circle(canvas, p1, 3, cv::Scalar(0, 69, 255), 1);circle(canvas, p1, 63, cv::Scalar(0, 169, 255), 1);circle(canvas, p2, 3, cv::Scalar(0, 69, 255), 1);circle(canvas, p2, 43, cv::Scalar(255, 169, 0), 1);circle(canvas, p3, 3, cv::Scalar(0, 69, 255), 1);circle(canvas, p3, 63, cv::Scalar(0, 169, 255), 1);circle(canvas, p4, 3, cv::Scalar(0, 69, 255), 1);circle(canvas, p4, 43, cv::Scalar(255, 169, 0), 1);}else{cv::putText(canvas, "false", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);}cv::Mat ROIcanvas;img.copyTo(ROIcanvas);if (debug) circle(ROIcanvas, p1, 3, cv::Scalar(0, 69, 255), 1);if (debug) circle(ROIcanvas, p1, 63, cv::Scalar(0, 169, 255), 1);if (debug) circle(ROIcanvas, p2, 3, cv::Scalar(0, 69, 255), 1);if (debug) circle(ROIcanvas, p2, 63, cv::Scalar(0, 169, 255), 1);if (debug) circle(ROIcanvas, p3, 3, cv::Scalar(0, 69, 255), 1);if (debug) circle(ROIcanvas, p3, 63, cv::Scalar(0, 169, 255), 1);if (debug) circle(ROIcanvas, p4, 3, cv::Scalar(0, 69, 255), 1);if (debug) circle(ROIcanvas, p4, 63, cv::Scalar(0, 169, 255), 1);if (debug) rectangle(ROIcanvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);rectangle(canvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);if (debug) printf("---------------****------ roiF p1=【%d, %d】, p2=【%d, %d】\n", p1.x, p1.y, p2.x, p2.y);if (debug) printf("---------------****------ roiF p3=【%d, %d】, p4=【%d, %d】\n", p3.x, p3.y, p4.x, p4.y);if (debug) printf("---------------****------ roiF midP=【%f, %f】\n", midP.x, midP.y);if (debug) imshow("ROI", ROIcanvas);if (debug) imshow("ROI_canvas", canvas);//ROIcanvas.copyTo(canvas);return result;
}
调用main:
//两弧线夹悬空的圆弧 返回五点+骨干点集 定"L"型管相贯线水平用
int mainTwoArcsClipTheHangingArc() {bool flag;//std::string filePath = "../../../../Log08141641/TestImg/src";std::string filePath = "E://vsproject//压力罐\\img\\L型管定水平";string resPath = "/output";//string resPath = filePath + "./output";cv::Point tlP = cv::Point(500, 292);cv::Point brP = cv::Point(750, 677);//cv::Rect ROI = cv::Rect(0, 0, 0, 0);//cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);//cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);//cv::Rect ROI = cv::Rect(539, 218, 113, 513);cv::Point top(90, 90);cv::Point bottom(90, 90);cv::Point p3(90, 90);cv::Point p4(90, 90);cv::Point2f midP(90, 90);int outMidY;cv::Mat canvas;PTank_imgProcess m_ImageProcessing;ofstream ofs("log.txt", ios::out);if (ofs){ofs.clear();ofs << "日志启动" << endl;}std::vector<cv::Point> allPntList;std::vector<cv::Point> tPntList;std::vector<cv::Point> bPntList;std::vector<cv::Point> mPntList;vector<string> path_name;bool getROI = true;bool lianxu = false; //循环测试if (!lianxu){string name = cv::format("\\Image_20240627151133378.png");string path = filePath + name;cv::Mat src = cv::imread(path);src.copyTo(canvas);cv::namedWindow("main_OriginalIMG", cv::RECURS_FILTER);cvSetMouseCallback("main_OriginalIMG", on_mouse_singleClick, 0);cv::imshow("main_OriginalIMG", src);//cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);if (getROI) ROI = getROIFromString(name);bool flag = m_ImageProcessing.twoArcsClipTheHangingArc_ROI(src, ROI, top, bottom, midP, p3, p4, allPntList, canvas, true);m_ImageProcessing.By4Pnt_SplitPLst_1to3(canvas, top, bottom, p3, p4, allPntList, tPntList, bPntList, mPntList, canvas, true);cout << "\nmain ==== flag " << flag << endl;if (flag) {cout << "top = " << top.x << " " << top.y << endl;cout << "bottom = " << bottom.x << " " << bottom.y << endl;cout << "midP = " << midP.x << " " << midP.y << endl;}canvas.copyTo(src);//cout << "\nmain ==== i " << endl;circle(canvas, top, 63, cv::Scalar(0, 69, 255), 1);circle(canvas, bottom, 63, cv::Scalar(0, 69, 255), 1);cv::putText(src, to_string(flag), cv::Point(src.cols / 2 - 20, src.rows / 2 - 65), cv::FONT_HERSHEY_COMPLEX, 1.75, cv::Scalar(255, 135, 160), 3);cv::namedWindow("main-结果图src", cv::RECURS_FILTER);cvSetMouseCallback("main-结果图src", on_mouse_singleClick, 0);cv::imshow("main-结果图src", src);cv::namedWindow("main-canvas", cv::RECURS_FILTER);cvSetMouseCallback("main-canvas", on_mouse_singleClick, 0);cv::imshow("main-canvas", canvas);}else{vector<string> path_name;getAllFiles(filePath, path_name);cout << "path_name.size()=" << path_name.size() << endl;int number = 1;for (auto i : path_name){//cout << i.size() << endl;if (i.size() == 7) continue;if (i.find(".log") != std::string::npos) continue;if (i.find("png") == std::string::npos && i.find("bmp") == std::string::npos && i.find("jpg") == std::string::npos) continue;std::string path11 = filePath + "\\" + i;cv::Mat src = cv::imread(path11);//cv::Mat src = cv::imread(filePath + "\\" + i);cout << endl << "number【" << number << "】src path=" << i << " ;" << endl;src.copyTo(canvas);cv::imshow("main_OriginalIMG", src);//将结果图写入文件方便查看结果int len = filePath.length();//i = i.substr(i.find_last_of('\\') + 1, len);cout << "i=" << i << ", path11=" << path11 << endl;int time_start = clock();int time_end = clock();cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);//cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);if (getROI) ROI = getROIFromString(i);bool flag = m_ImageProcessing.twoArcsClipTheHangingArc_ROI(src, ROI, top, bottom, midP, p3, p4, allPntList, canvas, false);m_ImageProcessing.By4Pnt_SplitPLst_1to3(canvas, top, bottom, p3, p4, allPntList, tPntList, bPntList, mPntList, canvas, false);time_end = clock();printf("\n耗时 %d ms \n", time_end - time_start);cout << "\nmain ==== flag " << flag << endl;if (flag) {cout << "top = " << top.x << " " << top.y << endl;cout << "bottom = " << bottom.x << " " << bottom.y << endl;cout << "midP = " << midP.x << " " << midP.y << endl;}canvas.copyTo(src);cv::putText(src, to_string(flag), cv::Point(src.cols / 2 - 20, src.rows / 2 - 65), cv::FONT_HERSHEY_COMPLEX, 1.75, cv::Scalar(255, 135, 160), 3);cv::imshow("main-结果图src", src);cv::imshow("main-canvas", canvas);//将结果图写入文件方便查看结果char* filePath_ = new char[len + 1];strcpy(filePath_, filePath.c_str());len = filePath.length();char* resPath_ = new char[len + 1];strcpy(resPath_, resPath.c_str());//i.erase(0, strlen(filePath_) - strlen(resPath_) - 2);string out = filePath + resPath;cout << "\nmain ==== i " << i << endl;out.append("\\").append(i);cout << "number【" << number << "】res path=" << out << endl;cv::imwrite(out, src);number++;cout << "path_name.size() = " << path_name.size() << endl;cout << "*********************************************************************************************************************" << endl;cv::waitKey(10);}cout << "循环结束!!! main " << endl;}ofs.close();cv::waitKey(0);system("Pause");return 0;
}
传入原图和模板图,返回vector
/*//泡泡cv::Mat img, 原图cv::Rect ROI, cv::Mat imgTemplate:模板图片(无泡泡的图)cv::Mat &canvas,效果图可视化*/bool DetectingBubble(const cv::Mat imgOriginal, cv::Mat imgTemplate, std::vector<cv::Rect> &bubbles, cv::Mat &canvas, bool debug = false);bool DetectingBubble_ROI(cv::Mat img, cv::Mat imgTemplate, std::vector<cv::Rect> &bubbles, cv::Rect ROI, cv::Mat &canvas, bool debug = false);
bool ImageProcessing::DetectingBubble_ROI(cv::Mat img, cv::Mat imgTemplate, std::vector<cv::Rect> &bubbles, cv::Rect ROI, cv::Mat & canvas, bool debug)
{cout << __FUNCTION__ << endl;int endRes = 0;bool result = false;img.copyTo(canvas);bubbles.clear();cv::Mat imgOriginal;bool ROI_flag;//是否有给信息区cv::Point ROI_tl = cv::Point2i(ROI.x, ROI.y);cv::Point ROI_br = cv::Point2i(ROI.x + ROI.width, ROI.y + ROI.height);if (ROI_tl == cv::Point(0, 0) && ROI_br == cv::Point(0, 0) || ROI.width == 0 || ROI.height == 0){img.copyTo(imgOriginal);ROI_flag = false;}else{if (ROI_tl.x > ROI_br.x || ROI_tl.y > ROI_br.y)//信息区两点疑似传反{printf("信息区两点疑似传反!");return false;}if (ROI_tl.x < 0 || ROI_br.x > img.cols || ROI_tl.y < 0 || ROI_br.y > img.rows)//信息区的框选超出图像范围{printf("信息区的框选超出图像范围!");return false;}if (abs(ROI_tl.x - ROI_br.x) > img.cols || abs(ROI_tl.y - ROI_br.y) > img.rows)//信息区大小超出图像大小{printf("信息区大小超出图像大小!");return false;}//此时不合法的ROI都已提前返回falsecv::Rect roi(ROI_tl.x, ROI_tl.y, ROI_br.x - ROI_tl.x, ROI_br.y - ROI_tl.y);imgOriginal = img(roi); //裁剪出的ROI区域放于imgOriginalimgTemplate = imgTemplate(roi);ROI_flag = true;}result = DetectingBubble(imgOriginal, imgTemplate, bubbles, canvas, debug);//调用识别算法//if (debug) printf("-------------------------------------****------ roiF top=【%d, %d】, bottom=【%d, %d】\n", top.x, top.y, bottom.x, bottom.y);img.copyTo(canvas);//调试时注释掉cv::Mat t1;canvas.convertTo(t1, -1, 200 / 100.0, 0 + 55);//if (debug) cv::imshow("线性变换0", t1);t1.copyTo(canvas);if (result){endRes = 1;cv::putText(canvas, "true", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);//for (int i = 0; i < bubbles.size(); i++) {// //bubbles.at(i).tl.x = bubbles.at(i).tl.x + ROI_tl.x;// //bubbles.at(i).tl.y = bubbles.at(i).tl.y + ROI_tl.y;// //bubbles.at(i).br.x = bubbles.at(i).br.x + ROI_tl.x;// //bubbles.at(i).br.y = bubbles.at(i).br.y + ROI_tl.y;// cv::Rect curBR = bubbles.at(i);// bubbles.at(i).x = bubbles.at(i).x + ROI_tl.x;// bubbles.at(i).y = bubbles.at(i).y + ROI_tl.y;// //curBR.tl.x = bubbles.at(i).tl.x + ROI_tl.x;// //curBR.tl.y = bubbles.at(i).tl.y + ROI_tl.y;// //curBR.br.x = bubbles.at(i).br.x + ROI_tl.x;// //curBR.br.y = bubbles.at(i).br.y + ROI_tl.y;//}for (int i = 0; i < bubbles.size(); i++) {//可视化bubbles.at(i).x = bubbles.at(i).x + ROI_tl.x;bubbles.at(i).y = bubbles.at(i).y + ROI_tl.y;cv::Rect curBR = bubbles.at(i);cv::rectangle(canvas, curBR.tl(), curBR.br(), cv::Scalar(0, 255, 0), 1);cv::putText(canvas, to_string(i), curBR.br(), cv::FONT_HERSHEY_COMPLEX, 0.45, cv::Scalar(55, 35, 160), 1);}}else{cv::putText(canvas, "false", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);}cv::Mat ROIcanvas;img.copyTo(ROIcanvas);if (debug) rectangle(ROIcanvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);rectangle(canvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);if (debug) imshow("ROI", ROIcanvas);if (debug) imshow("ROI_canvas", canvas);//ROIcanvas.copyTo(canvas);return result;
}
调用main:
//泡泡 OneSideSquare_ROI
int main/*pp*/() {bool flag;std::string filePath = "../../../../泡泡/0708/6000";//std::string filePath = "../../../../泡泡/0708/20000";string resPath = "/output";//string resPath = filePath + "./output";cv::Point tlP = cv::Point(491, 50);cv::Point brP = cv::Point(1596, 760);tlP = cv::Point(1, 296);brP = cv::Point(1160, 2278);tlP = cv::Point(190, 0);brP = cv::Point(840, 1024);//cv::Rect ROI = cv::Rect(0, 0, 0, 0);//cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);//cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);//cv::Rect ROI = cv::Rect(639, 188, 125, 569);cv::Point top(90, 90);cv::Point bottom(90, 90);cv::Point2f midP(90, 90);int outMidY;cv::Mat canvas;ImageProcessing m_ImageProcessing;ofstream ofs("log.txt", ios::out);if (ofs){ofs.clear();ofs << "日志启动" << endl;}std::vector<cv::Rect> bubbles;//泡泡集合vector<Picture_set> img_buf;vector<string> path_name;//cv::Mat templ = cv::imread(filePath + cv::format("\\屏幕截图(13).png"));//模板图的灰度图cv::Mat templ = cv::imread(filePath + cv::format("\\Image_20240708175744959.png"));//6000bool getROI = !true;bool lianxu = false; //循环测试if (lianxu){std::string name = cv::format("\\Image_20240708175747311.png");string path = filePath + name;cv::Mat src = cv::imread(path);src.copyTo(canvas);cv::namedWindow("main_OriginalIMG", cv::NORMCONV_FILTER);cvSetMouseCallback("main_OriginalIMG", on_mouse_singleClick, 0);cv::imshow("main_OriginalIMG", src);cv::imshow("templ", templ);//cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);if (getROI) {ROI = getROIFromString(name);}//cv::Mat imgCur = src - templ;imgCur = imgOriginal - imgTemplate;//if (1) cv::imshow("减去模板图后", imgCur);bool flag = m_ImageProcessing.DetectingBubble_ROI(src, templ, bubbles, ROI, canvas, true);cout << "\nmain ==== flag " << flag << endl;if (flag) {cout << "top = " << top.x << " " << top.y << endl;cout << "bottom = " << bottom.x << " " << bottom.y << endl;}canvas.copyTo(src);//cout << "\nmain ==== i " << endl;circle(canvas, top, 63, cv::Scalar(0, 69, 255), 1);circle(canvas, bottom, 63, cv::Scalar(0, 69, 255), 1);cv::putText(src, to_string(flag), cv::Point(src.cols / 2 - 20, src.rows / 2 - 65), cv::FONT_HERSHEY_COMPLEX, 1.75, cv::Scalar(255, 135, 160), 3);cv::namedWindow("main-结果图src", cv::NORMCONV_FILTER);cvSetMouseCallback("main-结果图src", on_mouse_singleClick, 0);cv::imshow("main-结果图src", src);cv::namedWindow("main-canvas", cv::NORMCONV_FILTER);cvSetMouseCallback("main-canvas", on_mouse_singleClick, 0);cv::imshow("main-canvas", canvas);}else{vector<string> path_name;getAllFiles(filePath, path_name);cout << "path_name.size()=" << path_name.size() << endl;int number = 1;for (auto i : path_name){//cout << i.size() << endl;if (i.size() == 7) continue;if (i.find("output") != std::string::npos) continue;if (i.find(".log") != std::string::npos) continue;if (i.find(".txt") != std::string::npos) continue;if (i.find("png") == std::string::npos && i.find("bmp") == std::string::npos && i.find("jpg") == std::string::npos) continue;//if (i.find("_202404220930171") == std::string::npos) continue;std::string name = i;std::string path11 = filePath + "\\" + i;cv::Mat src = cv::imread(path11);//cv::Mat src = cv::imread(filePath + "\\" + i);cout << endl << "number【" << number << "】src path=" << i << " ;" << endl;src.copyTo(canvas);cv::imshow("main_OriginalIMG", src);//将结果图写入文件方便查看结果int len = filePath.length();//i = i.substr(i.find_last_of('\\') + 1, len);cout << "i=" << i << ", path11=" << path11 << endl;int time_start = clock();int time_end = clock();cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);if (getROI) {ROI = getROIFromString(name);}bool flag = m_ImageProcessing.DetectingBubble_ROI(src, templ, bubbles, ROI, canvas, false);time_end = clock();printf("\n耗时 %d ms \n", time_end - time_start);cout << "\nmain ==== flag " << flag << endl;if (flag) {cout << "top = " << top.x << " " << top.y << endl;cout << "bottom = " << bottom.x << " " << bottom.y << endl;}canvas.copyTo(src);//cv::putText(src, to_string(number - 1), { cv::Point(250, 250) }, cv::FONT_HERSHEY_COMPLEX, 8, cv::Scalar(255, 255, 255), 5);cv::putText(src, to_string(flag), cv::Point(src.cols / 2 - 20, src.rows / 2 - 65), cv::FONT_HERSHEY_COMPLEX, 1.75, cv::Scalar(255, 135, 160), 3);cv::namedWindow("main-结果图src", cv::NORMCONV_FILTER);cv::imshow("main-结果图src", src);cv::namedWindow("main-canvas", cv::NORMCONV_FILTER);cv::imshow("main-canvas", canvas);//将结果图写入文件方便查看结果char* filePath_ = new char[len + 1];strcpy(filePath_, filePath.c_str());len = filePath.length();char* resPath_ = new char[len + 1];strcpy(resPath_, resPath.c_str());//i.erase(0, strlen(filePath_) - strlen(resPath_) - 2);string out = filePath + resPath;cout << "\nmain ==== i " << i << endl;out.append("\\").append(i);cout << "number【" << number << "】res path=" << out << endl;cv::imwrite(out, src);number++;cout << "path_name.size() = " << path_name.size() << endl;cout << "*********************************************************************************************************************" << endl;cv::waitKey(1);}cout << "循环结束!!! main " << endl;}ofs.close();cv::waitKey(0);system("Pause");return 0;
}
***识别接口开头模板***
{bool result = false;if (imgOriginal.empty()) {printf("传入图像为空,直接返回false!!!! \n");return false;}imgOriginal.copyTo(canvas);top = cv::Point(0, 0);bottom = cv::Point(0, 0);midP = cv::Point(0, 0);cv::Mat imgGray;if (imgOriginal.type() != CV_8UC1)cv::cvtColor(imgOriginal, imgGray, cv::COLOR_BGR2GRAY);else imgOriginal.copyTo(imgGray);//if (1) {// cv::Mat imgMedianBlur;// cv::medianBlur(imgGray, imgMedianBlur, 3);// if (debug) cv::imshow("imgMedianBlur", imgMedianBlur);// imgMedianBlur.copyTo(imgGray);//}cv::Mat close;cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(7, 5));cv::morphologyEx(imgGray, close, cv::MORPH_CLOSE, kernel);if (debug) cv::imshow("闭运算", close);cv::Mat thresholdMat;cv::adaptiveThreshold(close, thresholdMat, 255, cv::ADAPTIVE_THRESH_GAUSSIAN_C, cv::THRESH_BINARY, 85, -15);if (debug) cv::imshow("threshold", thresholdMat);//一个不为0的像素都没有,即全黑时,直接返回falseint iVal255 = cv::countNonZero(thresholdMat);if (!iVal255) return false;std::vector<std::vector<cv::Point>> contours;std::vector<cv::Vec4i> hierarchy;std::vector<std::vector<cv::Point>>::iterator k;cv::findContours(thresholdMat, contours, hierarchy, cv::RETR_EXTERNAL, CV_RETR_LIST);if (contours.size() <= 0)//图为全黑时{std::cout << "contours.size() <= 0";return false;}if (debug) printf("图像处理后 检测到的轮廓数 contours.size() = %d \n", contours.size());int remainNum = 0;//剩余的轮廓数cv::Mat tmpMat = cv::Mat(thresholdMat.rows, thresholdMat.cols, CV_8UC1, cv::Scalar(0, 0, 0));//画出轮廓;int count = 0;for (k = contours.begin(); k != contours.end(); ++k, count++) //删除小连通域的{std::vector<cv::Point> curContours = *k;if (curContours.size() < 40) continue;remainNum++;cv::drawContours(tmpMat, contours, count, cv::Scalar(255, 255, 255), -1, CV_AA, hierarchy); //用全黑色填充}if (debug) cv::imshow("tmpMat", tmpMat);if (debug) printf("删减后 剩余的轮廓数 remainNum = %d \n", remainNum);if (remainNum == 0)//图为全黑时{std::cout << "contours.size() <= 0";return false;}//------------------------------------------------------------------------------------------------------------------------------------//提取骨干点集std::vector<cv::Point> bright_point;//max点std::vector<int> bright_value;//max像素值//bright_point = extrectBackbone(tmpMat, bright_value);if (1) {if (debug) cout << "tmpMat.size() =" << tmpMat.size() << std::endl;int splitRow = tmpMat.rows / 2 - 5;cv::Mat tmpMatU, tmpMatD;tmpMat.rowRange(0, splitRow).copyTo(tmpMatU);tmpMat.rowRange(splitRow, tmpMat.rows).copyTo(tmpMatD);cv::flip(tmpMatU, tmpMatU, 0);std::vector<cv::Point> bright_pointU;//max点std::vector<cv::Point> bright_pointD;//max点std::vector<int> bright_valueU;//max像素值std::vector<int> bright_valueD;//max像素值bright_pointU = extrectBackbone(tmpMatU, bright_valueU, 0);bright_pointD = extrectBackbone(tmpMatD, bright_valueD, 0);std::reverse(bright_pointU.begin(), bright_pointU.end());for (int i = 0; i < bright_pointU.size(); i++) {//把上半部分的骨干上下翻转回cv::Point curPoint = bright_pointU.at(i);if (curPoint.x != 0) curPoint.y = tmpMatU.rows - curPoint.y - 1;//if(debug) printf("将上半截骨干排序反转:第%d 行, 【%d, %d】 ============= \n", i, curPoint.x, curPoint.y);//curPoint.x = tmpMat.cols - curPoint.x;bright_point.push_back(curPoint);}std::vector<cv::Point> bright_pointD_new;for (int i = 0; i < bright_pointD.size(); i++) {cv::Point curPoint = bright_pointD.at(i);if (curPoint.x != 0) curPoint.y = splitRow + curPoint.y;bright_pointD_new.push_back(curPoint);}bright_pointD = bright_pointD_new;bright_point.insert(bright_point.end(), bright_pointD.begin(), bright_pointD.end());std::reverse(bright_valueU.begin(), bright_valueU.end());bright_value = bright_valueU;bright_value.insert(bright_value.end(), bright_valueD.begin(), bright_valueD.end());}//有效骨干个数过少,直接返回 false !!!!int vaildBackbone = 0;//有效骨干个数for (int i = 0; i < bright_point.size(); i++){cv::Point P = bright_point.at(i);if (P != cv::Point(0, 0)) vaildBackbone++;}if (debug) printf("有效骨干个数 vaildBackbone = %d \n", vaildBackbone);if (vaildBackbone <= 30){printf("有效骨干个数过少!!!!\n");return false;}if (debug) {printf("骨干点集更新前:\n");for (int i = 0; i < bright_point.size(); i++){cv::Point curPoint = bright_point.at(i);int curGray = bright_value.at(i);//printf("骨干点集更新前:第%d 行, 【%d, %d】 灰度值:%d \n", i, curPoint.x, curPoint.y, curGray);}}std::vector<cv::Point> tmpPoint;std::vector<int> tmpValue;for (int i = 0; i < bright_point.size(); i++) {cv::Point curPoint = bright_point.at(i);if (curPoint.x == 0 || curPoint.y == 0) continue;if (tmpMat.at<uchar>(curPoint) < 185) continue;//if (imgGray.at<uchar>(curPoint) < 185) continue;tmpPoint.push_back(curPoint);}bright_point = tmpPoint;//把无效点删掉if (0) {std::vector<cv::Point> rightmost;//激光最右点集//for (int row = 0; row < tmpMat.rows; row++)//for (int row = bright_point.at(0).y; row < bright_point.at(bright_point.size() - 1).y; row++)for (int i = 0; i < bright_point.size(); i++){int row = bright_point[i].y;//for (int col = bright_point.at(row).x; col < tmpMat.cols - 1; col++)//-1是为了防崩溃for (int col = bright_point.at(i).x; col < tmpMat.cols - 1 && col < bright_point.at(i).x + 70; col++)//-1是为了防崩溃{int pv = tmpMat.at<uchar>(row, col);//int pv = tmpMat.at<uchar>(row, col);if (pv != 0 && tmpMat.at<uchar>(row, col + 1) == 0)//激光最右点入列{if (!rightmost.empty() && rightmost.back().y == row) rightmost.pop_back();rightmost.push_back(cv::Point(col - 1, row));//break;}}}bright_point = rightmost;}if (debug) {printf("骨干点集更新后:\n");for (int i = 0; i < bright_point.size(); i++) {cv::Point curPoint = bright_point.at(i);printf("骨干点集更新后:第%d 行, 【%d, %d】 \n", i, curPoint.x, curPoint.y);}}if (debug) printf("有效骨干个数 bright_point.size() = %d \n", bright_point.size());if (bright_point.size() <= 30){printf("有效骨干个数过少!!!!\n");return false;}allPntList = bright_point;//可视化骨干点集cv::Mat newArcMat = cv::Mat::zeros(tmpMat.size(), CV_8UC1);for (int i = 0; i < bright_point.size(); i++){cv::Point P = cv::Point(bright_point.at(i).x, bright_point.at(i).y);newArcMat.at<uchar>(cv::Point(bright_point.at(i).x, bright_point.at(i).y)) = 255;}cv::Mat BowCurveMat;cv::Mat imgRGB_Begin;if (newArcMat.type() != CV_8UC1)cvtColor(newArcMat, imgRGB_Begin, cv::COLOR_RGB2GRAY);else newArcMat.copyTo(imgRGB_Begin);//重叠看效果cv::addWeighted(tmpMat, 0.5, imgRGB_Begin, 0.5, 0, BowCurveMat);//if (debug) cv::namedWindow("BowCurveMat", cv::WINDOW_NORMAL);if (debug) cv::imshow("BowCurveMat", BowCurveMat);result = true;// TODOreturn result;
}
相关文章:
ROI 接口便捷修改
传入的图片截取ROI后再进入识别接口 (识别接口比ROI接口的函数参数少一个传入的ROI) 无点只有点集 返回双点集 //平直冷侧翅片 bool ImageProcessingTest::straightColdSideFin_ROI(cv::Mat img, cv::Rect ROI, std::vector<cv::Point>& topL…...
jenkins打包java项目报错Error: Unable to access jarfile tlm-admin.jar
jenkins打包boot项目 自动重启脚本失败 查看了一下项目日志报错: Error: Unable to access jarfile tlm-admin.jar我检查了一下这个配置,感觉没有问题,包可以正常打, cd 到项目目录下面,手动执行这个sh脚本也是能正常…...
SQL Server设置端口:跨平台指南
在使用SQL Server时,设置或修改其监听的端口是确保数据库服务安全访问和高效管理的重要步骤。由于SQL Server可以部署在多种操作系统上,包括Windows、Linux和Docker容器等,因此设置端口的步骤和方法也会因平台而异。本文将为您提供一个跨平台…...
ActiveMQ-CVE-2023-46604
Apache ActiveMQ OpenWire 协议反序列化命令执行漏洞 OpenWire协议在ActiveMQ中被用于多语言客户端与服务端通信。在Apache ActvieMQ5.18.2版本以及以前,OpenWire协议通信过程中存在一处反序列化漏洞,该漏洞可以允许具有网络访问权限的远程攻击者通过操作…...
TensorBoard ,PIL 和 OpenCV 在深度学习中的应用
重要工具介绍 TensorBoard: 是一个TensorFlow提供的强大工具,用于可视化和理解深度学习模型的训练过程和结果。下面我将介绍TensorBoard的相关知识和使用方法。 TensorBoard 简介 TensorBoard是TensorFlow提供的一个可视化工具,用于&#x…...
【超音速 专利 CN117576413A】基于全连接网络分类模型的AI涂布抓边处理方法及系统
申请号CN202311568976.4公开号(公开)CN117576413A申请日2023.11.22申请人(公开)超音速人工智能科技股份有限公司发明人(公开)张俊峰(总); 杨培文(总); 沈俊羽…...
iPhone数据恢复篇:iPhone 数据恢复软件有哪些
问题:iPhone 15 最好的免费恢复软件是什么?我一直在寻找一个恢复程序来恢复从iPhone中意外删除的照片,联系人和消息,但是我有很多选择。 谷歌一下,你会发现许多付费或免费的iPhone数据恢复工具,声称它们可…...
Html5+Css3学习笔记
Html5 CSS3 一、概念 1.什么是html5 html: Hyper Text Markup Language ( 超文本标记语言) 文本:记事本 超文本: 文字、图片、音频、视频、动画等等(网页) html语言经过浏览器的编译显示成超文本 开发者使用5种浏览器…...
WPF学习(2) -- 样式基础
一、代码 <Window x:Class"学习.MainWindow"xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x"http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d"http://schemas.microsoft.com/expression/blend/2008&…...
独家揭秘!五大内网穿透神器,访问你的私有服务
本文精心筛选了五款炙手可热的内网穿透工具,它们各怀绝技,无论您是企业用户、独立开发者,还是技术探索者,这篇文章都物有所值,废话不多说,主角们即将上场。 目录 1. 巴比达 - 安全至上的企业护航者 2. 花…...
Ubuntu 编译和运行ZLMediaKit
摘要 本文描述了如何在Ubuntu上构建ZLMediaKIt项目源码,以及如何体验其WebRTC推流和播放功能。 实验环境 操作系统版本:Ubuntu 22.04.3 LTS gcc版本:11.4.0 g版本:11.4.0 依赖库安装 #让ZLMediaKit媒体服务器具备WebRTC流转发…...
基于JavaSpringBoot+Vue+uniapp微信小程序校园宿舍管理系统设计与实现
基于JavaSpringBootVueuniapp微信小程序实现校园宿舍管理系统设计与实现 目录 第一章 绪论 1.1 研究背景 1.2 研究现状 1.3 研究内容 第二章 相关技术介绍 2.1 Java语言 2.2 HTML网页技术 2.3 MySQL数据库 2.4 Springboot 框架介绍 2.5 VueJS介绍 2.6 ElementUI介绍…...
Hive的基本操作(创建与修改)
必备知识 数据类型 基本类型 类型写法字符char, varchar, string✔整数tinyint, smallint, int✔, bigint✔小数float, double, numeric(m,n), decimal(m,n)✔布尔值boolean✔时间date✔, timestamp✔ 复杂类型(集合类型) 1、数组:array<T> 面向用户提供…...
Linux开发讲课37--- ARM的22个常用概念
1. ARM中一些常见英文缩写解释 MSB:最高有效位; LSB:最低有效位; AHB:先进的高性能总线; VPB:连接片内外设功能的VLSI外设总线; EMC:外部存储器…...
7-1、2、3 IPFS介绍使用及浏览器交互(react+区块链实战)
7-1、2、3 IPFS介绍使用及浏览器交互(react区块链实战) 7-1 ipfs介绍7-2 IPFS-desktop使用7-3 reactipfs-api浏览器和ipfs交互 7-1 ipfs介绍 IPFS区块链上的文件系统 https://ipfs.io/ 这个网站本身是需要科学上网的 Ipfs是点对点的分布式系统 无限…...
CentOS 7 中出现 cannot open Packages database in /var/lib/rpm 错误
转载自:https://www.jianshu.com/p/423306f43e72 # 进入 rpmdb 所在目录 [roothostbase ~]# cd /var/lib/rpm [roothostbase rpm]# ls Basenames __db.001 __db.003 Group Name Packages Requirename Sigmd5 Conflictname __db.002 Dirnames Ins…...
【java深入学习第6章】深入解析Spring事件监听机制
在Spring框架中,事件监听机制是一个强大且灵活的功能,允许我们在应用程序中发布和监听事件。这种机制可以帮助我们实现松耦合的设计,使得不同模块之间的通信更加灵活和可维护。本文将详细介绍Spring的事件监听机制,并通过代码示例…...
Flask与Celery实现Python调度服务
文章目录 Flask与Celery实现Python调度服务一、前言1.组件2.场景说明3.环境 二、安装依赖1.安装Anaconda3.安装redis2.安装依赖包 三、具体实现1.目录结构2.业务流程3.配置文件4.Celery程序5.Flask程序6.测试脚本7.程序启动1)Windows开发调试2)Linux服务…...
Eureka应用场景和优势
Eureka是一款由Netflix开源的服务注册与发现框架,在微服务架构中扮演着至关重要的角色。以下是Eureka的应用场景和优势: Eureka的应用场景 Eureka主要应用于微服务架构中,特别是在大型、复杂的分布式系统中,用于管理和发现服务。…...
prompt第三讲-PromptTemplate
文章目录 前提回顾PromptTemplateprompt 模板定义以f-string渲染格式以mustache渲染格式以jinja2渲染格式直接实例化PromptTemplatePromptTemplate核心变量 prompt value生成invokeformat_prompt(不建议使用)format(不建议使用) batchstreamainvoke PromptTemplate核心方法part…...
**发散创新:基于Python与OpenCV的智能交通流量实时监测系统设计
发散创新:基于Python与OpenCV的智能交通流量实时监测系统设计与实现 在智慧城市建设不断深化的背景下,智能交通系统(ITS) 正成为城市治理现代化的重要突破口。传统的交通信号控制多依赖固定时长或人工经验判断,难以应对…...
AI 模型推理延迟与吞吐率的权衡
AI模型推理延迟与吞吐率的权衡:优化策略与实践 在AI应用场景中,模型推理的延迟(Latency)和吞吐率(Throughput)是衡量系统性能的两大核心指标。延迟指单次请求的响应时间,直接影响用户体验&…...
零基础友好:跟着快马生成的交互式脚本轻松完成openclaw安装入门
作为一个刚接触编程的新手,第一次安装openclaw这样的工具时,面对复杂的命令行操作和可能出现的各种错误,确实容易感到手足无措。最近我在InsCode(快马)平台上发现了一个特别适合新手的交互式安装教程项目,它把整个安装过程变成了一…...
星闪实战指南:10分钟掌握WS63 SDK任务调度与调试技巧
1. 星闪WS63 SDK任务调度基础 第一次接触星闪WS63 SDK的任务调度功能时,我完全被各种API搞晕了。经过几个项目的实战,才发现这套任务管理系统设计得非常巧妙。简单来说,它就像个智能管家,能帮你把各种工作安排得井井有条。 任务调…...
【VLA】Vision Language Action
文章目录一、什么是世界模型(World Model)?✅ 定义:🌍 核心功能:🔧 技术原理(典型架构):二、世界模型在具身智能中的作用三、VLA(Vision-Language…...
宝塔面板怎样实现数据库的多地异地自动备份_结合阿里云OSS与定时任务插件
宝塔面板需通过定时任务ossutilmysqldump实现阿里云OSS数据库自动备份:先配置ossutil及MySQL凭据文件,再编写含时间戳命名与NTP校时的Shell脚本,避免依赖无效的远程备份模块。宝塔面板怎么配置阿里云OSS自动备份数据库能,但得绕过…...
你的瀑布图“站”对角度了吗?Matlab view命令参数详解与三维数据最佳视角选择
你的瀑布图“站”对角度了吗?Matlab view命令参数详解与三维数据最佳视角选择 在科研论文或技术报告中,一张精心设计的瀑布图(Waterfall Plot)往往能直观展示多维数据的复杂特征。但许多Matlab用户都有这样的困惑:明明数据准确无误࿰…...
【硬件小达人-基础篇(1)】-电阻那些事儿
文章目录什么是电阻电阻的功率一定要降额使用电阻的额定电压和精度额定电压精度PCB设计中,电阻的作用1.限流电阻保护敏感元件常用经验2.分压电阻电压反馈ADC采集电路一些经验3.分流电阻4.上拉电阻/下拉电阻什么是上下拉作用一、 防止引脚悬空,消除外部干…...
downkyi全链路解决方案:从视频获取到专业处理的一站式视频工作流指南
downkyi全链路解决方案:从视频获取到专业处理的一站式视频工作流指南 【免费下载链接】downkyi 哔哩下载姬downkyi,哔哩哔哩网站视频下载工具,支持批量下载,支持8K、HDR、杜比视界,提供工具箱(音视频提取、…...
DownKyi:3分钟学会B站视频下载的终极免费方案
DownKyi:3分钟学会B站视频下载的终极免费方案 【免费下载链接】downkyi 哔哩下载姬downkyi,哔哩哔哩网站视频下载工具,支持批量下载,支持8K、HDR、杜比视界,提供工具箱(音视频提取、去水印等)。…...
