精华内容
下载资源
问答
  • 区域生长算法

    2015-04-19 17:15:55
    区域生长算法的简单实现,人工选取种子,对二值图像的前景进行分割。
  • 摘要:多种子的区域生长算法,基于C++编写。关键字:图像处理, 种子生长, 区域生长1. 题外话最近需要找一种简单对图像进行分割的算法,作为后续算法的前处理阶段。最开始想到的是聚类,但是聚类会有分割后不保证连通...

    摘要:多种子的区域生长算法,基于C++编写。

    关键字:图像处理, 种子生长, 区域生长

    1. 题外话

    最近需要找一种简单对图像进行分割的算法,作为后续算法的前处理阶段。最开始想到的是聚类,但是聚类会有分割后不保证连通性的问题。

    区域生长法可以保证分割后各自区域的连通性。但网上大多数的代码都是单个种子的,用的多是matlab或旧版本的opencv。索性,我照着单种子的思路,写了一个多种子的区域生长算法分享出来。

    2. 单种子的区域生长

    事实上,我就是参照这篇文章的思路写的代码。这篇文章的代码思路清晰,可惜用的旧版本的opencv,而且是单种子。

    3. 多种子的区域生长

    大体思路是这样的:

    1、遍历全图,寻找是否还有undetermined的点,如有,作为种子

    2、进行单种子的区域生长算法,生长出的区域记入矩阵mask

    3、如果mask记录的区域面积足够大,把mask中的区域记录到矩阵dest中,状态为determined;如果mask记录的区域面积太小,把mask中的区域记录到矩阵dest中,状态为ignored(忽略分割出来面积过小的区域)

    4、重复上述步骤,直到全图不存在undetermined的点

    4. TODO

    我对现在的算法还不是很满意,其一,我没有做太多优化,代码运行卡卡的;其二,我用的灰度图,以及“差值/阈值”的方式来判断是否相似,阈值不是自适应的。

    注:新版本添加了自动寻找阈值的demo,详见本文最后一节

    对于图片尺寸越大越卡这个问题,可以在读图片的时候统一resize成256×256,大多数追求速度的图像处理算法都会有这步。

    对于彩色图,用3个通道的距离来判断相似度会更好。

    以上两个问题,我为了保持算法的原汁原味,就没有添加。(其实是我懒得写了~)

    注:关于彩色图那点,最新版本已经添加了相关代码。思路是RGB三个通道的差值取平方和。Delta = R^2 + G^2 + B^2 。

    5. 代码

    6. 效果原图

    结果

    7. 关于阈值自适应

    新版本的代码中,已经添加了阈值自适应的demo。想法来自于二值化领域的OTSU(大津法),不懂大津法的可以搜索下,虽然属于不同领域,但算法思想可以借鉴。我在demo中的具体做法如下:

    1、threshold的取值在一定范围内,遍历所有可取的threshold

    2、对于一个取到的threshold,区域生长算法可以得到分割后的N个区域。计算同一区域内的像素值的方差var(same_region)以及不同区域间像素平均值的差值delta(mean(different_region))

    3、用loss表征分割的好坏,公式中a和b是手动设置的参数,loss越小说明分割得越好:$$loss=a \div delta(mean(different-region)) + b \times Var(same-region)$$

    4、遍历所有可取的threshold,求出各自的loss,取loss最小值对应的threshold

    原图

    结果

    展开全文
  • 区域生长算法程序

    2018-03-19 15:07:03
    区域生长的matlab程序。可以用来进行学习区域生长算法时使用,
  • 区域生长算法实现

    2017-07-11 15:45:48
    区域生长算法实现简单历程
  • Halcon区域生长算法.pdf

    2021-04-10 23:14:12
    Halcon区域生长算法解析,中文
  • function ret=growseed()%=====区域生长算法========%input :二值图像数据%output:边界点二值图像数据global I;global M;global N;global Y;global T;global newy;global newx;%==边界点x,y坐标%获取多张图片的二值...

    function ret=growseed()

    %=====区域生长算法========

    %input :二值图像数据

    %output:边界点二值图像数据

    global I;global M;

    global N;global Y;global T;global newy;global newx;%==边界点x,y坐标

    %获取多张图片的二值数据

    tempI=draw(); %tempI 36*45*numbertotal

    count=length(tempI(1,1,:));

    wide=length(tempI(:,1,1));%36

    high=length(tempI(1,:,1));%45

    result=zeros(wide,high,count);

    for k=1:count

    I=tempI(:,:,k);

    % figure,imshow(I),title('原始图像')

    I=double(I);

    [M,N]=size(I);

    [seedx,seedy]=searchseed(I);

    Y=zeros(M,N); %作一个全零与原图像等大的图像矩阵Y,作为输出图像矩阵

    T=zeros(M,N);%标记点。。。

    newx=0;newy=0;

    calseed(seedx,seedy);

    figure,imshow(Y);

    % if k>1&&k

    % result(:,:,k)=Y;

    % figure,imshow(Y);

    % else

    % result(:,:,k)=T;

    % % imshow(T);

    % % figure,imshow(T);

    % end

    end

    ret=result;

    end

    function calseed(seedx,seedy)

    global M;

    global N;

    global Y;

    global I;

    global newx;

    global newy;

    global T;

    for i = -1 : 1

    for j = -1 : 1

    newseedx = seedx + i;

    newseedy = seedy+ j;

    %生长准则:判断生长点8邻域内像素的各自灰度值是否与生长点所在像素灰度值相等

    if newseedx> 0 && newseedx <= M && newseedy > 0 && newseedy <= N &&T(newseedx,newseedy)==0&&I(newseedx,newseedy)==1

    T(newseedx,newseedy)=1;

    if isequal(newseedx,newseedy)==1

    calseed(newseedx,newseedy);

    else

    Y(newx,newy)=1;%set边界点值为1

    end

    end

    end

    end

    end

    function ret=isequal(x,y)%====判断点的领域是否相等

    %===输入1个点的x,y坐标

    %==返回1 相等

    global I;

    global newx;

    global newy;

    global M;

    global N;

    ret=1;

    tag=0;

    for i = -1 : 1

    if tag==0

    for j = -1 : 1

    if x+i> 0 && x+i <= M && y+j > 0 && y+j <= N

    if I( x+i,y+j)==0

    ret=0;

    tag=1;

    newx=x+i;

    newy=y+j;

    end

    end

    end

    end

    end

    end

    function [x,y]=searchseed(I)

    %=========寻找种子点=====

    %Input:一张二值数据的图片

    %Output:返回种子点的x,y坐标

    %======求数据为1的质心====

    [M,N]=size(I);

    corx=0;

    cory=0;

    count=0;

    for i=1:M

    for j=1:N

    if I(i,j)==1

    corx=corx+i;

    cory=cory+j;

    count=count+1;

    end

    end

    end

    x=round(corx/count);

    y=round(cory/count);

    end

    17be3aeeebbaf098383a8664198c06d1.png

    处理结果

    展开全文
  • 区域生长算法,种子点选取
  • CV | 区域生长算法

    2020-08-21 17:10:55
    区域生长算法基础灰度差值的区域生长算法 3. 区域生长算法 摘自: 图像中区域生长算法的详解和实现 OpenCV-区域生长算法 区域生长算法 基础 图像分割是一种重要的图像处理技术,而区域生长是图像分割技术的鄂一种。...

    3. 区域生长算法

    摘自:
    图像中区域生长算法的详解和实现
    OpenCV-区域生长算法
    区域生长算法

    基础

    图像分割是一种重要的图像处理技术,而区域生长是图像分割技术的鄂一种。

    区域生长算法的基本思想是将有相似性质的像素点合并到一起。对每一个区域要先指定一个种子点作为生长的起点,然后将种子点周围领域的像素点和种子点进行对比,将具有相似性质的点合并起来继续向外生长,直到没有满足条件的像素被包括进来为止。这样一个区域的生长就完成了。

    1. 给定种子点(种子点如何选取?)

    种子点的选取很多时候都采用人工交互的方法实现,也有用其他方式的,
    比如寻找物体并提取物体内部点或者利用其它算法找到的特征点作为种子点。

    1. 确定在生长过程中能将相邻像素包括进来的准则

    这个准则很重要:例如包括灰度值的差值;彩色图像的颜色;梯度特征,包括梯度的方向和幅值特征。该点周围的区域特征,例如harr特征,也就是区域像素和特征。

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

    1. 生长的停止条件

    灰度差值的区域生长算法

    算法实现的步骤:
    a> 创建一个空白的图像(全黑);
    b> 将种子点存入vector中,vector中存储待生长的种子点;
    c> 依次弹出种子点并判断种子点如周围8领域的关系(生长规则),相似的点则作为下次生长的种子点;
    d> vector中不存在种子点后就停止生长。

    在这里插入图片描述

    展开全文
  • // 注:本内容为作者原创,禁止在其他网站复述内容以及用于商业盈利,如需引用...当然,如果是对图像中的某一类型进行区域生长可能更容易一些个人理解区域生长算法需要确定一个阈值,这个值代表同一类图像信息灰度值...

    // 注:本内容为作者原创,禁止在其他网站复述内容以及用于商业盈利,如需引用,请标明出处:https://www.cnblogs.com/lv-anchoret/

    今天我们来介绍用C++算法如何来实现图像分割算法中的区域生长算法

    我们解决的是对一整张图像所有内容进行区域生长分类,当然,如果是对图像中的某一类型进行区域生长可能更容易一些

    个人理解

    区域生长算法需要确定一个阈值,这个值代表同一类图像信息灰度值的差值,比如,我要一个人脸图(假设眼睛是蓝色的),头发是黑色的但是不同光线反射原因或者位置不同,图像中显示的灰度颜色值有5、10、3等,虽然灰度值不一样,但是他们代表的都是黑色,都是头发,区域生长,就是把这些相似灰度值的一类事物统一标注显示,这也就达到了分类识别的目的,关于阈值,比如上述的头发,我们需要将所有是头发的像素点都标注出来,那么我们的阈值就应该设置为10,如果设置为3,可能灰度值为3和5的点会统一识别,但是10就被排除在外了。

    算法核心就是一个bfs,设立一个种子点,向四周扩张,如果相邻的点的灰度值相对于种子点在阈值范围之内,那么,我们把它识别并包含统一进来,扩张完毕之后,所有相似的一类图像将被统一标注。

    关于标注我们还需要说一下,一开始,想起了四色定理,即用四种颜色就可以吧整个地图分类标注且相邻类别颜色不同,后来想了想还不如把同一类型区域中的所有点都设置为种子点灰度像素值。

    之后想起来我们光线追踪一直用的ppm彩色文件格式,索性将灰度值转成rgb彩色图看着更爽

    区域生长算法流程

    1. 找种子点

    2. 扩张原则

    3. 终止条件

    数据介绍

    我们的数据是一张灰度图 : 见 纹理相册夹中的第二张图

    我们处理输出的是一张彩色图像,图像格式是我们光线追踪的文件格式 .ppm,用我们光线追踪的图片解析器(ppmviewer)就能打开(没有的也没关系,搜索一下,下载不超过十几秒,超轻量级ppm解读器)

    我们都知道,C/C++ 中读取图像麻烦,特别是这种.jpg复杂格式数据,所以,我们用matlab先把图像读出来,输出到一个TXT中,存储为二维矩阵形式,然后用C++代码读取TXT文件内容,存储到一个二维数据序列中。(都有代码在后面)

    我们侧重实现算法本身,所以关于图像的读取和写入我们不做过多描述

    算法介绍

    算法自命名:首次左上区域生长算法

    时间复杂度:O(图像大小*种子数量*log(种子数量))

    一、区域生长的三大要素确立:

    (1)生长合并规则:

    用户自定义阈值,根据种子点和当前点的差值,如果在阈值之内,那么合并,将当前点的灰度值设为种子灰度值

    (2)种子选取:

    将图像左上角第一个点作为第一个种子,在扩张的过程中第一个不符合生长合并规则的位置,作为下一次生长的种子,即首次选定,后期自适应确定。

    (3)算法结束:

    种子为空

    二、优缺点

    该算法的优点:  针对大型全局生长而衍生

    该算法种子不会将同一个位置作为种子多次重复生长(时间空间复杂度优化)

    某个种子在开始生长时,如果已经被包含于另一个种子的生长区域中,那么该种子将不会进行生长(时间复杂度优化)

    该算法的缺点:  首次选定法不能用合适的灰度代表整个区域,只能是坐标小的点的灰度值

    生长出来的区域可能不是很完美,因为该区域是由该区域坐标最小的点生长而成的。

    三、灰度值转rgb算法设计

    因为要将单一的灰度值映射到r、g、b,使其代表的颜色具有独特性

    这个可以自己设计,我的设计如下:

    四、构架设计

    含有一个类 —— regional

    数据成员

    _img:用于存储图像灰度矩阵

    reset:用于记录某个位置的灰度是否被重置

    _delt:阈值

    成员函数

    readfile:读图像灰度矩阵文件

    bfs:进行区域生长

    out:输出处理后的图像灰度矩阵

    readout:读取处理后的图像灰度矩阵文件

    gograph:将灰度图像转为rgb图像,由于ppmview显示空间有限,所以将此图划分为6块(将原图像分为3行2列的6块),分别输出6个图像

    流程图如下:

    五、数据结构设计:(C++描述)

    用bfs算法进行的话,必然需要队列,但是种子们不能用队列去存,某个种子进行生长的时候可以用队列记录每一个生长状态

    此法采用8领域进行生长

    用队列存储当前种子生长过程中的状态点,进行bfs扩展,确定该种子生长所形成的区域

    用set容器存储各个种子,保证了种子点唯一性,即优点2,同时,set容器还会根据位置自动排序,所以导致了缺点2,其次,set容器的存取操作的时间复杂度均为O(n log n)

    Bfs状态采用只包含x、y坐标的一个结构体

    六、效果与讨论

    采用C++描述的首次左上区域生长算法针对2012*1881的灰度卫星图像矩阵数据处理时间为:78.9s

    阈值为20

    图1

    首先蓝色圈所代表的部分,如果是水域的深浅,那么这一块还是被划分的很清楚的,大致分了5部分

    再看下阈值为25的图

    图2

    如我们所预期的那样,图1中蓝色圈的水深划分等级更少了

    其次,我们看图1的红色圈代表的水体,内部中间划分出来的区域更小了,或者说水体的边缘区域扩张了。

    再如,黑色圈代表的水域,中间的黑色圈有一块东西,它的区域更小了,不利于捕捉细微的水内状况

    如果图1的黑色内的小黑圈部分看不太清楚,那么可以看一下下面这个,都是一样的

    XnView打开效果

    图3

    如果把黄色部分看做是竖着的地质锤,那么图2显然少了锤头~

    还有水边一片房子聚集地,也被基本划分为一种色调

    图4

    而针对下图以及图4以及原图上方一片森林山脉,将各种处理方法进行叠加,效果可能会更好,方案如下:

    有很多星星点点的噪声,可以选择先去噪声,但是,效果也不是很好

    如果要将其纳入到统一的大片区域中,还是选择先做一个平滑处理,将其尖锐的边缘过渡更加平滑些,再进行区域生长,加以阈值调整,星点可能会减少,可能还存在一些,但是不会那么显眼,和周围环境的色差不会那么大了

    图5

    七、代码

    matlab 代码

    matlab:

    function writetxt

    I= imread('poyanghu.jpg');

    fid= fopen('image.txt','w');

    [x,y]=size(I);

    fprintf(fid,'%d %d\n',x,y);for i = 1:xfor j = 1:y

    fprintf(fid,'%d',I(i,j));

    end

    fprintf(fid,'\n');

    end

    fclose(fid);

    C++:

    regional.h

    //regional.h#pragma once

    namespaceregion

    {

    constexprint dir[8][2]

    {

    {-1,-1},

    {-1, 0},

    {-1, 1},

    {0,-1},

    {0, 1},

    {1,-1},

    {1, 0},

    {1, 1}

    };

    constexpr size_t H= 2012;

    constexpr size_t L= 1881;classregional

    {public:structpos

    {int_x, _y;

    pos(const int a, const intb) :_x(a), _y(b) { }bool operator

    }

    };public:

    regional(constsize_t delt);voidreadfile();voidbfs();void out();voidreadout();void gograph()const;private:short _img[2012 + 1][1881 + 1];bool reset[H + 1][L + 1];

    size_t _delt;

    };

    }

    regional.cpp

    #include "regional.h"#include#include#include#include

    using namespacestd;using namespaceregion;

    regional::regional(constsize_t delt)

    :_delt(delt)

    {

    memset(reset,false, sizeofreset);

    }voidregional::readfile()

    {

    ifstream infile;

    infile.open("image.txt");if (!infile.is_open())

    cerr<< "open failed" <

    infile>> x >>y;for (int i = 1; i <= x; ++i)for (int j = 1; j <= y; ++j)

    infile>>_img[i][j];

    infile.close();

    }voidregional::bfs()

    {

    queueQcurrent;setQnew;

    Qnew.insert(pos(1, 1));while(Qnew.size())

    {

    Qcurrent.push(*Qnew.begin());

    Qnew.erase(Qnew.begin());if (reset[Qcurrent.front()._x][Qcurrent.front()._y])//该种子点已经访问过

    {

    Qcurrent.pop();continue;

    }while(Qcurrent.size())

    {

    pos seed=Qcurrent.front();

    reset[seed._x][seed._y]= true;

    Qcurrent.pop();for (int trans = 0; trans < 8; ++trans)

    {

    pos p(seed._x+ dir[trans][0], seed._y + dir[trans][1]);if (p._x > 0 && p._x <= H && p._y > 0 && p._y <= L && !reset[p._x][p._y])if (abs(_img[p._x][p._y] - _img[seed._x][seed._y]) <_delt>

    {

    _img[p._x][p._y]=_img[seed._x][seed._y];

    reset[p._x][p._y]= true;

    Qcurrent.push(p);

    }elseQnew.insert(p);

    }

    }

    }

    }void regional::out()

    {

    ofstream outfile;

    outfile.open("outall.txt");if (!outfile.is_open())

    cerr<< "open failed" <

    {for (int j = 1; j <= L; ++j)

    outfile<< _img[i][j] << " ";

    outfile<

    }

    outfile.close();

    }voidregional::readout()

    {

    ifstream infile("outall.txt");if (!infile.is_open())

    {

    cerr<< "error open" <

    }for (int i = 1; i <= H; ++i)for (int j = 1; j <= L; ++j)

    infile>>_img[i][j];

    infile.close();

    }void regional::gograph()const{

    ofstream file;

    auto left= [&](intcnt)

    {for (int i = (cnt - 1) * 700 + 1; i <= 700 * cnt; ++i)for (int j = 1; j <= 1000; ++j)

    file<< (int)((0.2 + float(_img[i][j] % 10) / 10)*_img[i][j])<< " " << (int)((0.5 + float(_img[i][j] % 10) / 10)*_img[i][j])<< " " << (int)((0.7 + float(_img[i][j] % 10) / 10)*_img[i][j]) <

    };

    auto right= [&](intcnt)

    {for (int i = (cnt - 1) * 700 + 1; i <= 700 * cnt; ++i)for (int j = L - 1000 + 1; j <= L; ++j)

    file<< (int)((0.2 + float(_img[i][j] % 10) / 10)*_img[i][j])<< " " << (int)((0.5 + float(_img[i][j] % 10) / 10)*_img[i][j])<< " " << (int)((0.7 + float(_img[i][j] % 10) / 10)*_img[i][j]) <

    };

    file.open("slip1'.ppm");

    file<< "P3" <

    file<< 1000 << " " << 700 <

    file<< "255" <

    left(1);

    file.close();

    file.open("slip2'.ppm");

    file<< "P3" <

    file<< 1000 << " " << 700 <

    file<< "255" <

    right(1);

    file.close();

    file.open("slip3'.ppm");

    file<< "P3" <

    file<< 1000 << " " << 700 <

    file<< "255" <

    left(2);

    file.close();

    file.open("slip4'.ppm");

    file<< "P3" <

    file<< 1000 << " " << 700 <

    file<< "255" <

    right(2);

    file.close();

    file.open("slip5'.ppm");

    file<< "P3" <

    file<< 1000 << " " << 700 <

    file<< "255" <

    left(3);

    file.close();

    file.open("slip6'.ppm");

    file<< "P3" <

    file<< 1000 << " " << 700 <

    file<< "255" <

    right(3);

    file.close();

    }

    main.cpp

    #include "regional.h"

    using namespaceregion;

    #include#include

    #define stds std::

    intmain()

    {

    regional reg(25);

    reg.readfile();

    reg.bfs();

    reg.out();//reg.readout();

    reg.gograph();

    stds cout<< "complished" <

    }

    感谢您的阅读,生活愉快~

    展开全文
  • 可参考:图像处理算法1——区域生长法 区域生长算法 C++实现 区域生长算法的一种C++实现
  • 引言本文章将带大家实现灾害监测中一种常用的图像分类方法,即区域生长算法。与前面介绍的几种图像分割方法不同,区域生长算法可直接对高于Uint8灰级的数据直接进行处理,所以保持了原数据的结构形式。另外,区域...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 596
精华内容 238
关键字:

区域生长算法