opencv如何标记连通区域 并且提取连通区域

 我来答
那时虾米
推荐于2016-08-08 · TA获得超过4.4万个赞
知道大有可为答主
回答量:5054
采纳率:0%
帮助的人:3392万
展开全部
代码

1)Two-pass算法的一种实现
说明:
基于OpenCV和C++实现,领域:4-领域。实现与算法描述稍有差别(具体为记录具有相等关系的label方法实现上)。

// Connected Component Analysis/Labeling By Two-Pass Algorithm
// Author: www.icvpr.com
// Blog : http://blog.csdn.net/icvpr
#include <iostream>
#include <string>
#include <list>
#include <vector>
#include <map>

#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>

void icvprCcaByTwoPass(const cv::Mat& _binImg, cv::Mat& _lableImg)
{
// connected component analysis (4-component)
// use two-pass algorithm
// 1. first pass: label each foreground pixel with a label
// 2. second pass: visit each labeled pixel and merge neighbor labels
//
// foreground pixel: _binImg(x,y) = 1
// background pixel: _binImg(x,y) = 0

if (_binImg.empty() ||
_binImg.type() != CV_8UC1)
{
return ;
}

// 1. first pass

_lableImg.release() ;
_binImg.convertTo(_lableImg, CV_32SC1) ;

int label = 1 ; // start by 2
std::vector<int> labelSet ;
labelSet.push_back(0) ; // background: 0
labelSet.push_back(1) ; // foreground: 1

int rows = _binImg.rows - 1 ;
int cols = _binImg.cols - 1 ;
for (int i = 1; i < rows; i++)
{
int* data_preRow = _lableImg.ptr<int>(i-1) ;
int* data_curRow = _lableImg.ptr<int>(i) ;
for (int j = 1; j < cols; j++)
{
if (data_curRow[j] == 1)
{
std::vector<int> neighborLabels ;
neighborLabels.reserve(2) ;
int leftPixel = data_curRow[j-1] ;
int upPixel = data_preRow[j] ;
if ( leftPixel > 1)
{
neighborLabels.push_back(leftPixel) ;
}
if (upPixel > 1)
{
neighborLabels.push_back(upPixel) ;
}

if (neighborLabels.empty())
{
labelSet.push_back(++label) ; // assign to a new label
data_curRow[j] = label ;
labelSet[label] = label ;
}
else
{
std::sort(neighborLabels.begin(), neighborLabels.end()) ;
int smallestLabel = neighborLabels[0] ;
data_curRow[j] = smallestLabel ;

// save equivalence
for (size_t k = 1; k < neighborLabels.size(); k++)
{
int tempLabel = neighborLabels[k] ;
int& oldSmallestLabel = labelSet[tempLabel] ;
if (oldSmallestLabel > smallestLabel)
{
labelSet[oldSmallestLabel] = smallestLabel ;
oldSmallestLabel = smallestLabel ;
}
else if (oldSmallestLabel < smallestLabel)
{
labelSet[smallestLabel] = oldSmallestLabel ;
}
}
}
}
}
}

// update equivalent labels
// assigned with the smallest label in each equivalent label set
for (size_t i = 2; i < labelSet.size(); i++)
{
int curLabel = labelSet[i] ;
int preLabel = labelSet[curLabel] ;
while (preLabel != curLabel)
{
curLabel = preLabel ;
preLabel = labelSet[preLabel] ;
}
labelSet[i] = curLabel ;
}

// 2. second pass
for (int i = 0; i < rows; i++)
{
int* data = _lableImg.ptr<int>(i) ;
for (int j = 0; j < cols; j++)
{
int& pixelLabel = data[j] ;
pixelLabel = labelSet[pixelLabel] ;
}
}
}

2)Seed-Filling种子填充方法
说明:
基于OpenCV和C++实现;领域:4-领域。

// Connected Component Analysis/Labeling By Seed-Filling Algorithm
// Author: www.icvpr.com
// Blog : http://blog.csdn.net/icvpr
#include <iostream>
#include <string>
#include <list>
#include <vector>
#include <map>
#include <stack>

#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>

void icvprCcaBySeedFill(const cv::Mat& _binImg, cv::Mat& _lableImg)
{
// connected component analysis (4-component)
// use seed filling algorithm
// 1. begin with a foreground pixel and push its foreground neighbors into a stack;
// 2. pop the top pixel on the stack and label it with the same label until the stack is empty
//
// foreground pixel: _binImg(x,y) = 1
// background pixel: _binImg(x,y) = 0

if (_binImg.empty() ||
_binImg.type() != CV_8UC1)
{
return ;
}

_lableImg.release() ;
_binImg.convertTo(_lableImg, CV_32SC1) ;

int label = 1 ; // start by 2

int rows = _binImg.rows - 1 ;
int cols = _binImg.cols - 1 ;
for (int i = 1; i < rows-1; i++)
{
int* data= _lableImg.ptr<int>(i) ;
for (int j = 1; j < cols-1; j++)
{
if (data[j] == 1)
{
std::stack<std::pair<int,int>> neighborPixels ;
neighborPixels.push(std::pair<int,int>(i,j)) ; // pixel position: <i,j>
++label ; // begin with a new label
while (!neighborPixels.empty())
{
// get the top pixel on the stack and label it with the same label
std::pair<int,int> curPixel = neighborPixels.top() ;
int curX = curPixel.first ;
int curY = curPixel.second ;
_lableImg.at<int>(curX, curY) = label ;

// pop the top pixel
neighborPixels.pop() ;

// push the 4-neighbors (foreground pixels)
if (_lableImg.at<int>(curX, curY-1) == 1)
{// left pixel
neighborPixels.push(std::pair<int,int>(curX, curY-1)) ;
}
if (_lableImg.at<int>(curX, curY+1) == 1)
{// right pixel
neighborPixels.push(std::pair<int,int>(curX, curY+1)) ;
}
if (_lableImg.at<int>(curX-1, curY) == 1)
{// up pixel
neighborPixels.push(std::pair<int,int>(curX-1, curY)) ;
}
if (_lableImg.at<int>(curX+1, curY) == 1)
{// down pixel
neighborPixels.push(std::pair<int,int>(curX+1, curY)) ;
}
}
}
}
}
}

3)颜色标记(用于显示)

// Connected Component Analysis/Labeling -- Color Labeling
// Author: www.icvpr.com
// Blog : http://blog.csdn.net/icvpr
#include <iostream>
#include <string>
#include <list>
#include <vector>
#include <map>
#include <stack>

#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>

cv::Scalar icvprGetRandomColor()
{
uchar r = 255 * (rand()/(1.0 + RAND_MAX));
uchar g = 255 * (rand()/(1.0 + RAND_MAX));
uchar b = 255 * (rand()/(1.0 + RAND_MAX));
return cv::Scalar(b,g,r) ;
}

void icvprLabelColor(const cv::Mat& _labelImg, cv::Mat& _colorLabelImg)
{
if (_labelImg.empty() ||
_labelImg.type() != CV_32SC1)
{
return ;
}

std::map<int, cv::Scalar> colors ;

int rows = _labelImg.rows ;
int cols = _labelImg.cols ;

_colorLabelImg.release() ;
_colorLabelImg.create(rows, cols, CV_8UC3) ;
_colorLabelImg = cv::Scalar::all(0) ;

for (int i = 0; i < rows; i++)
{
const int* data_src = (int*)_labelImg.ptr<int>(i) ;
uchar* data_dst = _colorLabelImg.ptr<uchar>(i) ;
for (int j = 0; j < cols; j++)
{
int pixelValue = data_src[j] ;
if (pixelValue > 1)
{
if (colors.count(pixelValue) <= 0)
{
colors[pixelValue] = icvprGetRandomColor() ;
}
cv::Scalar color = colors[pixelValue] ;
*data_dst++ = color[0] ;
*data_dst++ = color[1] ;
*data_dst++ = color[2] ;
}
else
{
data_dst++ ;
data_dst++ ;
data_dst++ ;
}
}
}
}

4)测试程序

// Connected Component Analysis/Labeling -- Test code
// Author: www.icvpr.com
// Blog : http://blog.csdn.net/icvpr
#include <iostream>
#include <string>
#include <list>
#include <vector>
#include <map>
#include <stack>

#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>

int main(int argc, char** argv)
{
cv::Mat binImage = cv::imread("../icvpr.com.jpg", 0) ;
cv::threshold(binImage, binImage, 50, 1, CV_THRESH_BINARY_INV) ;

// connected component labeling
cv::Mat labelImg ;
icvprCcaByTwoPass(binImage, labelImg) ;
//icvprCcaBySeedFill(binImage, labelImg) ;

// show result
cv::Mat grayImg ;
labelImg *= 10 ;
labelImg.convertTo(grayImg, CV_8UC1) ;
cv::imshow("labelImg", grayImg) ;

cv::Mat colorLabelImg ;
icvprLabelColor(labelImg, colorLabelImg) ;
cv::imshow("colorImg", colorLabelImg) ;
cv::waitKey(0) ;

return 0 ;
}
本回答被提问者和网友采纳
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
光点科技
2023-08-15 广告
通常情况下,我们会按照结构模型把系统产生的数据分为三种类型:结构化数据、半结构化数据和非结构化数据。结构化数据,即行数据,是存储在数据库里,可以用二维表结构来逻辑表达实现的数据。最常见的就是数字数据和文本数据,它们可以某种标准格式存在于文件... 点击进入详情页
本回答由光点科技提供
推荐律师服务: 若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询

为你推荐:

下载百度知道APP,抢鲜体验
使用百度知道APP,立即抢鲜体验。你的手机镜头里或许有别人想知道的答案。
扫描二维码下载
×

类别

我们会通过消息、邮箱等方式尽快将举报结果通知您。

说明

0/200

提交
取消

辅 助

模 式