OpenCV:区域生长法实现
来源:网络收集 点击: 时间:2024-05-07基本思想:
区域生长法的基本思想是:将具有相似性质的像素点合并到一起;
在每一个区域内首先要指定一个种子点作为生长的起点;
然后将种子点周围邻域的像素点与种子点进行比较,
对具有相似性质的点合并之后继续向外生长,
直到没有满足条件的像素被包括进来为止;
这样一个区域的生长就完成了。
下图是:发在PAMI上的LSD直线检测算法中的关键一步就是找line support regions.这个区域的查找就是利用区域生长法则,生长的条件就是梯度的方向角度;
图中第一张图是原始图像,第二张是计算梯度角度,第三张是根据梯度角度区域生长的结果,相同颜色就是一个区域生长结果。

关键点在于:
①给定种子点(种子点如何选取)
种子点的选取很多时候都采用人工交互的方法实现,
也有用其他方式的,比如寻找物体并提取物体内部点作为种子点。
②确定在生长过程中能将相邻像素包括进来的准则(相似性质准则)
灰度图像的差值;
彩色图像的颜色等等。
都是关于像素与像素间的关系描述。
③生长的停止条件:
四连通与八连通

区域生长流程:
①给出种子点,这里一次给出一个种子点
②给出相似性准则,这里采用灰度差;
③将种子点与其八邻域像素点进行相似性比较;相似点则作为下次生长的种子点;
④停止生长:八邻域内没有合并的像素点时,即没有新的种子点时,停止。
如图所示:

示例程序:
OpenCV没有自带区域生长函数;
为了说明区域是如何生长的,
#include opencv2\opencv.hpp
#include opencv2\highgui\highgui.hpp
#include opencv2\features2d\features2d.hpp
#include opencv2\core\core.hpp
using namespace std;
using namespace cv;
void RegionGrowing(Mat srcImg,Mat dstImg,Point pt,int thre)
{
Point ptGrowing;//生长点像素坐标
int nGrowLabel=0;//是否被标记
int startPtValue=0;//生长起始点灰度值
int currPtValue=0;//当前生长点灰度值
//8邻域
int mDir={{-1,-1},{0,-1},{1,-1},{-1,0},{1,0},{-1,1},{0,1},{1,1}};
vectorPoint growPtVec;//生长点堆栈
growPtVec.push_back(pt);//将初始生长点压入堆栈
Mat markImg=Mat::zeros(srcImg.size(),CV_8UC1);//标记点
unsigned char *pData = (unsigned char *)(markImg.data+pt.y*markImg.step);
pData=255;//标记初始生长点
startPtValue = ((unsigned char*)(srcImg.data+pt.y*srcImg.step));
while (!growPtVec.empty())
{
Point currPt = growPtVec.back();//返回当前vector最末一个元素
growPtVec.pop_back();//弹出最后压入的数据
for (int i=0;i8;i++)
{
ptGrowing.x = currPt.x+mDir;
ptGrowing.y = currPt.y+mDir;
//判断是否是边缘点
if (ptGrowing.x0||ptGrowing.y0||(ptGrowing.xsrcImg.cols-1)||(ptGrowing.ysrcImg.rows))
continue;//继续执行下一次循环
//判断是否已被标记
nGrowLabel = ((unsigned char*)(markImg.data+ptGrowing.y*markImg.step));
if (nGrowLabel==0)//没有被标记
{
currPtValue = ((unsigned char*)(srcImg.data+ptGrowing.y*srcImg.step));
if (abs(currPtValue-startPtValue)=thre)
{
((unsigned char*)(markImg.data+ptGrowing.y*markImg.step))=255;
growPtVec.push_back(ptGrowing);
}
}
}
}
markImg.copyTo(dstImg);
}
int main()
{
Mat srcImg = imread(1.jpg,0);
if (srcImg.empty())
printf(image read error);
Mat srcImg1=srcImg.clone();
Mat outImg1,outImg2;
RegionGrowing(srcImg1,outImg1,Point(241,258),10);
RegionGrowing(srcImg1,outImg2,Point(302,118),80);
add(outImg1,outImg2,outImg1);
imshow(p1p2,outImg1);
Mat resultImg;
srcImg.copyTo(resultImg,~outImg1);
imshow(outImg,resultImg);
waitKey(0);
return 0;
}


算法效果:
这里首先人为选取一个种子点,
在其八邻域内,由相似性准则进行判断并更新种子点;
当不再产生新的种子点时,截止;
当区分多目标是,可以认为选取多个种子点,然后将每个种子点分割区域合并;
即可分割出多目标。

给出一个比较好区域生长法的程序:
//仅根据纹理分割图像,纹理特征是四维集合;
void segmentTexture(Mat texture)
{
Mat regions(texture.rows, texture.cols, CV_8UC1, 0.0);
Mat mark(texture.rows, texture.cols, CV_8UC1, 0.0);
int min_regions = 10;
RNG rng(25);
Point seedPoint, now;
Vec4b curr, next, seed;
queuePoint Q;
vectorpairpairPoint, Vec3b, int Points;
int pixelCount=0;//pixel covered in a segment
for(int i =250; i10; i -= 250/min_regions)
{
rng(12345);
do
{
seedPoint.x = rng.uniform(0, texture.cols);
seedPoint.y = rng.uniform(0, texture.rows);
seed = texture.atVec4b(seedPoint.y, seedPoint.x);
}
while(mark.atuchar(seedPoint.y, seedPoint.x) !=0 );
mark.atuchar(seedPoint.y, seedPoint.x) = i;
Q.push(seedPoint);
while(!Q.empty())
{
now = Q.front();
Q.pop();
curr=texture.atVec4b(now.y, now.x);
for(int p=-1; p=1; p++)
{
for(int q=-1; q=1; q++)
{
if(0=now.x+p now.x+ptexture.cols 0=now.y+q now.y+qtexture.rows)
{
next=texture.atVec4b(now.y+q, now.x+p);
if(mark.atuchar(now.y+q, now.x+p)==0
(textureDifference(next, seed)==1 || farTextureDifference(next, curr)==2))
{
Q.push(Point(now.x+p, now.y+q));
mark.atuchar(now.y+q, now.x+p)=i;
//segm.atVec3b(now.y, now.x)=image.atVec3b(seedPoint.y, seedPoint.x);
}
}
}
}
}
}
///namedWindow(texture segment,2);
///imshow(texture segment,mark);
imwrite(textureSegment.bmp,mark);
}
注意事项在每一个区域内首先要指定一个种子点作为生长的起点;
然后将种子点周围邻域的像素点与种子点进行比较,
对具有相似性质的点合并之后继续向外生长, 直到没有满足条件的像素被包括进来为止;
区域生长法OPENCV区域OPENCV分割聚类分割版权声明:
1、本文系转载,版权归原作者所有,旨在传递信息,不代表看本站的观点和立场。
2、本站仅提供信息发布平台,不承担相关法律责任。
3、若侵犯您的版权或隐私,请联系本站管理员删除。
4、文章链接:http://www.1haoku.cn/art_703432.html