OpenCV:区域生长法实现

2025-10-03 17:58:07

1、基本思想:

区域生长法的基本思想是:将具有相似性质的像素点合并到一起;

在每一个区域内首先要指定一个种子点作为生长的起点;

然后将种子点周围邻域的像素点与种子点进行比较,

对具有相似性质的点合并之后继续向外生长,

直到没有满足条件的像素被包括进来为止;

这样一个区域的生长就完成了。

下图是:发在PAMI上的LSD直线检测算法中的关键一步就是找line support regions.这个区域的查找就是利用区域生长法则,生长的条件就是梯度的方向角度;

图中第一张图是原始图像,第二张是计算梯度角度,第三张是根据梯度角度区域生长的结果,相同颜色就是一个区域生长结果。

OpenCV:区域生长法实现

2、关键点在于:

①给定种子点(种子点如何选取)

种子点的选取很多时候都采用人工交互的方法实现,

也有用其他方式的,比如寻找物体并提取物体内部点作为种子点。

②确定在生长过程中能将相邻像素包括进来的准则(相似性质准则)

灰度图像的差值;

彩色图像的颜色等等。

都是关于像素与像素间的关系描述。

③生长的停止条件:

四连通与八连通

OpenCV:区域生长法实现

3、区域生长流程:

①给出种子点,这里一次给出一个种子点

②给出相似性准则,这里采用灰度差;

③将种子点与其八邻域像素点进行相似性比较;相似点则作为下次生长的种子点;

④停止生长:八邻域内没有合并的像素点时,即没有新的种子点时,停止。

如图所示:

OpenCV:区域生长法实现

4、示例程序:

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[8][2]={{-1,-1},{0,-1},{1,-1},{-1,0},{1,0},{-1,1},{0,1},{1,1}};

       vector<Point> 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[pt.x]=255;//标记初始生长点

      

       startPtValue = ((unsigned char*)(srcImg.data+pt.y*srcImg.step))[pt.x];

      

       while (!growPtVec.empty())

       {

              Point currPt = growPtVec.back();//返回当前vector最末一个元素

              growPtVec.pop_back();//弹出最后压入的数据

              for (int i=0;i<8;i++)

              {

                     ptGrowing.x = currPt.x+mDir[i][0];

                     ptGrowing.y = currPt.y+mDir[i][1];

                     //判断是否是边缘点

                     if (ptGrowing.x<0||ptGrowing.y<0||(ptGrowing.x>srcImg.cols-1)||(ptGrowing.y>srcImg.rows))

                            continue;//继续执行下一次循环

                     //判断是否已被标记

                     nGrowLabel = ((unsigned char*)(markImg.data+ptGrowing.y*markImg.step))[ptGrowing.x];

                     if (nGrowLabel==0)//没有被标记

                     {

                            currPtValue = ((unsigned char*)(srcImg.data+ptGrowing.y*srcImg.step))[ptGrowing.x];

                            if (abs(currPtValue-startPtValue)<=thre)

                            {

                                   ((unsigned char*)(markImg.data+ptGrowing.y*markImg.step))[ptGrowing.x]=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;

}

OpenCV:区域生长法实现

OpenCV:区域生长法实现

5、算法效果:

这里首先人为选取一个种子点,

在其八邻域内,由相似性准则进行判断并更新种子点;

当不再产生新的种子点时,截止;

当区分多目标是,可以认为选取多个种子点,然后将每个种子点分割区域合并;

即可分割出多目标。

OpenCV:区域生长法实现

6、给出一个比较好区域生长法的程序:

//仅根据纹理分割图像,纹理特征是四维集合;

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;

    queue<Point> Q;

    vector<pair<pair<Point, Vec3b>, int> > Points;

    int pixelCount=0;//pixel covered in a segment

    for(int i =250; i>10; i -= 250/min_regions)

    {

        rng(12345);

        do

        {

            seedPoint.x = rng.uniform(0, texture.cols);

            seedPoint.y = rng.uniform(0, texture.rows);

            seed = texture.at<Vec4b>(seedPoint.y, seedPoint.x);

        }

        while(mark.at<uchar>(seedPoint.y, seedPoint.x) !=0 );

        mark.at<uchar>(seedPoint.y, seedPoint.x) = i;

        Q.push(seedPoint);

        while(!Q.empty())

        {

            now = Q.front();

            Q.pop();

            curr=texture.at<Vec4b>(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+p<texture.cols && 0<=now.y+q && now.y+q<texture.rows)

                    {

                        next=texture.at<Vec4b>(now.y+q, now.x+p);

                        if(mark.at<uchar>(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.at<uchar>(now.y+q, now.x+p)=i;

                            //segm.at<Vec3b>(now.y, now.x)=image.at<Vec3b>(seedPoint.y, seedPoint.x);

                        }

                    }

                }

            }

        }

    }

    ///namedWindow("texture segment",2);

    ///imshow("texture segment",mark);

    imwrite("textureSegment.bmp",mark);

}

声明:本网站引用、摘录或转载内容仅供网站访问者交流或参考,不代表本站立场,如存在版权或非法内容,请联系站长删除,联系邮箱:site.kefu@qq.com。
猜你喜欢