【18】OpenCV C++實戰篇——【項目實戰】OpenCV C++ 精準定位“十字刻度尺”中心坐標,過濾圖片中的干擾,精準獲取十字交點坐標

文章目錄

  • 1 問題及分析
  • 2 多尺度霍夫直線 與 漸進概率霍夫線段 細節對比
    • 2.1 多尺度霍夫直線 HoughLines
    • 2.2 漸進概率霍夫線段 HoughLinesP
    • 2.3 HoughLines 和 HoughLinesP 所求結果細節對比
    • 2.4 為什么 HoughLinesP 直線兩端沒有呈放射狀態呢?直線總是平行嗎?
    • 2.5 HoughLines 直線角度,輸出有順序?
  • 3 獲取十字交點坐標
    • 3.1 找到兩直線
      • 3.1.1 獲得 HoughLines 橫豎兩條線
      • 3.1.2 獲得HoughLinesP 橫豎兩條線
    • 3.2 計算交點坐標原理 及實現
  • 4 項目源碼
    • 4.1 .h文件
    • 4.2 .cpp文件
    • 4.3 main文件
  • 5 將 以上兩種封裝成一個函數——新增方法切換,轉換大圖坐標等功能

1 問題及分析

該問題,是由實際工業項目中玻璃出來的,實驗詳細記錄分析,便于日后查看;
(雖然使用的知識點簡單,但要把簡單的知識點 用于解決好 實際工業問題 還是要做很多優化與改進的)

問題:
2000萬像素的工業相機,要對拍攝的畫面中“十字刻度尺”精準定位 (改刻度尺在原圖中占比很小);
原圖很大,下面截取需要定位的ROI區域如下圖 。

難點:圖像較暗,有紅色黃色干擾,刻度尺上有記號筆涂抹干擾,圖像細節模糊;

在這里插入圖片描述
定位結果
在這里插入圖片描述

思路 :

  • 先對原圖灰度化,
  • 再進行反色使刻度尺部分凸顯出來;
  • 二值化,找直線,直線篩選,求兩線交點。

在這里插入圖片描述
在這里插入圖片描述

2 多尺度霍夫直線 與 漸進概率霍夫線段 細節對比

2.1 多尺度霍夫直線 HoughLines

int getCrossScale_HoughL(cv::Mat srcImg, cv::Point2f& crossPoint, bool isShow)
{cv::Mat grayImg, binaryImg, grayImg2;cvtColor(srcImg, grayImg, COLOR_BGR2GRAY);//反色grayImg2 = 255 - grayImg;cv::threshold(grayImg2, binaryImg, 200, 255, THRESH_BINARY);vector<Vec2f> lines;//極坐標(r,theta)HoughLines(binaryImg, lines, 1, CV_PI / 180, 260, 0, 0);//累加器閾值threshold,越大線條越少,反之越多drawHoughLine(srcImg, lines,Scalar(0,0,255),1);//getLineCross(srcImg, lines, crossPoint, isShow);if (isShow){cv::imshow("灰度圖", grayImg);cv::imshow("反色", grayImg2);cv::imshow("二值化", binaryImg);cv::imshow("getCrossScale_HoughL", srcImg);cv::waitKey(0);destroyAllWindows();}return 0;
}

橫豎各找到3條線,
傾斜較為明顯,線段兩端呈放射狀;

在這里插入圖片描述
再看中間交點 橫向占2個像素,豎向占3個像素
在這里插入圖片描述

2.2 漸進概率霍夫線段 HoughLinesP

int getCrossScale_HoughLP(cv::Mat srcImg, cv::Point2f& crossPoint, bool isShow)
{cv::Mat grayImg, binaryImg, grayImg2;cvtColor(srcImg, grayImg, COLOR_BGR2GRAY);//反色grayImg2 = 255 - grayImg;cv::threshold(grayImg2, binaryImg, 200, 255, THRESH_BINARY);//利用漸進概率式霍夫變換提取 直線段vector<Vec4i> linesP;//每條線有四個參數,分別是選段兩端點坐標(x1,y1,x2,y2)HoughLinesP(binaryImg, linesP, 1, CV_PI / 180, 260, srcImg.cols * 0.6, 5);  //兩個點連接最大距離10,CV_PI / 180表示1度對應的弧度for (size_t i = 0; i < linesP.size(); i++){line(srcImg, Point(linesP[i][0], linesP[i][1]), Point(linesP[i][2], linesP[i][3]), Scalar(255,0,0), 1);//測試坐標點//cout << "linesP1[" << i << "][0]" << linesP1[i][0] << "," << "linesP1[" << i << "][1]" << linesP1[i][1] << endl;}//getLineCross(srcImg, lines, crossPoint, isShow);if (isShow){cv::imshow("灰度圖", grayImg);cv::imshow("反色", grayImg2);cv::imshow("二值化", binaryImg);cv::imshow("getCrossScale_HoughLP", srcImg);cv::waitKey(0);destroyAllWindows();}return 0;
}

橫向找到3條線,豎向找到1條線;
橫向線段 3條線非常貼合,看似平行;(線段兩端沒有呈放射狀;)
在這里插入圖片描述

再看中間交點 橫向占3個像素,豎向占1個像素
在這里插入圖片描述

2.3 HoughLines 和 HoughLinesP 所求結果細節對比

對比兩函數參數,發現HoughLinesP 似乎比 HoughLines 有更多的約束條件;
HoughLinesP 多了最先線段長度minLineLength ,最小間隙maxLineGap

void HoughLines( InputArray image, OutputArray lines,double rho, double theta, int threshold,double srn = 0, double stn = 0,double min_theta = 0, double max_theta = CV_PI );
void HoughLinesP( InputArray image, OutputArray lines,double rho, double theta, int threshold,double minLineLength = 0, double maxLineGap = 0 );

在這里插入圖片描述

  • 在使用上的區別,HoughLinesP設定 最小那線段長度為 圖片高度的0.6倍;兩線之間最小間隙為5
  • 此外在使用上HoughLinesP,似乎更方便
    • HoughLines, 每條線返回2個參數,(r,theta);
    • HoughLinesP,每條線返回4個參數,分別是選段兩端點坐標(x1,y1,x2,y2);
	vector<Vec2f> lines;////每條線有2個參數,極坐標(r,theta)HoughLines(binaryImg, lines, 1, CV_PI / 180, 260, 0, 0);//累加器閾值threshold,越大線條越少,反之越多//利用漸進概率式霍夫變換提取 直線段vector<Vec4i> linesP;//每條線有四個參數,分別是選段兩端點坐標(x1,y1,x2,y2)HoughLinesP(binaryImg, linesP, 1, CV_PI / 180, 260, srcImg.cols * 0.6, 5);  //兩個點連接最大距離10,CV_PI / 180表示1度對應的弧度

紅色HoughLines :橫豎各找到3條線;線段兩端呈放射狀;
藍色HoughLinesP :橫向找到3條線,豎向找到1條線;橫向線段 3條線非常貼合,看似平行,線段兩端沒有呈放射狀;

紅色HoughLines : 再看中間交點 橫向占2個像素,豎向占3個像素;
藍色HoughLinesP :再看中間交點 橫向占3個像素,豎向占1個像素

在這里插入圖片描述

對比來看,HoughLinesP 效果更好一下;

2.4 為什么 HoughLinesP 直線兩端沒有呈放射狀態呢?直線總是平行嗎?

在觀察發現 HoughLinesP ,返回的直線vector linesP是 int型,而HoughLines 返回的直線是flaot類型;
難道是HoughLinesP 直線精度不高,稍微的歪斜,放射狀沒表現出來嗎?

	vector<Vec2f> lines;////每條線有2個參數,極坐標(r,theta)HoughLines(binaryImg, lines, 1, CV_PI / 180, 260, 0, 0);//累加器閾值threshold,越大線條越少,反之越多//利用漸進概率式霍夫變換提取 直線段vector<Vec4i> linesP;//每條線有四個參數,分別是選段兩端點坐標(x1,y1,x2,y2)HoughLinesP(binaryImg, linesP, 1, CV_PI / 180, 260, srcImg.cols * 0.6, 5);  //兩個點連接最大距離10,CV_PI / 180表示1度對應的弧度

HoughLinesP的直線類型vector<Vec4i> linesP;改為float類型vector<Vec4f> linesP;
更換傾斜的十字測試
發現,線集是平行的,沒有放射狀;
在這里插入圖片描述

linesP.size() = 5
[262, 390, 319, 28]
[107, 215, 475, 215]
[108, 216, 474, 216]
[260, 391, 318, 23]
[107, 214, 474, 214]

在這里插入圖片描述

更換傾斜的十字測試
發現,線集是平行的,還是沒有放射狀;
在這里插入圖片描述

linesP.size() = 16
[25, 193, 392, 206]
[203, 365, 215, 20]
[196, 363, 208, 17]
[200, 365, 212, 20]
[206, 365, 218, 14]
[202, 365, 214, 19]
[204, 365, 217, 15]
[26, 192, 397, 205]
[26, 195, 387, 207]
[198, 364, 210, 18]
[26, 190, 398, 203]
[27, 7, 286, 48]
[26, 196, 385, 209]
[62, 190, 398, 202]
[197, 365, 208, 51]
[22, 198, 385, 211]

在這里插入圖片描述

2.5 HoughLines 直線角度,輸出有順序?

一依此繪制出HoughLines的每一條直線,發現還是有規律的;

如下圖所示:
第一條直線 傾斜 9度,豎向;(OpenCV里HoughLines的角度應該是與Y軸的夾角)
第二條直線 傾斜90度,橫向;



依次豎向,橫向,豎向,橫向。。。循環輸出所有直線 (輸出順序似乎是碰巧)

lines 0[319, 0.15708]   角度 9
lines 1[215, 1.5708]    角度 90
lines 2[315, 0.139626]  角度 8
lines 3[221, 1.55334]   角度 89
lines 4[323, 0.174533]  角度 10
lines 5[211, 1.58825]   角度 91

在這里插入圖片描述

在這里插入圖片描述
輸出順序似乎是碰巧,再換一個圖像試試;
這次就么那么規律了,橫向和豎向的線 “群居”;

lines 0[192, 1.6057]    角度 92
lines 1[196, 1.58825]   角度 91
lines 2[189, 1.62316]   角度 93
lines 3[209, 0.0174533] 角度 1
lines 4[185, 1.64061]   角度 94
lines 5[206, 0] 角度 0
lines 6[215, 0.0349066] 角度 2
lines 7[213, 0.0349066] 角度 2
lines 8[216, 0.0523599] 角度 3
lines 9[218, 0.0523599] 角度 3
lines 10[219, 0.0698132]        角度 4
lines 11[222, 0.0698132]        角度 4
lines 12[224, 0.0872665]        角度 5
lines 13[199, 1.5708]   角度 90

在這里插入圖片描述
在這里插入圖片描述

3 獲取十字交點坐標

前面只是獲得了 橫豎直線,視覺上交點找到了,但交點坐標是多少?還不知道

思路:橫豎方向各選取一條直線,然后求兩線交點坐標;

兩線交點坐標函數如下,為了方便,每條線各取兩個點帶入;

bool get2linesIntersectionPoint3(cv::Point2f pointA, cv::Point2f pointB, cv::Point2f pointC, cv::Point2f pointD, cv::Point2f& crossPoint);

3.1 找到兩直線

3.1.1 獲得 HoughLines 橫豎兩條線

注意 : HoughLines 水平線90度,豎直線0度;

OpenCV里HoughLines的角度應該是與Y軸的夾角;

思路:
輸入HoughLines直線lines,選取橫豎兩條直線,在選取的直線上各取兩個點,由ptsOnLine帶出來;

bool getPointOn2Line(Mat& img, vector<Vec2f> lines, vector<cv::Point2f>& ptsOnLine,bool isShow)
{vector<Vec2f> linesHV;float rho, theta;bool linesH = false, linesV = false;//找水平、垂直,兩條線 //水平線90度,豎直線0度;OpenCV里HoughLines的角度應該是與Y軸的夾角for (size_t i = 0; i < lines.size(); i++){theta = lines[i][1];  //直線過坐標原點垂線與x軸夾角if (!linesH && (theta > CV_PI / 2 - 0.2 && theta < CV_PI / 2 + 0.2))//橫線theta接近π/2,±δ,{linesHV.push_back(lines[i]);linesH = true;}else if (!linesV && ((theta > -0.2 && theta < 0.2) || theta > CV_PI - 0.2 && theta < CV_PI + 0.2))//豎線theta接近π或0,±δ{linesHV.push_back(lines[i]);linesV = true;}//橫線豎線都找到了,跳出循環if (linesH && linesV){break;}}//求兩條直線上的四個點if (linesHV.size() == 2){drawHoughLine(img, linesHV, ptsOnLine, Scalar(0, 0, 255), 1, isShow);}else{cout << "沒找到兩條直線" << endl;return false;}cv::Rect rect;return true;
}

交點坐標為(248.8,215.0)
在這里插入圖片描述

3.1.2 獲得HoughLinesP 橫豎兩條線

思路:
輸入HoughLinesP直線linesP,選取橫豎兩條直線,在選取的直線上各取兩個點,由ptsOnLine帶出來

注意:
因為HoughLinesP線集是平行的,當同一方向有多條線時,隨便選一條會導致中心不準,
當同一方向有多條線時,端點坐標取均值;

//輸入HoughLinesP直線linesP,選取橫豎兩條直線,在選取的直線上各取兩個點,由ptsOnLine帶出來
bool getPointOn2LineP(Mat& img, vector<Vec4i> linesP, vector<cv::Point2f>& ptsOnLine, bool isShow)
{float rho, theta;Point2f pt1, pt2;double angle;Point2f pts1_H(0,0), pts2_H(0, 0), pts1_V(0, 0), pts2_V(0, 0);int h = 0, v = 0;//找水平、垂直,兩條線//因為HoughLinesP線集是平行的,當同一方向有多條線時,隨便選一條會導致中心不準,//當同一方向有多條線端點坐標取均值;for (size_t i = 0; i < linesP.size(); i++){pt1.x = linesP[i][0];pt1.y = linesP[i][1];pt2.x = linesP[i][2];pt2.y = linesP[i][3];//linesP的每條直線與y軸的夾角angle = getLineAngle(pt1, pt2, Point2f(0,0), Point2f(0,img.rows));//水平線90度,豎直線0度;;;直線與Y軸的夾角(與HoughLines的夾角保持一致)if (angle > 70 && angle < 110)//如果橫線90°±20°{pts1_H.x += pt1.x;pts1_H.y += pt1.y;pts2_H.x += pt2.x;pts2_H.y += pt2.y;h++;}else if (angle > -20 && angle < 20)//如果豎線0°±20°{pts1_V.x += pt1.x;pts1_V.y += pt1.y;pts2_V.x += pt2.x;pts2_V.y += pt2.y;v++;}}pts1_H.x /= h;pts1_H.y /= h;pts2_H.x /= h;pts2_H.y /= h;pts1_V.x /= v;pts1_V.y /= v;pts2_V.x /= v;pts2_V.y /= v;ptsOnLine.push_back(pts1_H);ptsOnLine.push_back(pts2_H);ptsOnLine.push_back(pts1_V);ptsOnLine.push_back(pts2_V);line(img, pts1_H, pts2_H, Scalar(255, 0, 0), 1);line(img, pts1_V, pts2_V, Scalar(255, 0, 0), 1);if(isShow){cv::imshow("img", img);cv::waitKey(0);destroyAllWindows();}return true;
}

交點坐標為(249.1,215.0)
在這里插入圖片描述

3.2 計算交點坐標原理 及實現

////****************************************************************************************
//  求二條直線的交點的公式
//  有如下方程 (x-x1)/(y-y1) = (x2-x1)/(y2-y1) ==> a1*x+b1*y=c1
//             (x-x3)/(y-y3) = (x4-x3)/(y4-y3) ==> a2*x+b2*y=c2
//  則交點為
//          x= D1/D =| c1 b1|  / | a1 b1 |      y= D2/D= | a1 c1| / | a1 b1 |  //當兩條線平行或重合時,分母為零
//                   | c2 b2|  / | a2 b2 |               | a2 c2| / | a2 b2 |
// 
// 注:D是其次ax+by=0,的行列式,Di是把第i列換成等式右邊的列(常數),i是所求未知數所在的列,如x在第一列,D1 
//
//   a1= y2-y1
//   b1= x1-x2
//   c1= x1*y2-x2*y1,這里 a1*x+b1*y=c1,和Ax+By+C=0,的C是一個負號關系
//   a2= y4-y3
//   b2= x3-x4
//   c2= x3*y4-x4*y3
// 
////****************************************************************************************
//// 
////行列式法,x= D1/D, y= D2/D,求兩直線的交點, //適合任意情況(斜率存在,不存在)
bool get2linesIntersectionPoint(cv::Point2f pointA, cv::Point2f pointB, cv::Point2f pointC, cv::Point2f pointD, cv::Point2f& crossPoint)
{float a1 = pointB.y - pointA.y;float b1 = pointA.x - pointB.x;float c1 = pointA.x * pointB.y - pointB.x * pointA.y;//這里 a1*x+b1*y=c1,和Ax+By+C=0,的C是一個負號關系float a2 = pointD.y - pointC.y;float b2 = pointC.x - pointD.x;float c2 = pointC.x * pointD.y - pointD.x * pointC.y;float det = a1 * b2 - a2 * b1;// 直線平行:A1/A2=B1/B2≠C1/C2 (A2B2C2≠0); 重合:A1/A2=B1/B2=C1/C2(A2B2C2≠0)// 直線平行:A1B2=A2B1; 重合:A1B2=A2B1=A1C2if (det == 0) return false;//平行或重合//Now this is cross point of linescrossPoint.x = (b2 * c1 - b1 * c2) / det;//這里和公式法(ABC)也是負號關系crossPoint.y = (a1 * c2 - a2 * c1) / det;return true;
}

由上面兩種方式獲取的直線,分別帶入交點坐標函數,求得交點如圖:

紅色HoughLines : 交點坐標為(248.8,215.0)
藍色HoughLinesP :交點坐標為(249.1,215.0)

二者橫坐標,相差0.3像素,縱坐標相等,
該工業相機為2000萬像素,可見精度還是很高的

在這里插入圖片描述

在這里插入圖片描述
比較細節,看看哪個更準?
比較發現,由于刻度尺上端被黑色的記號筆涂抹記號,對直線檢測結果有一定影響
但比較細節,藍色受影響更小一些; 如果想要更加精準,ROI范圍可以再小一些,把記號筆涂抹部分去掉;

在這里插入圖片描述

在這里插入圖片描述
在這里插入圖片描述

4 項目源碼

4.1 .h文件

#pragma once
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;//獲得黑十字刻度尺 交點坐標(轉換為在B2大ROI中的位置),顯示在srcImgBigROI上
int getCrossScale_HoughL(cv::Mat srcImg, cv::Point2f& crossPoint, bool isShow);
int getCrossScale_HoughLP(cv::Mat srcImg, cv::Point2f& crossPoint, bool isShow);bool getPointOn2Line( Mat& img, vector<Vec2f> lines, vector<cv::Point2f>& ptsOnLine, bool isShow);
bool getPointOn2LineP(Mat& img, vector<Vec4i> linesP, vector<cv::Point2f>& ptsOnLine, bool isShow);//返回直線上兩坐標點,isDraw設置是否繪制直線
void drawHoughLine(Mat& img, vector<Vec2f> lines, vector<cv::Point2f> &ptsOnLine, const Scalar& color, int thickness, bool isDraw);//要標記直線的圖像,檢測的直線數據bool get2linesIntersectionPoint(cv::Point2f pointA, cv::Point2f pointB, cv::Point2f pointC, cv::Point2f pointD, cv::Point2f& crossPoint);
//已知每條直線的兩個點求夾角,,返回角度
double getLineAngle(cv::Point2f pointA, cv::Point2f pointB, cv::Point2f pointC, cv::Point2f pointD);

4.2 .cpp文件

#include "getCross.h"int getCrossScale_HoughL(cv::Mat srcImg, cv::Point2f& crossPoint, bool isShow)
{cv::Mat grayImg, binaryImg, grayImg2;cvtColor(srcImg, grayImg, COLOR_BGR2GRAY);//反色grayImg2 = 255 - grayImg;cv::threshold(grayImg2, binaryImg, 200, 255, THRESH_BINARY);vector<Vec2f> lines;////每條線有2個參數,極坐標(r,theta)HoughLines(binaryImg, lines, 1, CV_PI / 180, 260, 0, 0);//累加器閾值threshold,越大線條越少,反之越多vector<cv::Point2f> ptsOnLine;//獲得兩直線getPointOn2Line(srcImg, lines, ptsOnLine, false);//獲得兩直線交點get2linesIntersectionPoint(ptsOnLine[0], ptsOnLine[1], ptsOnLine[2], ptsOnLine[3], crossPoint);if (isShow){//繪制交點坐標char buf[50];memset(buf, '\0', 50);sprintf_s(buf, "X = %.1f; Y = %.1f;", crossPoint.x, crossPoint.y);int font_face = FONT_HERSHEY_COMPLEX;double font_scale = 0.5;int thickness = 1;putText(srcImg, buf, Point(crossPoint.x + 20, crossPoint.y - 20), font_face, font_scale, Scalar(0, 0, 255), thickness, 8, 0);imshow("十字刻度尺 交點:", srcImg);cv::waitKey(0);destroyAllWindows();}return 0;
}int getCrossScale_HoughLP(cv::Mat srcImg, cv::Point2f& crossPoint, bool isShow)
{cv::Mat grayImg, binaryImg, grayImg2;cvtColor(srcImg, grayImg, COLOR_BGR2GRAY);//反色grayImg2 = 255 - grayImg;cv::threshold(grayImg2, binaryImg, 200, 255, THRESH_BINARY);//利用漸進概率式霍夫變換提取 直線段vector<Vec4i> linesP;//每條線有四個參數,分別是選段兩端點坐標(x1,y1,x2,y2)HoughLinesP(binaryImg, linesP, 1, CV_PI / 180, 260, srcImg.cols * 0.6, 5);  //兩個點連接最大距離10,CV_PI / 180表示1度對應的弧度////繪制所有線段查看效果//cout << "linesP.size() = " << linesP.size() << endl;//for (size_t i = 0; i < linesP.size(); i++)//{//	//linesP1[i][0]第i條線段的x坐標、linesP1[i][1]第i條線段的y坐標//	line(srcImg, Point(linesP[i][0], linesP[i][1]), Point(linesP[i][2], linesP[i][3]), Scalar(255,0,0), 1);//	cout << linesP[i]<< endl;//測試坐標點//}vector<cv::Point2f> ptsOnLine;//獲得兩直線getPointOn2LineP(srcImg, linesP, ptsOnLine, false);//獲得兩直線交點get2linesIntersectionPoint(ptsOnLine[0], ptsOnLine[1], ptsOnLine[2], ptsOnLine[3], crossPoint);if (isShow){//繪制交點坐標char buf[50];memset(buf, '\0', 50);sprintf_s(buf, "X = %.1f; Y = %.1f;", crossPoint.x, crossPoint.y);int font_face = FONT_HERSHEY_COMPLEX;double font_scale = 0.5;int thickness = 1;putText(srcImg, buf, Point(crossPoint.x + 20, crossPoint.y - 20), font_face, font_scale, Scalar(0, 0, 255), thickness, 8, 0);imshow("十字刻度尺 交點:", srcImg);cv::waitKey(0);destroyAllWindows();}return 0;
}//輸入HoughLines直線lines,選取橫豎兩條直線,在選取的直線上各取兩個點,由ptsOnLine帶出來
bool getPointOn2Line(Mat& img, vector<Vec2f> lines, vector<cv::Point2f>& ptsOnLine,bool isShow)
{vector<Vec2f> linesHV;float rho, theta;bool linesH = false, linesV = false;//找水平、垂直,兩條線 //水平線90度,豎直線0度;OpenCV里HoughLines的角度應該是與Y軸的夾角for (size_t i = 0; i < lines.size(); i++){theta = lines[i][1];  //直線過坐標原點垂線與x軸夾角if (!linesH && (theta > CV_PI / 2 - 0.2 && theta < CV_PI / 2 + 0.2))//橫線theta接近π/2,±δ,{linesHV.push_back(lines[i]);linesH = true;}else if (!linesV && ((theta > -0.2 && theta < 0.2) || theta > CV_PI - 0.2 && theta < CV_PI + 0.2))//豎線theta接近π或0,±δ{linesHV.push_back(lines[i]);linesV = true;}//橫線豎線都找到了,跳出循環if (linesH && linesV){break;}}//求兩條直線上的四個點if (linesHV.size() == 2){drawHoughLine(img, linesHV, ptsOnLine, Scalar(0, 0, 255), 1, isShow);}else{cout << "沒找到兩條直線" << endl;return false;}cv::Rect rect;return true;
}//輸入HoughLinesP直線linesP,選取橫豎兩條直線,在選取的直線上各取兩個點,由ptsOnLine帶出來
bool getPointOn2LineP(Mat& img, vector<Vec4i> linesP, vector<cv::Point2f>& ptsOnLine, bool isShow)
{float rho, theta;Point2f pt1, pt2;double angle;Point2f pts1_H(0,0), pts2_H(0, 0), pts1_V(0, 0), pts2_V(0, 0);int h = 0, v = 0;//找水平、垂直,兩條線//因為HoughLinesP線集是平行的,當同一方向有多條線時,隨便選一條會導致中心不準,//當同一方向有多條線端點坐標取均值;for (size_t i = 0; i < linesP.size(); i++){pt1.x = linesP[i][0];pt1.y = linesP[i][1];pt2.x = linesP[i][2];pt2.y = linesP[i][3];//linesP的每條直線與y軸的夾角angle = getLineAngle(pt1, pt2, Point2f(0,0), Point2f(0,img.rows));//水平線90度,豎直線0度;;;直線與Y軸的夾角(與HoughLines的夾角保持一致)if (angle > 70 && angle < 110)//如果橫線90°±20°{pts1_H.x += pt1.x;pts1_H.y += pt1.y;pts2_H.x += pt2.x;pts2_H.y += pt2.y;h++;}else if (angle > -20 && angle < 20)//如果豎線0°±20°{pts1_V.x += pt1.x;pts1_V.y += pt1.y;pts2_V.x += pt2.x;pts2_V.y += pt2.y;v++;}}pts1_H.x /= h;pts1_H.y /= h;pts2_H.x /= h;pts2_H.y /= h;pts1_V.x /= v;pts1_V.y /= v;pts2_V.x /= v;pts2_V.y /= v;ptsOnLine.push_back(pts1_H);ptsOnLine.push_back(pts2_H);ptsOnLine.push_back(pts1_V);ptsOnLine.push_back(pts2_V);line(img, pts1_H, pts2_H, Scalar(255, 0, 0), 1);line(img, pts1_V, pts2_V, Scalar(255, 0, 0), 1);if(isShow){cv::imshow("img", img);cv::waitKey(0);destroyAllWindows();}return true;
}////****************************************************************************************
//  求二條直線的交點的公式
//  有如下方程 (x-x1)/(y-y1) = (x2-x1)/(y2-y1) ==> a1*x+b1*y=c1
//             (x-x3)/(y-y3) = (x4-x3)/(y4-y3) ==> a2*x+b2*y=c2
//  則交點為
//          x= D1/D =| c1 b1|  / | a1 b1 |      y= D2/D= | a1 c1| / | a1 b1 |  //當兩條線平行或重合時,分母為零
//                   | c2 b2|  / | a2 b2 |               | a2 c2| / | a2 b2 |
// 
// 注:D是其次ax+by=0,的行列式,Di是把第i列換成等式右邊的列(常數),i是所求未知數所在的列,如x在第一列,D1 
//
//   a1= y2-y1
//   b1= x1-x2
//   c1= x1*y2-x2*y1,這里 a1*x+b1*y=c1,和Ax+By+C=0,的C是一個負號關系
//   a2= y4-y3
//   b2= x3-x4
//   c2= x3*y4-x4*y3
// 
////****************************************************************************************
//// 
////行列式法,x= D1/D, y= D2/D,求兩直線的交點, //適合任意情況(斜率存在,不存在)
bool get2linesIntersectionPoint(cv::Point2f pointA, cv::Point2f pointB, cv::Point2f pointC, cv::Point2f pointD, cv::Point2f& crossPoint)
{float a1 = pointB.y - pointA.y;float b1 = pointA.x - pointB.x;float c1 = pointA.x * pointB.y - pointB.x * pointA.y;//這里 a1*x+b1*y=c1,和Ax+By+C=0,的C是一個負號關系float a2 = pointD.y - pointC.y;float b2 = pointC.x - pointD.x;float c2 = pointC.x * pointD.y - pointD.x * pointC.y;float det = a1 * b2 - a2 * b1;// 直線平行:A1/A2=B1/B2≠C1/C2 (A2B2C2≠0); 重合:A1/A2=B1/B2=C1/C2(A2B2C2≠0)// 直線平行:A1B2=A2B1; 重合:A1B2=A2B1=A1C2if (det == 0) return false;//平行或重合//Now this is cross point of linescrossPoint.x = (b2 * c1 - b1 * c2) / det;//這里和公式法(ABC)也是負號關系crossPoint.y = (a1 * c2 - a2 * c1) / det;return true;
}//*********************************************************
//求兩直線的夾角//已知兩點坐標求向量:A(a1, b1), B(a2, b2, ), 則向量AB為:B點坐標減A點坐標,即:向量AB = (a2-a1, b2-b1);
//已知兩向量坐標,求兩向量夾角:設兩個向量分別為a = (x1,y1), b = (x2, y2),其夾角為α,因為ab = |a||b| cosα,所以cosα = ab/|a||b|= (x1x2+y1y2) / (根號(x1^2 + y1^2)根號(x2^2 + y2^2));
//兩向量內積:已知兩向量a = [a1, a2, …, an]和b = [b1, b2, …, bn]的點積定義為:內積就是點積 a·b=a1b1+a2b2+……+anbn;
//向量的模,即向量的長度,設向量a = (x, y),則向量a的模 = 根號(x方 + y方)//夾角為α = arccos(∑(xiyi) / sqrt((∑(xixi)∑(yiyi)))
//cosα = 兩個向量的內積 / 向量的模(“長度”)的乘積//*********************************************************//已知每條直線的兩個點求夾角
double getLineAngle(cv::Point2f pointA, cv::Point2f pointB, cv::Point2f pointC, cv::Point2f pointD) 
{//向量AB,CDauto v1 = pointB - pointA;auto v2 = pointD - pointC;//向量AB,CD的模double n1 = cv::norm(v1);double n2 = cv::norm(v2);//cosα = ab/|a||b|double cosv = (v1.x * v2.x + v1.y * v2.y) / n1 / n2;double angle_rad = acos(cosv);//弧度轉角度return angle_rad * 180 / CV_PI;
}//返回直線上兩坐標點,有時只需要兩個點的坐標,并不需要繪制顯示直線
void drawHoughLine(Mat& img, vector<Vec2f> lines, vector<cv::Point2f> &ptsOnLine ,const Scalar& color, int thickness,bool isShow )//要標記直線的圖像,檢測的直線數據
{double length = max(img.rows, img.cols);  //圖像高寬的最大值Point2f pt1, pt2;float rho, theta;double a, b, x0, y0;for (size_t i = 0; i < lines.size(); i++){rho = lines[i][0];    //直線距離坐標原點的距離theta = lines[i][1];  //直線過坐標原點垂線與x軸夾角a = cos(theta);  //夾角的余弦值b = sin(theta);  //夾角的正弦值//x = r*cos(θ),y = r*sin(θ)x0 = a * rho, y0 = b * rho;  //直線與過坐標原點的垂線的交點//計算直線上的一點pt1.x = x0 + length * (-b);pt1.y = y0 + length * (a);//計算直線上另一點pt2.x = x0 - length * (-b);pt2.y = y0 - length * (a);////若想獲得整數點,可用cvRound()四舍五入;//pt1.x = cvRound(x0 + length * (-b));//返回跟參數最接近的整數值,即四舍五入;//pt1.y = cvRound(y0 + length * (a));//pt2.x = cvRound(x0 - length * (-b));//pt2.y = cvRound(y0 - length * (a));//兩點繪制一條直線line(img, pt1, pt2, color, thickness);if (isShow){cout << "lines " << i << lines[i] << "\t角度 " << lines[i][1] * 180 / CV_PI << endl;cv::imshow("img", img);cv::waitKey(0);destroyAllWindows();}ptsOnLine.push_back(pt1);ptsOnLine.push_back(pt2);	}
}

4.3 main文件

#include "getCross.h"void main()
{char imgPath[] = "D:\\C_test\\images\\8.bmp";cv::Mat srcImg = imread(imgPath);cv::Point2f crossPoint;//getCrossScale_HoughL(srcImg, crossPoint, true);getCrossScale_HoughLP(srcImg, crossPoint, true);
}

5 將 以上兩種封裝成一個函數——新增方法切換,轉換大圖坐標等功能

獲得黑十字刻度尺交點坐標,有HoughLP、HoughL兩種方法可選用,(ptsROIltop可將交點轉換為大圖中的位置,顯示在ROI所在的圖像上)

bool getLineCrossPoint2f(cv::Mat srcImg, Mat ImgDraw, string getLineMethod , Point ptsROIltop, cv::Point2f& crossPoint, bool isShow)

新增參數解釋:

  • Mat ImgDraw,傳入用來繪制線條等信息的圖像(有時并不需要將線條繪制在處理的圖像上);
  • string getLineMethod ,有HoughLP、HoughL兩種方法可選用;
  • Point ptsROIltop 是ROI左上角坐標,用于將交點轉換為大圖中的位置,顯示在ROI所在的圖像上;
// 獲得黑十字刻度尺交點坐標,有HoughLP、HoughL兩種方法可選用,(ptsROIltop可將交點轉換為大圖中的位置,顯示在ROI所在的圖像上)
bool getLine::getLineCrossPoint2f(cv::Mat srcImg, Mat ImgDraw, string getLineMethod , Point ptsROIltop, cv::Point2f& crossPoint, bool isShow)
{cv::Mat grayImg, binaryImg, grayImg2;cvtColor(srcImg, grayImg, COLOR_BGR2GRAY);//反色grayImg2 = 255 - grayImg;cv::threshold(grayImg2, binaryImg, 200, 255, THRESH_BINARY);vector<cv::Point2f> ptsOnLine;//獲取直線上的兩點if (getLineMethod == "HoughLP"){//利用漸進概率式霍夫變換提取 直線段vector<Vec4i> linesP;//每條線有四個參數,分別是選段兩端點坐標(x1,y1,x2,y2)HoughLinesP(binaryImg, linesP, 1, CV_PI / 180, 260, srcImg.cols * 0.6, 5);  //兩個點連接最大距離10,CV_PI / 180表示1度對應的弧度////繪制所有線段查看效果//drawHoughLineP(srcImg, linesP, Scalar(0, 0, 255), 1, isShow);//獲得兩相交直線get2CrossHoughLP(srcImg, linesP,ptsOnLine, false);}else if (getLineMethod == "HoughL"){vector<Vec2f> lines;////每條線有2個參數,極坐標(r,theta)HoughLines(binaryImg, lines, 1, CV_PI / 180, 260, 0, 0);//累加器閾值threshold,越大線條越少,反之越多//繪制所有直線查看效果//drawHoughLine(srcImg, lines,ptsOnLine, Scalar(0, 0, 255), 1, isShow);vector<cv::Point2f> ptsOnLine;//獲得兩相交直線,get2CrossHoughL(srcImg, lines,ptsOnLine, false);}if (ptsOnLine.size() == 4){//將直線坐標點轉換為大圖中的位置,ptsROIltop是ROI左上角坐標, 直線顯示在srcImgBigROI上//當ptsROIltop為(0,0)時,繪制在ROI圖上;當為ROI左上角坐標時,直線繪制在ROI所在的大圖上;ptsOnLine[0].x += ptsROIltop.x;  ptsOnLine[0].y += ptsROIltop.y;ptsOnLine[1].x += ptsROIltop.x;  ptsOnLine[1].y += ptsROIltop.y;ptsOnLine[2].x += ptsROIltop.x;  ptsOnLine[2].y += ptsROIltop.y;ptsOnLine[3].x += ptsROIltop.x;  ptsOnLine[3].y += ptsROIltop.y;//獲得兩直線交點get2linesIntersectionPoint3(ptsOnLine[0], ptsOnLine[1], ptsOnLine[2], ptsOnLine[3], crossPoint);}else{cout << "沒找到兩條直線" << endl;return false;}if (isShow){	//繪制兩交線line(ImgDraw, ptsOnLine[0], ptsOnLine[1], Scalar(255, 0, 0), 1);line(ImgDraw, ptsOnLine[2], ptsOnLine[3], Scalar(255, 0, 0), 1);//繪制交點坐標char buf[50];memset(buf, '\0', 50);sprintf_s(buf, "X = %.1f; Y = %.1f;", crossPoint.x, crossPoint.y);int font_face = FONT_HERSHEY_COMPLEX;double font_scale = 0.5;int thickness = 1;putText(ImgDraw, buf, Point(crossPoint.x + 20, crossPoint.y - 20), font_face, font_scale, Scalar(0, 0, 255), thickness, 8, 0);imshow("十字刻度尺 交點:", ImgDraw);cv::waitKey(0);destroyAllWindows();}return true;
}

繪制兩種霍夫直線的函數

//返回每條直線上兩坐標點
void getLine::drawHoughLine(Mat& img, vector<Vec2f> lines,  vector<cv::Point2f>& ptsOnLine, const Scalar& color, int thickness, bool isShow)//要標記直線的圖像,檢測的直線數據
{double length = max(img.rows, img.cols);  //圖像高寬的最大值Point2f pt1, pt2;float rho, theta;double a, b, x0, y0;for (size_t i = 0; i < lines.size(); i++){rho = lines[i][0];    //直線距離坐標原點的距離theta = lines[i][1];  //直線過坐標原點垂線與x軸夾角a = cos(theta);  //夾角的余弦值b = sin(theta);  //夾角的正弦值//x = r*cos(θ),y = r*sin(θ)x0 = a * rho, y0 = b * rho;  //直線與過坐標原點的垂線的交點//計算直線上的一點pt1.x = x0 + length * (-b);pt1.y = y0 + length * (a) ;//計算直線上另一點pt2.x = x0 - length * (-b);pt2.y = y0 - length * (a);////若想獲得整數點,可用cvRound()四舍五入;//pt1.x = cvRound(x0 + length * (-b));//返回跟參數最接近的整數值,即四舍五入;//pt1.y = cvRound(y0 + length * (a));//pt2.x = cvRound(x0 - length * (-b));//pt2.y = cvRound(y0 - length * (a));//實踐發現://V方向,y軸向上超出img約 -img.rows,H方向,x軸向左超出img約 -img.cols,//為了將繪制的直線 限制在img范圍內,可將V方向,y軸上端 +img.rows,H方向,x軸左 +img.cols //這樣實際是不準的,因有傾斜,最準的方法用直線表達式,給定x,y,獲取指定位置坐標;//繪制的直線超出img范圍,以后在修改if (isShow){//兩點繪制一條直線line(img, pt1, pt2, color, thickness);cout << "lines " << i << lines[i] << "\t角度 " << lines[i][1] * 180 / CV_PI << endl;cv::imshow("img", img);cv::waitKey(0);destroyAllWindows();}ptsOnLine.push_back(pt1);ptsOnLine.push_back(pt2);}
}void getLine::drawHoughLineP(Mat& img, vector<Vec4i> linesP, const Scalar& color, int thickness, bool isShow)//要標記直線的圖像,檢測的直線數據
{cout << "linesP.size() = " << linesP.size() << endl;for (size_t i = 0; i < linesP.size(); i++){//linesP1[i][0]第i條線段的x坐標、linesP1[i][1]第i條線段的y坐標line(img, Point(linesP[i][0], linesP[i][1]), Point(linesP[i][2], linesP[i][3]), color, thickness);cout << linesP[i]<< endl;//測試坐標點}if (isShow){			cv::imshow("img", img);cv::waitKey(0);destroyAllWindows();}
}

下面的三個函數,前面已經介紹過,函數內容沒變,只是名字改了;

//行列式法,x= D1/D, y= D2/D,求兩直線的交點, //適合任意情況(斜率存在,不存在)
bool get2linesIntersectionPoint3(cv::Point2f pointA, cv::Point2f pointB, cv::Point2f pointC, cv::Point2f pointD, cv::Point2f& crossPoint);
//輸入HoughLines直線lines,選取橫豎兩條直線,在選取的直線上各取兩個點,由ptsOnLine帶出來;
bool get2CrossHoughL( Mat& img, vector<Vec2f> lines,  vector<cv::Point2f>& ptsOnLine, bool isShow);
//輸入HoughLinesP直線linesP,選取橫豎兩條直線,在選取的直線上各取兩個點,由ptsOnLine帶出來;
bool get2CrossHoughLP(Mat& img, vector<Vec4i> linesP,  vector<cv::Point2f>& ptsOnLine, bool isShow);

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/95223.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/95223.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/95223.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

云原生應用的DevOps2(Jenkins滲透場景)

結論 Jenkins歷史漏洞 Jenkins未授權訪問 登錄后命令執行 Jenkins代碼倉庫信息 Jenkins服務器建立多臺服務器信任連接 背景 目前我看到紅隊人員的現狀,不管是什么系統就是拿Shell,拿權限,然后把這臺機器當作跳板繼續橫向其它機器。而Jenkins在內網中是經常能夠遇到的,…

Gradle 配置教程:與 Maven 對比詳解(含完整遷移指南)

一、基礎對比&#xff1a;Gradle vs Maven1.1 核心特性對比維度MavenGradle配置語言XML (冗長)Groovy/Kotlin DSL (簡潔靈活)構建速度較慢(全量構建)快2-10倍(增量構建緩存)多模塊管理<modules> <parent>settings.gradle project()依賴管理<dependencies>d…

pcl 按比例去除點云的噪點

之前halcon3d中是這么做的&#xff1b;1&#xff0c;先查找點云中每個點最近第15個最近點的距離2&#xff0c;將距離進行排序3&#xff0c;求排序后在距離數組70%位置的距離 d4&#xff0c;篩選點云中每個點半徑為d&#xff0c;近鄰點的數量大于14的點用pcl實現的代碼如下&…

站在Vue的角度,對比鴻蒙開發中的遞歸渲染

第三類 引用數據的操作 引用數據類型 又叫復雜數類型&#xff0c; 典型的代表是對象和數組&#xff0c;而數組和對象往往又嵌套到到一起 普通數組和對象的使用 vue中使用for循環遍歷 <template><div>我是關于頁面<div v-for"item in arr">{{ i…

VBS 流程控制

一. if else 和 selec case 1. if end if Dim a a2If a0 ThenMsgBox "這里是0"End if 2. if else end if Dim a a2If a0 ThenMsgBox "這里是0"Else MsgBox "這里是2" 彈窗“這里是2”End if 3. if -----elseif-------else-------end…

HCIP項目之OSPF綜合實驗

一、項目背景隨著企業分支機構地理分散化&#xff0c;跨地域網絡互聯需求激增。MGRE&#xff08;多點 GRE&#xff09;技術因適應動態拓撲、降低鏈路成本&#xff0c;成為多分支互聯的常用方案&#xff1b;OSPF 作為鏈路狀態路由協議&#xff0c;適用于大型網絡且支持可變長子網…

class and enmu class

傳統枚舉與作用域污染及enum class的詳細介紹在編程中&#xff0c;枚舉&#xff08;enum&#xff09;是一種常見的特性&#xff0c;用于定義一組命名的常量。傳統枚舉&#xff08;如C中的enum&#xff09;雖然簡單易用&#xff0c;但容易導致作用域污染問題。而enum class&…

Numpy科學計算與數據分析:Numpy數組屬性入門之形狀、維度與大小

Numpy數組屬性探索 學習目標 通過本課程的學習&#xff0c;學員將掌握Numpy數組的基本屬性&#xff0c;如形狀&#xff08;shape&#xff09;、維度&#xff08;ndim&#xff09;和大小&#xff08;size&#xff09;&#xff0c;并能夠通過實際操作加深對這些屬性的理解。 相…

IF 33.3+ 通過多區域單細胞測序解析肺腺癌的空間和細胞結構

通過多區域單細胞測序解析肺腺癌的空間和細胞結構摘要對于肺腺癌演進過程中單個細胞群的地理空間架構知之甚少。在此&#xff0c;我們對來自5例早期LUAD和14個來自腫瘤的具有明確空間鄰近性的多區域正常肺組織的186&#xff0c;916個細胞進行了單細胞RNA測序。我們發現細胞譜系…

【Redis的安裝與配置】

一&#xff1a;下載 Redis ? 百度網盤分享 &#x1f449; https://pan.baidu.com/s/1xkrLlyUPyM0btCFFpGEhcw?pwdSVIP ? 從Github下載 &#x1f449; https://github.com/MicrosoftArchive/redis/releases 二&#xff1a;安裝 Redis 1?? 將下載的壓縮包文件 解壓到 某個文…

TDSQL GTS文件說明

基于時間點恢復&#xff1a;全備xlogGTS文件 在TDSQL的備份恢復體系中&#xff0c;GTS文件是全局時間戳&#xff08;Global Timestamp&#xff09;的存儲載體&#xff0c;用于記錄事務在分布式環境中的精確執行順序和時間點 其核心作用體現在以下方面&#xff1a; 1?。時間基準…

全星APQP數字化平臺在汽車零部件行業的深度應用與效益分析

全星APQP數字化平臺在汽車零部件行業的深度應用與效益分析 全星研發項目管理APQP軟件系統是專為汽車零部件行業打造的數字化研發管理平臺&#xff0c;通過深度集成行業核心工具鏈&#xff0c;實現從產品設計到量產的全程可控。以下為該系統在汽車零部件行業的應用解析&#xf…

網絡通信安全:HTTPS協議的密碼學基石

引言&#xff1a;從HTTP到HTTPS的安全升級 在網絡通信中&#xff0c;數據傳輸的安全性至關重要。早期的HTTP協議采用明文傳輸&#xff0c;存在三大安全隱患&#xff1a; 機密性問題&#xff1a;數據在傳輸過程中可能被竊聽&#xff08;如公共Wi-Fi中的監聽&#xff09;&#xf…

pip 和 conda,到底用哪個安裝?

為什么 pip 有時裝不下來而 --prefer-binary 可以&#xff1f;什么是源代碼發行版&#xff1f;什么是輪子&#xff1f;conda 和 pip 有什么區別&#xff1f;優先用誰啊&#xff1f;兩者適合的場景&#xff08;何時用哪個&#xff09;安裝路徑&#xff1a;pip / conda 分別裝到哪…

bert學習

首先了解一下幾種embedding。比如elmo就是一個embedding模型。one-hot編碼只能實現one word one embedding&#xff0c;而我們的elmo能實現one token one embeddingElmo是基于雙向LSTM&#xff0c;所以每個詞其實會有正向和反向兩個預測結果&#xff0c;那么我們用哪個呢&#…

Java安全-組件安全

一、Xstream啟動環境并訪問接下來我們構造反彈shell語句&#xff0c;bash -i >& /dev/tcp/8.152.2.86/9999 0>&1&#xff0c;緊接著對其進行base64編碼。接下來使用命令即可首先開啟監聽接下來執行命令接下來抓包對其進行payload構造即可緊接著回去查看回顯發現成…

【10】微網優聯——微網優聯 嵌入式技術一面,校招,面試問答記錄

微網優聯——微網優聯 嵌入式技術一面&#xff0c;校招&#xff0c;問答記錄 1. 2 分鐘簡單自自我介紹2. 問一遍筆試題目3. IP地址在哪個層4.手動配置過IP地址嗎?要配哪幾個&#xff1f;5. ARP 是域名找IP地址還是IP地址找域名?6. Linux、計算機網絡、操作系統掌握的怎么樣&a…

C#使用EPPlus讀寫Excel

依賴EPPlus 獲取依賴可以閱讀:Nuget For Unity插件介紹_nugetforunity-CSDN博客 可以參閱該篇快速入門:在Unity中使用Epplus寫Excel_unity epplus-CSDN博客 下面是我封裝的幾個方法: 要在合適的時機配置許可證,比如你的工具類的靜態函數.建議使用版本7.7.1 #region Excel封裝,…

高性能Web服務器

一、Web服務基礎介紹 1.1、互聯網發展歷程 1993年3月2日&#xff0c;中國科學院高能物理研究所租用AT&T公司的國際衛星信道建立的接入美國SLAC國家實驗室的64K專線正式開通&#xff0c;成為我國連入Internet的第一根專線。 1995年馬云開始創業并推出了一個web網站中國黃…

《算法導論》第 16 章 - 貪心算法

大家好&#xff01;今天我們來深入探討《算法導論》第 16 章的核心內容 —— 貪心算法。貪心算法是一種在每一步選擇中都采取在當前狀態下最好或最優&#xff08;即最有利&#xff09;的選擇&#xff0c;從而希望導致結果是全局最好或最優的算法。它在許多優化問題中都有廣泛應…