目标分割算法之基于区域增长

区域生长算法

1.理论基础

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

a> 给定种子点(种子点如何选取?)

种子点的选取很多时候采用人工交互的方法实现,也有用其他方式的,比如寻找物体并提取物体内部点作为种子点

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

灰度值的差值,彩色图像的颜色等等,是关于像素与像素之间的关系描述

c> 生长的停止条件

2.灰度差值的区域生长算法实现

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

在这里插入图片描述
简单实现:

cv::Mat MainWindow::regionGrowFast(const cv::Mat &src, const cv::Point2i seed, int throld)
{
    //convert src to gray for getting gray value of every pixel
    cv::Mat gray;
    cv::cvtColor(src,gray, cv::COLOR_RGB2GRAY);

    // set every pixel to black
    cv::Mat result = cv::Mat::zeros(src.size(), CV_8UC1);
    if((seed.x < 0) || (seed.y < 0))
        return result;
    result.at<uchar>(seed.y, seed.x) = 255;

    //gray value of seed
    int seed_gray = gray.at<uchar>(seed.y, seed.x);
    //grow direction sequenc
    int grow_direction[8][2] = {{-1,-1}, {0,-1}, {1,-1}, {1,0}, {1,1}, {0,1}, {-1,1}, {-1,0}};
    //seeds collection
    std::vector<cv::Point2i> seeds;
    seeds.push_back(seed);

    //start growing
    while(! seeds.empty()){
        //get a seed
        cv::Point2i current_seed = seeds.back();
        seeds.pop_back();

        for(int i = 0; i < 8; ++i){
            cv::Point2i neighbor_seed(current_seed.x + grow_direction[i][0], current_seed.y + grow_direction[i][1]);
            //check wether in image
            if(neighbor_seed.x < 0 || neighbor_seed.y < 0 || neighbor_seed.x > (gray.cols-1) || (neighbor_seed.y > gray.rows -1))
                continue;
            int value = gray.at<uchar>(neighbor_seed.y, neighbor_seed.x);
            if((result.at<uchar>(neighbor_seed.y, neighbor_seed.x) == 0) && (abs(value - seed_gray) <= throld)){
                result.at<uchar>(neighbor_seed.y, neighbor_seed.x) = 255;
                seeds.push_back(neighbor_seed);
            }
        }
    }
    return result;
}

3.区域生长算法的一种C++实现

首先,定义种子点的类

class Point2D
{
public:
    Point2D(){}
    Point2D(int ix,int iy)
    {
        this->x=ix;
        this->y=iy;
    }

    ~Point2D(){}
    Point2D operator+(const Point2D& a)const
    {
        return Point2D(x+a.x,y+a.y);
    }
    Point2D operator-(const Point2D& a)const
    {
        return Point2D(x-a.x,y-a.y);
    }
    bool operator=(const Point2D& a)
    {
        return(x==a.x&&y==a.y);
    }
    int x;
    int y;

然后,定义种子点的邻域信息

const Point2D PointShift2D[8]=
{
    Point2D(1,0),
    Point2D(1,-1),
    Point2D(0,-1),
    Point2D(-1,-1),
    Point2D(-1,0),
    Point2D(-1,1),
    Point2D(0,1),
    Point2D(1,1)
};

然后,定义区域生长算法类的头文件

class RegionGrowing
{
public:
    RegionGrowing();
    ~RegionGrowing();
    void SetInputData(chat *pData,int width,int height);
    void SetSeedPoint(Point2D &p);
    void SetThreshold(int low,int height);
    bool RegionGrow2D();
    char* GetOutput();
private:
    int LowThreshold;
    int HighThreshold;
    int Width;
    int Height;
    char *InputData;
    char *OutputData;
    Point2D SeePoint;
}

然后,是区域生长算法类的实现

#include"RegionGrowing.h"
#include<stack。

RegionGrowing::RegionGrowing()
{
    this->InputData=nullptr;
    this->OutputData=nullptr();
}
RegionGrowing::~RegionGrowing()
{

}
void RegionGrowing::SetInputData(char *pData,int width,int height)
{
    this->InputData=pData;
    this->Width=width;
    this->Height=height;
}
void RegionGrowing::SetSeedPoint(Point2D &p)
{
    this->SeedPoint=p;
}
void RegionGrowing::SetThreshold(int low,int high)
{
    this->LowThreshold=low;
    this_HighThreshold=high;
}
bool RegionGrowing::RegionGrow2D()
{
    if(this->InputData==nullptr||this->OutputData==nullptr)
    {
        return false;
    }
    int index=this->SeedPoint.y*this->Width+this->SeedPoint.x;
    int seedValue=this->InputData[index];
    std::stack<Point2D>pointStack;
    pointStack.push(this->SeedPoint);
    memset(this->OutputData,0,sizeof(char)*this->Width*this-Height);
    
    while(!pointStack.empty())
    {
        Point2D topPoint=pointStack.top();
        pointStack.pop();
        for(int i=0;i<8;i++)
        {
            Point2D  p=topPoint+PointShift2D[i];
            index=p.y*this->width+p.x;
            if(this->InputData[index]>this->LowThreshold&&
                this->InputData[index]<this->HighThreshold&&
                this->OutputData[index]==0)
            {
                this->OutputData[index]=126;
                pointStack.push(p);
            }
        }
    }
    return true;
}
char* RegionGrowing::GetOutput()
{
    return this->OutputData;
}

参考:https://blog.csdn.net/robin__chou/article/details/50071313
https://www.cnblogs.com/xuhui24/p/6262011.html
https://blog.csdn.net/webzhuce/article/details/81412508

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

明月醉窗台

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值