首页 文章

从C中的Blob检测中提取OpenCV轮廓阵列

提问于
浏览
0

我正在玩C和OpenCV中的blob检测技术,但是我无法以可用的格式提取轮廓信息 .

目前,我将所有轮廓数据存储为 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] 的结果给出了一个数组,其轮廓坐标为第三个blob;但是,我想将这个数组提取到一个普通变量,所以我可以实际使用它 . 我假设这意味着某种 cv::Point 转换?

更新:我应该澄清一下,我想要最大blob轮廓的坐标,以便我可以操纵数据,例如找到最小的x点,找到平均x点,找到blob的质心等 .

目前,我已经能够找到所有轮廓,然后识别最大的斑点,并识别其轮廓坐标 . 但是,我还没有找到一种方法来搜索这个数组以找到最小的x值,或者找到一个只计算x坐标的方法 . 我最终还想找到最有效的方法来找到blob的质心(使用边界框,矩,简单算术或其他方法 . )

** contours [2]以下列形式吐出一个数组:

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

我想找到一种方法来搜索左列(即所有x值)以找到最小和最大的等等 . 我尝试了几种方法,但没有一种让我接近 . 当然,这是一个简单的解决方案 . 似乎我的所有问题都源于轮廓数组采用cv :: Point的形式 .

1 回答

  • 2

    如果您想要构成第3轮廓的点,您可以执行以下操作:

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

    或者你可以通过以下方式循环遍历所有的计数:

    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找到每个blob的时刻

    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个时刻是斑点的区域,质心和第2个时刻的第一个瞬间可用于找到斑点的方向和偏心 .

    维基百科是了解图像时刻的良好起点 . 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;
        }
    }
    

相关问题