it-swarm.com.de

verbundene Komponenten in OpenCV

Ich bin auf der Suche nach einer OpenCV-Funktion, die verbundene Komponenten finden und einige Aufgaben ausführen kann (z. B. Abfragen der Pixelanzahl, der Kontur, der Pixelliste im Objekt usw.).

Gibt es eine Funktion von OpenCV (C++), die den Regionsprops von MatLab ähnelt?

37
EyalG

Ab Version 3.0 verfügt OpenCV über die Funktion connectedComponents .

26

Schauen Sie sich die Funktion cvFindContours an. Es ist sehr vielseitig - es kann sowohl innere als auch äußere Konturen finden und die Ergebnisse in verschiedenen Formaten anzeigen (z. B. flache Liste oder Baumstruktur). Sobald Sie die Konturen haben, können Sie mit Funktionen wie cvContourArea grundlegende Eigenschaften der verbundenen Komponente bestimmen, die einer bestimmten Kontur entsprechen.

Wenn Sie es vorziehen, die neuere C++ - Schnittstelle zu verwenden (im Gegensatz zur älteren C-Schnittstelle, die ich oben beschrieben habe), sind die Funktionsnamen ähnlich .

22
mpenkov

set -std = c ++ 0x -Option beim Kompilieren

.h Datei

//connected_components.h
#ifndef CONNECTED_COMPONENTS_H_
#define CONNECTED_COMPONENTS_H_
#include <opencv2/core/core.hpp>
#include <memory>

class DisjointSet {
  private:
    std::vector<int> m_disjoint_array;
    int m_subset_num;
  public:
    DisjointSet();
    DisjointSet(int size);
    ~DisjointSet();
    int add(); //add a new element, which is a subset by itself;
    int find(int x); //return the root of x
    void unite(int x, int y);
    int getSubsetNum(void);
};

class ConnectedComponent {
private:
  cv::Rect m_bb;
  int m_pixel_count;
  std::shared_ptr< std::vector<cv::Point2i> > m_pixels;
public:
  ConnectedComponent();
  ConnectedComponent(int x, int y);
  ~ConnectedComponent();
  void addPixel(int x, int y);
  int getBoundingBoxArea(void) const;
  cv::Rect getBoundingBox(void) const;
  int getPixelCount(void) const;
  std::shared_ptr< const std::vector<cv::Point2i> > getPixels(void) const;
};

void findCC(const cv::Mat& src, std::vector<ConnectedComponent>& cc);
#endif //CONNECTED_COMPONENTS_H_

.cc Datei

//connected_components.cpp
#include "connected_components.h"

using namespace std;
/** DisjointSet **/
DisjointSet::DisjointSet() :
  m_disjoint_array(),
  m_subset_num(0)
{  }

DisjointSet::DisjointSet(int size) :
  m_disjoint_array(),
  m_subset_num(0)
{
  m_disjoint_array.reserve(size);
}

DisjointSet::~DisjointSet()
{  }

//add a new element, which is a subset by itself;
int DisjointSet::add()
{
  int cur_size = m_disjoint_array.size();
  m_disjoint_array.Push_back(cur_size);
  m_subset_num ++;
  return cur_size;
}
//return the root of x
int DisjointSet::find(int x)
{
  if (m_disjoint_array[x] < 0 || m_disjoint_array[x] == x)
    return x;
  else {
    m_disjoint_array[x] = this->find(m_disjoint_array[x]);
    return m_disjoint_array[x];
  }
}
// point the x and y to smaller root of the two
void DisjointSet::unite(int x, int y)
{
  if (x==y) {
    return;
  }
  int xRoot = find(x);
  int yRoot = find(y);
  if (xRoot == yRoot)
    return;
  else if (xRoot < yRoot) {
    m_disjoint_array[yRoot] = xRoot;
  }
  else {
    m_disjoint_array[xRoot] = yRoot;
  }
  m_subset_num--;
}

int DisjointSet::getSubsetNum()
{
  return m_subset_num;
}

/** ConnectedComponent **/
ConnectedComponent::ConnectedComponent() :
  m_bb(0,0,0,0),
  m_pixel_count(0),
  m_pixels()
{
  m_pixels = std::make_shared< std::vector<cv::Point2i> > ();
}

ConnectedComponent::ConnectedComponent(int x, int y) :
  m_bb(x,y,1,1),
  m_pixel_count(1),
  m_pixels()
{
  m_pixels = std::make_shared< std::vector<cv::Point2i> > ();
}

ConnectedComponent::~ConnectedComponent(void)
{ }

void ConnectedComponent::addPixel(int x, int y) {
  m_pixel_count++;
  // new bounding box;
  if (m_pixel_count == 0) {
    m_bb = cv::Rect(x,y,1,1);
  }
  // extend bounding box if necessary
  else {
    if (x < m_bb.x ) {
      m_bb.width+=(m_bb.x-x);
      m_bb.x = x;
    }
    else if ( x > (m_bb.x+m_bb.width) ) {
      m_bb.width=(x-m_bb.x);
    }
    if (y < m_bb.y ) {
      m_bb.height+=(m_bb.y-y);
      m_bb.y = y;
    }
    else if ( y > (m_bb.y+m_bb.height) ) {
      m_bb.height=(y-m_bb.y);
    }
  }
  m_pixels->Push_back(cv::Point(x,y));
}

int ConnectedComponent::getBoundingBoxArea(void) const {
  return (m_bb.width*m_bb.height);
}

cv::Rect ConnectedComponent::getBoundingBox(void) const {
  return m_bb;
}

std::shared_ptr< const std::vector<cv::Point2i> > ConnectedComponent::getPixels(void) const {
  return m_pixels;
}


int ConnectedComponent::getPixelCount(void) const {
  return m_pixel_count;
}

/** find connected components **/

void findCC(const cv::Mat& src, std::vector<ConnectedComponent>& cc) {
  if (src.empty()) return;
  CV_Assert(src.type() == CV_8U);
  cc.clear();
  int total_pix = src.total();
  int frame_label[total_pix];
  DisjointSet labels(total_pix);
  int root_map[total_pix];
  int x, y;
  const uchar* cur_p;
  const uchar* prev_p = src.ptr<uchar>(0);
  int left_val, up_val;
  int cur_idx, left_idx, up_idx;
  cur_idx = 0;
  //first logic loop
  for (y = 0; y < src.rows; y++ ) {
    cur_p = src.ptr<uchar>(y);
    for (x = 0; x < src.cols; x++, cur_idx++) {
      left_idx = cur_idx - 1;
      up_idx = cur_idx - src.size().width;
      if ( x == 0)
        left_val = 0;
      else
        left_val = cur_p[x-1];
      if (y == 0)
        up_val = 0;
      else
        up_val = prev_p[x];
      if (cur_p[x] > 0) {
        //current pixel is foreground and has no connected neighbors
        if (left_val == 0 && up_val == 0) {
          frame_label[cur_idx] = (int)labels.add();
          root_map[frame_label[cur_idx]] = -1;
        }
        //current pixel is foreground and has left neighbor connected
        else if (left_val != 0 && up_val == 0) {
          frame_label[cur_idx] = frame_label[left_idx];
        }
        //current pixel is foreground and has up neighbor connect
        else if (up_val != 0 && left_val == 0) {
          frame_label[cur_idx] = frame_label[up_idx];
        }
        //current pixel is foreground and is connected to left and up neighbors
        else {
          frame_label[cur_idx] = (frame_label[left_idx] > frame_label[up_idx]) ? frame_label[up_idx] : frame_label[left_idx];
          labels.unite(frame_label[left_idx], frame_label[up_idx]);
        }
      }//endif
      else {
        frame_label[cur_idx] = -1;
      }
    } //end for x
    prev_p = cur_p;
  }//end for y
  //second loop logic
  cur_idx = 0;
  int curLabel;
  int connCompIdx = 0;
  for (y = 0; y < src.size().height; y++ ) {
    for (x = 0; x < src.size().width; x++, cur_idx++) {
      curLabel = frame_label[cur_idx];
      if (curLabel != -1) {
        curLabel = labels.find(curLabel);
        if( root_map[curLabel] != -1 ) {
          cc[root_map[curLabel]].addPixel(x, y);
        }
        else {
          cc.Push_back(ConnectedComponent(x,y));
          root_map[curLabel] = connCompIdx;
          connCompIdx++;
        }
      }
    }//end for x
  }//end for y
}
8
DXM

Wenn es Ihnen nichts ausmacht, eine externe Bibliothek zu verwenden, die OpenCV verwendet, können Sie dies mit cvBlobsLib tun.

Eine Bibliothek zum Durchführen binärer Bilder, die die Beschriftung von Komponenten betreffen (ähnlich wie regionprops Matlab-Funktion). Es bietet auch Funktionen um die Ergebnisse aus den extrahierten Blobs zu manipulieren, zu filtern und zu extrahieren, Weitere Informationen finden Sie im Abschnitt zu den Funktionen.

3
Dan

Sie können die Funktion cv :: connectedComponentsWithStats () verwenden.

Hier ist ein Beispiel.

    // ...
    cv::Mat labels, stats, centroids;
    int connectivity = 8; // or 4
    int label_count = cv::connectedComponentsWithStats(src, labels, stats, centroids, connectivity);
    for (int i = 0; i < label_count; i++)
    {
        int x = stats.at<int>(i, cv::CC_STAT_LEFT);
        int y = stats.at<int>(i, cv::CC_STAT_TOP);
        int w = stats.at<int>(i, cv::CC_STAT_WIDTH);
        int h = stats.at<int>(i, cv::CC_STAT_HEIGHT);
        int area = stats.at<int>(i, cv::CC_STAT_AREA);
        double cx = centroids.at<double>(i, 0);
        double cy = centroids.at<double>(i, 1);

        // ...
    }
1
ChangYun Du

Nach dem obigen Code von DXM, der 4 verbundene Komponenten voraussetzt, folgt hier eine Version für 'findCC', die acht verbundene Komponenten erkennt.

void findCC(const cv::Mat& src, std::vector<ConnectedComponent>& cc) {
if (src.empty()) return;
CV_Assert(src.type() == CV_8U);
cc.clear();
int total_pix = int(src.total());
int *frame_label = new int[total_pix];
DisjointSet labels(total_pix);
int *root_map = new int[total_pix];
int x, y;
const uchar* cur_p;
const uchar* prev_p = src.ptr<uchar>(0);
int left_val, up_val, up_left_val, up_right_val;
int cur_idx, left_idx, up_idx, up_left_idx, up_right_idx;
cur_idx = 0;
//first logic loop
for (y = 0; y < src.rows; y++) {
    cur_p = src.ptr<uchar>(y);
    for (x = 0; x < src.cols; x++, cur_idx++) {
        left_idx = cur_idx - 1;
        up_idx = cur_idx - src.size().width;
        up_left_idx = up_idx - 1;
        up_right_idx = up_idx + 1;

        if (x == 0)
        {
            left_val = 0;
        }
        else
        {
            left_val = cur_p[x - 1];
        }
        if (y == 0)
        {
            up_val = 0;
        }
        else
        {
            up_val = prev_p[x];
        }
        if (x == 0 || y == 0)
        {
            up_left_val = 0;
        }
        else
        {
            up_left_val = prev_p[x-1];
        }
        if (x == src.cols - 1 || y == 0)
        {
            up_right_val = 0;
        }
        else
        {
            up_right_val = prev_p[x+1];
        }

        if (cur_p[x] > 0) {
            //current pixel is foreground and has no connected neighbors
            if (left_val == 0 && up_val == 0 && up_left_val == 0 && up_right_val == 0) {
                frame_label[cur_idx] = (int)labels.add();
                root_map[frame_label[cur_idx]] = -1;
            }

            //Current pixel is foreground and has at least one neighbor
            else
            {
                vector<int> frame_lbl;
                frame_lbl.reserve(4);
                //Find minimal label
                int min_frame_lbl = INT_MAX;
                int valid_entries_num = 0;

                if (left_val != 0)
                {
                    frame_lbl.Push_back(frame_label[left_idx]);
                    min_frame_lbl = min(min_frame_lbl, frame_label[left_idx]);
                    valid_entries_num++;
                }
                if (up_val != 0)
                {
                    frame_lbl.Push_back(frame_label[up_idx]);
                    min_frame_lbl = min(min_frame_lbl, frame_label[up_idx]);
                    valid_entries_num++;
                }
                if (up_left_val != 0)
                {
                    frame_lbl.Push_back(frame_label[up_left_idx]);
                    min_frame_lbl = min(min_frame_lbl, frame_label[up_left_idx]);
                    valid_entries_num++;
                }
                if (up_right_val != 0)
                {
                    frame_lbl.Push_back(frame_label[up_right_idx]);
                    min_frame_lbl = min(min_frame_lbl, frame_label[up_right_idx]);
                    valid_entries_num++;
                }

                CV_Assert(valid_entries_num > 0);
                frame_label[cur_idx] = min_frame_lbl;

                //Unite if necessary
                if (valid_entries_num > 1)
                {
                    for (size_t i = 0; i < frame_lbl.size(); i++)
                    {
                        labels.unite(frame_lbl[i], min_frame_lbl);
                    }
                }
            }

        }//endif
        else {
            frame_label[cur_idx] = -1;
        }
    } //end for x
    prev_p = cur_p;
}//end for y
//second loop logic
cur_idx = 0;
int curLabel;
int connCompIdx = 0;
for (y = 0; y < src.size().height; y++) {
    for (x = 0; x < src.size().width; x++, cur_idx++) {
        curLabel = frame_label[cur_idx];
        if (curLabel != -1) {
            curLabel = labels.find(curLabel);
            if (root_map[curLabel] != -1) {
                cc[root_map[curLabel]].addPixel(x, y);
            }
            else {
                cc.Push_back(ConnectedComponent(x, y));
                root_map[curLabel] = connCompIdx;
                connCompIdx++;
            }
        }
    }//end for x
}//end for y

//Free up allocated memory
delete[] frame_label;
delete[] root_map;

}

1
Ido