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

Extract OpenCV Contour Array from Blob Detection in C++

本文关键字:OpenCV 轮廓 阵列 提取 Blob 检测      更新时间:2023-10-16

我正在使用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的质心等。

目前我已经能够找到所有的轮廓,然后确定最大的blob,以及确定其轮廓坐标。然而,我还没有找到一种方法来搜索这个数组来找到最小的x值,或者一个方法来计算x坐标的总和。我最终也想找到找到blob的质心的最有效的方法(使用边界框,力矩,简单的算术或其他方法)。

** contours[2]生成一个数组,格式为:

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

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

如果你想要组成第三个轮廓的点,你可以这样做:

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阶矩为斑点的面积,第1阶矩为质心,第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;
         }
    }
}
等高线[我]:

最左点在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;
    }
}