2015-07-20 169 views
0

我在C++和OpenCV中使用斑點檢測技術,但我無法在可用格式中提取輪廓信息。從C++中的斑點檢測中提取OpenCV輪廓陣列

目前我所有的輪廓數據都以cv::Point格式存儲爲數組;不過,我希望提取座標並將它們存儲在一個數組下,以便我可以根據需要操作這些數據。

我的代碼看起來是這樣的:

#include "opencv2/highgui/highgui.hpp" 
#include "opencv2/opencv.hpp" 
#include <iostream> 
#define _USE_MATH_DEFINES 
#include <math.h> 

using namespace cv; 
using namespace std; 

int main(int argc, const char** argv) 
{ 
    cv::Mat src = cv::imread("frame-1.jpg"); 
    if (src.empty()) 
     return -1; 

    cv::Mat gray; 
    cv::cvtColor(~src, gray, CV_BGR2GRAY); 

    cv::threshold(gray, gray, 160, 255, cv::THRESH_BINARY); 

    // Find all contours 
    std::vector<std::vector<cv::Point> > contours; 
    cv::findContours(gray.clone(), contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE); 

    // Fill holes in each contour 
    cv::drawContours(gray, contours, -1, CV_RGB(255, 255, 255), -1); 

    cout << contours.size(); 

std::vector<cv::Point> minXY(contours.size()); // Top Left Point of Bounding Box 
std::vector<cv::Point> maxXY(contours.size()); // Bottom Right Point of Bounding Box 
for (int i = 0; i < contours.size()){ 
    minXY[i] = maxXY[i] = contours[i][0]; // Assumes the contour has at least 1 point 
    for(int j = 1; j < contours[i].size(); ++j){ 
     if (contours[i][j].x < minXY[i].x){ 
      minXY[i].x = contours[i][j].x; 
     } else if (contours[i][j].x > maxXY[i].x){ 
      maxXY[i].x = contours[i][j].x; 
     } 
     if (contours[i][j].y < minXY[i].y){ 
      minXY[i].y = contours[i][j].y; 
     } else if (contours[i][j].y > maxXY[i].y){ 
      maxXY[i].y = contours[i][j].y; 
     } 
    } 
} 

    namedWindow("MyWindow", CV_WINDOW_AUTOSIZE); 
    imshow("MyWindow", gray); 

    waitKey(0); 

    destroyWindow("MyWindow"); 

    return 0; 
} 

contours[2]結果給出與第三斑點的輪廓座標陣列;不過,我想將這個數組提取到一個普通變量中,所以我可以真正使用它。我假設這意味着某種cv::Point轉換?

更新:我應該澄清一下,我想要最大斑點的輪廓的座標,以便我可以操縱數據,例如找到最小x點,找到平均x點,找到斑點的質心等。

目前我已經能夠找到所有的輪廓,然後確定最大的斑點,以及確定其輪廓座標。然而,我還沒有找到一種方法來搜索這個數組來找到最小的x值,或者一個只求和x座標的方法。我將最終也想找到發現斑點的形心的最有效的方法

**輪廓[2]吐出的陣列的形式(使用邊界框,力矩,簡單的算術或其它方法):

[100,267]
[101,270]
[102,271]

我想找到一種方法來搜索左列(即所有的x值),以找到最小和最大等我已經嘗試了幾個方法,但沒有讓我接近。當然,這有一個簡單的解決方案。看起來我所有的問題都來源於輪廓數組的形式爲cv :: Point。

+0

這是你想要的,'std :: vector xxx =等值線[2]'? – herohuyongtao

+0

使用cv :: Point有什麼問題?你可以訪問點座標爲point.x和point.y – Miki

+0

你應該澄清你的「可用」的概念 – Miki

回答

2

如果你想組成第三輪廓,你可以做以下幾點:

std::vector<cv::Point> my_contour = contours[2]; 

或者您可以通過在所有countours只是循環:

for (int i = 0; i < contours.size(); ++i){ 
    double avg_x(0), avg_y(0); // average of contour points 
    for (int j = 0; j < contours[i].size(); ++j){ 
     // Do whatever you need to do with the points in the ith contour 
     avg_x += contours[i][j].x; 
     avg_y += contours[i][j].y; 
    } 
    avg_x /= contours[i].size(); 
    avg_y /= contours[i].size(); 
    cout << avg_x << " " << avg_y << endl; 
} 

從你評論你也想計算輪廓的質心。

可以使用OpenCV的

std::vector<cv::Moment> moments(contours.size()); 
std::vector<cv::Point> centroids(contours.size()); 
for (int i = 0; i < contours.size()){ 
    moments[i] = cv::moments(contours[i], false); 
    centroids[i] = cv::Point(moments[i].m10/moments[i].m00, moments[i].m01/moments[i].m00); 
} 

的0階矩是塊的區域發現每個斑的時刻,第一時刻心與第二時刻可以用來發現斑點的方向和偏心。

維基百科是瞭解更多關於影像時刻的好起點。 https://en.wikipedia.org/wiki/Image_moment

使用OpenCV,您可以通過首先將輪廓近似爲多邊形來獲得邊界框和包圍輪廓的圓。

下面的代碼是從OpenCV

std::vector<vector<cv::Point> > contours_poly(contours.size()); 
std::vector<cv::Rect> boundingRect (contours.size()); 
std::vector<cv::Point> center(contours.size()); 
std::vector<float> radius(contours.size()); 
for (int i = 0; i < contours.size(); ++i){ 
    cv::approxPolyDP(cv::Mat(contours[i]), contours_poly[i], 3, true); 
    boundingRect[i] = cv::boundingRect(cv::Mat(contours_poly[i])); 
    cv::MinEnclosingCircle((cv::Mat)contours_poly[i], center[i], radius[i]); 
} 

或者你可以自己做(對於邊框)。

std::vector<cv::Point> minXY(contours.size()); // Top Left Point of Bounding Box 
std::vector<cv::Point> maxXY(contours.size()); // Bottom Right Point of Bounding Box 
for (int i = 0; i < contours.size()){ 
    minXY[i] = maxXY[i] = contours[i][0]; // Assumes the contour has at least 1 point 
    for(int j = 1; j < contours[i].size(); ++j){ 
     if (contours[i][j].x < minXY[i].x){ 
      minXY[i].x = contours[i][j].x; 
     } else if (contours[i][j].x > maxXY[i].x){ 
      maxXY[i].x = contours[i][j].x; 
     } 
     if (contours[i][j].y < minXY[i].y){ 
      minXY[i].y = contours[i][j].y; 
     } else if (contours[i][j].y > maxXY[i].y){ 
      maxXY[i].y = contours[i][j].y; 
     } 
    } 
} 

對於輪廓[I]:

最左點是在MinXY[i].x

最右邊的點是在MaxXY[i].x

最頂部的點是在MinXY[i].y(注意Y軸是倒置的)

最底點是在MaxXY[i].y

編輯:回答修改後的問題。

float min_x = contours[2][0].x; 
for (int i = 1; i < countours[2].size(); ++i){ 
    if (contours[2][i].x < min_x){ 
     min_x = contours[2][i].x; 
    } 
} 
+0

非常感謝您的幫助!請原諒我的困惑 - 我對C++/OpenCV非常陌生。基本上我已經確定了最大的斑點,也發現它是輪廓座標,但我似乎無法分開數組的列來查找最大和最小的x值。我覺得我在這裏錯過了一些簡單的東西 - 也許我從錯誤的角度來看待這個問題。 – MSTTm

+0

您是否在問如何找到blob/contour的軸對齊邊界框? AKA如何找到blob佔據的最小/最大x和y值? –

+0

正如在試圖找到blob輪廓上最小的x座標(找到blob的最左點)等。 – MSTTm