首页 文章

OpenCV中连接的组件

提问于
浏览
37

我正在寻找一个OpenCV函数,它可以找到连接的组件并对它们执行一些任务(比如获取像素数,轮廓,对象中的像素列表等) .

是否有OpenCV(C)的功能类似于MatLab的regionprops?

5 回答

  • 8

    从3.0版开始,OpenCV具有connectedComponents功能 .

  • 27

    看看cvFindContours函数 . 它非常通用 - 它可以找到内部和外部轮廓,并以各种格式返回结果(例如,平面列表与树形结构) . 一旦有了轮廓,像cvContourArea这样的函数就可以确定与特定轮廓相对应的连通分量的基本属性 .

    如果您更喜欢使用较新的C接口(与我上面描述的旧C风格接口相反),则函数名称为similar .

  • 22

    编译时设置-std = c 0x选项

    .h文件

    //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文件

    //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
    }
    
  • 1

    如果您不介意使用使用OpenCV的外部库,则可以使用cvBlobsLib来执行此操作 .

    用于执行二进制图像连接组件标记的库(类似于regionprops Matlab函数) . 它还提供了从提取的blob中操作,过滤和提取结果的功能,有关详细信息,请参阅功能部分 .

  • 3

    遵循上面的DXM代码假定有4个连接的组件,这里是'findCC'的版本,可以检测8个连接的组件 .

    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;
    

    }

相关问题