问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

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

发布网友 发布时间:2022-04-23 10:42

我来回答

1个回答

热心网友 时间:2023-06-29 17:57

代码

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 ;
}
声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
小孩子的谜语有哪些? 高频UPS不间断电源厂家有推荐的吗? 农历 女:1986-10-16 属虎,男 1985-02-11 属牛,想在2013 年结婚,请问... ...12月21日出生属牛,女阴历1986年10月20日出生属虎,请问2012上半年哪天... 男属牛农历1985年正月16日生日,女属虎1986年10月26日生日,今年九月份左 ... ...属牛 女方:1986年农历10月20日 属虎 11年4月或5月结婚有合适的日子吗... 凌云诺怎么查看技能信息 凌云诺如何查看技能信息 凌云诺查看品阶福利的操作方法 凌云诺怎么查看品阶福利 凌云诺怎么查看本周个人活跃度 凌云诺查看本周个人活跃度的方法_百度... 深圳宝安正规医院割痔疮要多少钱 如何使用ssd训练自己的数据 imagelab 闪退? 和神经网络有关,labelimg图片标注生成了xml文件,.xml里面记录了什么?希望有大神解答,感激不尽 双证非全日制研究生是属于全日制大学本科及以上学历吗?虽然是在职研 北京航空航天大学的非全日制硕士研究生是双证的吗? 在职研究生有没有双证? 在职研究生的哪些专业可以获得双证? 在职研究生双证指的是什么?都有什么作用? 非全日制研究生是双证吗?考公务员认可吗? 非全日制研究生(双证)可以用研究生身份报考公务员吗? 谁能帮忙解答以《勤俭节约,热爱生活》的主题班会主持人开场白 让学生养成节约的好习惯,老师要怎么做? 以学会节约,美丽中国 为主题的班会材料 bios禁用usb怎么解开 USB接口被禁用,如何在BIOS设置中打开USB bios里的usb被我关了,该怎么启动 有时候开机所有USB口不能用,需要进BIOS恢复出厂设置才好 你好,我在bios里不小心把usb禁用了,现在怎么办? bios中不小心把电脑的USB接口给关闭了,怎样开启 在bios中禁用了usb怎么解除,鼠标键盘都不能用了 如何用opencv实现任意联通区域的最大内接圆 labelimg放在桌面上打不开了 独立显卡驱动与系统不兼容怎么办? 电脑系统与驱动程序不兼容怎么办? 电脑蓝屏了说可能是软件和驱动互不兼容该怎么处理这个问题 这显卡驱动不兼容怎么办 软件驱动不兼容怎么办? 电脑中有不兼容的驱动程序,可以怎样找出来删掉呢? 电脑驱动程序和Windows系统不兼容是怎么回事,我还是在官网下载的,哪位大神棒棒忙 台式电脑软件与硬件不兼容,有什么好的解决方案 硬件或软件的驱动相互不兼容!!!怎么办啊! 显卡的驱动程序与显卡不兼容怎么办? 为什么我电脑蓝屏显示软件和硬件不兼容怎么修 名侦探柯南海上的万圣节是哪一集 名侦探柯南哪一集服部平次扮成工藤新一参加幽灵船万圣节晚会? 名侦探柯南中万圣节派对那集里美杜莎是有希子吗? 名侦探柯南里有一集是小五郎和园子去参加一个万圣节的化装舞会是哪集 名侦探柯南 原子和毛利小五郎去参加一个船上派对。原子扮成的魔女。毛利小五郎是吸血鬼。 名侦探柯南小五郎去参加幽灵船派对是哪一集 跪求名侦探柯南船上的万圣节派对特别篇!!!