❶ 计算机图形学中。写出内点表示的8连通区域的递归填充算法。 请写出完整的函数代码:
用八邻域的话,有重复的,这个你要考虑到,一般都用四邻域的,八邻域你可以设置一个标志数组,对于已经处理的点就不管了
❷ opencv如何标记连通区域 并且提取连通区域
代码
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 ;
}
❸ 简述边界表示的四连通区域的种子填充算法的基本思想和执行步骤
一、种子填充算法思想:
首先填充种子所在的尚未填充的一区段,然后确定与这一区段相邻的上下两条扫描线上位于该区段内是否存在需要填充的新区段,如果存在,则依次把每个新区段最右端的象素作为种子放入堆栈。反复这个过程,直到堆栈为空。
二、种子填充算法步骤:
1、初始化堆栈。
2、种子压入堆栈。
3、While(堆栈非空)从堆栈弹出种子象素。
❹ matlab bwboundaries 函数思想原理
只不是一个简单的问题
首先要明白这个函数是给出二值图像的边界
二值图像就是数值只有0和1两种值的图像,或者叫逻辑真或假
其边界,就是0和1数据的交接出,一般是求数据为1的区域的边界
由于图像中本身数据为一的区域可能不止一块
所以最用边界也可能不止一条,连在一起的一个全是1的区域,我们叫它做连通域
所以本身这个问题,可以分为两个子问题
第一,求图像的连通域
第二,求每个连通域的边界
这两个问题都不是简单用一两句语句就能解决的
对于第一个问题,matlab有bwlable函数标记每个连通域
而bwlable函数的具体工作代码,matlab没有给出
关键的函数的源代码,matlab是保密的,所以不确切知道其所用的算法
而具体的思想,是扫描矩阵,然后合拼互相连接的区域
你可以搜索 二值图像 连通域 看看,有很多种算法,效率各不相同,不知道matlab用的哪种
第二个问题,也不是个简单的问题
在matlab内部bwboundaties函数首先是调用bwlable解决第一个问题的
而第二个问题又调用了一个内部的不提供源代码的函数,所以具体算法也不得而知
实际上连通域问题解决后,在单一连通域上提取边界也不算太难
比较麻烦的是,在连通域中有洞的情况下,一个连通域也可能有多个边界
一个对外的边界,和若干个内部洞洞的边界
如果是有心想学习算法,最好多找资料看看。
如果只是想了解一下,尝试自己编着玩玩,没有很硬行的规定需要
还是用系统提供的现成函数好了,自己编的即便运行无误多半效率不及系统提供的
❺ 对图像中连通域进行标记并计算面积matlab
matlab里有连通域标记的函数bwlabel,具体自己help吧
至于求连通域面积,stats=regionprops(ibw,'Area');%ibw是标记号的图
求中值也有这函数的,median(A)
别的就很随意了
❻ 对于二值化图像怎么进行连通性分析并计算每一个连通性区域的大小
原型: int WINAPI icePub_imgToSingleBmp(char *strImgFilename,char *strBmpFilename,int thresholdValue) 输入:strImgFilename 待处理图像文件名 strBmpFilename bmp图像名 thresholdValue 256级灰度值的阈值(函数会先将图像转换成灰度再根
❼ 求解格林公式复连通区域计算 其中根据图11_13得两式相减为0是如何得到的 求详细过程
因为L+(-l)=0
什么意思,我用L表示在外圈的积分,方向是逆时针,也就是正向.-l表示在内圈的积分,方向是顺时针,也是正向.根据格林公式,L+(-l)=二重积分,但在这个多连通区域上,二重积分是0啊.为什么是0自己去想.
所以就有L=l
❽ BWLABEL函数得到的是一个和原矩阵一样size的矩阵,但里面的连通域我怎么算不清楚呢
看c++数据结构与算法分析
❾ 谁能给个好用的连通域处理的算法,要8邻域的
楼主要处理的图像是什么样的?黑白图像还是彩色的?我这里有个以前用过的只针对黑白图像的连通域处理,目标是白色,背景是黑色的,不过,如果你的图像不是这样的,那先二值化,然后变换为黑色背景白色目标的图片 CodeGo.net,再调用我这个函数,先看懂我这个函数,然后修改为可以处理白色背景黑色目标 具体函数
其中THRESHOLD_JOINNUM 是个宏定义……
你要先把图像的边缘像素处理下,把边缘1到2个像素宽度的位置,都置为背景色,否则,可能得不到正确的结果,也可能造成访问越界。也就是把四周的边缘像素都置为背景色 然后,如果你仔细看这个函数的实现的话,其实是使用两次连通域处理,一次是用来把黑色的小区域变为白色,也就是填补目标区域中可能出现的小黑洞。然后第二次处理才是用来删除那些小于阈值的白色目标小连通域 这个函数你要看明白才能正确使用。看吧。
2. 楼主要处理的图像是什么样的?黑白图像还是彩色的?我这里有个以前用过的只针对黑白图像的连通域处理,目标是白色,背景是黑色的,不过,如果你的图像不是这样的,那先二值化,然后变换为黑色背景白色目标的图片,再调用我这个函数,先看懂我这个函数,然后修改为可以处理白色背景黑色目标 具体函数