問題來源為網友提供的資料,原文位址為:《Object Orientation, Principal Component Analysis & OpenCV》
問題描述:
對于這樣的圖像(2副,采用了背投光),如何獲得上面工件的主要方向
主要思路:
1、分别獲得每個工件的輪廓;
2、處理每個輪廓,采用pca(主成分分析)方法,獲得所有輪廓點的集合的中點,主要方向等資訊;
3、繪圖并傳回結果。
注:pca相關函數請檢視
https://docs.opencv.org/master/d3/d8d/classcv_1_1PCA.html代碼略解:
1、讀入圖檔,尋找輪廓;
//讀入圖像,轉換為灰階
Mat img = imread("e:/sandbox/pca1.jpg");
Mat bw;
cvtColor(img, bw, COLOR_BGR2GRAY);
//門檻值處理
threshold(bw, bw, 150, 255, CV_THRESH_BINARY);
//尋找輪廓
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
findContours(bw, contours, hierarchy, CV_RETR_LIST, CV_CHAIN_APPROX_NONE);
2、首先以大小篩選輪廓;
//輪廓分析,找到工件
for (size_t i = 0; i < contours.size(); ++i)
{
//計算輪廓大小
double area = contourArea(contours[i]);
//去除過小或者過大的輪廓區域(科學計數法表示)
if (area < 1e2 || 1e5 < area) continue;
//繪制輪廓
drawContours(img, contours, i, CV_RGB(255, 0, 0), 2, 8, hierarchy, 0);
//尋找每一個輪廓的方向
getOrientation(contours[i], img);
}
3、單獨處理每個輪廓,分析其主要方向,繪制結果
//獲得建構的主要方向
double getOrientation(vector<Point> &pts, Mat &img)
{
//建構pca資料。這裡做的是将輪廓點的x和y作為兩個維壓到data_pts中去。
Mat data_pts = Mat(pts.size(), 2, CV_64FC1);//使用mat來儲存資料,也是為了後面pca處理需要
for (int i = 0; i < data_pts.rows; ++i)
data_pts.at<double>(i, 0) = pts[i].x;
data_pts.at<double>(i, 1) = pts[i].y;
//執行PCA分析
PCA pca_analysis(data_pts, Mat(), CV_PCA_DATA_AS_ROW);
//獲得最主要分量,在本例中,對應的就是輪廓中點,也是圖像中點
Point pos = Point(pca_analysis.mean.at<double>(0, 0),pca_analysis.mean.at<double>(0, 1));
//存儲特征向量和特征值
vector<Point2d> eigen_vecs(2);
vector<double> eigen_val(2);
for (int i = 0; i < 2; ++i)
eigen_vecs[i] = Point2d(pca_analysis.eigenvectors.at<double>(i, 0),pca_analysis.eigenvectors.at<double>(i, 1));
eigen_val[i] = pca_analysis.eigenvalues.at<double>(i,0);//注意,這個地方原代碼寫錯了
//在輪廓/圖像中點繪制小圓
circle(img, pos, 3, CV_RGB(255, 0, 255), 2);
//計算出直線,在主要方向上繪制直線
line(img, pos, pos + 0.02 * Point(eigen_vecs[0].x * eigen_val[0], eigen_vecs[0].y * eigen_val[0]) , CV_RGB(255, 255, 0));
line(img, pos, pos + 0.02 * Point(eigen_vecs[1].x * eigen_val[1], eigen_vecs[1].y * eigen_val[1]) , CV_RGB(0, 255, 255));
//傳回角度結果
return atan2(eigen_vecs[0].y, eigen_vecs[0].x);
}
結果展示:
感謝關注,希望有所幫助。
此外,特别感謝:
https://github.com/NickeManarin/ScreenToGif/wiki/Help提供的這個gif錄屏軟體,非常好用。
目前方向:圖像拼接融合、圖像識别
聯系方式:[email protected]