当前位置:   article > 正文

ROI 接口便捷修改

ROI 接口便捷修改

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

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

无点只有点集

 返回双点集

  1. //平直冷侧翅片
  2. 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)
  3. {
  4. int endRes = 0;
  5. bool result = false;
  6. img.copyTo(canvas);
  7. //top = cv::Point(0, 0);
  8. //bottom = cv::Point(0, 0);
  9. cv::Mat imgOriginal;
  10. bool ROI_flag;//是否有给信息区
  11. cv::Point ROI_tl = cv::Point2i(ROI.x, ROI.y);
  12. cv::Point ROI_br = cv::Point2i(ROI.x + ROI.width, ROI.y + ROI.height);
  13. if (ROI_tl == cv::Point(0, 0) && ROI_br == cv::Point(0, 0) || ROI.width == 0 || ROI.height == 0)
  14. {
  15. img.copyTo(imgOriginal);
  16. ROI_flag = false;
  17. }
  18. else
  19. {
  20. if (ROI_tl.x > ROI_br.x || ROI_tl.y > ROI_br.y)//信息区两点疑似传反
  21. {
  22. printf("信息区两点疑似传反!");
  23. return false;
  24. }
  25. if (ROI_tl.x < 0 || ROI_br.x > img.cols || ROI_tl.y < 0 || ROI_br.y > img.rows)//信息区的框选超出图像范围
  26. {
  27. printf("信息区的框选超出图像范围!");
  28. return false;
  29. }
  30. if (abs(ROI_tl.x - ROI_br.x) > img.cols || abs(ROI_tl.y - ROI_br.y) > img.rows)//信息区大小超出图像大小
  31. {
  32. printf("信息区大小超出图像大小!");
  33. return false;
  34. }
  35. //此时不合法的ROI都已提前返回false
  36. cv::Rect roi(ROI_tl.x, ROI_tl.y, ROI_br.x - ROI_tl.x, ROI_br.y - ROI_tl.y);
  37. imgOriginal = img(roi); //裁剪出的ROI区域放于imgOriginal
  38. ROI_flag = true;
  39. }
  40. result = straightColdSideFin(imgOriginal, topList, bottomList, canvas, debug);//调用识别算法
  41. if (debug) {
  42. for (int i = 0; i < topList.size(); i++) {
  43. cv::Point top = topList.at(i);
  44. top += ROI_tl;
  45. if (debug) printf("-------------------------------------****------ roiF top=【%d, %d】\n", top.x, top.y);
  46. }
  47. for (int i = 0; i < bottomList.size(); i++) {
  48. cv::Point bottom = bottomList.at(i);
  49. bottom += ROI_tl;
  50. if (debug) printf("-------------------------------------****------ roiF bottom=【%d, %d】\n", bottom.x, bottom.y);
  51. }
  52. }
  53. //if (debug) printf("-------------------------------------****------ roiF top=【%d, %d】, bottom=【%d, %d】\n", top.x, top.y, bottom.x, bottom.y);
  54. //img.copyTo(canvas);
  55. x值和y值补上ROI左上点x和y
  56. //if (ROI_flag) {
  57. // if (Corner != cv::Point(0, 0))
  58. // {
  59. // Corner.x += ROI_tl.x;
  60. // Corner.y += ROI_tl.y;
  61. // }
  62. //}
  63. img.copyTo(canvas);//调试时注释掉
  64. if (result)
  65. {
  66. cv::Point textP(6, 0);//演示用
  67. endRes = 1;
  68. for (int i = 0; i < topList.size(); i++) {
  69. topList.at(i) += ROI_tl;
  70. cv::Point top = topList.at(i);
  71. circle(canvas, top, 2, cv::Scalar(0, 69, 255), -1);
  72. cv::putText(canvas, to_string(i), top + textP, cv::FONT_HERSHEY_COMPLEX, 0.45, cv::Scalar(0, 69, 255), 1);//演示用
  73. }
  74. for (int i = 0; i < bottomList.size(); i++) {
  75. bottomList.at(i) += ROI_tl;
  76. cv::Point bottom = bottomList.at(i);
  77. circle(canvas, bottom, 2, cv::Scalar(255, 69, 0), -1);
  78. cv::putText(canvas, to_string(i), bottom + textP, cv::FONT_HERSHEY_COMPLEX, 0.45, cv::Scalar(255, 69, 0), 1);//演示用
  79. }
  80. printf("topList.size()=%d , bottomList.size()=%d \n", topList.size(), bottomList.size());
  81. cv::putText(canvas, "true", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);
  82. }
  83. else
  84. {
  85. cv::putText(canvas, "false", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);
  86. }
  87. cv::Mat ROIcanvas;
  88. img.copyTo(ROIcanvas);
  89. if (debug) {
  90. if (debug) printf("topList.size()=%d , bottomList.size()=%d \n", topList.size(), bottomList.size());
  91. for (int i = 0; i < topList.size(); i++) {
  92. cv::Point top = topList.at(i);
  93. circle(ROIcanvas, top, 3, cv::Scalar(0, 69, 255), 1);
  94. if (debug) printf("-------------------------------------****------ roiF top=【%d, %d】\n", top.x, top.y);
  95. }
  96. for (int i = 0; i < bottomList.size(); i++) {
  97. cv::Point bottom = bottomList.at(i);
  98. circle(ROIcanvas, bottom, 3, cv::Scalar(255, 69, 0), 1);
  99. if (debug) printf("-------------------------------------****------ roiF bottom=【%d, %d】\n", bottom.x, bottom.y);
  100. }
  101. }
  102. //if (debug) circle(ROIcanvas, top, 3, cv::Scalar(0, 69, 255), 1);
  103. //if (debug) circle(ROIcanvas, bottom, 3, cv::Scalar(0, 69, 255), 1);
  104. if (debug) rectangle(ROIcanvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);
  105. rectangle(canvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);
  106. //if (debug) printf("-------------------------------------****------ roiF top=【%d, %d】, bottom=【%d, %d】\n", top.x, top.y, bottom.x, bottom.y);
  107. if (debug) imshow("ROI", ROIcanvas);
  108. if (debug) imshow("ROI接口_canvas", canvas);
  109. //ROIcanvas.copyTo(canvas);
  110. return result;
  111. }

调用main:

  1. //平直冷侧翅片:straightColdSideFin_ROI
  2. int main333() {
  3. bool flag = false;
  4. std::string filePath = "../img/straightColdSideFin/0616img";
  5. string resPath = "/output";
  6. //string resPath = filePath + "./output";
  7. cv::Point tlP = cv::Point(200, 0);
  8. cv::Point brP = cv::Point(950, 1024);
  9. std::vector<cv::Point> topList;
  10. std::vector<cv::Point> bottomList;
  11. cv::Mat canvas;
  12. ImageProcessingTest m_ImageProcessing;
  13. ofstream ofs("log.txt", ios::out);
  14. if (ofs)
  15. {
  16. ofs.clear();
  17. ofs << "日志启动" << endl;
  18. }
  19. vector<string> path_name;
  20. bool lianxu = false; //循环测试
  21. if (lianxu)
  22. {
  23. string path = filePath + cv::format("\\Image_20230614160744823.png");
  24. //string path = filePath + cv::format("\\Image_20230609111800152.png");
  25. //string path = filePath + cv::format("\\Image_20230601143638388.png");
  26. //string path = filePath + cv::format("\\Image_20230601143505168.png");
  27. //string path = filePath + cv::format("\\Image_20230609113049539.png");
  28. cv::Mat src = cv::imread(path);
  29. src.copyTo(canvas);
  30. cv::namedWindow("main_OriginalIMG", cv::RECURS_FILTER);
  31. cvSetMouseCallback("main_OriginalIMG", on_mouse_singleClick, 0);
  32. cv::imshow("main_OriginalIMG", src);
  33. //cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);
  34. cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);
  35. bool flag = m_ImageProcessing.straightColdSideFin_ROI(src, ROI, topList, bottomList, canvas, true);
  36. cout << "\nmain ==== flag " << flag << endl;
  37. if (flag) {
  38. for (int i = 0; i < topList.size(); i++) {
  39. cv::Point top = topList.at(i);
  40. cout << "top = " << top.x << " " << top.y << endl;
  41. circle(canvas, top, 6, cv::Scalar(0, 69, 255), 1);
  42. }
  43. for (int i = 0; i < bottomList.size(); i++) {
  44. cv::Point bottom = bottomList.at(i);
  45. cout << "bottom = " << bottom.x << " " << bottom.y << endl;
  46. circle(canvas, bottom, 6, cv::Scalar(255, 69, 0), 1);
  47. }
  48. printf("topList.size()=%d , bottomList.size()=%d \n", topList.size(), bottomList.size());
  49. }
  50. canvas.copyTo(src);
  51. //cout << "\nmain ==== i " << endl;
  52. //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);
  53. cv::namedWindow("main-结果图src", cv::RECURS_FILTER);
  54. cvSetMouseCallback("main-结果图src", on_mouse_singleClick, 0);
  55. cv::imshow("main-结果图src", src);
  56. }
  57. else
  58. {
  59. vector<string> path_name;
  60. getAllFiles(filePath, path_name);
  61. cout << "path_name.size()=" << path_name.size() << endl;
  62. int number = 1;
  63. for (auto i : path_name)
  64. {
  65. cv::Mat src = cv::imread(filePath + "\\" + i);
  66. cout << endl << "number【" << number << "】src path=" << i << " ;" << endl;
  67. src.copyTo(canvas);
  68. cv::imshow("main_OriginalIMG", src);
  69. //将结果图写入文件方便查看结果
  70. int len = filePath.length();
  71. //i = i.substr(i.find_last_of('\\') + 1, len);
  72. cout << "i=" << i << endl;
  73. int time_start = clock();
  74. int time_end = clock();
  75. //cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);
  76. cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);
  77. bool flag = m_ImageProcessing.straightColdSideFin_ROI(src, ROI, topList, bottomList, canvas);
  78. time_end = clock();
  79. printf("\n耗时 %d ms \n", time_end - time_start);
  80. cout << "\nmain ==== flag " << flag << endl;
  81. if (flag) {
  82. for (int i = 0; i < topList.size(); i++) {
  83. cv::Point top = topList.at(i);
  84. cout << "top = " << top.x << " " << top.y << endl;
  85. }
  86. for (int i = 0; i < bottomList.size(); i++) {
  87. cv::Point bottom = bottomList.at(i);
  88. cout << "bottom = " << bottom.x << " " << bottom.y << endl;
  89. }
  90. printf("topList.size()=%d , bottomList.size()=%d \n", topList.size(), bottomList.size());
  91. }
  92. canvas.copyTo(src);
  93. //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);
  94. cv::imshow("main-结果图src", src);
  95. cv::waitKey(10);
  96. //将结果图写入文件方便查看结果
  97. char* filePath_ = new char[len + 1];
  98. strcpy(filePath_, filePath.c_str());
  99. len = filePath.length();
  100. char* resPath_ = new char[len + 1];
  101. strcpy(resPath_, resPath.c_str());
  102. //i.erase(0, strlen(filePath_) - strlen(resPath_) - 2);
  103. string out = filePath + resPath;
  104. cout << "\nmain ==== i " << i << endl;
  105. out.append("\\").append(i);
  106. cout << "number【" << number << "】res path=" << out << endl;
  107. cv::imwrite(out, src);
  108. number++;
  109. cout << "path_name.size() = " << path_name.size() << endl;
  110. cout << "*********************************************************************************************************************" << endl;
  111. if (number == path_name.size()) break;
  112. }
  113. }
  114. cout << "main 循环结束!!!" << endl;
  115. ofs.close();
  116. cv::waitKey(0);
  117. system("Pause");
  118. return 0;
  119. }

单点

返回只有单点 

  1. bool ImageProcess::arcPlusLine_ROI(cv::Mat img, cv::Rect ROI, cv::Point & top, cv::Mat & canvas, bool debug)
  2. {
  3. int endRes = 0;
  4. bool result = false;
  5. img.copyTo(canvas);
  6. top = cv::Point(0, 0);
  7. cv::Mat imgOriginal;
  8. bool ROI_flag;//是否有给信息区
  9. cv::Point ROI_tl = cv::Point2i(ROI.x, ROI.y);
  10. cv::Point ROI_br = cv::Point2i(ROI.x + ROI.width, ROI.y + ROI.height);
  11. if (ROI_tl == cv::Point(0, 0) && ROI_br == cv::Point(0, 0) || ROI.width == 0 || ROI.height == 0)
  12. {
  13. img.copyTo(imgOriginal);
  14. ROI_flag = false;
  15. }
  16. else
  17. {
  18. if (ROI_tl.x > ROI_br.x || ROI_tl.y > ROI_br.y)//信息区两点疑似传反
  19. {
  20. printf("信息区两点疑似传反!");
  21. return false;
  22. }
  23. if (ROI_tl.x < 0 || ROI_br.x > img.cols || ROI_tl.y < 0 || ROI_br.y > img.rows)//信息区的框选超出图像范围
  24. {
  25. printf("信息区的框选超出图像范围!");
  26. return false;
  27. }
  28. if (abs(ROI_tl.x - ROI_br.x) > img.cols || abs(ROI_tl.y - ROI_br.y) > img.rows)//信息区大小超出图像大小
  29. {
  30. printf("信息区大小超出图像大小!");
  31. return false;
  32. }
  33. //此时不合法的ROI都已提前返回false
  34. cv::Rect roi(ROI_tl.x, ROI_tl.y, ROI_br.x - ROI_tl.x, ROI_br.y - ROI_tl.y);
  35. imgOriginal = img(roi); //裁剪出的ROI区域放于imgOriginal
  36. ROI_flag = true;
  37. }
  38. result = arcPlusLine(imgOriginal, top, canvas, debug);//调用识别算法
  39. if (debug) printf("-------------------------------------****------ roiF top=【%d, %d】\n", top.x, top.y);
  40. //img.copyTo(canvas);
  41. //img.copyTo(canvas);//调试时注释掉
  42. cv::Mat t1;
  43. //canvas.convertTo(t1, -1, 900 / 100.0, 200 - 100);//第一次线性变换100
  44. canvas.convertTo(t1, -1, 900 / 100.0, 200 - 100);//第一次线性变换100
  45. if (debug)cv::imshow("线性变换ROI", t1);
  46. t1.copyTo(canvas);
  47. if (result)
  48. {
  49. endRes = 1;
  50. top += ROI_tl;
  51. cv::putText(canvas, "true", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);
  52. int w = 38;
  53. int thickness = 4;
  54. cv::Point curPoint = top;
  55. cv::line(canvas, curPoint, cv::Point(curPoint.x - w, curPoint.y), cv::Scalar(235, 135, 40), thickness);
  56. circle(canvas, top, 2, cv::Scalar(0, 69, 255), -1);
  57. circle(canvas, top, 63, cv::Scalar(0, 169, 255), 1);
  58. }
  59. else
  60. {
  61. cv::putText(canvas, "false", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);
  62. }
  63. cv::Mat ROIcanvas;
  64. img.copyTo(ROIcanvas);
  65. if (debug) circle(ROIcanvas, top, 3, cv::Scalar(0, 69, 255), 1);
  66. if (debug) circle(ROIcanvas, top, 63, cv::Scalar(0, 169, 255), 1);
  67. if (debug) rectangle(ROIcanvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);
  68. rectangle(canvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);
  69. if (debug) printf("-------------------------------------****------ roiF top=【%d, %d】 \n", top.x, top.y);
  70. if (debug) imshow("ROI", ROIcanvas);
  71. if (debug) imshow("ROI_canvas", canvas);
  72. //ROIcanvas.copyTo(canvas);
  73. //cv::Rect roi_(ROI_tl.x, ROI_tl.y, ROI_br.x - ROI_tl.x, ROI_br.y - ROI_tl.y);
  74. //if(!ROI_flag) canvas.copyTo(canvas);
  75. //else canvas = canvas(roi_); //裁剪出的ROI区域
  76. return result;
  77. }

调用main:

  1. //圆弧+直线 内角:arcPlusLine_ROI
  2. int main/*arcl*/() {
  3. bool flag = false;
  4. //std::string filePath = "E://vsproject//WeldingLine//1219img//in//宁波金波";
  5. //std::string filePath = "E://vsproject//WeldingLine//1219img//in//宁波金波//down";
  6. std::string filePath = "E://vsproject//WeldingLine//1219img//in//宁波金波//LogImg";
  7. //std::string filePath = "../img/ThreadedRoundPipe/0530img";
  8. string resPath = "/output";
  9. //string resPath = filePath + "./output";
  10. cv::Point tlP = cv::Point(200, 340);
  11. cv::Point brP = cv::Point(950, 999);
  12. cv::Point top(90, 90);
  13. cv::Mat canvas;
  14. VisualInterface m_ImageProcessing;
  15. //ImageProcess m_ImageProcessing;
  16. ofstream ofs("log.txt", ios::out);
  17. if (ofs)
  18. {
  19. ofs.clear();
  20. ofs << "日志启动" << endl;
  21. }
  22. vector<string> path_name;
  23. bool lineOnTop = true;
  24. bool getROI = !true;
  25. bool lianxu = false; //循环测试
  26. if (!lianxu)
  27. {
  28. string name = cv::format("\\Img_2024_03_12_15_01_57_350_TYPE_12_ROI_486_64_257_474_src.png");
  29. string path = filePath + name;
  30. //string path = filePath + cv::format("\\Image_20240228115544906.bmp");
  31. cv::Mat src = cv::imread(path);
  32. src.copyTo(canvas);
  33. cv::namedWindow("main_OriginalIMG", cv::RECURS_FILTER);
  34. cvSetMouseCallback("main_OriginalIMG", on_mouse_singleClick, 0);
  35. cv::imshow("main_OriginalIMG", src);
  36. cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);
  37. //cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);
  38. if (getROI) ROI = getROIFromString(name);
  39. bool flag = m_ImageProcessing.arcPlusLine_ROI(src, ROI, top, canvas, lineOnTop, true);
  40. cout << "\nmain ==== flag " << flag << endl;
  41. if (flag) {
  42. cout << "top = " << top.x << " " << top.y << endl;
  43. }
  44. canvas.copyTo(src);
  45. //cout << "\nmain ==== i " << endl;
  46. circle(canvas, top, 63, cv::Scalar(0, 69, 255), 1);
  47. 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);
  48. cv::namedWindow("main-结果图src", cv::RECURS_FILTER);
  49. cvSetMouseCallback("main-结果图src", on_mouse_singleClick, 0);
  50. cv::imshow("main-结果图src", src);
  51. }
  52. else
  53. {
  54. vector<string> path_name;
  55. getAllFiles(filePath, path_name);
  56. cout << "path_name.size()=" << path_name.size() << endl;
  57. int number = 1;
  58. for (auto i : path_name)
  59. {
  60. if (i.find("_res") != std::string::npos ) continue;
  61. if (i.find("png") == std::string::npos && i.find("bmp") == std::string::npos && i.find("jpg") == std::string::npos) continue;
  62. cv::Mat src = cv::imread(filePath + "\\" + i);
  63. cout << endl << "number【" << number << "】src path=" << i << " ;" << endl;
  64. src.copyTo(canvas);
  65. cv::imshow("main_OriginalIMG", src);
  66. //将结果图写入文件方便查看结果
  67. int len = filePath.length();
  68. //i = i.substr(i.find_last_of('\\') + 1, len);
  69. cout << "i=" << i << endl;
  70. int time_start = clock();
  71. int time_end = clock();
  72. cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);
  73. //cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);
  74. if (getROI) ROI = getROIFromString(i);
  75. bool flag = m_ImageProcessing.arcPlusLine_ROI(src, ROI, top, canvas, lineOnTop, false);
  76. time_end = clock();
  77. printf("\n耗时 %d ms \n", time_end - time_start);
  78. cout << "\nmain ==== flag " << flag << endl;
  79. if (flag) {
  80. cout << "top = " << top.x << " " << top.y << endl;
  81. }
  82. canvas.copyTo(src);
  83. 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);
  84. cv::imshow("main-结果图src", src);
  85. cv::waitKey(10);
  86. //将结果图写入文件方便查看结果
  87. char* filePath_ = new char[len + 1];
  88. strcpy(filePath_, filePath.c_str());
  89. len = filePath.length();
  90. char* resPath_ = new char[len + 1];
  91. strcpy(resPath_, resPath.c_str());
  92. //i.erase(0, strlen(filePath_) - strlen(resPath_) - 2);
  93. string out = filePath + resPath;
  94. cout << "\nmain ==== i " << i << endl;
  95. out.append("\\").append(i);
  96. cout << "number【" << number << "】res path=" << out << endl;
  97. cv::imwrite(out, src);
  98. number++;
  99. cout << "path_name.size() = " << path_name.size() << endl;
  100. cout << "*********************************************************************************************************************" << endl;
  101. if (number == path_name.size()) break;
  102. }
  103. }
  104. cout << "main 循环结束!!!" << endl;
  105. ofs.close();
  106. cv::waitKey(0);
  107. system("Pause");
  108. return 0;
  109. }
  1. cv::Rect getROIFromString(std::string str) {
  2. //图像名字格式:“SrcImg_2023_10_11_11_39_19_002_ROI_600_396_137_218_src.png”
  3. if (str.empty()) return cv::Rect(0, 0, 0, 0);
  4. using namespace std;
  5. const char *split = "_";
  6. char *p = strtok((char*)str.c_str(), split);
  7. std::vector<char*>data;
  8. while (p != NULL) {
  9. cout << p << endl;
  10. data.push_back(p);
  11. p = strtok(NULL, split);
  12. }
  13. //9 12;
  14. if (data.size() < 12)return cv::Rect();
  15. return cv::Rect(
  16. atoi(data[data.size() - 5]),
  17. atoi(data[data.size() - 4]),
  18. atoi(data[data.size() - 3]),
  19. atoi(data[data.size() - 2]));
  20. //return cv::Rect(
  21. // atoi(data[9]),
  22. // atoi(data[10]),
  23. // atoi(data[11]),
  24. // atoi(data[12]));
  25. }

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

  1. 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)
  2. {
  3. int endRes = 0;
  4. bool result = false;
  5. imgHE.copyTo(canvas);
  6. cv::addWeighted(imgHE, 0.5, imgLE, 0.5, 0, canvas);
  7. ImageProcess pd;
  8. cv::Mat imgHE_roi;
  9. cv::Mat imgOriginal;
  10. bool ROI_flag;//是否有给信息区
  11. cv::Point ROI_tl = cv::Point2i(ROI.x, ROI.y);
  12. cv::Point ROI_br = cv::Point2i(ROI.x + ROI.width, ROI.y + ROI.height);
  13. cv::Mat img;
  14. imgLE.copyTo(img);
  15. if (ROI_tl == cv::Point(0, 0) && ROI_br == cv::Point(0, 0))
  16. {
  17. img.copyTo(imgOriginal);
  18. imgHE.copyTo(imgHE_roi);
  19. ROI_flag = false;
  20. }
  21. else
  22. {
  23. if (ROI_tl.x > ROI_br.x || ROI_tl.y > ROI_br.y)//信息区两点疑似传反
  24. {
  25. printf("信息区两点疑似传反!");
  26. return false;
  27. }
  28. if (ROI_tl.x < 0 || ROI_br.x > img.cols || ROI_tl.y < 0 || ROI_br.y > img.rows)//信息区的框选超出图像范围
  29. {
  30. printf("信息区的框选超出图像范围!");
  31. return false;
  32. }
  33. if (abs(ROI_tl.x - ROI_br.x) > img.cols || abs(ROI_tl.y - ROI_br.y) > img.rows)//信息区大小超出图像大小
  34. {
  35. printf("信息区大小超出图像大小!");
  36. return false;
  37. }
  38. //此时不合法的ROI都已提前返回false
  39. cv::Rect roi(ROI_tl.x, ROI_tl.y, ROI_br.x - ROI_tl.x, ROI_br.y - ROI_tl.y);
  40. imgOriginal = img(roi); //裁剪出的ROI区域放于imgOriginal
  41. imgHE_roi = imgHE(roi);
  42. ROI_flag = true;
  43. if (debug) {
  44. cv::Mat tmp;
  45. img.copyTo(tmp);
  46. rectangle(tmp, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);
  47. if (debug) cv::imshow("根据roi裁剪后进入识别的图", tmp);
  48. }
  49. }
  50. result = getPnt_2Dwith3D_MaiSi(imgHE_roi, imgOriginal, canvas, resPoint, MaiSi_isTopPnt, debug);
  51. cv::addWeighted(imgHE, 0.5, imgLE, 0.5, 0, canvas);
  52. //x值和y值补上ROI左上点x和y
  53. if (ROI_flag)
  54. {
  55. if (resPoint != cv::Point(0, 0))
  56. {
  57. resPoint.x += ROI_tl.x;
  58. resPoint.y += ROI_tl.y;
  59. }
  60. }
  61. if (debug) std::cout << img.size() << imgOriginal.size() << std::endl;
  62. if (result)
  63. {
  64. endRes = 1;
  65. cv::circle(canvas, resPoint, 3, cv::Scalar(0, 0, 255), -1, 8, 0);
  66. putText(canvas, "true", { cv::Point(250, 250) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);
  67. //putText(canvas, "EmbWare_Leg", { cv::Point(250, 350) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);
  68. if (MaiSi_isTopPnt) {
  69. putText(canvas, "isTopPnt", { resPoint + cv::Point(15, 5) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(195, 165, 255), 1);
  70. }
  71. else {
  72. putText(canvas, "isBotPnt", { resPoint + cv::Point(15, 5) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(155, 155, 255), 1);
  73. }
  74. Mark(canvas);
  75. }
  76. else
  77. {
  78. putText(canvas, "false", { cv::Point(250, 250) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);
  79. Mark(canvas);
  80. }
  81. rectangle(canvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);
  82. return endRes;
  83. }

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

  1. /*
  2. //圆弧+直线 求内角
  3. cv::Mat img, 原图
  4. cv::Rect ROI,
  5. cv::Point& Corner, 输出角点
  6. cv::Mat &canvas,效果图可视化
  7. bool lineOnTop = true,直线部分是否为较上端的角边,true则为是,false反之
  8. */
  9. bool arcPlusLine(cv::Mat imgOriginal, cv::Point& Corner, cv::Mat &canvas, bool debug = false);
  10. bool arcPlusLine_ROI(cv::Mat img, cv::Rect ROI, cv::Point& Corner, cv::Mat &canvas, bool lineOnTop = true, bool debug = false);
  1. bool ImageProcess::arcPlusLine_ROI(cv::Mat img, cv::Rect ROI, cv::Point & top, cv::Mat & canvas, bool lineOnTop, bool debug)
  2. {
  3. int endRes = 0;
  4. bool result = false;
  5. img.copyTo(canvas);
  6. top = cv::Point(0, 0);
  7. cv::Mat imgOriginal;
  8. bool ROI_flag;//是否有给信息区
  9. cv::Point ROI_tl = cv::Point2i(ROI.x, ROI.y);
  10. cv::Point ROI_br = cv::Point2i(ROI.x + ROI.width, ROI.y + ROI.height);
  11. if (ROI_tl == cv::Point(0, 0) && ROI_br == cv::Point(0, 0) || ROI.width == 0 || ROI.height == 0)
  12. {
  13. img.copyTo(imgOriginal);
  14. ROI_flag = false;
  15. }
  16. else
  17. {
  18. if (ROI_tl.x > ROI_br.x || ROI_tl.y > ROI_br.y)//信息区两点疑似传反
  19. {
  20. printf("信息区两点疑似传反!");
  21. return false;
  22. }
  23. if (ROI_tl.x < 0 || ROI_br.x > img.cols || ROI_tl.y < 0 || ROI_br.y > img.rows)//信息区的框选超出图像范围
  24. {
  25. printf("信息区的框选超出图像范围!");
  26. return false;
  27. }
  28. if (abs(ROI_tl.x - ROI_br.x) > img.cols || abs(ROI_tl.y - ROI_br.y) > img.rows)//信息区大小超出图像大小
  29. {
  30. printf("信息区大小超出图像大小!");
  31. return false;
  32. }
  33. //此时不合法的ROI都已提前返回false
  34. cv::Rect roi(ROI_tl.x, ROI_tl.y, ROI_br.x - ROI_tl.x, ROI_br.y - ROI_tl.y);
  35. imgOriginal = img(roi); //裁剪出的ROI区域放于imgOriginal
  36. ROI_flag = true;
  37. }
  38. if (lineOnTop) {
  39. result = arcPlusLine(imgOriginal, top, canvas, debug);//调用识别算法
  40. }
  41. else {
  42. cv::Mat fpMt;
  43. cv::flip(imgOriginal, fpMt, 0); // 上下翻转 x对称
  44. result = arcPlusLine(fpMt, top, canvas, debug);//调用识别算法
  45. if (result) {
  46. top.y = fpMt.rows - top.y - 1;
  47. }
  48. }
  49. cv::Mat lockCanvas = canvas.clone();
  50. if (debug) printf("-------------------------------------****------ roiF top=【%d, %d】\n", top.x, top.y);
  51. //img.copyTo(canvas);
  52. //img.copyTo(canvas);//调试时注释掉
  53. //cv::Mat t1;
  54. //canvas.convertTo(t1, -1, 900 / 100.0, 200 - 100);//第一次线性变换100
  55. //if (debug)cv::imshow("线性变换ROI", t1);
  56. //t1.copyTo(canvas);
  57. if (result)
  58. {
  59. endRes = 1;
  60. top += ROI_tl;
  61. cv::putText(canvas, "true", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);
  62. int w = 38;
  63. int thickness = 4;
  64. cv::Point curPoint = top;
  65. cv::line(canvas, curPoint, cv::Point(curPoint.x - w, curPoint.y), cv::Scalar(235, 135, 40), thickness);
  66. circle(canvas, top, 2, cv::Scalar(0, 69, 255), -1);
  67. circle(canvas, top, 63, cv::Scalar(0, 169, 255), 1);
  68. }
  69. else
  70. {
  71. cv::putText(canvas, "false", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);
  72. }
  73. cv::Mat ROIcanvas;
  74. img.copyTo(ROIcanvas);
  75. if (debug) circle(ROIcanvas, top, 3, cv::Scalar(0, 69, 255), 1);
  76. if (debug) circle(ROIcanvas, top, 63, cv::Scalar(0, 169, 255), 1);
  77. if (debug) rectangle(ROIcanvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);
  78. rectangle(canvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);
  79. if (debug) printf("-------------------------------------****------ roiF top=【%d, %d】 \n", top.x, top.y);
  80. if (debug) imshow("ROI", ROIcanvas);
  81. if (debug) imshow("ROI_canvas", canvas);
  82. //ROIcanvas.copyTo(canvas);
  83. //cv::Rect roi_(ROI_tl.x, ROI_tl.y, ROI_br.x - ROI_tl.x, ROI_br.y - ROI_tl.y);
  84. //if(!ROI_flag) canvas.copyTo(canvas);
  85. //else canvas = canvas(roi_); //裁剪出的ROI区域
  86. lockCanvas.copyTo(canvas);
  87. return result;
  88. }

调用main:

  1. // 内角:arcPlusLine_ROI
  2. int main/*arcl*/() {
  3. bool flag = false;
  4. std::string filePath = "E://vsproject//WeldingLine//1219img//in//宁波金波";
  5. //std::string filePath = "E://vsproject//WeldingLine//1219img//in//宁波金波//down";
  6. //std::string filePath = "../img/ThreadedRoundPipe/0530img";
  7. string resPath = "/output";
  8. //string resPath = filePath + "./output";
  9. cv::Point tlP = cv::Point(200, 340);
  10. cv::Point brP = cv::Point(950, 999);
  11. cv::Point top(90, 90);
  12. cv::Mat canvas;
  13. //VisualInterface m_ImageProcessing;
  14. ImageProcess m_ImageProcessing;
  15. ofstream ofs("log.txt", ios::out);
  16. if (ofs)
  17. {
  18. ofs.clear();
  19. ofs << "日志启动" << endl;
  20. }
  21. vector<string> path_name;
  22. bool lineOnTop = true;
  23. bool lianxu = false; //循环测试
  24. if (lianxu)
  25. {
  26. string path = filePath + cv::format("\\Image_20240304155500627.png");
  27. //string path = filePath + cv::format("\\Image_20240228115544906.bmp");
  28. cv::Mat src = cv::imread(path);
  29. src.copyTo(canvas);
  30. cv::namedWindow("main_OriginalIMG", cv::RECURS_FILTER);
  31. cvSetMouseCallback("main_OriginalIMG", on_mouse_singleClick, 0);
  32. cv::imshow("main_OriginalIMG", src);
  33. cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);
  34. //cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);
  35. bool flag = m_ImageProcessing.arcPlusLine_ROI(src, ROI, top, canvas, lineOnTop, true);
  36. cout << "\nmain ==== flag " << flag << endl;
  37. if (flag) {
  38. cout << "top = " << top.x << " " << top.y << endl;
  39. }
  40. canvas.copyTo(src);
  41. //cout << "\nmain ==== i " << endl;
  42. circle(canvas, top, 63, cv::Scalar(0, 69, 255), 1);
  43. 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);
  44. cv::namedWindow("main-结果图src", cv::RECURS_FILTER);
  45. cvSetMouseCallback("main-结果图src", on_mouse_singleClick, 0);
  46. cv::imshow("main-结果图src", src);
  47. }
  48. else
  49. {
  50. vector<string> path_name;
  51. getAllFiles(filePath, path_name);
  52. cout << "path_name.size()=" << path_name.size() << endl;
  53. int number = 1;
  54. for (auto i : path_name)
  55. {
  56. if (i.find("png") == std::string::npos && i.find("bmp") == std::string::npos && i.find("jpg") == std::string::npos) continue;
  57. cv::Mat src = cv::imread(filePath + "\\" + i);
  58. cout << endl << "number【" << number << "】src path=" << i << " ;" << endl;
  59. src.copyTo(canvas);
  60. cv::imshow("main_OriginalIMG", src);
  61. //将结果图写入文件方便查看结果
  62. int len = filePath.length();
  63. //i = i.substr(i.find_last_of('\\') + 1, len);
  64. cout << "i=" << i << endl;
  65. int time_start = clock();
  66. int time_end = clock();
  67. cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);
  68. //cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);
  69. bool flag = m_ImageProcessing.arcPlusLine_ROI(src, ROI, top, canvas, lineOnTop, false);
  70. time_end = clock();
  71. printf("\n耗时 %d ms \n", time_end - time_start);
  72. cout << "\nmain ==== flag " << flag << endl;
  73. if (flag) {
  74. cout << "top = " << top.x << " " << top.y << endl;
  75. }
  76. canvas.copyTo(src);
  77. 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);
  78. cv::imshow("main-结果图src", src);
  79. cv::waitKey(10);
  80. //将结果图写入文件方便查看结果
  81. char* filePath_ = new char[len + 1];
  82. strcpy(filePath_, filePath.c_str());
  83. len = filePath.length();
  84. char* resPath_ = new char[len + 1];
  85. strcpy(resPath_, resPath.c_str());
  86. //i.erase(0, strlen(filePath_) - strlen(resPath_) - 2);
  87. string out = filePath + resPath;
  88. cout << "\nmain ==== i " << i << endl;
  89. out.append("\\").append(i);
  90. cout << "number【" << number << "】res path=" << out << endl;
  91. cv::imwrite(out, src);
  92. number++;
  93. cout << "path_name.size() = " << path_name.size() << endl;
  94. cout << "*********************************************************************************************************************" << endl;
  95. if (number == path_name.size()) break;
  96. }
  97. }
  98. cout << "main 循环结束!!!" << endl;
  99. ofs.close();
  100. cv::waitKey(0);
  101. system("Pause");
  102. return 0;
  103. }

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

  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)
  2. {
  3. int endRes = 0;
  4. bool result = false;
  5. img.copyTo(canvas);
  6. top = cv::Point(0, 0);
  7. cv::Mat imgOriginal;
  8. bool ROI_flag;//是否有给信息区
  9. cv::Point ROI_tl = cv::Point2i(ROI.x, ROI.y);
  10. cv::Point ROI_br = cv::Point2i(ROI.x + ROI.width, ROI.y + ROI.height);
  11. if (ROI_tl == cv::Point(0, 0) && ROI_br == cv::Point(0, 0) || ROI.width == 0 || ROI.height == 0)
  12. {
  13. img.copyTo(imgOriginal);
  14. ROI_flag = false;
  15. }
  16. else
  17. {
  18. if (ROI_tl.x > ROI_br.x || ROI_tl.y > ROI_br.y)//信息区两点疑似传反
  19. {
  20. printf("信息区两点疑似传反!");
  21. return false;
  22. }
  23. if (ROI_tl.x < 0 || ROI_br.x > img.cols || ROI_tl.y < 0 || ROI_br.y > img.rows)//信息区的框选超出图像范围
  24. {
  25. printf("信息区的框选超出图像范围!");
  26. return false;
  27. }
  28. if (abs(ROI_tl.x - ROI_br.x) > img.cols || abs(ROI_tl.y - ROI_br.y) > img.rows)//信息区大小超出图像大小
  29. {
  30. printf("信息区大小超出图像大小!");
  31. return false;
  32. }
  33. //此时不合法的ROI都已提前返回false
  34. cv::Rect roi(ROI_tl.x, ROI_tl.y, ROI_br.x - ROI_tl.x, ROI_br.y - ROI_tl.y);
  35. imgOriginal = img(roi); //裁剪出的ROI区域放于imgOriginal
  36. ROI_flag = true;
  37. }
  38. cv::Mat lockCanvas;
  39. if (lineOnTop) {
  40. result = arcPlusLine(imgOriginal, top, allPntList, canvas, debug);//调用识别算法
  41. canvas.copyTo(lockCanvas);
  42. //for (int i = 0; i < allPntList.size(); i++) {
  43. // cv::line(lockCanvas, allPntList.at(i), cv::Point(allPntList.at(i).x - 3, allPntList.at(i).y), cv::Scalar(55, 195, 40), 1);
  44. //}
  45. }
  46. else {
  47. cv::Mat fpMt;
  48. cv::flip(imgOriginal, fpMt, 0); // 上下翻转 x对称
  49. result = arcPlusLine(fpMt, top, allPntList, canvas, debug);//调用识别算法
  50. canvas.copyTo(lockCanvas);
  51. if (result) {
  52. top.y = fpMt.rows - top.y - 1;
  53. for (int i = 0; i < allPntList.size(); i++) {
  54. //cv::line(lockCanvas, allPntList.at(i), cv::Point(allPntList.at(i).x - 3, allPntList.at(i).y), cv::Scalar(55, 195, 40), 1);
  55. allPntList.at(i).y = fpMt.rows - allPntList.at(i).y - 1;
  56. }
  57. }
  58. }
  59. if (debug) printf("-------------------------------------****------ roiF top=【%d, %d】\n", top.x, top.y);
  60. //img.copyTo(canvas);
  61. //img.copyTo(canvas);//调试时注释掉
  62. //cv::Mat t1;
  63. //canvas.convertTo(t1, -1, 900 / 100.0, 200 - 100);//第一次线性变换100
  64. //if (debug)cv::imshow("线性变换ROI", t1);
  65. //t1.copyTo(canvas);
  66. if (result)
  67. {
  68. img.copyTo(canvas);
  69. endRes = 1;
  70. top += ROI_tl;
  71. for (int i = 0; i < allPntList.size(); i++) {
  72. allPntList.at(i) += ROI_tl;
  73. }
  74. cv::putText(canvas, "true", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);
  75. int w = 38;
  76. int thickness = 4;
  77. cv::Point curPoint = top;
  78. cv::line(canvas, curPoint, cv::Point(curPoint.x - w, curPoint.y), cv::Scalar(235, 135, 40), thickness);
  79. circle(canvas, top, 2, cv::Scalar(0, 69, 255), -1);
  80. circle(canvas, top, 63, cv::Scalar(0, 169, 255), 1);
  81. w = 3;
  82. for (int i = 0; i < allPntList.size(); i++) {
  83. cv::Point curPoint = allPntList.at(i);
  84. cv::line(canvas, curPoint, cv::Point(curPoint.x - w, curPoint.y), cv::Scalar(55, 195, 40), 1);
  85. }
  86. }
  87. else
  88. {
  89. cv::putText(canvas, "false", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);
  90. }
  91. cv::Mat ROIcanvas;
  92. img.copyTo(ROIcanvas);
  93. if (debug) circle(ROIcanvas, top, 3, cv::Scalar(0, 69, 255), 1);
  94. if (debug) circle(ROIcanvas, top, 63, cv::Scalar(0, 169, 255), 1);
  95. if (debug) rectangle(ROIcanvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);
  96. rectangle(canvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);
  97. if (debug) printf("-------------------------------------****------ roiF top=【%d, %d】 \n", top.x, top.y);
  98. if (debug) imshow("ROI", ROIcanvas);
  99. if (debug) imshow("ROI_canvas", canvas);
  100. //ROIcanvas.copyTo(canvas);
  101. //cv::Rect roi_(ROI_tl.x, ROI_tl.y, ROI_br.x - ROI_tl.x, ROI_br.y - ROI_tl.y);
  102. //if(!ROI_flag) canvas.copyTo(canvas);
  103. //else canvas = canvas(roi_); //裁剪出的ROI区域
  104. if (result) lockCanvas.copyTo(canvas);
  105. cv::putText(canvas, to_string(result), cv::Point(30, 65), cv::FONT_HERSHEY_COMPLEX, 1.75, cv::Scalar(255, 135, 160), 3);
  106. return result;
  107. }

调用main:

  1. // 内角:arcPlusLine_ROI 类似金波(金波优化版)
  2. int main/*arcl*/() {
  3. bool flag = false;
  4. //std::string filePath = "E://vsproject//压力罐\\img\\类金波/top";
  5. std::string filePath = "E://vsproject//压力罐\\img\\类金波";
  6. //std::string filePath = "E://vsproject//压力罐\\img\\叶子";
  7. //std::string filePath = "../img/ThreadedRoundPipe/0530img";
  8. string resPath = "/output";
  9. //string resPath = filePath + "./output";
  10. cv::Point tlP = cv::Point(200, 340);
  11. cv::Point brP = cv::Point(950, 999);
  12. cv::Point top(90, 90);
  13. std::vector<cv::Point> allPntList;
  14. cv::Mat canvas;
  15. PTank_imgProcess m_ImageProcessing;
  16. //ImageProcess m_ImageProcessing;
  17. ofstream ofs("log.txt", ios::out);
  18. if (ofs)
  19. {
  20. ofs.clear();
  21. ofs << "日志启动" << endl;
  22. }
  23. vector<string> path_name;
  24. bool lineOnTop = !true;
  25. bool getROI = true;
  26. bool lianxu = false; //循环测试
  27. if (!lianxu)
  28. {
  29. string name = cv::format("\\Image_20240627151014832.png");
  30. string path = filePath + name;
  31. cv::Mat src = cv::imread(path);
  32. src.copyTo(canvas);
  33. cv::namedWindow("main_OriginalIMG", cv::RECURS_FILTER);
  34. cvSetMouseCallback("main_OriginalIMG", on_mouse_singleClick, 0);
  35. cv::imshow("main_OriginalIMG", src);
  36. cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);
  37. //cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);
  38. if (getROI) ROI = getROIFromString(name);
  39. bool flag = m_ImageProcessing.arcPlusLine_ROI(src, ROI, top, allPntList, canvas, lineOnTop, true);
  40. cout << "\nmain ==== flag " << flag << endl;
  41. if (flag) {
  42. cout << "top = " << top.x << " " << top.y << endl;
  43. }
  44. canvas.copyTo(src);
  45. //cout << "\nmain ==== i " << endl;
  46. circle(canvas, top, 63, cv::Scalar(0, 69, 255), 1);
  47. 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);
  48. cv::namedWindow("main-结果图src", cv::RECURS_FILTER);
  49. cvSetMouseCallback("main-结果图src", on_mouse_singleClick, 0);
  50. cv::imshow("main-结果图src", src);
  51. }
  52. else
  53. {
  54. vector<string> path_name;
  55. getAllFiles(filePath, path_name);
  56. cout << "path_name.size()=" << path_name.size() << endl;
  57. int number = 1;
  58. for (auto i : path_name)
  59. {
  60. if (i.find("_res") != std::string::npos) continue;
  61. if (i.find("png") == std::string::npos && i.find("bmp") == std::string::npos && i.find("jpg") == std::string::npos) continue;
  62. cv::Mat src = cv::imread(filePath + "\\" + i);
  63. cout << endl << "number【" << number << "】src path=" << i << " ;" << endl;
  64. src.copyTo(canvas);
  65. cv::imshow("main_OriginalIMG", src);
  66. //将结果图写入文件方便查看结果
  67. int len = filePath.length();
  68. //i = i.substr(i.find_last_of('\\') + 1, len);
  69. cout << "i=" << i << endl;
  70. int time_start = clock();
  71. int time_end = clock();
  72. cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);
  73. //cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);
  74. if (getROI) ROI = getROIFromString(i);
  75. bool flag = m_ImageProcessing.arcPlusLine_ROI(src, ROI, top, allPntList, canvas, lineOnTop, false);
  76. time_end = clock();
  77. printf("\n耗时 %d ms \n", time_end - time_start);
  78. cout << "\nmain ==== flag " << flag << endl;
  79. if (flag) {
  80. cout << "top = " << top.x << " " << top.y << endl;
  81. }
  82. canvas.copyTo(src);
  83. 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);
  84. cv::imshow("main-结果图src", src);
  85. cv::waitKey(10);
  86. //将结果图写入文件方便查看结果
  87. char* filePath_ = new char[len + 1];
  88. strcpy(filePath_, filePath.c_str());
  89. len = filePath.length();
  90. char* resPath_ = new char[len + 1];
  91. strcpy(resPath_, resPath.c_str());
  92. //i.erase(0, strlen(filePath_) - strlen(resPath_) - 2);
  93. string out = filePath + resPath;
  94. cout << "\nmain ==== i " << i << endl;
  95. out.append("\\").append(i);
  96. cout << "number【" << number << "】res path=" << out << endl;
  97. cv::imwrite(out, src);
  98. number++;
  99. cout << "path_name.size() = " << path_name.size() << endl;
  100. cout << "*********************************************************************************************************************" << endl;
  101. if (number == path_name.size()) break;
  102. }
  103. }
  104. cout << "main 循环结束!!!" << endl;
  105. ofs.close();
  106. cv::waitKey(0);
  107. system("Pause");
  108. return 0;
  109. }

双点

返回只有双点 

  1. bool ImageProcessingTest::ThreadedRoundPipe_ROI(cv::Mat img, cv::Rect ROI, cv::Point& top, cv::Point& bottom, cv::Mat & canvas, bool debug)
  2. {
  3. int endRes = 0;
  4. bool result = false;
  5. img.copyTo(canvas);
  6. top = cv::Point(0, 0);
  7. bottom = cv::Point(0, 0);
  8. cv::Mat imgOriginal;
  9. bool ROI_flag;//是否有给信息区
  10. cv::Point ROI_tl = cv::Point2i(ROI.x, ROI.y);
  11. cv::Point ROI_br = cv::Point2i(ROI.x + ROI.width, ROI.y + ROI.height);
  12. if (ROI_tl == cv::Point(0, 0) && ROI_br == cv::Point(0, 0) || ROI.width == 0 || ROI.height == 0)
  13. {
  14. img.copyTo(imgOriginal);
  15. ROI_flag = false;
  16. }
  17. else
  18. {
  19. if (ROI_tl.x > ROI_br.x || ROI_tl.y > ROI_br.y)//信息区两点疑似传反
  20. {
  21. printf("信息区两点疑似传反!");
  22. return false;
  23. }
  24. if (ROI_tl.x < 0 || ROI_br.x > img.cols || ROI_tl.y < 0 || ROI_br.y > img.rows)//信息区的框选超出图像范围
  25. {
  26. printf("信息区的框选超出图像范围!");
  27. return false;
  28. }
  29. if (abs(ROI_tl.x - ROI_br.x) > img.cols || abs(ROI_tl.y - ROI_br.y) > img.rows)//信息区大小超出图像大小
  30. {
  31. printf("信息区大小超出图像大小!");
  32. return false;
  33. }
  34. //此时不合法的ROI都已提前返回false
  35. cv::Rect roi(ROI_tl.x, ROI_tl.y, ROI_br.x - ROI_tl.x, ROI_br.y - ROI_tl.y);
  36. imgOriginal = img(roi); //裁剪出的ROI区域放于imgOriginal
  37. ROI_flag = true;
  38. }
  39. result = ThreadedRoundPipe(imgOriginal, top, bottom, canvas, debug);//调用识别算法
  40. if (debug) printf("-------------------------------------****------ roiF top=【%d, %d】, bottom=【%d, %d】\n", top.x, top.y, bottom.x, bottom.y);
  41. //img.copyTo(canvas);
  42. x值和y值补上ROI左上点x和y
  43. //if (ROI_flag) {
  44. // if (Corner != cv::Point(0, 0))
  45. // {
  46. // Corner.x += ROI_tl.x;
  47. // Corner.y += ROI_tl.y;
  48. // }
  49. //}
  50. img.copyTo(canvas);//调试时注释掉
  51. cv::Mat t1;
  52. //canvas.convertTo(t1, -1, 900 / 100.0, 200 - 100);//第一次线性变换100
  53. canvas.convertTo(t1, -1, 900 / 100.0, 200 - 100);//第一次线性变换100
  54. if (debug)cv::imshow("线性变换ROI", t1);
  55. t1.copyTo(canvas);
  56. if (result)
  57. {
  58. endRes = 1;
  59. top += ROI_tl;
  60. bottom += ROI_tl;
  61. cv::putText(canvas, "true", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);
  62. int w = 38;
  63. int thickness = 4;
  64. cv::Point curPoint = top;
  65. cv::line(canvas, curPoint, cv::Point(curPoint.x - w, curPoint.y), cv::Scalar(235, 135, 40), thickness);
  66. curPoint = bottom;
  67. cv::line(canvas, curPoint, cv::Point(curPoint.x - w, curPoint.y), cv::Scalar(235, 135, 40), thickness);
  68. circle(canvas, top, 2, cv::Scalar(0, 69, 255), -1);
  69. circle(canvas, top, 63, cv::Scalar(0, 169, 255), 1);
  70. circle(canvas, bottom, 2, cv::Scalar(0, 69, 255), -1);
  71. circle(canvas, bottom, 43, cv::Scalar(255, 169, 0), 1);
  72. }
  73. else
  74. {
  75. cv::putText(canvas, "false", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);
  76. }
  77. cv::Mat ROIcanvas;
  78. img.copyTo(ROIcanvas);
  79. if (debug) circle(ROIcanvas, top, 3, cv::Scalar(0, 69, 255), 1);
  80. if (debug) circle(ROIcanvas, top, 63, cv::Scalar(0, 169, 255), 1);
  81. if (debug) circle(ROIcanvas, bottom, 3, cv::Scalar(0, 69, 255), 1);
  82. if (debug) circle(ROIcanvas, bottom, 63, cv::Scalar(0, 169, 255), 1);
  83. if (debug) rectangle(ROIcanvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);
  84. rectangle(canvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);
  85. if (debug) printf("-------------------------------------****------ roiF top=【%d, %d】, bottom=【%d, %d】\n", top.x, top.y, bottom.x, bottom.y);
  86. if (debug) imshow("ROI", ROIcanvas);
  87. if (debug) imshow("ROI_canvas", canvas);
  88. //ROIcanvas.copyTo(canvas);
  89. //cv::Rect roi_(ROI_tl.x, ROI_tl.y, ROI_br.x - ROI_tl.x, ROI_br.y - ROI_tl.y);
  90. //if(!ROI_flag) canvas.copyTo(canvas);
  91. //else canvas = canvas(roi_); //裁剪出的ROI区域
  92. return result;
  93. }

调用main:

  1. //螺纹圆管:ThreadedRoundPipe_ROI
  2. int main222() {
  3. bool flag = false;
  4. //std::string filePath = "E:\\vsproject\\勋仪交接\\标克艾芬达暖水管/0529img";
  5. //std::string filePath = "../img/ThreadedRoundPipe/0530img";
  6. std::string filePath = "../img/ThreadedRoundPipe/0606img";
  7. string resPath = "/output";
  8. //string resPath = filePath + "./output";
  9. cv::Point tlP = cv::Point(200, 340);
  10. cv::Point brP = cv::Point(950, 999);
  11. cv::Point top(90, 90);
  12. cv::Point bottom(90, 90);
  13. cv::Mat canvas;
  14. ImageProcessingTest m_ImageProcessing;
  15. ofstream ofs("log.txt", ios::out);
  16. if (ofs)
  17. {
  18. ofs.clear();
  19. ofs << "日志启动" << endl;
  20. }
  21. vector<string> path_name;
  22. bool lianxu = false; //循环测试
  23. if (!lianxu)
  24. {
  25. //string path = filePath + cv::format("\\Image_20230606135229441.png");
  26. string path = filePath + cv::format("\\Image_20230606135308519.png");
  27. //string path = filePath + cv::format("\\Image_20230601143638388.png");
  28. //string path = filePath + cv::format("\\Image_20230601143505168.png");
  29. //string path = filePath + cv::format("\\Image_20230529095011455.png");
  30. cv::Mat src = cv::imread(path);
  31. src.copyTo(canvas);
  32. cv::namedWindow("main_OriginalIMG", cv::RECURS_FILTER);
  33. cvSetMouseCallback("main_OriginalIMG", on_mouse_singleClick, 0);
  34. cv::imshow("main_OriginalIMG", src);
  35. //cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);
  36. cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);
  37. bool flag = m_ImageProcessing.ThreadedRoundPipe_ROI(src, ROI, top, bottom, canvas, true);
  38. cout << "\nmain ==== flag " << flag << endl;
  39. if (flag) {
  40. cout << "top = " << top.x << " " << top.y << endl;
  41. cout << "bottom = " << bottom.x << " " << bottom.y << endl;
  42. }
  43. canvas.copyTo(src);
  44. //cout << "\nmain ==== i " << endl;
  45. circle(canvas, top, 63, cv::Scalar(0, 69, 255), 1);
  46. circle(canvas, bottom, 63, cv::Scalar(0, 69, 255), 1);
  47. 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);
  48. cv::namedWindow("main-结果图src", cv::RECURS_FILTER);
  49. cvSetMouseCallback("main-结果图src", on_mouse_singleClick, 0);
  50. cv::imshow("main-结果图src", src);
  51. }
  52. else
  53. {
  54. vector<string> path_name;
  55. getAllFiles(filePath, path_name);
  56. cout << "path_name.size()=" << path_name.size() << endl;
  57. int number = 1;
  58. for (auto i : path_name)
  59. {
  60. cv::Mat src = cv::imread(filePath + "\\" + i);
  61. cout << endl << "number【" << number << "】src path=" << i << " ;" << endl;
  62. src.copyTo(canvas);
  63. cv::imshow("main_OriginalIMG", src);
  64. //将结果图写入文件方便查看结果
  65. int len = filePath.length();
  66. //i = i.substr(i.find_last_of('\\') + 1, len);
  67. cout << "i=" << i << endl;
  68. int time_start = clock();
  69. int time_end = clock();
  70. //cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);
  71. cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);
  72. bool flag = m_ImageProcessing.ThreadedRoundPipe_ROI(src, ROI, top, bottom, canvas, false);
  73. time_end = clock();
  74. printf("\n耗时 %d ms \n", time_end - time_start);
  75. cout << "\nmain ==== flag " << flag << endl;
  76. if (flag) {
  77. cout << "top = " << top.x << " " << top.y << endl;
  78. cout << "bottom = " << bottom.x << " " << bottom.y << endl;
  79. }
  80. canvas.copyTo(src);
  81. 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);
  82. cv::imshow("main-结果图src", src);
  83. cv::waitKey(10);
  84. //将结果图写入文件方便查看结果
  85. char* filePath_ = new char[len + 1];
  86. strcpy(filePath_, filePath.c_str());
  87. len = filePath.length();
  88. char* resPath_ = new char[len + 1];
  89. strcpy(resPath_, resPath.c_str());
  90. //i.erase(0, strlen(filePath_) - strlen(resPath_) - 2);
  91. string out = filePath + resPath;
  92. cout << "\nmain ==== i " << i << endl;
  93. out.append("\\").append(i);
  94. cout << "number【" << number << "】res path=" << out << endl;
  95. cv::imwrite(out, src);
  96. number++;
  97. cout << "path_name.size() = " << path_name.size() << endl;
  98. cout << "*********************************************************************************************************************" << endl;
  99. if (number == path_name.size()) break;
  100. }
  101. }
  102. cout << "main 循环结束!!!" << endl;
  103. ofs.close();
  104. cv::waitKey(0);
  105. system("Pause");
  106. return 0;
  107. }

返回双点+1个点集

  1. /*
  2. //矩形位置 返回双点+骨干点集
  3. cv::Mat img, 原图
  4. cv::Rect ROI,
  5. cv::Point& top, 输出焊点(图像上位于较上方的点)
  6. cv::Point& bottom, 输出焊点(图像上位于较下方的点)
  7. std::vector<cv::Point>& allPntList:直线部分非弧线的点集
  8. cv::Mat &canvas,效果图可视化
  9. */
  10. bool rectangle2Pnt(cv::Mat imgOriginal, cv::Point& top, cv::Point& bottom, std::vector<cv::Point>& allPntList, cv::Mat &canvas, bool debug = false);
  11. 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);
  1. 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)
  2. {
  3. int endRes = 0;
  4. bool result = false;
  5. img.copyTo(canvas);
  6. top = cv::Point(0, 0);
  7. bottom = cv::Point(0, 0);
  8. allPntList.clear();
  9. cv::Mat imgOriginal;
  10. bool ROI_flag;//是否有给信息区
  11. cv::Point ROI_tl = cv::Point2i(ROI.x, ROI.y);
  12. cv::Point ROI_br = cv::Point2i(ROI.x + ROI.width, ROI.y + ROI.height);
  13. if (ROI_tl == cv::Point(0, 0) && ROI_br == cv::Point(0, 0) || ROI.width == 0 || ROI.height == 0)
  14. {
  15. img.copyTo(imgOriginal);
  16. ROI_flag = false;
  17. }
  18. else
  19. {
  20. if (ROI_tl.x > ROI_br.x || ROI_tl.y > ROI_br.y)//信息区两点疑似传反
  21. {
  22. printf("信息区两点疑似传反!");
  23. return false;
  24. }
  25. if (ROI_tl.x < 0 || ROI_br.x > img.cols || ROI_tl.y < 0 || ROI_br.y > img.rows)//信息区的框选超出图像范围
  26. {
  27. printf("信息区的框选超出图像范围!");
  28. return false;
  29. }
  30. if (abs(ROI_tl.x - ROI_br.x) > img.cols || abs(ROI_tl.y - ROI_br.y) > img.rows)//信息区大小超出图像大小
  31. {
  32. printf("信息区大小超出图像大小!");
  33. return false;
  34. }
  35. //此时不合法的ROI都已提前返回false
  36. cv::Rect roi(ROI_tl.x, ROI_tl.y, ROI_br.x - ROI_tl.x, ROI_br.y - ROI_tl.y);
  37. imgOriginal = img(roi); //裁剪出的ROI区域放于imgOriginal
  38. ROI_flag = true;
  39. }
  40. result = rectangle2Pnt(imgOriginal, top, bottom, allPntList, canvas, debug);//调用识别算法
  41. if (debug) printf("-------------------------------------****------ roiF top=【%d, %d】, bottom=【%d, %d】\n", top.x, top.y, bottom.x, bottom.y);
  42. //img.copyTo(canvas);
  43. img.copyTo(canvas);//调试时注释掉
  44. if (result)
  45. {
  46. endRes = 1;
  47. top += ROI_tl;
  48. bottom += ROI_tl;
  49. for (int i = 0; i < allPntList.size(); i++) {
  50. allPntList.at(i) += ROI_tl;
  51. }
  52. int w = 5;
  53. for (int i = 0; i < allPntList.size(); i++) {
  54. cv::Point curPoint = allPntList.at(i);
  55. cv::line(canvas, curPoint, cv::Point(curPoint.x - w, curPoint.y), cv::Scalar(55, 195, 40), 1);
  56. }
  57. cv::putText(canvas, "true", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);
  58. circle(canvas, top, 3, cv::Scalar(0, 69, 255), 1);
  59. circle(canvas, top, 63, cv::Scalar(0, 169, 255), 1);
  60. circle(canvas, bottom, 3, cv::Scalar(0, 69, 255), 1);
  61. circle(canvas, bottom, 43, cv::Scalar(255, 169, 0), 1);
  62. }
  63. else
  64. {
  65. cv::putText(canvas, "false", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);
  66. }
  67. cv::Mat ROIcanvas;
  68. img.copyTo(ROIcanvas);
  69. if (debug) circle(ROIcanvas, top, 3, cv::Scalar(0, 69, 255), 1);
  70. if (debug) circle(ROIcanvas, top, 63, cv::Scalar(0, 169, 255), 1);
  71. if (debug) circle(ROIcanvas, bottom, 3, cv::Scalar(0, 69, 255), 1);
  72. if (debug) circle(ROIcanvas, bottom, 63, cv::Scalar(0, 169, 255), 1);
  73. if (debug) rectangle(ROIcanvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);
  74. rectangle(canvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);
  75. if (debug) printf("-------------------------------------****------ roiF top=【%d, %d】, bottom=【%d, %d】\n", top.x, top.y, bottom.x, bottom.y);
  76. if (debug) imshow("ROI", ROIcanvas);
  77. if (debug) imshow("ROI_canvas", canvas);
  78. //ROIcanvas.copyTo(canvas);
  79. return result;
  80. }

调用main:

  1. //矩形位置 返回双点+骨干点集
  2. int main/*Rectangle2Pnt_ROI*/() {
  3. bool flag;
  4. //std::string filePath = "../../../../Log08141641/TestImg/src";
  5. std::string filePath = "E://vsproject//压力罐\\img\\矩形";
  6. string resPath = "/output";
  7. //string resPath = filePath + "./output";
  8. cv::Point tlP = cv::Point(500, 292);
  9. cv::Point brP = cv::Point(750, 677);
  10. //cv::Rect ROI = cv::Rect(0, 0, 0, 0);
  11. //cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);
  12. //cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);
  13. //cv::Rect ROI = cv::Rect(539, 218, 113, 513);
  14. cv::Point top(90, 90);
  15. cv::Point bottom(90, 90);
  16. int outMidY;
  17. cv::Mat canvas;
  18. PTank_imgProcess m_ImageProcessing;
  19. ofstream ofs("log.txt", ios::out);
  20. if (ofs)
  21. {
  22. ofs.clear();
  23. ofs << "日志启动" << endl;
  24. }
  25. std::vector<cv::Point> allPntList;
  26. vector<string> path_name;
  27. bool getROI = true;
  28. bool lianxu = false; //循环测试
  29. if (!lianxu)
  30. {
  31. string name = cv::format("\\Image_20240627144421072.png");
  32. string path = filePath + name;
  33. cv::Mat src = cv::imread(path);
  34. src.copyTo(canvas);
  35. cv::namedWindow("main_OriginalIMG", cv::RECURS_FILTER);
  36. cvSetMouseCallback("main_OriginalIMG", on_mouse_singleClick, 0);
  37. cv::imshow("main_OriginalIMG", src);
  38. cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);
  39. //cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);
  40. if (getROI) ROI = getROIFromString(name);
  41. bool flag = m_ImageProcessing.rectangle2Pnt_ROI(src, ROI, top, bottom, allPntList, canvas, true);
  42. cout << "\nmain ==== flag " << flag << endl;
  43. if (flag) {
  44. cout << "top = " << top.x << " " << top.y << endl;
  45. cout << "bottom = " << bottom.x << " " << bottom.y << endl;
  46. }
  47. canvas.copyTo(src);
  48. //cout << "\nmain ==== i " << endl;
  49. circle(canvas, top, 63, cv::Scalar(0, 69, 255), 1);
  50. circle(canvas, bottom, 63, cv::Scalar(0, 69, 255), 1);
  51. 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);
  52. cv::namedWindow("main-结果图src", cv::RECURS_FILTER);
  53. cvSetMouseCallback("main-结果图src", on_mouse_singleClick, 0);
  54. cv::imshow("main-结果图src", src);
  55. cv::namedWindow("main-canvas", cv::RECURS_FILTER);
  56. cvSetMouseCallback("main-canvas", on_mouse_singleClick, 0);
  57. cv::imshow("main-canvas", canvas);
  58. }
  59. else
  60. {
  61. vector<string> path_name;
  62. getAllFiles(filePath, path_name);
  63. cout << "path_name.size()=" << path_name.size() << endl;
  64. int number = 1;
  65. for (auto i : path_name)
  66. {
  67. //cout << i.size() << endl;
  68. if (i.size() == 7) continue;
  69. if (i.find(".log") != std::string::npos) continue;
  70. std::string path11 = filePath + "\\" + i;
  71. cv::Mat src = cv::imread(path11);
  72. //cv::Mat src = cv::imread(filePath + "\\" + i);
  73. cout << endl << "number【" << number << "】src path=" << i << " ;" << endl;
  74. src.copyTo(canvas);
  75. cv::imshow("main_OriginalIMG", src);
  76. //将结果图写入文件方便查看结果
  77. int len = filePath.length();
  78. //i = i.substr(i.find_last_of('\\') + 1, len);
  79. cout << "i=" << i << ", path11=" << path11 << endl;
  80. int time_start = clock();
  81. int time_end = clock();
  82. cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);
  83. //cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);
  84. if (getROI) ROI = getROIFromString(i);
  85. bool flag = m_ImageProcessing.rectangle2Pnt_ROI(src, ROI, top, bottom, allPntList, canvas, false);
  86. time_end = clock();
  87. printf("\n耗时 %d ms \n", time_end - time_start);
  88. cout << "\nmain ==== flag " << flag << endl;
  89. if (flag) {
  90. cout << "top = " << top.x << " " << top.y << endl;
  91. cout << "bottom = " << bottom.x << " " << bottom.y << endl;
  92. }
  93. canvas.copyTo(src);
  94. 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);
  95. cv::imshow("main-结果图src", src);
  96. cv::imshow("main-canvas", canvas);
  97. //将结果图写入文件方便查看结果
  98. char* filePath_ = new char[len + 1];
  99. strcpy(filePath_, filePath.c_str());
  100. len = filePath.length();
  101. char* resPath_ = new char[len + 1];
  102. strcpy(resPath_, resPath.c_str());
  103. //i.erase(0, strlen(filePath_) - strlen(resPath_) - 2);
  104. string out = filePath + resPath;
  105. cout << "\nmain ==== i " << i << endl;
  106. out.append("\\").append(i);
  107. cout << "number【" << number << "】res path=" << out << endl;
  108. cv::imwrite(out, src);
  109. number++;
  110. cout << "path_name.size() = " << path_name.size() << endl;
  111. cout << "*********************************************************************************************************************" << endl;
  112. cv::waitKey(10);
  113. }
  114. cout << "循环结束!!! main " << endl;
  115. }
  116. ofs.close();
  117. cv::waitKey(0);
  118. system("Pause");
  119. return 0;
  120. }

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

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

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

  1. /*
  2. //D型主管,方形支管 只处理上半部分或下半部分
  3. cv::Mat img, 原图
  4. cv::Rect ROI, 可以让右边的干扰直反光落进去,上下不用截,左右可适当截小一下减少识别时的计算时间
  5. std::vector<cv::Point>& linearPnt:直线部分非弧线的点集
  6. cv::Point& top, 输出焊点(图像上位于较上方的点)倒角弧形边边上的激光最边边点
  7. cv::Point& bottom, 输出焊点(图像上位于较下方的点)倒角弧形边边上的激光最边边点
  8. cv::Mat &canvas,效果图可视化
  9. bool arcTop_right = true;//圆弧顶点是否朝右的标志量,默认为true(true为朝右,false为朝左)
  10. bool isTopHalf = true;//识别区域是否为上半部分,上半部分为true,下半部分反之
  11. 注:该接口中 bottom, linearPntB无效!!!
  12. */
  13. 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);
  14. 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);
  1. 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)
  2. {
  3. int endRes = 0;
  4. bool result = false;
  5. img.copyTo(canvas);
  6. top = cv::Point(0, 0);
  7. bottom = cv::Point(0, 0);
  8. linearPntT.clear();
  9. linearPntB.clear();
  10. linearPntM.clear();
  11. cv::Mat imgOriginal;
  12. bool ROI_flag;//是否有给信息区
  13. cv::Point ROI_tl = cv::Point2i(ROI.x, ROI.y);
  14. cv::Point ROI_br = cv::Point2i(ROI.x + ROI.width, ROI.y + ROI.height);
  15. if (ROI_tl == cv::Point(0, 0) && ROI_br == cv::Point(0, 0) || ROI.width == 0 || ROI.height == 0)
  16. {
  17. img.copyTo(imgOriginal);
  18. ROI_flag = false;
  19. }
  20. else
  21. {
  22. if (ROI_tl.x > ROI_br.x || ROI_tl.y > ROI_br.y)//信息区两点疑似传反
  23. {
  24. printf("信息区两点疑似传反!");
  25. return false;
  26. }
  27. if (ROI_tl.x < 0 || ROI_br.x > img.cols || ROI_tl.y < 0 || ROI_br.y > img.rows)//信息区的框选超出图像范围
  28. {
  29. printf("信息区的框选超出图像范围!");
  30. return false;
  31. }
  32. if (abs(ROI_tl.x - ROI_br.x) > img.cols || abs(ROI_tl.y - ROI_br.y) > img.rows)//信息区大小超出图像大小
  33. {
  34. printf("信息区大小超出图像大小!");
  35. return false;
  36. }
  37. //此时不合法的ROI都已提前返回false
  38. cv::Rect roi(ROI_tl.x, ROI_tl.y, ROI_br.x - ROI_tl.x, ROI_br.y - ROI_tl.y);
  39. imgOriginal = img(roi); //裁剪出的ROI区域放于imgOriginal
  40. ROI_flag = true;
  41. }
  42. if (arcTop_right) {//圆弧顶点朝右的情况
  43. if (isTopHalf) {
  44. result = OneSideSquare(imgOriginal, linearPntT, linearPntB, linearPntM, top, bottom, canvas, debug);//调用识别算法
  45. }
  46. else {
  47. cv::Mat fpMt;
  48. cv::flip(imgOriginal, fpMt, 0); // 上下翻转 x对称
  49. result = OneSideSquare(fpMt, linearPntT, linearPntB, linearPntM, top, bottom, canvas, debug);//调用识别算法
  50. if (result) {
  51. top.y = fpMt.rows - top.y - 1;
  52. for (int i = 0; i < linearPntT.size(); i++) {
  53. linearPntT.at(i).y = fpMt.rows - linearPntT.at(i).y - 1;
  54. }
  55. for (int i = 0; i < linearPntM.size(); i++) {
  56. linearPntM.at(i).y = fpMt.rows - linearPntM.at(i).y - 1;
  57. }
  58. }
  59. }
  60. }
  61. else {//圆弧顶点朝左的情况
  62. cv::Mat flipMat;
  63. cv::flip(imgOriginal, flipMat, 1); // 左右翻转 y对称
  64. if (debug) imshow("图像左右翻转", flipMat);
  65. if (isTopHalf) {
  66. result = OneSideSquare(flipMat, linearPntT, linearPntB, linearPntM, top, bottom, canvas, debug);//调用识别算法
  67. }
  68. else {
  69. cv::Mat fpMt;
  70. cv::flip(flipMat, fpMt, 0); // 上下翻转 x对称
  71. result = OneSideSquare(fpMt, linearPntT, linearPntB, linearPntM, top, bottom, canvas, debug);//调用识别算法
  72. if (result) {
  73. top.y = fpMt.rows - top.y - 1;
  74. for (int i = 0; i < linearPntT.size(); i++) {
  75. linearPntT.at(i).y = fpMt.rows - linearPntT.at(i).y - 1;
  76. }
  77. for (int i = 0; i < linearPntM.size(); i++) {
  78. linearPntM.at(i).y = fpMt.rows - linearPntM.at(i).y - 1;
  79. }
  80. }
  81. }
  82. if (result) {
  83. top.x = flipMat.cols - top.x - 1;
  84. //bottom.x = flipMat.cols - bottom.x - 1;
  85. for (int i = 0; i < linearPntT.size(); i++) {
  86. linearPntT.at(i).x = flipMat.cols - linearPntT.at(i).x - 1;
  87. }
  88. for (int i = 0; i < linearPntB.size(); i++) {
  89. linearPntB.at(i).x = flipMat.cols - linearPntB.at(i).x - 1;
  90. }
  91. for (int i = 0; i < linearPntM.size(); i++) {
  92. linearPntM.at(i).x = flipMat.cols - linearPntM.at(i).x - 1;
  93. }
  94. }
  95. }
  96. if (debug) printf("-------------------------------------****------ roiF top=【%d, %d】, bottom=【%d, %d】\n", top.x, top.y, bottom.x, bottom.y);
  97. //img.copyTo(canvas);
  98. x值和y值补上ROI左上点x和y
  99. //if (ROI_flag) {
  100. // if (Corner != cv::Point(0, 0))
  101. // {
  102. // Corner.x += ROI_tl.x;
  103. // Corner.y += ROI_tl.y;
  104. // }
  105. //}
  106. img.copyTo(canvas);//调试时注释掉
  107. if (result)
  108. {
  109. endRes = 1;
  110. top += ROI_tl;
  111. //bottom += ROI_tl;
  112. for (int i = 0; i < linearPntT.size(); i++) {
  113. linearPntT.at(i) += ROI_tl;
  114. }
  115. for (int i = 0; i < linearPntB.size(); i++) {
  116. linearPntB.at(i) += ROI_tl;
  117. }
  118. for (int i = 0; i < linearPntM.size(); i++) {
  119. linearPntM.at(i) += ROI_tl;
  120. }
  121. for (int i = 0; i < linearPntT.size(); i++) {
  122. cv::Point curPoint = linearPntT.at(i);
  123. cv::line(canvas, curPoint, cv::Point(curPoint.x - 5, curPoint.y), cv::Scalar(55, 195, 40), 1);
  124. }
  125. for (int i = 0; i < linearPntB.size(); i++) {
  126. cv::Point curPoint = linearPntB.at(i);
  127. cv::line(canvas, curPoint, cv::Point(curPoint.x - 5, curPoint.y), cv::Scalar(55, 195, 40), 1);
  128. }
  129. for (int i = 0; i < linearPntM.size(); i++) {
  130. cv::Point curPoint = linearPntM.at(i);
  131. cv::line(canvas, curPoint, cv::Point(curPoint.x - 5, curPoint.y), cv::Scalar(145, 175, 40), 1);
  132. }
  133. cv::putText(canvas, "true", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);
  134. circle(canvas, top, 3, cv::Scalar(0, 69, 255), 1);
  135. circle(canvas, top, 63, cv::Scalar(0, 169, 255), 1);
  136. //circle(canvas, bottom, 3, cv::Scalar(0, 69, 255), 1);
  137. //circle(canvas, bottom, 43, cv::Scalar(255, 169, 0), 1);
  138. }
  139. else
  140. {
  141. cv::putText(canvas, "false", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);
  142. }
  143. cv::Mat ROIcanvas;
  144. img.copyTo(ROIcanvas);
  145. if (debug) circle(ROIcanvas, top, 3, cv::Scalar(0, 69, 255), 1);
  146. if (debug) circle(ROIcanvas, top, 63, cv::Scalar(0, 169, 255), 1);
  147. //if (debug) circle(ROIcanvas, bottom, 3, cv::Scalar(0, 69, 255), 1);
  148. //if (debug) circle(ROIcanvas, bottom, 63, cv::Scalar(0, 169, 255), 1);
  149. if (debug) rectangle(ROIcanvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);
  150. rectangle(canvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);
  151. if (debug) printf("-------------------------------------****------ roiF top=【%d, %d】, bottom=【%d, %d】\n", top.x, top.y, bottom.x, bottom.y);
  152. if (debug) imshow("ROI", ROIcanvas);
  153. if (debug) imshow("ROI_canvas", canvas);
  154. //ROIcanvas.copyTo(canvas);
  155. return result;
  156. }

调用main:

  1. //D型主管,方形支管 上或下单侧 OneSideSquare_ROI
  2. int main() {
  3. bool flag;
  4. //std::string filePath = "../../../../0方管支管/1023img";
  5. std::string filePath = "../../../../0方管支管/left";
  6. //std::string filePath = "../../../../0方管支管/right";
  7. string resPath = "/output";
  8. //string resPath = filePath + "./output";
  9. //cv::Point tlP = cv::Point(500, 40);
  10. //cv::Point brP = cv::Point(750, 777);
  11. cv::Point tlP = cv::Point(584, 236);
  12. cv::Point brP = cv::Point(660, 820);
  13. //cv::Rect ROI = cv::Rect(0, 0, 0, 0);
  14. //cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);
  15. //cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);
  16. //cv::Rect ROI = cv::Rect(639, 188, 125, 569);
  17. cv::Point top(90, 90);
  18. cv::Point bottom(90, 90);
  19. cv::Point2f midP(90, 90);
  20. int outMidY;
  21. cv::Mat canvas;
  22. ImageProcessing m_ImageProcessing;
  23. ofstream ofs("log.txt", ios::out);
  24. if (ofs)
  25. {
  26. ofs.clear();
  27. ofs << "日志启动" << endl;
  28. }
  29. std::vector<cv::Point> linearPntT;
  30. std::vector<cv::Point> linearPntB;
  31. std::vector<cv::Point> linearPntM;
  32. vector<Picture_set> img_buf;
  33. vector<string> path_name;
  34. bool arcTop_right = !true;
  35. bool isTopHalf = true;
  36. int midyTolerant = 4;
  37. bool getROI = true;
  38. bool lianxu = false; //循环测试
  39. if (lianxu)
  40. {
  41. //string path = filePath + cv::format("\\Image_20231023105829348.png");
  42. //std::string name = cv::format("\\ImgD_2023_10_26_10_48_12_135_567_196_153_603_Src.png");
  43. std::string name = cv::format("\\ImgD_2023_10_25_18_16_24_519_569_200_166_559_Src.png");
  44. string path = filePath + name;
  45. cv::Mat src = cv::imread(path);
  46. src.copyTo(canvas);
  47. cv::namedWindow("main_OriginalIMG", cv::NORMCONV_FILTER);
  48. cvSetMouseCallback("main_OriginalIMG", on_mouse_singleClick, 0);
  49. cv::imshow("main_OriginalIMG", src);
  50. //cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);
  51. cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);
  52. if (getROI) {
  53. ROI = getROIFromString(name);
  54. ROI.height /= 2;
  55. if (!isTopHalf) {
  56. ROI.y += ROI.height;
  57. }
  58. }
  59. //鼠标点击的坐标【691, 319】
  60. // 鼠标点击的坐标【692, 632】
  61. //cout << src.size() << endl;
  62. //rotateImage(src);
  63. //cout << src.size() << endl;
  64. //鼠标点击的坐标【707, 691】
  65. // 鼠标点击的坐标【395, 691】
  66. //trueX=outY;
  67. //trueY=oriSrc.rows-outX;
  68. //circle(src, cv::Point(622, 424), 5, cv::Scalar(255, 255, 255), -1);
  69. //cv::Mat flipMat;
  70. //cv::flip(src, flipMat, 1);
  71. //cv::Point q = cv::Point(flipMat.cols - 622 - 1, 424)/* - cv::Point(546, 228)*/;
  72. //circle(flipMat, q, 3, cv::Scalar(0, 0, 0), -1);
  73. //cv::imshow("flipMat", flipMat);
  74. //cv::waitKey();
  75. //cv::flip(src, src, 0);
  76. bool flag = m_ImageProcessing.OneSideSquare_ROI(src, ROI, linearPntT, linearPntB, linearPntM, top, bottom, canvas, arcTop_right, isTopHalf, true);
  77. cout << "\nmain ==== flag " << flag << endl;
  78. if (flag) {
  79. cout << "top = " << top.x << " " << top.y << endl;
  80. cout << "bottom = " << bottom.x << " " << bottom.y << endl;
  81. }
  82. canvas.copyTo(src);
  83. //cout << "\nmain ==== i " << endl;
  84. circle(canvas, top, 63, cv::Scalar(0, 69, 255), 1);
  85. circle(canvas, bottom, 63, cv::Scalar(0, 69, 255), 1);
  86. 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);
  87. cv::namedWindow("main-结果图src", cv::RECURS_FILTER);
  88. cvSetMouseCallback("main-结果图src", on_mouse_singleClick, 0);
  89. cv::imshow("main-结果图src", src);
  90. cv::namedWindow("main-canvas", cv::RECURS_FILTER);
  91. cvSetMouseCallback("main-canvas", on_mouse_singleClick, 0);
  92. cv::imshow("main-canvas", canvas);
  93. }
  94. else
  95. {
  96. vector<string> path_name;
  97. getAllFiles(filePath, path_name);
  98. cout << "path_name.size()=" << path_name.size() << endl;
  99. int number = 1;
  100. for (auto i : path_name)
  101. {
  102. //cout << i.size() << endl;
  103. if (i.size() == 7) continue;
  104. if (i.find(".log") != std::string::npos) continue;
  105. if (i.find(".txt") != std::string::npos) continue;
  106. std::string name = i;
  107. std::string path11 = filePath + "\\" + i;
  108. cv::Mat src = cv::imread(path11);
  109. //cv::Mat src = cv::imread(filePath + "\\" + i);
  110. cout << endl << "number【" << number << "】src path=" << i << " ;" << endl;
  111. src.copyTo(canvas);
  112. cv::imshow("main_OriginalIMG", src);
  113. //将结果图写入文件方便查看结果
  114. int len = filePath.length();
  115. //i = i.substr(i.find_last_of('\\') + 1, len);
  116. cout << "i=" << i << ", path11=" << path11 << endl;
  117. int time_start = clock();
  118. int time_end = clock();
  119. cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);
  120. cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);
  121. if (getROI) {
  122. ROI = getROIFromString(name);
  123. ROI.height /= 2;
  124. if (!isTopHalf) {
  125. ROI.y += ROI.height;
  126. }
  127. }
  128. bool flag = m_ImageProcessing.OneSideSquare_ROI(src, ROI, linearPntT, linearPntB, linearPntM, top, bottom, canvas, arcTop_right, isTopHalf, false);
  129. time_end = clock();
  130. printf("\n耗时 %d ms \n", time_end - time_start);
  131. cout << "\nmain ==== flag " << flag << endl;
  132. if (flag) {
  133. cout << "top = " << top.x << " " << top.y << endl;
  134. cout << "bottom = " << bottom.x << " " << bottom.y << endl;
  135. }
  136. canvas.copyTo(src);
  137. 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);
  138. cv::imshow("main-结果图src", src);
  139. cv::imshow("main-canvas", canvas);
  140. //将结果图写入文件方便查看结果
  141. char* filePath_ = new char[len + 1];
  142. strcpy(filePath_, filePath.c_str());
  143. len = filePath.length();
  144. char* resPath_ = new char[len + 1];
  145. strcpy(resPath_, resPath.c_str());
  146. //i.erase(0, strlen(filePath_) - strlen(resPath_) - 2);
  147. string out = filePath + resPath;
  148. cout << "\nmain ==== i " << i << endl;
  149. out.append("\\").append(i);
  150. cout << "number【" << number << "】res path=" << out << endl;
  151. cv::imwrite(out, src);
  152. number++;
  153. cout << "path_name.size() = " << path_name.size() << endl;
  154. cout << "*********************************************************************************************************************" << endl;
  155. cv::waitKey(10);
  156. }
  157. cout << "循环结束!!! main " << endl;
  158. }
  159. ofs.close();
  160. cv::waitKey(0);
  161. system("Pause");
  162. return 0;
  163. }

三点

返回三点+1个点集  

  1. /*
  2. //两弧线夹圆弧 返回三点+骨干点集
  3. cv::Mat img, 原图
  4. cv::Rect ROI,
  5. cv::Point& top, 输出焊点(图像上位于较上方的点)
  6. cv::Point& bottom, 输出焊点(图像上位于较下方的点)
  7. cv::Point2f& midP, 圆弧中点
  8. std::vector<cv::Point>& allPntList:直线部分非弧线的点集
  9. cv::Mat &canvas,效果图可视化
  10. */
  11. 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);
  12. 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);
  1. 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)
  2. {
  3. int endRes = 0;
  4. bool result = false;
  5. img.copyTo(canvas);
  6. top = cv::Point(0, 0);
  7. bottom = cv::Point(0, 0);
  8. midP = cv::Point2f(0, 0);
  9. allPntList.clear();
  10. cv::Mat imgOriginal;
  11. bool ROI_flag;//是否有给信息区
  12. cv::Point ROI_tl = cv::Point2i(ROI.x, ROI.y);
  13. cv::Point ROI_br = cv::Point2i(ROI.x + ROI.width, ROI.y + ROI.height);
  14. if (ROI_tl == cv::Point(0, 0) && ROI_br == cv::Point(0, 0) || ROI.width == 0 || ROI.height == 0)
  15. {
  16. img.copyTo(imgOriginal);
  17. ROI_flag = false;
  18. }
  19. else
  20. {
  21. if (ROI_tl.x > ROI_br.x || ROI_tl.y > ROI_br.y)//信息区两点疑似传反
  22. {
  23. printf("信息区两点疑似传反!");
  24. return false;
  25. }
  26. if (ROI_tl.x < 0 || ROI_br.x > img.cols || ROI_tl.y < 0 || ROI_br.y > img.rows)//信息区的框选超出图像范围
  27. {
  28. printf("信息区的框选超出图像范围!");
  29. return false;
  30. }
  31. if (abs(ROI_tl.x - ROI_br.x) > img.cols || abs(ROI_tl.y - ROI_br.y) > img.rows)//信息区大小超出图像大小
  32. {
  33. printf("信息区大小超出图像大小!");
  34. return false;
  35. }
  36. //此时不合法的ROI都已提前返回false
  37. cv::Rect roi(ROI_tl.x, ROI_tl.y, ROI_br.x - ROI_tl.x, ROI_br.y - ROI_tl.y);
  38. imgOriginal = img(roi); //裁剪出的ROI区域放于imgOriginal
  39. ROI_flag = true;
  40. }
  41. if (arcTop_right) {//圆弧顶点朝右的情况
  42. result = twoArcsClipTheArc(imgOriginal, top, bottom, midP, allPntList, canvas, debug);//调用识别算法
  43. }
  44. else {//圆弧顶点朝左的情况
  45. cv::Mat flipMat;
  46. cv::flip(imgOriginal, flipMat, 1); // 左右翻转 y对称
  47. if (debug) imshow("图像左右翻转", flipMat);
  48. result = twoArcsClipTheArc(flipMat, top, bottom, midP, allPntList, canvas, debug);//调用识别算法
  49. if (result) {
  50. top.x = flipMat.cols - top.x - 1;
  51. bottom.x = flipMat.cols - bottom.x - 1;
  52. for (int i = 0; i < allPntList.size(); i++) {
  53. allPntList.at(i).x = flipMat.cols - allPntList.at(i).x - 1;
  54. }
  55. if (midP != cv::Point2f(0, 0)) midP.x = flipMat.cols - midP.x - 1;
  56. }
  57. }
  58. if (debug) printf("-------------------------------------****------ roiF top=【%d, %d】, bottom=【%d, %d】\n", top.x, top.y, bottom.x, bottom.y);
  59. if (debug) printf(" roiF midP=【%f, %f】\n", midP.x, midP.y);
  60. //img.copyTo(canvas);
  61. //img.copyTo(canvas);//调试时注释掉
  62. if (result)
  63. {
  64. endRes = 1;
  65. for (int i = 0; i < allPntList.size(); i++) {
  66. allPntList.at(i) += ROI_tl;
  67. }
  68. for (int i = 0; i < allPntList.size(); i++) {
  69. cv::Point curPoint = allPntList.at(i);
  70. cv::line(canvas, curPoint, cv::Point(curPoint.x - 5, curPoint.y), cv::Scalar(55, 195, 40), 1);
  71. }
  72. top += ROI_tl;
  73. bottom += ROI_tl;
  74. midP += cv::Point2f(ROI_tl);
  75. //if (midP != cv::Point2f(0, 0)) {
  76. // midP.x = midP.x + ROI_tl.x;
  77. // midP.y = midP.y + ROI_tl.y;
  78. //}
  79. circle(canvas, midP, 3, cv::Scalar(0, 69, 255), 1);
  80. circle(canvas, midP, 43, cv::Scalar(0, 169, 255), 1);
  81. cv::line(canvas, midP, cv::Point2f(5, midP.y), cv::Scalar(155, 195, 40), 1);
  82. cv::line(canvas, cv::Point2f(midP.x, midP.y - 5), cv::Point2f(midP.x, midP.y + 5), cv::Scalar(155, 195, 40), 1);
  83. cv::putText(canvas, "true", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);
  84. circle(canvas, top, 3, cv::Scalar(0, 69, 255), 1);
  85. circle(canvas, top, 63, cv::Scalar(0, 169, 255), 1);
  86. circle(canvas, bottom, 3, cv::Scalar(0, 69, 255), 1);
  87. circle(canvas, bottom, 43, cv::Scalar(255, 169, 0), 1);
  88. }
  89. else
  90. {
  91. cv::putText(canvas, "false", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);
  92. }
  93. cv::Mat ROIcanvas;
  94. img.copyTo(ROIcanvas);
  95. if (debug) circle(ROIcanvas, top, 3, cv::Scalar(0, 69, 255), 1);
  96. if (debug) circle(ROIcanvas, top, 63, cv::Scalar(0, 169, 255), 1);
  97. if (debug) circle(ROIcanvas, bottom, 3, cv::Scalar(0, 69, 255), 1);
  98. if (debug) circle(ROIcanvas, bottom, 63, cv::Scalar(0, 169, 255), 1);
  99. if (debug) rectangle(ROIcanvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);
  100. rectangle(canvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);
  101. if (debug) printf("-------------------------------------****------ roiF top=【%d, %d】, bottom=【%d, %d】\n", top.x, top.y, bottom.x, bottom.y);
  102. if (debug) printf(" roiF midP=【%f, %f】\n", midP.x, midP.y);
  103. if (debug) imshow("ROI", ROIcanvas);
  104. if (debug) imshow("ROI_canvas", canvas);
  105. //ROIcanvas.copyTo(canvas);
  106. return result;
  107. }

 调用main:

  1. //两弧线夹圆弧 返回三点+骨干点集
  2. int main/*TwoArcsClipTheArc*/() {
  3. bool flag;
  4. std::string filePath = "../../img/圆弧夹圆弧";
  5. string resPath = "/output";
  6. //string resPath = filePath + "./output";
  7. cv::Point tlP = cv::Point(500, 292);
  8. cv::Point brP = cv::Point(750, 677);
  9. //cv::Rect ROI = cv::Rect(0, 0, 0, 0);
  10. //cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);
  11. //cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);
  12. //cv::Rect ROI = cv::Rect(539, 218, 113, 513);
  13. cv::Rect ROI = cv::Rect(546, 228, 101, 520);
  14. cv::Point top(90, 90);
  15. cv::Point bottom(90, 90);
  16. cv::Point2f midP(90, 90);
  17. int outMidY;
  18. cv::Mat canvas;
  19. PTank_imgProcess m_ImageProcessing;
  20. ofstream ofs("log.txt", ios::out);
  21. if (ofs)
  22. {
  23. ofs.clear();
  24. ofs << "日志启动" << endl;
  25. }
  26. std::vector<cv::Point> allPntList;
  27. vector<string> path_name;
  28. bool arcTop_right = true;
  29. bool getROI = true;
  30. bool lianxu = false; //循环测试
  31. if (!lianxu)
  32. {
  33. string name = cv::format("\\Image_20240702114054217.png");
  34. //string name = cv::format("\\Image_20240702170558613.png");//斜
  35. //string name = cv::format("\\Image_20240702170644641.png");//斜
  36. string path = filePath + name;
  37. //string path = filePath + cv::format("\\ImgD_2023_08_17_15_06_45_412_639_188_125_569_Src.png");
  38. cv::Mat src = cv::imread(path);
  39. src.copyTo(canvas);
  40. cv::namedWindow("main_OriginalIMG", cv::NORMCONV_FILTER);
  41. cvSetMouseCallback("main_OriginalIMG", on_mouse_singleClick, 0);
  42. cv::imshow("main_OriginalIMG", src);
  43. //cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);
  44. //cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);
  45. if (getROI) ROI = getROIFromString(name);
  46. bool flag = m_ImageProcessing.twoArcsClipTheArc_ROI(src, ROI, top, bottom, midP, allPntList, canvas, arcTop_right, true);
  47. cout << "\nmain ==== flag " << flag << endl;
  48. if (flag) {
  49. cout << "top = " << top.x << " " << top.y << endl;
  50. cout << "bottom = " << bottom.x << " " << bottom.y << endl;
  51. cout << "midP = " << midP.x << " " << midP.y << endl;
  52. }
  53. canvas.copyTo(src);
  54. //cout << "\nmain ==== i " << endl;
  55. circle(canvas, top, 63, cv::Scalar(0, 69, 255), 1);
  56. circle(canvas, bottom, 63, cv::Scalar(0, 69, 255), 1);
  57. 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);
  58. cv::namedWindow("main-结果图src", cv::RECURS_FILTER);
  59. cvSetMouseCallback("main-结果图src", on_mouse_singleClick, 0);
  60. cv::imshow("main-结果图src", src);
  61. cv::namedWindow("main-canvas", cv::RECURS_FILTER);
  62. cvSetMouseCallback("main-canvas", on_mouse_singleClick, 0);
  63. cv::imshow("main-canvas", canvas);
  64. }
  65. else
  66. {
  67. vector<string> path_name;
  68. getAllFiles(filePath, path_name);
  69. cout << "path_name.size()=" << path_name.size() << endl;
  70. int number = 1;
  71. for (auto i : path_name)
  72. {
  73. //cout << i.size() << endl;
  74. if (i.size() == 7) continue;
  75. if (i.find(".log") != std::string::npos) continue;
  76. if (i.find(".txt") != std::string::npos) continue;
  77. if (i.find("_result") != std::string::npos) continue;
  78. if (i.find("png") == std::string::npos && i.find("bmp") == std::string::npos && i.find("jpg") == std::string::npos) continue;
  79. std::string path11 = filePath + "\\" + i;
  80. cv::Mat src = cv::imread(path11);
  81. //cv::Mat src = cv::imread(filePath + "\\" + i);
  82. cout << endl << "number【" << number << "】src path=" << i << " ;" << endl;
  83. src.copyTo(canvas);
  84. cv::imshow("main_OriginalIMG", src);
  85. //将结果图写入文件方便查看结果
  86. int len = filePath.length();
  87. //i = i.substr(i.find_last_of('\\') + 1, len);
  88. cout << "i=" << i << ", path11=" << path11 << endl;
  89. int time_start = clock();
  90. int time_end = clock();
  91. cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);
  92. //cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);
  93. if (getROI) ROI = getROIFromString(i);
  94. bool flag = m_ImageProcessing.twoArcsClipTheArc_ROI(src, ROI, top, bottom, midP, allPntList, canvas, arcTop_right, false);
  95. time_end = clock();
  96. printf("\n耗时 %d ms \n", time_end - time_start);
  97. cout << "\nmain ==== flag " << flag << endl;
  98. if (flag) {
  99. cout << "top = " << top.x << " " << top.y << endl;
  100. cout << "bottom = " << bottom.x << " " << bottom.y << endl;
  101. }
  102. canvas.copyTo(src);
  103. 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);
  104. cv::imshow("main-结果图src", src);
  105. cv::imshow("main-canvas", canvas);
  106. //将结果图写入文件方便查看结果
  107. char* filePath_ = new char[len + 1];
  108. strcpy(filePath_, filePath.c_str());
  109. len = filePath.length();
  110. char* resPath_ = new char[len + 1];
  111. strcpy(resPath_, resPath.c_str());
  112. //i.erase(0, strlen(filePath_) - strlen(resPath_) - 2);
  113. string out = filePath + resPath;
  114. cout << "\nmain ==== i " << i << endl;
  115. out.append("\\").append(i);
  116. cout << "number【" << number << "】res path=" << out << endl;
  117. cv::imwrite(out, src);
  118. number++;
  119. cout << "path_name.size() = " << path_name.size() << endl;
  120. cout << "*********************************************************************************************************************" << endl;
  121. cv::waitKey(10);
  122. }
  123. cout << "循环结束!!! main " << endl;
  124. }
  125. ofs.close();
  126. cv::waitKey(0);
  127. system("Pause");
  128. return 0;
  129. }

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

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

  1. /*
  2. //D型管的两直线夹圆弧
  3. //周六新策略:两边直线中间圆弧,激光平行于主管 (__O__两端直线中间半圆弧找圆弧的两端拐点)---圆轨迹
  4. cv::Mat img, 原图
  5. cv::Rect ROI, 可以让右边的干扰直反光落进去,上下不用截,左右可适当截小一下减少识别时的计算时间
  6. int outMidY,因y偏差过大时返回的两点无效,则返回圆弧区域的中心y
  7. cv::Point& midP, outMidY对应的圆弧上的骨干点(midP为(0,0)时,该值无效)
  8. std::vector<cv::Point>& linearPnt:直线部分非弧线的点集
  9. cv::Point& top, 输出焊点(图像上位于较上方的点)
  10. cv::Point& bottom, 输出焊点(图像上位于较下方的点)
  11. cv::Mat &canvas,效果图可视化
  12. int midyTolerant = 2;//outMidY的容差范围
  13. bool arcTop_right = true;//圆弧顶点是否朝右的标志量,默认为true(true为朝右,false为朝左)
  14. */
  15. 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);
  16. 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);
  1. 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)
  2. {
  3. int endRes = 0;
  4. bool result = false;
  5. img.copyTo(canvas);
  6. top = cv::Point(0, 0);
  7. bottom = cv::Point(0, 0);
  8. midP = cv::Point2f(0, 0);
  9. linearPntT.clear();
  10. linearPntB.clear();
  11. outMidY = 0;
  12. cv::Mat imgOriginal;
  13. bool ROI_flag;//是否有给信息区
  14. cv::Point ROI_tl = cv::Point2i(ROI.x, ROI.y);
  15. cv::Point ROI_br = cv::Point2i(ROI.x + ROI.width, ROI.y + ROI.height);
  16. if (ROI_tl == cv::Point(0, 0) && ROI_br == cv::Point(0, 0) || ROI.width == 0 || ROI.height == 0)
  17. {
  18. img.copyTo(imgOriginal);
  19. ROI_flag = false;
  20. }
  21. else
  22. {
  23. if (ROI_tl.x > ROI_br.x || ROI_tl.y > ROI_br.y)//信息区两点疑似传反
  24. {
  25. printf("信息区两点疑似传反!");
  26. return false;
  27. }
  28. if (ROI_tl.x < 0 || ROI_br.x > img.cols || ROI_tl.y < 0 || ROI_br.y > img.rows)//信息区的框选超出图像范围
  29. {
  30. printf("信息区的框选超出图像范围!");
  31. return false;
  32. }
  33. if (abs(ROI_tl.x - ROI_br.x) > img.cols || abs(ROI_tl.y - ROI_br.y) > img.rows)//信息区大小超出图像大小
  34. {
  35. printf("信息区大小超出图像大小!");
  36. return false;
  37. }
  38. //此时不合法的ROI都已提前返回false
  39. cv::Rect roi(ROI_tl.x, ROI_tl.y, ROI_br.x - ROI_tl.x, ROI_br.y - ROI_tl.y);
  40. imgOriginal = img(roi); //裁剪出的ROI区域放于imgOriginal
  41. ROI_flag = true;
  42. }
  43. if (arcTop_right) {//圆弧顶点朝右的情况
  44. result = LaserParallelToTheMainD(imgOriginal, outMidY, midP, linearPntT, linearPntB, top, bottom, canvas, midyTolerant, debug);//调用识别算法
  45. }
  46. else {//圆弧顶点朝左的情况
  47. cv::Mat flipMat;
  48. cv::flip(imgOriginal, flipMat, 1); // 左右翻转 y对称
  49. if (debug) imshow("图像左右翻转", flipMat);
  50. result = LaserParallelToTheMainD(flipMat, outMidY, midP, linearPntT, linearPntB, top, bottom, canvas, midyTolerant, debug);//调用识别算法
  51. if (result) {
  52. top.x = flipMat.cols - top.x - 1;
  53. bottom.x = flipMat.cols - bottom.x - 1;
  54. for (int i = 0; i < linearPntT.size(); i++) {
  55. linearPntT.at(i).x = flipMat.cols - linearPntT.at(i).x - 1;
  56. }
  57. for (int i = 0; i < linearPntB.size(); i++) {
  58. linearPntB.at(i).x = flipMat.cols - linearPntB.at(i).x - 1;
  59. }
  60. if (midP != cv::Point2f(0, 0)) midP.x = flipMat.cols - midP.x - 1;
  61. }
  62. }
  63. if (debug) printf("-------------------------------------****------ roiF top=【%d, %d】, bottom=【%d, %d】\n", top.x, top.y, bottom.x, bottom.y);
  64. if (debug) printf(" roiF midP=【%f, %f】\n", midP.x, midP.y);
  65. //img.copyTo(canvas);
  66. x值和y值补上ROI左上点x和y
  67. //if (ROI_flag) {
  68. // if (Corner != cv::Point(0, 0))
  69. // {
  70. // Corner.x += ROI_tl.x;
  71. // Corner.y += ROI_tl.y;
  72. // }
  73. //}
  74. img.copyTo(canvas);//调试时注释掉
  75. if (result)
  76. {
  77. endRes = 1;
  78. top += ROI_tl;
  79. bottom += ROI_tl;
  80. if (midP != cv::Point2f(0, 0)) {
  81. midP.x = midP.x + ROI_tl.x;
  82. midP.y = midP.y + ROI_tl.y;
  83. }
  84. cv::line(canvas, midP, cv::Point2f(5, midP.y), cv::Scalar(55, 195, 40), 1);
  85. cv::line(canvas, cv::Point2f(midP.x, midP.y - 5), cv::Point2f(midP.x, midP.y + 5), cv::Scalar(55, 195, 40), 1);
  86. for (int i = 0; i < linearPntT.size(); i++) {
  87. linearPntT.at(i) += ROI_tl;
  88. }
  89. for (int i = 0; i < linearPntB.size(); i++) {
  90. linearPntB.at(i) += ROI_tl;
  91. }
  92. for (int i = 0; i < linearPntT.size(); i++) {
  93. cv::Point curPoint = linearPntT.at(i);
  94. cv::line(canvas, curPoint, cv::Point(curPoint.x - 5, curPoint.y), cv::Scalar(55, 195, 40), 1);
  95. }
  96. for (int i = 0; i < linearPntB.size(); i++) {
  97. cv::Point curPoint = linearPntB.at(i);
  98. cv::line(canvas, curPoint, cv::Point(curPoint.x - 5, curPoint.y), cv::Scalar(55, 195, 40), 1);
  99. }
  100. cv::putText(canvas, "true", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);
  101. circle(canvas, top, 3, cv::Scalar(0, 69, 255), 1);
  102. circle(canvas, top, 63, cv::Scalar(0, 169, 255), 1);
  103. circle(canvas, bottom, 3, cv::Scalar(0, 69, 255), 1);
  104. circle(canvas, bottom, 43, cv::Scalar(255, 169, 0), 1);
  105. }
  106. else
  107. {
  108. cv::putText(canvas, "false", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);
  109. }
  110. cv::Mat ROIcanvas;
  111. img.copyTo(ROIcanvas);
  112. if (debug) circle(ROIcanvas, top, 3, cv::Scalar(0, 69, 255), 1);
  113. if (debug) circle(ROIcanvas, top, 63, cv::Scalar(0, 169, 255), 1);
  114. if (debug) circle(ROIcanvas, bottom, 3, cv::Scalar(0, 69, 255), 1);
  115. if (debug) circle(ROIcanvas, bottom, 63, cv::Scalar(0, 169, 255), 1);
  116. if (debug) rectangle(ROIcanvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);
  117. rectangle(canvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);
  118. if (debug) printf("-------------------------------------****------ roiF top=【%d, %d】, bottom=【%d, %d】\n", top.x, top.y, bottom.x, bottom.y);
  119. if (debug) printf(" roiF midP=【%f, %f】\n", midP.x, midP.y);
  120. if (debug) imshow("ROI", ROIcanvas);
  121. if (debug) imshow("ROI_canvas", canvas);
  122. //ROIcanvas.copyTo(canvas);
  123. return result;
  124. }

调用main:

  1. //CXL 两边直线中间圆弧,激光平行于主管 DDDDDDDDDDDDDDDDD 圆轨迹 增加直线部分点集 的重载
  2. int main() {
  3. bool flag;
  4. std::string filePath = "../../../../Log08141641/TestImg/src";
  5. string resPath = "/output";
  6. //string resPath = filePath + "./output";
  7. cv::Point tlP = cv::Point(500, 292);
  8. cv::Point brP = cv::Point(750, 677);
  9. //cv::Rect ROI = cv::Rect(0, 0, 0, 0);
  10. //cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);
  11. //cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);
  12. //cv::Rect ROI = cv::Rect(539, 218, 113, 513);
  13. cv::Point top(90, 90);
  14. cv::Point bottom(90, 90);
  15. cv::Point2f midP(90, 90);
  16. int outMidY;
  17. cv::Mat canvas;
  18. ImageProcessing m_ImageProcessing;
  19. ofstream ofs("log.txt", ios::out);
  20. if (ofs)
  21. {
  22. ofs.clear();
  23. ofs << "日志启动" << endl;
  24. }
  25. std::vector<cv::Point> linearPntT;
  26. std::vector<cv::Point> linearPntB;
  27. vector<string> path_name;
  28. bool arcTop_right = !true;
  29. int midyTolerant = 4;
  30. bool getROI = true;
  31. bool lianxu = false; //循环测试
  32. if (!lianxu)
  33. {
  34. string name = cv::format("\\ImgD_2024_06_04_09_14_48_111_565_82_86_851_Src.png");
  35. string path = filePath + name;
  36. //string path = filePath + cv::format("\\ImgD_2023_08_17_15_06_45_412_639_188_125_569_Src.png");
  37. cv::Mat src = cv::imread(path);
  38. src.copyTo(canvas);
  39. cv::namedWindow("main_OriginalIMG", cv::NORMCONV_FILTER);
  40. cvSetMouseCallback("main_OriginalIMG", on_mouse_singleClick, 0);
  41. cv::imshow("main_OriginalIMG", src);
  42. //cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);
  43. //cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);
  44. if (getROI) ROI = getROIFromString(name);
  45. //trueX=outY;
  46. //trueY=oriSrc.rows-outX;
  47. //circle(src, cv::Point(622, 424), 5, cv::Scalar(255, 255, 255), -1);
  48. //cv::Mat flipMat;
  49. //cv::flip(src, flipMat, 1);
  50. //cv::Point q = cv::Point(flipMat.cols - 622 - 1, 424)/* - cv::Point(546, 228)*/;
  51. //circle(flipMat, q, 3, cv::Scalar(0, 0, 0), -1);
  52. //cv::imshow("flipMat", flipMat);
  53. //cv::waitKey();
  54. bool flag = m_ImageProcessing.LaserParallelToTheMainD_ROI(src, ROI, outMidY, midP, linearPntT, linearPntB, top, bottom, canvas, midyTolerant, arcTop_right, true);
  55. cout << "\nmain ==== flag " << flag << endl;
  56. if (flag) {
  57. cout << "top = " << top.x << " " << top.y << endl;
  58. cout << "bottom = " << bottom.x << " " << bottom.y << endl;
  59. }
  60. canvas.copyTo(src);
  61. //cout << "\nmain ==== i " << endl;
  62. circle(canvas, top, 63, cv::Scalar(0, 69, 255), 1);
  63. circle(canvas, bottom, 63, cv::Scalar(0, 69, 255), 1);
  64. 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);
  65. cv::namedWindow("main-结果图src", cv::RECURS_FILTER);
  66. cvSetMouseCallback("main-结果图src", on_mouse_singleClick, 0);
  67. cv::imshow("main-结果图src", src);
  68. cv::namedWindow("main-canvas", cv::RECURS_FILTER);
  69. cvSetMouseCallback("main-canvas", on_mouse_singleClick, 0);
  70. cv::imshow("main-canvas", canvas);
  71. }
  72. else
  73. {
  74. vector<string> path_name;
  75. getAllFiles(filePath, path_name);
  76. cout << "path_name.size()=" << path_name.size() << endl;
  77. int number = 1;
  78. for (auto i : path_name)
  79. {
  80. //cout << i.size() << endl;
  81. if (i.size() == 7) continue;
  82. if (i.find(".log") != std::string::npos) continue;
  83. if (i.find(".txt") != std::string::npos) continue;
  84. if (i.find("_result") != std::string::npos) continue;
  85. if (i.find("png") == std::string::npos && i.find("bmp") == std::string::npos && i.find("jpg") == std::string::npos) continue;
  86. std::string path11 = filePath + "\\" + i;
  87. cv::Mat src = cv::imread(path11);
  88. //cv::Mat src = cv::imread(filePath + "\\" + i);
  89. cout << endl << "number【" << number << "】src path=" << i << " ;" << endl;
  90. src.copyTo(canvas);
  91. cv::imshow("main_OriginalIMG", src);
  92. //将结果图写入文件方便查看结果
  93. int len = filePath.length();
  94. //i = i.substr(i.find_last_of('\\') + 1, len);
  95. cout << "i=" << i << ", path11=" << path11 << endl;
  96. int time_start = clock();
  97. int time_end = clock();
  98. cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);
  99. //cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);
  100. if (getROI) ROI = getROIFromString(i);
  101. bool flag = m_ImageProcessing.LaserParallelToTheMainD_ROI(src, ROI, outMidY, midP, linearPntT, linearPntB, top, bottom, canvas, midyTolerant, arcTop_right, false);
  102. time_end = clock();
  103. printf("\n耗时 %d ms \n", time_end - time_start);
  104. cout << "\nmain ==== flag " << flag << endl;
  105. if (flag) {
  106. cout << "top = " << top.x << " " << top.y << endl;
  107. cout << "bottom = " << bottom.x << " " << bottom.y << endl;
  108. }
  109. canvas.copyTo(src);
  110. 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);
  111. cv::imshow("main-结果图src", src);
  112. cv::imshow("main-canvas", canvas);
  113. //将结果图写入文件方便查看结果
  114. char* filePath_ = new char[len + 1];
  115. strcpy(filePath_, filePath.c_str());
  116. len = filePath.length();
  117. char* resPath_ = new char[len + 1];
  118. strcpy(resPath_, resPath.c_str());
  119. //i.erase(0, strlen(filePath_) - strlen(resPath_) - 2);
  120. string out = filePath + resPath;
  121. cout << "\nmain ==== i " << i << endl;
  122. out.append("\\").append(i);
  123. cout << "number【" << number << "】res path=" << out << endl;
  124. cv::imwrite(out, src);
  125. number++;
  126. cout << "path_name.size() = " << path_name.size() << endl;
  127. cout << "*********************************************************************************************************************" << endl;
  128. cv::waitKey(10);
  129. }
  130. cout << "循环结束!!! main " << endl;
  131. }
  132. ofs.close();
  133. cv::waitKey(0);
  134. system("Pause");
  135. return 0;
  136. }

四点

返回四点+1个点集 

  1. /*
  2. //矩形位置 返回四点+骨干点集
  3. cv::Mat img, 原图
  4. cv::Rect ROI,
  5. cv::Point & p1, 图像较上方的主管底部点
  6. cv::Point & p2, 图像较上方的矩形顶部边缘点
  7. cv::Point & p3, 图像较下方的主管底部点
  8. cv::Point & p4,图像较下方的矩形顶部边缘点
  9. std::vector<cv::Point>& allPntList:直线部分非弧线的点集
  10. cv::Mat &canvas,效果图可视化
  11. */
  12. 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);
  13. 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);
  1. 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)
  2. {
  3. int endRes = 0;
  4. bool result = false;
  5. img.copyTo(canvas);
  6. p1 = cv::Point(0, 0);
  7. p2 = cv::Point(0, 0);
  8. p3 = cv::Point(0, 0);
  9. p4 = cv::Point(0, 0);
  10. allPntList.clear();
  11. cv::Mat imgOriginal;
  12. bool ROI_flag;//是否有给信息区
  13. cv::Point ROI_tl = cv::Point2i(ROI.x, ROI.y);
  14. cv::Point ROI_br = cv::Point2i(ROI.x + ROI.width, ROI.y + ROI.height);
  15. if (ROI_tl == cv::Point(0, 0) && ROI_br == cv::Point(0, 0) || ROI.width == 0 || ROI.height == 0)
  16. {
  17. img.copyTo(imgOriginal);
  18. ROI_flag = false;
  19. }
  20. else
  21. {
  22. if (ROI_tl.x > ROI_br.x || ROI_tl.y > ROI_br.y)//信息区两点疑似传反
  23. {
  24. printf("信息区两点疑似传反!");
  25. return false;
  26. }
  27. if (ROI_tl.x < 0 || ROI_br.x > img.cols || ROI_tl.y < 0 || ROI_br.y > img.rows)//信息区的框选超出图像范围
  28. {
  29. printf("信息区的框选超出图像范围!");
  30. return false;
  31. }
  32. if (abs(ROI_tl.x - ROI_br.x) > img.cols || abs(ROI_tl.y - ROI_br.y) > img.rows)//信息区大小超出图像大小
  33. {
  34. printf("信息区大小超出图像大小!");
  35. return false;
  36. }
  37. //此时不合法的ROI都已提前返回false
  38. cv::Rect roi(ROI_tl.x, ROI_tl.y, ROI_br.x - ROI_tl.x, ROI_br.y - ROI_tl.y);
  39. imgOriginal = img(roi); //裁剪出的ROI区域放于imgOriginal
  40. ROI_flag = true;
  41. }
  42. result = rectangle4Pnt(imgOriginal, p1, p2, p3, p4, allPntList, canvas, debug);//调用识别算法
  43. if (debug) printf("-------------------------------------****------ roiF p1=【%d, %d】, p2=【%d, %d】\n", p1.x, p1.y, p2.x, p2.y);
  44. if (debug) printf("-------------------------------------****------ roiF p3=【%d, %d】, p4=【%d, %d】\n", p3.x, p3.y, p4.x, p4.y);
  45. //img.copyTo(canvas);
  46. img.copyTo(canvas);//调试时注释掉
  47. if (result)
  48. {
  49. endRes = 1;
  50. p1 += ROI_tl;
  51. p2 += ROI_tl;
  52. p3 += ROI_tl;
  53. p4 += ROI_tl;
  54. for (int i = 0; i < allPntList.size(); i++) {
  55. allPntList.at(i) += ROI_tl;
  56. }
  57. int w = 5;
  58. for (int i = 0; i < allPntList.size(); i++) {
  59. cv::Point curPoint = allPntList.at(i);
  60. cv::line(canvas, curPoint, cv::Point(curPoint.x - w, curPoint.y), cv::Scalar(55, 195, 40), 1);
  61. }
  62. cv::putText(canvas, "true", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);
  63. circle(canvas, p1, 3, cv::Scalar(0, 69, 255), 1);
  64. circle(canvas, p1, 63, cv::Scalar(0, 169, 255), 1);
  65. circle(canvas, p2, 3, cv::Scalar(0, 69, 255), 1);
  66. circle(canvas, p2, 43, cv::Scalar(255, 169, 0), 1);
  67. circle(canvas, p3, 3, cv::Scalar(0, 69, 255), 1);
  68. circle(canvas, p3, 63, cv::Scalar(0, 169, 255), 1);
  69. circle(canvas, p4, 3, cv::Scalar(0, 69, 255), 1);
  70. circle(canvas, p4, 43, cv::Scalar(255, 169, 0), 1);
  71. }
  72. else
  73. {
  74. cv::putText(canvas, "false", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);
  75. }
  76. cv::Mat ROIcanvas;
  77. img.copyTo(ROIcanvas);
  78. if (debug) circle(ROIcanvas, p1, 3, cv::Scalar(0, 69, 255), 1);
  79. if (debug) circle(ROIcanvas, p1, 63, cv::Scalar(0, 169, 255), 1);
  80. if (debug) circle(ROIcanvas, p2, 3, cv::Scalar(0, 69, 255), 1);
  81. if (debug) circle(ROIcanvas, p2, 63, cv::Scalar(0, 169, 255), 1);
  82. if (debug) circle(ROIcanvas, p3, 3, cv::Scalar(0, 69, 255), 1);
  83. if (debug) circle(ROIcanvas, p3, 63, cv::Scalar(0, 169, 255), 1);
  84. if (debug) circle(ROIcanvas, p4, 3, cv::Scalar(0, 69, 255), 1);
  85. if (debug) circle(ROIcanvas, p4, 63, cv::Scalar(0, 169, 255), 1);
  86. if (debug) rectangle(ROIcanvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);
  87. rectangle(canvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);
  88. if (debug) printf("---------------****------ roiF p1=【%d, %d】, p2=【%d, %d】\n", p1.x, p1.y, p2.x, p2.y);
  89. if (debug) printf("---------------****------ roiF p3=【%d, %d】, p4=【%d, %d】\n", p3.x, p3.y, p4.x, p4.y);
  90. if (debug) imshow("ROI", ROIcanvas);
  91. if (debug) imshow("ROI_canvas", canvas);
  92. //ROIcanvas.copyTo(canvas);
  93. return result;
  94. }

调用main:

  1. //矩形位置 返回四点+骨干点集
  2. int main/*Rectangle4Pnt_ROI*/() {
  3. bool flag;
  4. //std::string filePath = "../../../../Log08141641/TestImg/src";
  5. std::string filePath = "E://vsproject//压力罐\\img\\矩形";
  6. string resPath = "/output";
  7. //string resPath = filePath + "./output";
  8. cv::Point tlP = cv::Point(500, 292);
  9. cv::Point brP = cv::Point(750, 677);
  10. //cv::Rect ROI = cv::Rect(0, 0, 0, 0);
  11. //cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);
  12. //cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);
  13. //cv::Rect ROI = cv::Rect(539, 218, 113, 513);
  14. cv::Point top(90, 90);
  15. cv::Point bottom(90, 90);
  16. cv::Point p3(90, 90);
  17. cv::Point p4(90, 90);
  18. int outMidY;
  19. cv::Mat canvas;
  20. PTank_imgProcess m_ImageProcessing;
  21. ofstream ofs("log.txt", ios::out);
  22. if (ofs)
  23. {
  24. ofs.clear();
  25. ofs << "日志启动" << endl;
  26. }
  27. std::vector<cv::Point> allPntList;
  28. vector<string> path_name;
  29. bool getROI = true;
  30. bool lianxu = false; //循环测试
  31. if (lianxu)
  32. {
  33. string name = cv::format("\\Image_20240627144521008.png");
  34. string path = filePath + name;
  35. cv::Mat src = cv::imread(path);
  36. src.copyTo(canvas);
  37. cv::namedWindow("main_OriginalIMG", cv::RECURS_FILTER);
  38. cvSetMouseCallback("main_OriginalIMG", on_mouse_singleClick, 0);
  39. cv::imshow("main_OriginalIMG", src);
  40. //cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);
  41. cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);
  42. if (getROI) ROI = getROIFromString(name);
  43. bool flag = m_ImageProcessing.rectangle4Pnt_ROI(src, ROI, top, bottom, p3, p4, allPntList, canvas, true);
  44. cout << "\nmain ==== flag " << flag << endl;
  45. if (flag) {
  46. cout << "top = " << top.x << " " << top.y << endl;
  47. cout << "bottom = " << bottom.x << " " << bottom.y << endl;
  48. }
  49. canvas.copyTo(src);
  50. //cout << "\nmain ==== i " << endl;
  51. circle(canvas, top, 63, cv::Scalar(0, 69, 255), 1);
  52. circle(canvas, bottom, 63, cv::Scalar(0, 69, 255), 1);
  53. 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);
  54. cv::namedWindow("main-结果图src", cv::RECURS_FILTER);
  55. cvSetMouseCallback("main-结果图src", on_mouse_singleClick, 0);
  56. cv::imshow("main-结果图src", src);
  57. cv::namedWindow("main-canvas", cv::RECURS_FILTER);
  58. cvSetMouseCallback("main-canvas", on_mouse_singleClick, 0);
  59. cv::imshow("main-canvas", canvas);
  60. }
  61. else
  62. {
  63. vector<string> path_name;
  64. getAllFiles(filePath, path_name);
  65. cout << "path_name.size()=" << path_name.size() << endl;
  66. int number = 1;
  67. for (auto i : path_name)
  68. {
  69. //cout << i.size() << endl;
  70. if (i.size() == 7) continue;
  71. if (i.find(".log") != std::string::npos) continue;
  72. if (i.find("png") == std::string::npos && i.find("bmp") == std::string::npos && i.find("jpg") == std::string::npos) continue;
  73. std::string path11 = filePath + "\\" + i;
  74. cv::Mat src = cv::imread(path11);
  75. //cv::Mat src = cv::imread(filePath + "\\" + i);
  76. cout << endl << "number【" << number << "】src path=" << i << " ;" << endl;
  77. src.copyTo(canvas);
  78. cv::imshow("main_OriginalIMG", src);
  79. //将结果图写入文件方便查看结果
  80. int len = filePath.length();
  81. //i = i.substr(i.find_last_of('\\') + 1, len);
  82. cout << "i=" << i << ", path11=" << path11 << endl;
  83. int time_start = clock();
  84. int time_end = clock();
  85. cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);
  86. //cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);
  87. if (getROI) ROI = getROIFromString(i);
  88. bool flag = m_ImageProcessing.rectangle4Pnt_ROI(src, ROI, top, bottom, p3, p4, allPntList, canvas, false);
  89. time_end = clock();
  90. printf("\n耗时 %d ms \n", time_end - time_start);
  91. cout << "\nmain ==== flag " << flag << endl;
  92. if (flag) {
  93. cout << "top = " << top.x << " " << top.y << endl;
  94. cout << "bottom = " << bottom.x << " " << bottom.y << endl;
  95. }
  96. canvas.copyTo(src);
  97. 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);
  98. cv::imshow("main-结果图src", src);
  99. cv::imshow("main-canvas", canvas);
  100. //将结果图写入文件方便查看结果
  101. char* filePath_ = new char[len + 1];
  102. strcpy(filePath_, filePath.c_str());
  103. len = filePath.length();
  104. char* resPath_ = new char[len + 1];
  105. strcpy(resPath_, resPath.c_str());
  106. //i.erase(0, strlen(filePath_) - strlen(resPath_) - 2);
  107. string out = filePath + resPath;
  108. cout << "\nmain ==== i " << i << endl;
  109. out.append("\\").append(i);
  110. cout << "number【" << number << "】res path=" << out << endl;
  111. cv::imwrite(out, src);
  112. number++;
  113. cout << "path_name.size() = " << path_name.size() << endl;
  114. cout << "*********************************************************************************************************************" << endl;
  115. cv::waitKey(10);
  116. }
  117. cout << "循环结束!!! main " << endl;
  118. }
  119. ofs.close();
  120. cv::waitKey(0);
  121. system("Pause");
  122. return 0;
  123. }

返回四点+双点集

  1. /*
  2. //多层多道焊 圆管表面 & 四边形坡口拼接
  3. cv::Mat img, 原图
  4. cv::Point& top, 输出焊点(图像上位于较上方的点)
  5. cv::Point& bottom, 输出焊点(图像上位于较下方的点)
  6. std::vector<cv::Point>& groovePnt:坡口部分包括内侧面的点集
  7. cv::Point& valleyT, 位于焊道底部的焊点(图像上位于较上方的点)
  8. cv::Point& valleyB, 位于焊道底部的焊点(图像上位于较下方的点)
  9. std::vector<cv::Point>& valleyPnt,位于焊道底部的,焊道底部两点之间的点集
  10. cv::Mat &canvas,效果图可视化
  11. cv::Rect ROI,
  12. */
  13. 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);
  14. 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);
  1. 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)
  2. {
  3. int endRes = 0;
  4. bool result = false;
  5. img.copyTo(canvas);
  6. top = cv::Point(0, 0);
  7. bottom = cv::Point(0, 0);
  8. groovePnt.clear();
  9. valleyT = cv::Point(0, 0);
  10. valleyB = cv::Point(0, 0);
  11. valleyPnt.clear();
  12. cv::Mat imgOriginal;
  13. bool ROI_flag;//是否有给信息区
  14. cv::Point ROI_tl = cv::Point2i(ROI.x, ROI.y);
  15. cv::Point ROI_br = cv::Point2i(ROI.x + ROI.width, ROI.y + ROI.height);
  16. if (ROI_tl == cv::Point(0, 0) && ROI_br == cv::Point(0, 0) || ROI.width == 0 || ROI.height == 0)
  17. {
  18. img.copyTo(imgOriginal);
  19. ROI_flag = false;
  20. }
  21. else
  22. {
  23. if (ROI_tl.x > ROI_br.x || ROI_tl.y > ROI_br.y)//信息区两点疑似传反
  24. {
  25. printf("信息区两点疑似传反!");
  26. return false;
  27. }
  28. if (ROI_tl.x < 0 || ROI_br.x > img.cols || ROI_tl.y < 0 || ROI_br.y > img.rows)//信息区的框选超出图像范围
  29. {
  30. printf("信息区的框选超出图像范围!");
  31. return false;
  32. }
  33. if (abs(ROI_tl.x - ROI_br.x) > img.cols || abs(ROI_tl.y - ROI_br.y) > img.rows)//信息区大小超出图像大小
  34. {
  35. printf("信息区大小超出图像大小!");
  36. return false;
  37. }
  38. //此时不合法的ROI都已提前返回false
  39. cv::Rect roi(ROI_tl.x, ROI_tl.y, ROI_br.x - ROI_tl.x, ROI_br.y - ROI_tl.y);
  40. imgOriginal = img(roi); //裁剪出的ROI区域放于imgOriginal
  41. ROI_flag = true;
  42. }
  43. result = multilayerMultichannel4(imgOriginal, top, bottom, groovePnt, valleyT, valleyB, valleyPnt, canvas, debug);//调用识别算法
  44. if (debug) printf("-------------------------------------****------ roiF top=【%d, %d】, bottom=【%d, %d】\n", top.x, top.y, bottom.x, bottom.y);
  45. if (debug) printf("----- roiF valleyT=【%d, %d】, valleyB=【%d, %d】\n", valleyT.x, valleyT.y, valleyB.x, valleyB.y);
  46. //img.copyTo(canvas);
  47. x值和y值补上ROI左上点x和y
  48. //if (ROI_flag) {
  49. // if (Corner != cv::Point(0, 0))
  50. // {
  51. // Corner.x += ROI_tl.x;
  52. // Corner.y += ROI_tl.y;
  53. // }
  54. //}
  55. img.copyTo(canvas);//调试时注释掉
  56. cv::Mat t1;
  57. canvas.convertTo(t1, -1, 1900 / 100.0, 100 - 100);//第一次线性变换100
  58. if (debug)cv::imshow("线性变换ROI", t1);
  59. t1.copyTo(canvas);
  60. if (result)
  61. {
  62. endRes = 1;
  63. top += ROI_tl;
  64. bottom += ROI_tl;
  65. valleyT += ROI_tl;
  66. valleyB += ROI_tl;
  67. for (int i = 0; i < groovePnt.size(); i++) {
  68. groovePnt.at(i) += ROI_tl;
  69. }
  70. for (int i = 0; i < valleyPnt.size(); i++) {
  71. valleyPnt.at(i) += ROI_tl;
  72. }
  73. int w = 9;
  74. for (int i = 0; i < groovePnt.size(); i++) {
  75. cv::Point curPoint = groovePnt.at(i);
  76. cv::line(canvas, curPoint, cv::Point(curPoint.x + w, curPoint.y), cv::Scalar(55, 195, 40), 1);
  77. }
  78. cv::putText(canvas, "true", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);
  79. circle(canvas, top, 3, cv::Scalar(0, 69, 255), 1);
  80. circle(canvas, top, 63, cv::Scalar(0, 169, 255), 1);
  81. circle(canvas, bottom, 3, cv::Scalar(0, 69, 255), 1);
  82. circle(canvas, bottom, 43, cv::Scalar(255, 169, 0), 1);
  83. circle(canvas, valleyT, 3, cv::Scalar(0, 69, 255), 1);
  84. circle(canvas, valleyT, 43, cv::Scalar(0, 169, 255), 1);
  85. circle(canvas, valleyB, 3, cv::Scalar(0, 69, 255), 1);
  86. circle(canvas, valleyB, 23, cv::Scalar(255, 169, 0), 1);
  87. for (int i = 0; i < valleyPnt.size(); i++) {
  88. cv::Point curPoint = valleyPnt.at(i);
  89. cv::line(canvas, curPoint, cv::Point(curPoint.x - w, curPoint.y), cv::Scalar(75, 155, 40), 1);
  90. }
  91. }
  92. else
  93. {
  94. cv::putText(canvas, "false", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);
  95. }
  96. cv::Mat ROIcanvas;
  97. img.copyTo(ROIcanvas);
  98. if (debug) circle(ROIcanvas, top, 3, cv::Scalar(0, 69, 255), 1);
  99. if (debug) circle(ROIcanvas, top, 63, cv::Scalar(0, 169, 255), 1);
  100. if (debug) circle(ROIcanvas, bottom, 3, cv::Scalar(0, 69, 255), 1);
  101. if (debug) circle(ROIcanvas, bottom, 63, cv::Scalar(0, 169, 255), 1);
  102. if (debug) rectangle(ROIcanvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);
  103. rectangle(canvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);
  104. if (debug) printf("-------------------------------------****------ roiF top=【%d, %d】, bottom=【%d, %d】\n", top.x, top.y, bottom.x, bottom.y);
  105. if (debug) printf("----- roiF valleyT=【%d, %d】, valleyB=【%d, %d】\n", valleyT.x, valleyT.y, valleyB.x, valleyB.y);
  106. if (debug) imshow("ROI", ROIcanvas);
  107. if (debug) imshow("ROI_canvas", canvas);
  108. //ROIcanvas.copyTo(canvas);
  109. return result;
  110. }

调用main:

  1. //multilayerMultichannel4_ROI 多层多道焊 圆管表面 & 四边形坡口拼接
  2. int main() {
  3. bool flag;
  4. //std::string filePath = "E:\\vsproject\\WeldingLine\\多层多道4";
  5. std::string filePath = "E:\\vsproject\\WeldingLine\\多层多道4\\TestImgAAA";
  6. std::string resPath = "/output";
  7. //string resPath = filePath + "./output";
  8. //cv::Point tlP = cv::Point(500, 40);
  9. //cv::Point brP = cv::Point(750, 777);
  10. cv::Point tlP = cv::Point(345, 108);
  11. cv::Point brP = cv::Point(859, 951);
  12. cv::Rect ROI = cv::Rect(0, 0, 0, 0);
  13. //cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);
  14. //cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);
  15. //cv::Rect ROI = cv::Rect(544,208,107,545);
  16. //cv::Rect ROI = cv::Rect(639, 188, 125, 569);
  17. cv::Point top(90, 90);
  18. cv::Point bottom(90, 90);
  19. cv::Point valleyT(90, 90);
  20. cv::Point valleyB(90, 90);
  21. int outMidY;
  22. cv::Mat canvas;
  23. VisualInterface m_ImageProcessing;
  24. //ImageProcess m_ImageProcessing;
  25. std::vector<cv::Point> groovePnt;
  26. std::vector<cv::Point> valleyPnt;
  27. vector<string> path_name;
  28. bool arcTop_right = true;
  29. int midyTolerant = 4;
  30. bool getROI = !true;
  31. bool lianxu = false; //循环测试
  32. if (!lianxu)
  33. {
  34. string name = cv::format("\\SrcImg_2023_12_28_14_57_17_133_ROI_1132_999_401_126_src.png");
  35. //中间底部较高的情况
  36. string path = filePath + name;
  37. cv::Mat src = cv::imread(path);
  38. src.copyTo(canvas);
  39. cv::namedWindow("main_OriginalIMG", cv::NORMCONV_FILTER);
  40. cvSetMouseCallback("main_OriginalIMG", on_mouse_singleClick, 0);
  41. cv::imshow("main_OriginalIMG", src);
  42. cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);
  43. //ROI = cv::Rect(400, 0, 400, src.rows);
  44. //cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);
  45. if (getROI) ROI = getROIFromString(name);
  46. bool flag = m_ImageProcessing.multilayerMultichannel4_ROI(src, top, bottom, groovePnt, valleyT, valleyB, valleyPnt, canvas, ROI, true);
  47. cout << "\nmain ==== flag " << flag << endl;
  48. if (flag) {
  49. cout << "top = " << top.x << " " << top.y << endl;
  50. cout << "bottom = " << bottom.x << " " << bottom.y << endl;
  51. }
  52. canvas.copyTo(src);
  53. //cout << "\nmain ==== i " << endl;
  54. circle(canvas, top, 63, cv::Scalar(0, 69, 255), 1);
  55. circle(canvas, bottom, 63, cv::Scalar(0, 69, 255), 1);
  56. 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);
  57. cv::namedWindow("main-结果图src", cv::RECURS_FILTER);
  58. cvSetMouseCallback("main-结果图src", on_mouse_singleClick, 0);
  59. cv::imshow("main-结果图src", src);
  60. cv::namedWindow("main-canvas", cv::RECURS_FILTER);
  61. cvSetMouseCallback("main-canvas", on_mouse_singleClick, 0);
  62. cv::imshow("main-canvas", canvas);
  63. }
  64. else
  65. {
  66. vector<string> path_name;
  67. getAllFiles(filePath, path_name);
  68. cout << "path_name.size()=" << path_name.size() << endl;
  69. int number = 1;
  70. for (auto i : path_name)
  71. {
  72. //cout << i.size() << endl;
  73. if (i.size() == 7) continue;
  74. if (i.find(".log") != std::string::npos) continue;
  75. if (i.find(".txt") != std::string::npos) continue;
  76. if (i.find("_result") != std::string::npos) continue;
  77. if (i.find("png") == std::string::npos && i.find("bmp") == std::string::npos && i.find("jpg") == std::string::npos) continue;
  78. std::string path11 = filePath + "\\" + i;
  79. cv::Mat src = cv::imread(path11);
  80. //cv::Mat src = cv::imread(filePath + "\\" + i);
  81. cout << endl << "number【" << number << "】src path=" << i << " ;" << endl;
  82. src.copyTo(canvas);
  83. cv::imshow("main_OriginalIMG", src);
  84. //将结果图写入文件方便查看结果
  85. int len = filePath.length();
  86. //i = i.substr(i.find_last_of('\\') + 1, len);
  87. cout << "i=" << i << ", path11=" << path11 << endl;
  88. int time_start = clock();
  89. int time_end = clock();
  90. cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);
  91. //ROI = cv::Rect(400, 0, 400, src.rows);
  92. cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);
  93. if (getROI) ROI = getROIFromString(i);
  94. bool flag = m_ImageProcessing.multilayerMultichannel4_ROI(src, top, bottom, groovePnt, valleyT, valleyB, valleyPnt, canvas, ROI, false);
  95. time_end = clock();
  96. printf("\n耗时 %d ms \n", time_end - time_start);
  97. cout << "\nmain ==== flag " << flag << endl;
  98. if (flag) {
  99. cout << "top = " << top.x << " " << top.y << endl;
  100. cout << "bottom = " << bottom.x << " " << bottom.y << endl;
  101. }
  102. canvas.copyTo(src);
  103. 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);
  104. cv::imshow("main-结果图src", src);
  105. cv::imshow("main-canvas", canvas);
  106. //将结果图写入文件方便查看结果
  107. char* filePath_ = new char[len + 1];
  108. strcpy(filePath_, filePath.c_str());
  109. len = filePath.length();
  110. char* resPath_ = new char[len + 1];
  111. strcpy(resPath_, resPath.c_str());
  112. //i.erase(0, strlen(filePath_) - strlen(resPath_) - 2);
  113. string out = filePath + resPath;
  114. cout << "\nmain ==== i " << i << endl;
  115. out.append("\\").append(i);
  116. cout << "number【" << number << "】res path=" << out << endl;
  117. cv::imwrite(out, src);
  118. number++;
  119. cout << "path_name.size() = " << path_name.size() << endl;
  120. cout << "*********************************************************************************************************************" << endl;
  121. cv::waitKey(10);
  122. }
  123. cout << "循环结束!!! main " << endl;
  124. }
  125. cv::waitKey(0);
  126. system("Pause");
  127. return 0;
  128. }

五点

返回五点+1个点集

  1. /*
  2. //两弧线夹悬空的圆弧 返回五点+骨干点集 定"L"型管相贯线水平用
  3. cv::Mat img, 原图
  4. cv::Rect ROI,
  5. cv::Point & p1, 图像较上方的主管底部点
  6. cv::Point & p2, 图像较上方的弧形激光边缘点
  7. cv::Point2f & midP, 圆弧中点
  8. cv::Point & p3, 图像较下方的弧形激光边缘点
  9. cv::Point & p4,图像较下方的主管底部点
  10. std::vector<cv::Point>& allPntList:直线部分非弧线的点集
  11. cv::Mat &canvas,效果图可视化
  12. */
  13. 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);
  14. 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);
  1. 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)
  2. {
  3. int endRes = 0;
  4. bool result = false;
  5. img.copyTo(canvas);
  6. p1 = cv::Point(0, 0);
  7. p2 = cv::Point(0, 0);
  8. p3 = cv::Point(0, 0);
  9. p4 = cv::Point(0, 0);
  10. midP = cv::Point2f(0, 0);
  11. allPntList.clear();
  12. cv::Mat imgOriginal;
  13. bool ROI_flag;//是否有给信息区
  14. cv::Point ROI_tl = cv::Point2i(ROI.x, ROI.y);
  15. cv::Point ROI_br = cv::Point2i(ROI.x + ROI.width, ROI.y + ROI.height);
  16. if (ROI_tl == cv::Point(0, 0) && ROI_br == cv::Point(0, 0) || ROI.width == 0 || ROI.height == 0)
  17. {
  18. img.copyTo(imgOriginal);
  19. ROI_flag = false;
  20. }
  21. else
  22. {
  23. if (ROI_tl.x > ROI_br.x || ROI_tl.y > ROI_br.y)//信息区两点疑似传反
  24. {
  25. printf("信息区两点疑似传反!");
  26. return false;
  27. }
  28. if (ROI_tl.x < 0 || ROI_br.x > img.cols || ROI_tl.y < 0 || ROI_br.y > img.rows)//信息区的框选超出图像范围
  29. {
  30. printf("信息区的框选超出图像范围!");
  31. return false;
  32. }
  33. if (abs(ROI_tl.x - ROI_br.x) > img.cols || abs(ROI_tl.y - ROI_br.y) > img.rows)//信息区大小超出图像大小
  34. {
  35. printf("信息区大小超出图像大小!");
  36. return false;
  37. }
  38. //此时不合法的ROI都已提前返回false
  39. cv::Rect roi(ROI_tl.x, ROI_tl.y, ROI_br.x - ROI_tl.x, ROI_br.y - ROI_tl.y);
  40. imgOriginal = img(roi); //裁剪出的ROI区域放于imgOriginal
  41. ROI_flag = true;
  42. }
  43. result = twoArcsClipTheHangingArc(imgOriginal, p1, p2, midP, p3, p4, allPntList, canvas, debug);//调用识别算法
  44. if (debug) printf("-------------------------------------****------ roiF p1=【%d, %d】, p2=【%d, %d】\n", p1.x, p1.y, p2.x, p2.y);
  45. if (debug) printf("-------------------------------------****------ roiF p3=【%d, %d】, p4=【%d, %d】\n", p3.x, p3.y, p4.x, p4.y);
  46. if (debug) printf(" roiF midP=【%f, %f】\n", midP.x, midP.y);
  47. //img.copyTo(canvas);
  48. img.copyTo(canvas);//调试时注释掉
  49. if (result)
  50. {
  51. endRes = 1;
  52. p1 += ROI_tl;
  53. p2 += ROI_tl;
  54. p3 += ROI_tl;
  55. p4 += ROI_tl;
  56. midP += cv::Point2f(ROI_tl);
  57. for (int i = 0; i < allPntList.size(); i++) {
  58. allPntList.at(i) += ROI_tl;
  59. }
  60. int w = 5;
  61. for (int i = 0; i < allPntList.size(); i++) {
  62. cv::Point curPoint = allPntList.at(i);
  63. cv::line(canvas, curPoint, cv::Point(curPoint.x - w, curPoint.y), cv::Scalar(55, 195, 40), 1);
  64. }
  65. cv::putText(canvas, "true", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);
  66. circle(canvas, midP, 3, cv::Scalar(0, 69, 255), 1);
  67. circle(canvas, midP, 43, cv::Scalar(0, 169, 255), 1);
  68. cv::line(canvas, midP, cv::Point2f(5, midP.y), cv::Scalar(155, 195, 40), 1);
  69. cv::line(canvas, cv::Point2f(midP.x, midP.y - 5), cv::Point2f(midP.x, midP.y + 5), cv::Scalar(155, 195, 40), 1);
  70. circle(canvas, p1, 3, cv::Scalar(0, 69, 255), 1);
  71. circle(canvas, p1, 63, cv::Scalar(0, 169, 255), 1);
  72. circle(canvas, p2, 3, cv::Scalar(0, 69, 255), 1);
  73. circle(canvas, p2, 43, cv::Scalar(255, 169, 0), 1);
  74. circle(canvas, p3, 3, cv::Scalar(0, 69, 255), 1);
  75. circle(canvas, p3, 63, cv::Scalar(0, 169, 255), 1);
  76. circle(canvas, p4, 3, cv::Scalar(0, 69, 255), 1);
  77. circle(canvas, p4, 43, cv::Scalar(255, 169, 0), 1);
  78. }
  79. else
  80. {
  81. cv::putText(canvas, "false", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);
  82. }
  83. cv::Mat ROIcanvas;
  84. img.copyTo(ROIcanvas);
  85. if (debug) circle(ROIcanvas, p1, 3, cv::Scalar(0, 69, 255), 1);
  86. if (debug) circle(ROIcanvas, p1, 63, cv::Scalar(0, 169, 255), 1);
  87. if (debug) circle(ROIcanvas, p2, 3, cv::Scalar(0, 69, 255), 1);
  88. if (debug) circle(ROIcanvas, p2, 63, cv::Scalar(0, 169, 255), 1);
  89. if (debug) circle(ROIcanvas, p3, 3, cv::Scalar(0, 69, 255), 1);
  90. if (debug) circle(ROIcanvas, p3, 63, cv::Scalar(0, 169, 255), 1);
  91. if (debug) circle(ROIcanvas, p4, 3, cv::Scalar(0, 69, 255), 1);
  92. if (debug) circle(ROIcanvas, p4, 63, cv::Scalar(0, 169, 255), 1);
  93. if (debug) rectangle(ROIcanvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);
  94. rectangle(canvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);
  95. if (debug) printf("---------------****------ roiF p1=【%d, %d】, p2=【%d, %d】\n", p1.x, p1.y, p2.x, p2.y);
  96. if (debug) printf("---------------****------ roiF p3=【%d, %d】, p4=【%d, %d】\n", p3.x, p3.y, p4.x, p4.y);
  97. if (debug) printf("---------------****------ roiF midP=【%f, %f】\n", midP.x, midP.y);
  98. if (debug) imshow("ROI", ROIcanvas);
  99. if (debug) imshow("ROI_canvas", canvas);
  100. //ROIcanvas.copyTo(canvas);
  101. return result;
  102. }

 调用main:

  1. //两弧线夹悬空的圆弧 返回五点+骨干点集 定"L"型管相贯线水平用
  2. int mainTwoArcsClipTheHangingArc() {
  3. bool flag;
  4. //std::string filePath = "../../../../Log08141641/TestImg/src";
  5. std::string filePath = "E://vsproject//压力罐\\img\\L型管定水平";
  6. string resPath = "/output";
  7. //string resPath = filePath + "./output";
  8. cv::Point tlP = cv::Point(500, 292);
  9. cv::Point brP = cv::Point(750, 677);
  10. //cv::Rect ROI = cv::Rect(0, 0, 0, 0);
  11. //cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);
  12. //cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);
  13. //cv::Rect ROI = cv::Rect(539, 218, 113, 513);
  14. cv::Point top(90, 90);
  15. cv::Point bottom(90, 90);
  16. cv::Point p3(90, 90);
  17. cv::Point p4(90, 90);
  18. cv::Point2f midP(90, 90);
  19. int outMidY;
  20. cv::Mat canvas;
  21. PTank_imgProcess m_ImageProcessing;
  22. ofstream ofs("log.txt", ios::out);
  23. if (ofs)
  24. {
  25. ofs.clear();
  26. ofs << "日志启动" << endl;
  27. }
  28. std::vector<cv::Point> allPntList;
  29. std::vector<cv::Point> tPntList;
  30. std::vector<cv::Point> bPntList;
  31. std::vector<cv::Point> mPntList;
  32. vector<string> path_name;
  33. bool getROI = true;
  34. bool lianxu = false; //循环测试
  35. if (!lianxu)
  36. {
  37. string name = cv::format("\\Image_20240627151133378.png");
  38. string path = filePath + name;
  39. cv::Mat src = cv::imread(path);
  40. src.copyTo(canvas);
  41. cv::namedWindow("main_OriginalIMG", cv::RECURS_FILTER);
  42. cvSetMouseCallback("main_OriginalIMG", on_mouse_singleClick, 0);
  43. cv::imshow("main_OriginalIMG", src);
  44. //cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);
  45. cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);
  46. if (getROI) ROI = getROIFromString(name);
  47. bool flag = m_ImageProcessing.twoArcsClipTheHangingArc_ROI(src, ROI, top, bottom, midP, p3, p4, allPntList, canvas, true);
  48. m_ImageProcessing.By4Pnt_SplitPLst_1to3(canvas, top, bottom, p3, p4, allPntList, tPntList, bPntList, mPntList, canvas, true);
  49. cout << "\nmain ==== flag " << flag << endl;
  50. if (flag) {
  51. cout << "top = " << top.x << " " << top.y << endl;
  52. cout << "bottom = " << bottom.x << " " << bottom.y << endl;
  53. cout << "midP = " << midP.x << " " << midP.y << endl;
  54. }
  55. canvas.copyTo(src);
  56. //cout << "\nmain ==== i " << endl;
  57. circle(canvas, top, 63, cv::Scalar(0, 69, 255), 1);
  58. circle(canvas, bottom, 63, cv::Scalar(0, 69, 255), 1);
  59. 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);
  60. cv::namedWindow("main-结果图src", cv::RECURS_FILTER);
  61. cvSetMouseCallback("main-结果图src", on_mouse_singleClick, 0);
  62. cv::imshow("main-结果图src", src);
  63. cv::namedWindow("main-canvas", cv::RECURS_FILTER);
  64. cvSetMouseCallback("main-canvas", on_mouse_singleClick, 0);
  65. cv::imshow("main-canvas", canvas);
  66. }
  67. else
  68. {
  69. vector<string> path_name;
  70. getAllFiles(filePath, path_name);
  71. cout << "path_name.size()=" << path_name.size() << endl;
  72. int number = 1;
  73. for (auto i : path_name)
  74. {
  75. //cout << i.size() << endl;
  76. if (i.size() == 7) continue;
  77. if (i.find(".log") != std::string::npos) continue;
  78. if (i.find("png") == std::string::npos && i.find("bmp") == std::string::npos && i.find("jpg") == std::string::npos) continue;
  79. std::string path11 = filePath + "\\" + i;
  80. cv::Mat src = cv::imread(path11);
  81. //cv::Mat src = cv::imread(filePath + "\\" + i);
  82. cout << endl << "number【" << number << "】src path=" << i << " ;" << endl;
  83. src.copyTo(canvas);
  84. cv::imshow("main_OriginalIMG", src);
  85. //将结果图写入文件方便查看结果
  86. int len = filePath.length();
  87. //i = i.substr(i.find_last_of('\\') + 1, len);
  88. cout << "i=" << i << ", path11=" << path11 << endl;
  89. int time_start = clock();
  90. int time_end = clock();
  91. cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);
  92. //cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);
  93. if (getROI) ROI = getROIFromString(i);
  94. bool flag = m_ImageProcessing.twoArcsClipTheHangingArc_ROI(src, ROI, top, bottom, midP, p3, p4, allPntList, canvas, false);
  95. m_ImageProcessing.By4Pnt_SplitPLst_1to3(canvas, top, bottom, p3, p4, allPntList, tPntList, bPntList, mPntList, canvas, false);
  96. time_end = clock();
  97. printf("\n耗时 %d ms \n", time_end - time_start);
  98. cout << "\nmain ==== flag " << flag << endl;
  99. if (flag) {
  100. cout << "top = " << top.x << " " << top.y << endl;
  101. cout << "bottom = " << bottom.x << " " << bottom.y << endl;
  102. cout << "midP = " << midP.x << " " << midP.y << endl;
  103. }
  104. canvas.copyTo(src);
  105. 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);
  106. cv::imshow("main-结果图src", src);
  107. cv::imshow("main-canvas", canvas);
  108. //将结果图写入文件方便查看结果
  109. char* filePath_ = new char[len + 1];
  110. strcpy(filePath_, filePath.c_str());
  111. len = filePath.length();
  112. char* resPath_ = new char[len + 1];
  113. strcpy(resPath_, resPath.c_str());
  114. //i.erase(0, strlen(filePath_) - strlen(resPath_) - 2);
  115. string out = filePath + resPath;
  116. cout << "\nmain ==== i " << i << endl;
  117. out.append("\\").append(i);
  118. cout << "number【" << number << "】res path=" << out << endl;
  119. cv::imwrite(out, src);
  120. number++;
  121. cout << "path_name.size() = " << path_name.size() << endl;
  122. cout << "*********************************************************************************************************************" << endl;
  123. cv::waitKey(10);
  124. }
  125. cout << "循环结束!!! main " << endl;
  126. }
  127. ofs.close();
  128. cv::waitKey(0);
  129. system("Pause");
  130. return 0;
  131. }

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

  1. /*
  2. //泡泡
  3. cv::Mat img, 原图
  4. cv::Rect ROI,
  5. cv::Mat imgTemplate:模板图片(无泡泡的图)
  6. cv::Mat &canvas,效果图可视化
  7. */
  8. bool DetectingBubble(const cv::Mat imgOriginal, cv::Mat imgTemplate, std::vector<cv::Rect> &bubbles, cv::Mat &canvas, bool debug = false);
  9. bool DetectingBubble_ROI(cv::Mat img, cv::Mat imgTemplate, std::vector<cv::Rect> &bubbles, cv::Rect ROI, cv::Mat &canvas, bool debug = false);
  1. bool ImageProcessing::DetectingBubble_ROI(cv::Mat img, cv::Mat imgTemplate, std::vector<cv::Rect> &bubbles, cv::Rect ROI, cv::Mat & canvas, bool debug)
  2. {
  3. cout << __FUNCTION__ << endl;
  4. int endRes = 0;
  5. bool result = false;
  6. img.copyTo(canvas);
  7. bubbles.clear();
  8. cv::Mat imgOriginal;
  9. bool ROI_flag;//是否有给信息区
  10. cv::Point ROI_tl = cv::Point2i(ROI.x, ROI.y);
  11. cv::Point ROI_br = cv::Point2i(ROI.x + ROI.width, ROI.y + ROI.height);
  12. if (ROI_tl == cv::Point(0, 0) && ROI_br == cv::Point(0, 0) || ROI.width == 0 || ROI.height == 0)
  13. {
  14. img.copyTo(imgOriginal);
  15. ROI_flag = false;
  16. }
  17. else
  18. {
  19. if (ROI_tl.x > ROI_br.x || ROI_tl.y > ROI_br.y)//信息区两点疑似传反
  20. {
  21. printf("信息区两点疑似传反!");
  22. return false;
  23. }
  24. if (ROI_tl.x < 0 || ROI_br.x > img.cols || ROI_tl.y < 0 || ROI_br.y > img.rows)//信息区的框选超出图像范围
  25. {
  26. printf("信息区的框选超出图像范围!");
  27. return false;
  28. }
  29. if (abs(ROI_tl.x - ROI_br.x) > img.cols || abs(ROI_tl.y - ROI_br.y) > img.rows)//信息区大小超出图像大小
  30. {
  31. printf("信息区大小超出图像大小!");
  32. return false;
  33. }
  34. //此时不合法的ROI都已提前返回false
  35. cv::Rect roi(ROI_tl.x, ROI_tl.y, ROI_br.x - ROI_tl.x, ROI_br.y - ROI_tl.y);
  36. imgOriginal = img(roi); //裁剪出的ROI区域放于imgOriginal
  37. imgTemplate = imgTemplate(roi);
  38. ROI_flag = true;
  39. }
  40. result = DetectingBubble(imgOriginal, imgTemplate, bubbles, canvas, debug);//调用识别算法
  41. //if (debug) printf("-------------------------------------****------ roiF top=【%d, %d】, bottom=【%d, %d】\n", top.x, top.y, bottom.x, bottom.y);
  42. img.copyTo(canvas);//调试时注释掉
  43. cv::Mat t1;
  44. canvas.convertTo(t1, -1, 200 / 100.0, 0 + 55);
  45. //if (debug) cv::imshow("线性变换0", t1);
  46. t1.copyTo(canvas);
  47. if (result)
  48. {
  49. endRes = 1;
  50. cv::putText(canvas, "true", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);
  51. //for (int i = 0; i < bubbles.size(); i++) {
  52. // //bubbles.at(i).tl.x = bubbles.at(i).tl.x + ROI_tl.x;
  53. // //bubbles.at(i).tl.y = bubbles.at(i).tl.y + ROI_tl.y;
  54. // //bubbles.at(i).br.x = bubbles.at(i).br.x + ROI_tl.x;
  55. // //bubbles.at(i).br.y = bubbles.at(i).br.y + ROI_tl.y;
  56. // cv::Rect curBR = bubbles.at(i);
  57. // bubbles.at(i).x = bubbles.at(i).x + ROI_tl.x;
  58. // bubbles.at(i).y = bubbles.at(i).y + ROI_tl.y;
  59. // //curBR.tl.x = bubbles.at(i).tl.x + ROI_tl.x;
  60. // //curBR.tl.y = bubbles.at(i).tl.y + ROI_tl.y;
  61. // //curBR.br.x = bubbles.at(i).br.x + ROI_tl.x;
  62. // //curBR.br.y = bubbles.at(i).br.y + ROI_tl.y;
  63. //}
  64. for (int i = 0; i < bubbles.size(); i++) {//可视化
  65. bubbles.at(i).x = bubbles.at(i).x + ROI_tl.x;
  66. bubbles.at(i).y = bubbles.at(i).y + ROI_tl.y;
  67. cv::Rect curBR = bubbles.at(i);
  68. cv::rectangle(canvas, curBR.tl(), curBR.br(), cv::Scalar(0, 255, 0), 1);
  69. cv::putText(canvas, to_string(i), curBR.br(), cv::FONT_HERSHEY_COMPLEX, 0.45, cv::Scalar(55, 35, 160), 1);
  70. }
  71. }
  72. else
  73. {
  74. cv::putText(canvas, "false", { cv::Point(50, 50) }, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1);
  75. }
  76. cv::Mat ROIcanvas;
  77. img.copyTo(ROIcanvas);
  78. if (debug) rectangle(ROIcanvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);
  79. rectangle(canvas, ROI_tl, ROI_br, cv::Scalar(0, 0, 255), 1);
  80. if (debug) imshow("ROI", ROIcanvas);
  81. if (debug) imshow("ROI_canvas", canvas);
  82. //ROIcanvas.copyTo(canvas);
  83. return result;
  84. }

 调用main:

  1. //泡泡 OneSideSquare_ROI
  2. int main/*pp*/() {
  3. bool flag;
  4. std::string filePath = "../../../../泡泡/0708/6000";
  5. //std::string filePath = "../../../../泡泡/0708/20000";
  6. string resPath = "/output";
  7. //string resPath = filePath + "./output";
  8. cv::Point tlP = cv::Point(491, 50);
  9. cv::Point brP = cv::Point(1596, 760);
  10. tlP = cv::Point(1, 296);
  11. brP = cv::Point(1160, 2278);
  12. tlP = cv::Point(190, 0);
  13. brP = cv::Point(840, 1024);
  14. //cv::Rect ROI = cv::Rect(0, 0, 0, 0);
  15. //cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);
  16. //cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);
  17. //cv::Rect ROI = cv::Rect(639, 188, 125, 569);
  18. cv::Point top(90, 90);
  19. cv::Point bottom(90, 90);
  20. cv::Point2f midP(90, 90);
  21. int outMidY;
  22. cv::Mat canvas;
  23. ImageProcessing m_ImageProcessing;
  24. ofstream ofs("log.txt", ios::out);
  25. if (ofs)
  26. {
  27. ofs.clear();
  28. ofs << "日志启动" << endl;
  29. }
  30. std::vector<cv::Rect> bubbles;//泡泡集合
  31. vector<Picture_set> img_buf;
  32. vector<string> path_name;
  33. //cv::Mat templ = cv::imread(filePath + cv::format("\\屏幕截图(13).png"));//模板图的灰度图
  34. cv::Mat templ = cv::imread(filePath + cv::format("\\Image_20240708175744959.png"));//6000
  35. bool getROI = !true;
  36. bool lianxu = false; //循环测试
  37. if (lianxu)
  38. {
  39. std::string name = cv::format("\\Image_20240708175747311.png");
  40. string path = filePath + name;
  41. cv::Mat src = cv::imread(path);
  42. src.copyTo(canvas);
  43. cv::namedWindow("main_OriginalIMG", cv::NORMCONV_FILTER);
  44. cvSetMouseCallback("main_OriginalIMG", on_mouse_singleClick, 0);
  45. cv::imshow("main_OriginalIMG", src);
  46. cv::imshow("templ", templ);
  47. //cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);
  48. cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);
  49. if (getROI) {
  50. ROI = getROIFromString(name);
  51. }
  52. //cv::Mat imgCur = src - templ;
  53. imgCur = imgOriginal - imgTemplate;
  54. //if (1) cv::imshow("减去模板图后", imgCur);
  55. bool flag = m_ImageProcessing.DetectingBubble_ROI(src, templ, bubbles, ROI, canvas, true);
  56. cout << "\nmain ==== flag " << flag << endl;
  57. if (flag) {
  58. cout << "top = " << top.x << " " << top.y << endl;
  59. cout << "bottom = " << bottom.x << " " << bottom.y << endl;
  60. }
  61. canvas.copyTo(src);
  62. //cout << "\nmain ==== i " << endl;
  63. circle(canvas, top, 63, cv::Scalar(0, 69, 255), 1);
  64. circle(canvas, bottom, 63, cv::Scalar(0, 69, 255), 1);
  65. 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);
  66. cv::namedWindow("main-结果图src", cv::NORMCONV_FILTER);
  67. cvSetMouseCallback("main-结果图src", on_mouse_singleClick, 0);
  68. cv::imshow("main-结果图src", src);
  69. cv::namedWindow("main-canvas", cv::NORMCONV_FILTER);
  70. cvSetMouseCallback("main-canvas", on_mouse_singleClick, 0);
  71. cv::imshow("main-canvas", canvas);
  72. }
  73. else
  74. {
  75. vector<string> path_name;
  76. getAllFiles(filePath, path_name);
  77. cout << "path_name.size()=" << path_name.size() << endl;
  78. int number = 1;
  79. for (auto i : path_name)
  80. {
  81. //cout << i.size() << endl;
  82. if (i.size() == 7) continue;
  83. if (i.find("output") != std::string::npos) continue;
  84. if (i.find(".log") != std::string::npos) continue;
  85. if (i.find(".txt") != std::string::npos) continue;
  86. if (i.find("png") == std::string::npos && i.find("bmp") == std::string::npos && i.find("jpg") == std::string::npos) continue;
  87. //if (i.find("_202404220930171") == std::string::npos) continue;
  88. std::string name = i;
  89. std::string path11 = filePath + "\\" + i;
  90. cv::Mat src = cv::imread(path11);
  91. //cv::Mat src = cv::imread(filePath + "\\" + i);
  92. cout << endl << "number【" << number << "】src path=" << i << " ;" << endl;
  93. src.copyTo(canvas);
  94. cv::imshow("main_OriginalIMG", src);
  95. //将结果图写入文件方便查看结果
  96. int len = filePath.length();
  97. //i = i.substr(i.find_last_of('\\') + 1, len);
  98. cout << "i=" << i << ", path11=" << path11 << endl;
  99. int time_start = clock();
  100. int time_end = clock();
  101. cv::Rect ROI = cv::Rect(0, 0, src.cols, src.rows);
  102. cv::Rect ROI = cv::Rect(tlP.x, tlP.y, brP.x - tlP.x, brP.y - tlP.y);
  103. if (getROI) {
  104. ROI = getROIFromString(name);
  105. }
  106. bool flag = m_ImageProcessing.DetectingBubble_ROI(src, templ, bubbles, ROI, canvas, false);
  107. time_end = clock();
  108. printf("\n耗时 %d ms \n", time_end - time_start);
  109. cout << "\nmain ==== flag " << flag << endl;
  110. if (flag) {
  111. cout << "top = " << top.x << " " << top.y << endl;
  112. cout << "bottom = " << bottom.x << " " << bottom.y << endl;
  113. }
  114. canvas.copyTo(src);
  115. //cv::putText(src, to_string(number - 1), { cv::Point(250, 250) }, cv::FONT_HERSHEY_COMPLEX, 8, cv::Scalar(255, 255, 255), 5);
  116. 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);
  117. cv::namedWindow("main-结果图src", cv::NORMCONV_FILTER);
  118. cv::imshow("main-结果图src", src);
  119. cv::namedWindow("main-canvas", cv::NORMCONV_FILTER);
  120. cv::imshow("main-canvas", canvas);
  121. //将结果图写入文件方便查看结果
  122. char* filePath_ = new char[len + 1];
  123. strcpy(filePath_, filePath.c_str());
  124. len = filePath.length();
  125. char* resPath_ = new char[len + 1];
  126. strcpy(resPath_, resPath.c_str());
  127. //i.erase(0, strlen(filePath_) - strlen(resPath_) - 2);
  128. string out = filePath + resPath;
  129. cout << "\nmain ==== i " << i << endl;
  130. out.append("\\").append(i);
  131. cout << "number【" << number << "】res path=" << out << endl;
  132. cv::imwrite(out, src);
  133. number++;
  134. cout << "path_name.size() = " << path_name.size() << endl;
  135. cout << "*********************************************************************************************************************" << endl;
  136. cv::waitKey(1);
  137. }
  138. cout << "循环结束!!! main " << endl;
  139. }
  140. ofs.close();
  141. cv::waitKey(0);
  142. system("Pause");
  143. return 0;
  144. }

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

  1. {
  2. bool result = false;
  3. if (imgOriginal.empty()) {
  4. printf("传入图像为空,直接返回false!!!! \n");
  5. return false;
  6. }
  7. imgOriginal.copyTo(canvas);
  8. top = cv::Point(0, 0);
  9. bottom = cv::Point(0, 0);
  10. midP = cv::Point(0, 0);
  11. cv::Mat imgGray;
  12. if (imgOriginal.type() != CV_8UC1)
  13. cv::cvtColor(imgOriginal, imgGray, cv::COLOR_BGR2GRAY);
  14. else imgOriginal.copyTo(imgGray);
  15. //if (1) {
  16. // cv::Mat imgMedianBlur;
  17. // cv::medianBlur(imgGray, imgMedianBlur, 3);
  18. // if (debug) cv::imshow("imgMedianBlur", imgMedianBlur);
  19. // imgMedianBlur.copyTo(imgGray);
  20. //}
  21. cv::Mat close;
  22. cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(7, 5));
  23. cv::morphologyEx(imgGray, close, cv::MORPH_CLOSE, kernel);
  24. if (debug) cv::imshow("闭运算", close);
  25. cv::Mat thresholdMat;
  26. cv::adaptiveThreshold(close, thresholdMat, 255, cv::ADAPTIVE_THRESH_GAUSSIAN_C, cv::THRESH_BINARY, 85, -15);
  27. if (debug) cv::imshow("threshold", thresholdMat);
  28. //一个不为0的像素都没有,即全黑时,直接返回false
  29. int iVal255 = cv::countNonZero(thresholdMat);
  30. if (!iVal255) return false;
  31. std::vector<std::vector<cv::Point>> contours;
  32. std::vector<cv::Vec4i> hierarchy;
  33. std::vector<std::vector<cv::Point>>::iterator k;
  34. cv::findContours(thresholdMat, contours, hierarchy, cv::RETR_EXTERNAL, CV_RETR_LIST);
  35. if (contours.size() <= 0)//图为全黑时
  36. {
  37. std::cout << "contours.size() <= 0";
  38. return false;
  39. }
  40. if (debug) printf("图像处理后 检测到的轮廓数 contours.size() = %d \n", contours.size());
  41. int remainNum = 0;//剩余的轮廓数
  42. cv::Mat tmpMat = cv::Mat(thresholdMat.rows, thresholdMat.cols, CV_8UC1, cv::Scalar(0, 0, 0));
  43. //画出轮廓;
  44. int count = 0;
  45. for (k = contours.begin(); k != contours.end(); ++k, count++) //删除小连通域的
  46. {
  47. std::vector<cv::Point> curContours = *k;
  48. if (curContours.size() < 40) continue;
  49. remainNum++;
  50. cv::drawContours(tmpMat, contours, count, cv::Scalar(255, 255, 255), -1, CV_AA, hierarchy); //用全黑色填充
  51. }
  52. if (debug) cv::imshow("tmpMat", tmpMat);
  53. if (debug) printf("删减后 剩余的轮廓数 remainNum = %d \n", remainNum);
  54. if (remainNum == 0)//图为全黑时
  55. {
  56. std::cout << "contours.size() <= 0";
  57. return false;
  58. }
  59. //------------------------------------------------------------------------------------------------------------------------------------
  60. //提取骨干点集
  61. std::vector<cv::Point> bright_point;//max点
  62. std::vector<int> bright_value;//max像素值
  63. //bright_point = extrectBackbone(tmpMat, bright_value);
  64. if (1) {
  65. if (debug) cout << "tmpMat.size() =" << tmpMat.size() << std::endl;
  66. int splitRow = tmpMat.rows / 2 - 5;
  67. cv::Mat tmpMatU, tmpMatD;
  68. tmpMat.rowRange(0, splitRow).copyTo(tmpMatU);
  69. tmpMat.rowRange(splitRow, tmpMat.rows).copyTo(tmpMatD);
  70. cv::flip(tmpMatU, tmpMatU, 0);
  71. std::vector<cv::Point> bright_pointU;//max点
  72. std::vector<cv::Point> bright_pointD;//max点
  73. std::vector<int> bright_valueU;//max像素值
  74. std::vector<int> bright_valueD;//max像素值
  75. bright_pointU = extrectBackbone(tmpMatU, bright_valueU, 0);
  76. bright_pointD = extrectBackbone(tmpMatD, bright_valueD, 0);
  77. std::reverse(bright_pointU.begin(), bright_pointU.end());
  78. for (int i = 0; i < bright_pointU.size(); i++) {//把上半部分的骨干上下翻转回
  79. cv::Point curPoint = bright_pointU.at(i);
  80. if (curPoint.x != 0) curPoint.y = tmpMatU.rows - curPoint.y - 1;
  81. //if(debug) printf("将上半截骨干排序反转:第%d 行, 【%d, %d】 ============= \n", i, curPoint.x, curPoint.y);
  82. //curPoint.x = tmpMat.cols - curPoint.x;
  83. bright_point.push_back(curPoint);
  84. }
  85. std::vector<cv::Point> bright_pointD_new;
  86. for (int i = 0; i < bright_pointD.size(); i++) {
  87. cv::Point curPoint = bright_pointD.at(i);
  88. if (curPoint.x != 0) curPoint.y = splitRow + curPoint.y;
  89. bright_pointD_new.push_back(curPoint);
  90. }
  91. bright_pointD = bright_pointD_new;
  92. bright_point.insert(bright_point.end(), bright_pointD.begin(), bright_pointD.end());
  93. std::reverse(bright_valueU.begin(), bright_valueU.end());
  94. bright_value = bright_valueU;
  95. bright_value.insert(bright_value.end(), bright_valueD.begin(), bright_valueD.end());
  96. }
  97. //有效骨干个数过少,直接返回 false !!!!
  98. int vaildBackbone = 0;//有效骨干个数
  99. for (int i = 0; i < bright_point.size(); i++)
  100. {
  101. cv::Point P = bright_point.at(i);
  102. if (P != cv::Point(0, 0)) vaildBackbone++;
  103. }
  104. if (debug) printf("有效骨干个数 vaildBackbone = %d \n", vaildBackbone);
  105. if (vaildBackbone <= 30)
  106. {
  107. printf("有效骨干个数过少!!!!\n");
  108. return false;
  109. }
  110. if (debug) {
  111. printf("骨干点集更新前:\n");
  112. for (int i = 0; i < bright_point.size(); i++)
  113. {
  114. cv::Point curPoint = bright_point.at(i);
  115. int curGray = bright_value.at(i);
  116. //printf("骨干点集更新前:第%d 行, 【%d, %d】 灰度值:%d \n", i, curPoint.x, curPoint.y, curGray);
  117. }
  118. }
  119. std::vector<cv::Point> tmpPoint;
  120. std::vector<int> tmpValue;
  121. for (int i = 0; i < bright_point.size(); i++) {
  122. cv::Point curPoint = bright_point.at(i);
  123. if (curPoint.x == 0 || curPoint.y == 0) continue;
  124. if (tmpMat.at<uchar>(curPoint) < 185) continue;
  125. //if (imgGray.at<uchar>(curPoint) < 185) continue;
  126. tmpPoint.push_back(curPoint);
  127. }
  128. bright_point = tmpPoint;//把无效点删掉
  129. if (0) {
  130. std::vector<cv::Point> rightmost;//激光最右点集
  131. //for (int row = 0; row < tmpMat.rows; row++)
  132. //for (int row = bright_point.at(0).y; row < bright_point.at(bright_point.size() - 1).y; row++)
  133. for (int i = 0; i < bright_point.size(); i++)
  134. {
  135. int row = bright_point[i].y;
  136. //for (int col = bright_point.at(row).x; col < tmpMat.cols - 1; col++)//-1是为了防崩溃
  137. for (int col = bright_point.at(i).x; col < tmpMat.cols - 1 && col < bright_point.at(i).x + 70; col++)//-1是为了防崩溃
  138. {
  139. int pv = tmpMat.at<uchar>(row, col);
  140. //int pv = tmpMat.at<uchar>(row, col);
  141. if (pv != 0 && tmpMat.at<uchar>(row, col + 1) == 0)//激光最右点入列
  142. {
  143. if (!rightmost.empty() && rightmost.back().y == row) rightmost.pop_back();
  144. rightmost.push_back(cv::Point(col - 1, row));
  145. //break;
  146. }
  147. }
  148. }
  149. bright_point = rightmost;
  150. }
  151. if (debug) {
  152. printf("骨干点集更新后:\n");
  153. for (int i = 0; i < bright_point.size(); i++) {
  154. cv::Point curPoint = bright_point.at(i);
  155. printf("骨干点集更新后:第%d 行, 【%d, %d】 \n", i, curPoint.x, curPoint.y);
  156. }
  157. }
  158. if (debug) printf("有效骨干个数 bright_point.size() = %d \n", bright_point.size());
  159. if (bright_point.size() <= 30)
  160. {
  161. printf("有效骨干个数过少!!!!\n");
  162. return false;
  163. }
  164. allPntList = bright_point;
  165. //可视化骨干点集
  166. cv::Mat newArcMat = cv::Mat::zeros(tmpMat.size(), CV_8UC1);
  167. for (int i = 0; i < bright_point.size(); i++)
  168. {
  169. cv::Point P = cv::Point(bright_point.at(i).x, bright_point.at(i).y);
  170. newArcMat.at<uchar>(cv::Point(bright_point.at(i).x, bright_point.at(i).y)) = 255;
  171. }
  172. cv::Mat BowCurveMat;
  173. cv::Mat imgRGB_Begin;
  174. if (newArcMat.type() != CV_8UC1)
  175. cvtColor(newArcMat, imgRGB_Begin, cv::COLOR_RGB2GRAY);
  176. else newArcMat.copyTo(imgRGB_Begin);
  177. //重叠看效果
  178. cv::addWeighted(tmpMat, 0.5, imgRGB_Begin, 0.5, 0, BowCurveMat);
  179. //if (debug) cv::namedWindow("BowCurveMat", cv::WINDOW_NORMAL);
  180. if (debug) cv::imshow("BowCurveMat", BowCurveMat);
  181. result = true;
  182. // TODO
  183. return result;
  184. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/运维做开发/article/detail/825594
推荐阅读
相关标签
  

闽ICP备14008679号