简体   繁体   English

从C ++中的Blob检测中提取OpenCV轮廓数组

[英]Extract OpenCV Contour Array from Blob Detection in C++

I'm playing around with blob detection techniques in C++ and OpenCV but I'm having trouble extracting the contour information in a usable format. 我正在使用C ++和OpenCV中的斑点检测技术,但是我无法以可用格式提取轮廓信息。

Currently I have all contour data stored as an array in a cv::Point format; 目前,我已将所有轮廓数据以cv::Point格式存储为数组; however, I wish to extract the coordinates and store them in an array under a variable so I can manipulate this data as needed. 但是,我希望提取坐标并将它们存储在变量下的数组中,以便我可以根据需要操纵此数据。

My code looks like this: 我的代码如下所示:

#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;
}

The result of contours[2] gives an array with contour coordinates of the third blob; contours[2]的结果给出一个数组,该数组的轮廓坐标为第三个Blob; however, I want to extract this array into a normal variable so I can actually use it. 但是,我想将此数组提取到一个普通变量中,以便我可以实际使用它。 I'm assuming this means some sort of cv::Point conversion? 我假设这意味着某种cv::Point转换?

UPDATE: I should probably clarify that I'd like the coordinates of largest blob's contour so that I can manipulate the data such as finding the smallest x point, finding the average x point, find the centroid of the blob etc. 更新:我可能应该澄清一下,我想要最大的斑点轮廓的坐标,以便可以操纵数据,例如找到最小的x点,找到平均x点,找到斑点的质心等。

Currently I have been able to find all the contours and then identify the largest blob, as well as identify its contour coordinates. 目前,我已经能够找到所有轮廓,然后确定最大的斑点,并确定其轮廓坐标。 However, I haven't found a way to search through this array to find the least x value, or a method to sum just the x coordinates. 但是,我还没有找到一种方法来搜索该数组以找到最小的x值,或者只求和x坐标的方法。 I would ultimately also like to find the most efficient method of finding the blob's centroid (using bounding box, moments, simple arithmetic or other method.) 我最终还是想找到找到斑点的质心的最有效方法(使用边界框,矩,简单算术或其他方法。)

** contours[2] spits out an array in the form: ** Silhouettes [2]散布出以下形式的数组:

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

I want to find a way to search the left column (ie. all the x values) to find the smallest and largest etc. I've tried several methods but none have gotten me close. 我想找到一种方法搜索左列(即所有x值)以找到最小和最大等。我尝试了几种方法,但没有一个使我接近。 Surely there's an easy solution to this. 当然,有一个简单的解决方案。 It seems all my problems stem from the fact that the contour array is in the form of cv::Point. 看来我所有的问题都源于轮廓数组是cv :: Point形式的事实。

If you want the points that make up the 3rd contour you can do the following: 如果要组成第三轮廓的点,可以执行以下操作:

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

or you can just loop over all of the countours by doing: 或者您可以通过执行以下操作遍历所有国家:

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;
}

From your comment you also wanted to calculate the centroid of the contour. 根据您的评论,您还想计算轮廓的质心。

You can find the moments of each blob using OpenCV 您可以使用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);
}

The 0th moment is the area of the blob, first moments the centroid and 2nd moments can be used to find orientation and eccentricity of the blob. 0矩是团块的面积,质心和2nd矩的第一个矩可用于找到团块的方向和偏心率。

Wikipedia is a good starting place for learning more about image moments. Wikipedia是学习更多有关图像瞬间的好起点。 https://en.wikipedia.org/wiki/Image_moment https://zh.wikipedia.org/wiki/Image_moment

Using OpenCV you can get the Bounding Box and enclosing circle of a contour by first approximating it's contour as a polygon. 使用OpenCV,您可以通过首先将轮廓的轮廓近似为多边形来获得轮廓的边界框和封闭圆。

The following code is from 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]);
}

Or you can do it yourself (for bounding box). 或者您可以自己做(对于边界框)。

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;
         }
    }
}

For contour[i]: 对于轮廓[i]:

The most left point is at MinXY[i].x 最左点在MinXY[i].x

the right most point is at MaxXY[i].x 最右边的一点是MaxXY[i].x

the top most point is at MinXY[i].y (Note Y axis is inverted) 最上面的点是MinXY[i].y (注意Y轴是反向的)

the bottom most point is at MaxXY[i].y 最下点是MaxXY[i].y

EDIT: To answer Modified Question. 编辑:回答修改后的问题。

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;
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM