2017-04-10 72 views
1

我試圖轉動不規則矩形這樣的:如何正確使用OpenCV旋轉不規則矩形?

Example

有了將其直接的目的。我的輪廓是一個cv :: vector < cv :: Point>類型,並且在轉換之後,我得到一個cv :: vector < cv :: Point2f>類型,以便進行精細的精確計算。

因此,我也需要一個很好的方法來做這個旋轉,所以首先我需要檢測兩邊。我試圖使用'minarearect',但結果不好。邊界矩形與不規則矩形的方向不匹配,並具有足夠的精度。

有沒有'最佳周長矩形'或類似的,而不是'最小面積矩形'?我認爲這會給我更多的準確性。 但是,你知道任何其他旋轉矩形的方法嗎?

請原諒我的英語。並感謝您的幫助!

回答

3

您可以使用PCA獲取矩形方位(第1和第2部分)的邊,使這些軸方向可以計算旋轉角度。例如這裏:http://docs.opencv.org/3.1.0/d1/dee/tutorial_introduction_to_pca.html

enter image description here

只是做另一種變體的草圖:

#include <iostream> 
#include <vector> 
#include "opencv2/opencv.hpp" 
using namespace std; 
using namespace cv; 

//----------------------------------------------------------------------------------------------------- 
// 
//----------------------------------------------------------------------------------------------------- 
void getSamplePoints(Mat& src,vector<Point2f>& pts) 
{ 
    pts.clear(); 
    for (int i = 0; i < src.rows; ++i) 
    { 
     for (int j = 0; j < src.cols; ++j) 
     { 
      uchar v = src.at<uchar>(i, j); 
      if (v > 0) 
      { 
       pts.push_back(Point2f(j, i)); 
      } 
     } 
    } 
} 
//----------------------------------------------------------------------------------------------------- 
// 
//----------------------------------------------------------------------------------------------------- 
double distance_to_Line(cv::Point2f line_start, cv::Point2f line_end, cv::Point2f point) 
{ 
    double normalLength = _hypot(line_end.x - line_start.x, line_end.y - line_start.y); 
    double distance = (double)((point.x - line_start.x) * (line_end.y - line_start.y) - (point.y - line_start.y) * (line_end.x - line_start.x))/normalLength; 
    return distance; 
} 
//----------------------------------------------------------------------------------------------------- 
// 
//----------------------------------------------------------------------------------------------------- 
void getPointsFromVector(vector<Point2f>& pts,Point2f p1, Point2f p2, float dist, vector<Point2f>& pts_res) 
{ 
    for (int i = 0; i < pts.size(); ++i) 
    { 
     double d = distance_to_Line(p1, p2, pts[i]); 
     if (fabs(d) < dist) 
     { 
      pts_res.push_back(pts[i]); 
     } 
    } 
} 
//----------------------------------------------------------------------------------------------------- 
// 
//----------------------------------------------------------------------------------------------------- 
int main(int argc, unsigned int** argv) 
{ 
    string fname = "../../data/rect_to_fit.png"; 
    Mat src = imread(fname, 1); 
    if (src.empty()) 
    { 
     return 0; 
    } 
    cvtColor(src, src, COLOR_BGR2GRAY); 

    vector<Point2f> pts; 
    getSamplePoints(src, pts); 


    RotatedRect R = minAreaRect(pts); 
    Point2f r_pts[4]; 
    R.points(r_pts); 

    for (int j = 0; j < 4; j++) 
    { 
     vector<Point2f> res_pts; 
     Point2f p1 = r_pts[j]; 
     Point2f p2 = r_pts[(j + 1) % 4]; 
     getPointsFromVector(pts,p1,p2,20, res_pts); 
     for (auto p : res_pts) 
     { 
      circle(src, p, 3, Scalar::all(255), -1); 
     } 
     // imshow("src", src); 
     // waitKey(0); 
     Vec4f L; 
     fitLine(res_pts, L, cv::DIST_L2, 0, 0.01, 0.01); 
     float x = L[2]; 
     float y = L[3]; 
     float vx = L[0]; 
     float vy = L[1]; 
     float lefty = int((-x*vy/vx) + y); 
     float righty = int(((src.cols - x)*vy/vx) + y); 
     line(src, Point2f(src.cols - 1, righty), Point2f(0, lefty), Scalar::all(255), 2); 
    } 

    imshow("src", src); 
    imwrite("result.jpg", src); 
    waitKey(0); 

    return 0; 
} 

我得到的結果是: enter image description here

+0

謝謝!我首先嚐試PCA。一旦我得到我的第一個結果,我會給你反饋! – areify

+0

PCA給出了點的最長分佈的方向,如果是方形的,它可能會給出對角線的方向。 PCA將適用於重塑或其他細長物體。對於正方形的你可能需要使用RANSAC方法。 –

+0

PCA不給我任何好的方法,你可以在這裏看到:[例子](http://i68.tinypic.com/2cs72bt.png)。我認爲這也是一個糟糕的對角線接近... – areify