matlab OpenCV 2.4.10 bwLabel连接组件

cld4siwp  于 2022-11-15  发布在  Matlab
关注(0)|答案(2)|浏览(120)

以下是来自MatLab的原始代码:

% Calculate each separated object area
    cDist=regionprops(bwImg, 'Area');
    cDist=[cDist.Area];

    % Label each object
    [bwImgLabeled, ~]=bwlabel(bwImg);

    % Calculate min and max object size based on assumptions on the color
    % checker size
    maxLabelSize = prod(size(imageData)./[4 6]);
    minLabelSize = prod(size(imageData)./[4 6]./10);

    % Find label indices for objects that are too large or too small
    remInd = find(cDist > maxLabelSize);
    remInd = [remInd find(cDist < minLabelSize)];

    % Remove over/undersized objects
    for n=1:length(remInd)
        ri = bwImgLabeled == remInd(n);
        bwImgLabeled(ri) = 0;

以下是我使用OpenCV编写的代码

//regionprops(bwImg, 'Area');
// cDist=[cDist.Area]
//cv::FileStorage file("C:\\Users\\gdarmon\\Desktop\\gili.txt", cv::FileStorage::WRITE);
//
//file << dst;
dst.convertTo(dst,CV_8U);
cv::vector<cv::vector<cv::Point> > contours;
cv::vector<cv::Vec4i> hierarchy;
cv::findContours(dst,contours,hierarchy,CV_RETR_CCOMP, CV_CHAIN_APPROX_NONE);

std::vector<cv::Moments> mu(contours.size());
for (int i = 0; i < contours.size(); i++)
{
    mu[i] = cv::moments(contours[i],false);
}
vector<cv::Point2f> mc( contours.size() );
for( int i = 0; i < contours.size(); i++ )
{ 
    mc[i] = cv::Point2f( mu[i].m10/mu[i].m00 , mu[i].m01/mu[i].m00 ); 
}

因为现在我有了轮廓,我想使用bwLabel功能
1.我认为做标签是为了连接4-8个对象。你能解释一下什么是贴标签吗?我会指出任何联系。
2.connected components in OpenCV在本文中,有人在谈论CVBlob,也有人在谈论opecv的cvConourArea,你能解释一下这两者的区别吗?什么更适合我的用例?
更新:以下是我尝试使用cvBlobs的方法

IplImage* img_bw = new IplImage(dst);
CBlobResult blobs;
CBlob *currentBlob;
blobs = CBlobResult(img_bw, NULL, 0);
// Exclude all white blobs smaller than the given value (80)
// The bigger the last parameter, the bigger the blobs need
// to be for inclusion 
blobs.Filter( blobs,
    B_EXCLUDE,
    CBlobGetArea(),
    B_LESS,
    80 );

// Get the number of blobs discovered
int num_blobs = blobs.GetNumBlobs(); 

// Display the filtered blobs
IplImage* filtered = cvCreateImage( cvGetSize( img_bw ),
    IPL_DEPTH_8U,
    3 ); 

cvMerge( img_bw, img_bw, img_bw, NULL, filtered );

for ( int i = 0; i < num_blobs; i++ )
{
    currentBlob = blobs.GetBlob( i );
    currentBlob->FillBlob( filtered, CV_RGB(255,0,0));
}

// Display the input / output windows and images
cvNamedWindow( "input" );
cvNamedWindow( "output" );
cvShowImage("input", img_bw );

cvShowImage("output", filtered);
cv::waitKey(0);

 /*% Calculate min and max object size based on assumptions on the color
% checker size
maxLabelSize = prod(size(imageData)./[4 6]);
minLabelSize = prod(size(imageData)./[4 6]./10);*/
double maxLabelSize = (dst.rows/4.0) * (dst.cols/6.0);
double minLabelSize = ((dst.rows/40.0) * (dst.cols/60.0));
w1jd8yoj

w1jd8yoj1#

1.我认为做标签是为了连接4-8个对象。你能解释一下什么是贴标签吗?我会指出任何联系。
标签实际作用的最清楚演示是在bwlabel的MatLab文档中。如果将原始矩阵BW与结果矩阵L进行比较,您将看到它获取一个二进制图像,并为每个相连的1组分配唯一的标签:

L =

     1     1     1     0     0     0     0     0
     1     1     1     0     2     2     0     0
     1     1     1     0     2     2     0     0
     1     1     1     0     0     0     3     0
     1     1     1     0     0     0     3     0
     1     1     1     0     0     0     3     0
     1     1     1     0     0     3     3     0
     1     1     1     0     0     0     0     0

这里有三个标记的组件。本例寻找4连通分量;如果像素位于当前像素的左侧、右侧、上方或下方,则将其视为已连接到当前像素。8-连接的对象包括对角线,这将导致上面的矩阵的标签23合并,因为对象2的右下角和对象3的顶部是对角连接的。维基百科here上描述了连通分量标记算法。
2.OpenCV中的连接组件在本文中,有人说CVBlob,有人说opecv的cvConourArea,你能解释一下这两者的区别吗?什么更适合我的用例?
OpenCV 3.0还处于测试阶段,它有两个全新的方法:connectedComponentsconnectedComponentsWithStats(文档)。如果您正在尝试复制MatLab的bwlabel,那么这是一条可行的道路。
我编写了一个测试程序来试用connectedComponentsWithStats(下面的完整代码),并将其用作我的测试映像:

(实际上,此图像已从800x600缩小到400x300,但生成它的代码如下所示。)
我使用以下命令生成了标记的图像:

int nLabels = connectedComponentsWithStats(src, labels, stats, centroids, 8, CV_32S);

nLabels中返回的值为5。请记住,此方法将背景视为标签为0
要查看标记区域是什么,可以将灰阶值从[0..nLabels-1]放大到[0..255],或者可以指定随机的RGB值并创建彩色图像。在此测试中,我只打印出了几个位置的值,我知道这些位置位于不同的组件中。

cout << "Show label values:" << endl;
// Middle of square at top-left
int component1Pixel = labels.at<int>(150,150);
cout << "pixel at(150,150) = " << component1Pixel << endl;
// Middle of rectangle at far right
int component2Pixel = labels.at<int>(300,550);
cout << "pixel at(300,550) = " << component2Pixel << endl << endl;

Show label values:
pixel at(150,150) = 1  
pixel at(300,550) = 2

stats是包含每个组件(包括背景)的left, top, width, height, and area5 x nLabels垫。对于此图像:

stats:
(left,top,width,height,area)
[0, 0, 800, 600, 421697;
 100, 100, 101, 101, 10201;
 500, 150, 101, 301, 30401;
 350, 246, 10, 10, 36;
 225, 325, 151, 151, 17665]

您将注意到组件0是图像的全宽/全高。将所有区域相加,得到480,000 = 800x600。前4个元素可用于创建边界矩形:

Rect(Point(left,top), Size(width,height))

centroids是包含每个零部件质心的x, y坐标的2 x nLabels材质:

centroids:
(x, y)
[398.8575636060963, 298.8746232484461;
 150, 150;
 550, 300;
 354.5, 250.5;
 300, 400]

最后,在某些情况下,您可能需要单独对其中一个组件进行进一步处理。在这里,我使用compare生成一个新的mat only2,它只包含labels中标记为2的像素。

compare(labels, 2, only2, CMP_EQ);

compare有助于在新图像中将这些像素设置为255的值,以便您可以看到结果:

以下是完整的代码:

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>

using namespace std;
using namespace cv;

int main(int argc, const char * argv[]) {

    // Create an image
    const int color_white = 255;
    Mat src = Mat::zeros(600, 800, CV_8UC1);

    rectangle(src, Point(100, 100), Point(200, 200), color_white, CV_FILLED);
    rectangle(src, Point(500, 150), Point(600, 450), color_white, CV_FILLED);
    rectangle(src, Point(350,250), Point(359,251), color_white, CV_FILLED);
    rectangle(src, Point(354,246), Point(355,255), color_white, CV_FILLED);
    circle(src, Point(300, 400), 75, color_white, CV_FILLED);

    imshow("Original", src);

    // Get connected components and stats
    const int connectivity_8 = 8;
    Mat labels, stats, centroids;

    int nLabels = connectedComponentsWithStats(src, labels, stats, centroids, connectivity_8, CV_32S);

    cout << "Number of connected components = " << nLabels << endl << endl;

    cout << "Show label values:" << endl;
    int component1Pixel = labels.at<int>(150,150);
    cout << "pixel at(150,150) = " << component1Pixel << endl;
    int component2Pixel = labels.at<int>(300,550);
    cout << "pixel at(300,550) = " << component2Pixel << endl << endl;

    // Statistics
    cout << "Show statistics and centroids:" << endl;
    cout << "stats:" << endl << "(left,top,width,height,area)" << endl << stats << endl << endl;
    cout << "centroids:" << endl << "(x, y)" << endl << centroids << endl << endl;

    // Print individual stats for component 1 (component 0 is background)
    cout << "Component 1 stats:" << endl;
    cout << "CC_STAT_LEFT   = " << stats.at<int>(1,CC_STAT_LEFT) << endl;
    cout << "CC_STAT_TOP    = " << stats.at<int>(1,CC_STAT_TOP) << endl;
    cout << "CC_STAT_WIDTH  = " << stats.at<int>(1,CC_STAT_WIDTH) << endl;
    cout << "CC_STAT_HEIGHT = " << stats.at<int>(1,CC_STAT_HEIGHT) << endl;
    cout << "CC_STAT_AREA   = " << stats.at<int>(1,CC_STAT_AREA) << endl;

    // Create image with only component 2
    Mat only2;
    compare(labels, 2, only2, CMP_EQ);

    imshow("Component 2", only2);

    waitKey(0);

}
vsaztqbk

vsaztqbk2#

我使用了下面的代码,这可能是耗时取决于您的图像大小。

Mat labels;
Mat stats;
Mat centroids;
int nLabels = cv::connectedComponentsWithStats(bin_img, labels, stats, centroids,4);// bin_img is a binary image

vector<int> test;
int vector_size=0;
int temp_label_num=0;

for(int i=0; i<stats.rows; i++)
{

  int area = stats.at<int>(Point(4, i));//CC_STAT_AREA
   
  double cent_x = centroids.at<double>(i, 0);
  double cent_y = centroids.at<double>(i, 1);

  temp_label_num = labels.at<int>(cent_x,cent_y); //single value matrix

   if (area > 80) //your desired minimum area
  {
    if(temp_label_num>0){
    test.push_back(temp_label_num);
    vector_size++;
  }
    continue;      
  }
}

for(int i=0;i <labels.rows ; i++ )
  for(int j=0;j <labels.cols ; j++ )
    for(int k=0;k < vector_size; k++ )
      if(labels.at<int>(i,j)==test[k]){
        temp.at<char>(i,j)=255;
      }

相关问题