[视觉实战案例]Qt+Halcon实现区域生长算法(坐标种子点+灰度值种子点)

1 算法介绍

区域生长算法:将按照事先定义的生长准则讲一个像素或子区域逐步聚合成一个完整独立的区域的过程。对于图像上某个区域R,p为区域R上指定的一个像素点,称作种子点,按照规定的生长准则逐步将与种子点z一定邻域内符合相似性判据的像素合并成一个种子群以备下一阶段的生长,这样不断的进行循环生长直到满足生长停止条件为止,从而完成了对感兴趣区域由一个种子点生长为一个独立连通区域的过程。

实现步骤

1、在图像区域中选取一个像素点作为一个种子点(x,y)。
2、根据生长规则,判断种子点周围八邻域的哪几个像素点可以作为下次生长的点,判断完后将该点存入生长点Vector,并将当前已用的种子点标记为已使用。
3、按照规则判断下一个生长点。
4、判断生长点vector容器中是否还有生长点,容器为空时结束。

Halcon中区域生长算子

regiongrowing(Image:Regions : Row, Column, Tolerance, MinSize :)
Row:被测试的区域的垂直距离
Column:被测试的区域的水平距离
Tolerance:能忍受的最大的灰度差距
MinSize:最小的输出区域
regiongrowing (Image111, Regions, 2, 2, 4, 100)

Halcon区域生长.JPG

2 起点坐标种子点实现区域生长

在区域生长的算法中,我们需要输入一个已知的坐标点(x,y),以这个点作为起点,这里我们不使用Halcon自带的区域生长算子,而是通过算法的步骤去实现这一功能。
首先获取点击点的像素点灰度值,以这一点为起始点,向八领域按照灰度差值去计算生长点。

坐标点作为种子点.JPG
    HTuple Row,Col,Button;
    GetMbutton(m_hHalconID,&Row,&Col,&Button);
    if(Button == 1)
    {
        HObject ResultRegion;
//        HTuple posGray,GrayRows,GrayCols;
        GetGrayval(CurTestImg,Row, Col,&SelectGray);
        qDebug()<<"Gray"<<SelectGray.I();
        int curGray = SelectGray.I();
        ui->spb_gray->setValue(curGray);
        int index = ui->spb_growIndex->value();
        int posY = Row.I();
        int posX = Col.I();
        QPoint pos(posX,posY);
        RegionGrowing(CurTestImg,ResultRegion,pos,index);
        FillUp(ResultRegion,&ResultRegion);
        UpdateImgWindow();
        ui->PicShow->Region_ShowBuf.clear();
        region_Info h_RegionInfo;
        h_RegionInfo.region = ResultRegion;
        h_RegionInfo.color = "#ff0000c0";
        h_RegionInfo.size = 1;
        ui->PicShow->Region_ShowBuf.push_back(h_RegionInfo);
        ui->PicShow->updateShowInfoOnWindow();
    }

//区域生长算法
void RegionGrowDlg::RegionGrowing(HObject img, HObject &region, QPoint pt,int th)
{
    QPoint ptGrowing;                       //待生长点位置
    HTuple nGrowLable = 0;                              //标记是否生长过
    int nSrcValue = 0;                              //生长起点灰度值
    int nCurValue = 0;                              //当前生长点灰度值
//  matDst = cv::Mat::zeros(src.size(), CV_8UC1);   //创建一个空白区域,填充为黑色
    //生长方向顺序数据
    int DIR[8][2] = { { -1, -1 }, { 0, -1 }, { 1, -1 }, { 1, 0 }, { 1, 1 }, { 0, 1 }, { -1, 1 }, { -1, 0 } };
    std::vector<QPoint> vcGrowPt;                       //生长点栈
    vcGrowPt.push_back(pt);                         //将生长点压入栈中
    //首先设置区域为空
    GenEmptyRegion(&region);
//  matDst.at<uchar>(pt.y, pt.x) = 255;             //标记生长点
    HTuple posGray;
    GetGrayval(img,pt.y(), pt.x(),&posGray);
    nSrcValue = posGray.I();            //记录生长点的灰度值
    qDebug()<<"选择点灰度"<<nSrcValue;
    while (!vcGrowPt.empty())                       //生长栈不为空则生长
    {
        pt = vcGrowPt.back();                       //取出一个生长点
        vcGrowPt.pop_back();

        //分别对八个方向上的点进行生长
        for (int i = 0; i < 8; ++i)
        {
            int ppx = (pt.x() + DIR[i][0]);
            int ppy = (pt.y() + DIR[i][1]);
            ptGrowing = QPoint(ppx,ppy);
            //检查是否是边缘点
            if (ptGrowing.x() < 0 || ptGrowing.y() < 0 || ptGrowing.x() >(hv_Width - 1) || ptGrowing.y() > (hv_Height - 1))
                continue;
            //判断该点是否在region内
//            int nGrowLable;
            TestRegionPoint(region,ptGrowing.y(), ptGrowing.x(),&nGrowLable);
//            HTuple curGray;
//            GetGrayval(img,ptGrowing.y, ptGrowing.x,&curGray);
//          nGrowLable = matDst.at<uchar>(ptGrowing.y, ptGrowing.x);        //当前待生长点的灰度值


            if (nGrowLable == 0)                    //如果标记点还没有被生长
            {
                            HTuple curGray;
                            GetGrayval(img,ptGrowing.y(), ptGrowing.x(),&curGray);
                            nCurValue = curGray.I();
//              nCurValue = src.at<uchar>(ptGrowing.y, ptGrowing.x);
//                if (abs(nSrcValue - nCurValue) < th)
                //在阈值范围内则生长,这里选择灰度在当前灰度值左右th个灰度内
                if (nCurValue >nSrcValue || abs(nSrcValue - nCurValue) < th)
                {
                    HObject PointRegion;
                    GenRegionPoints(&PointRegion,ptGrowing.y(), ptGrowing.x());
                    Union2(PointRegion,region,&region);
//                  matDst.at<uchar>(ptGrowing.y, ptGrowing.x) = 255;       //标记为白色
                    vcGrowPt.push_back(ptGrowing);                  //将下一个生长点压入栈中
                }
            }
        }
    }
}

从函数中可以看出,区域生长算法的输入是图像、坐标点、灰度判定值,输出为生长出来的Region区域。

3 以灰度值作为种子点进行区域生长

相当于将图像中某个灰度值的像素点挑出来作为坐标种子点,然后再进行区域生长算法。这种的效果跟Halcon中局部阈值的var_threshold的效果类似。

灰度值作为种子点.gif

void RegionGrowDlg::on_spb_growIndex_valueChanged(int arg1)
{
    HObject Region,ResultRegion;
    HTuple GrayRows,GrayCols;
    int curGray = ui->spb_gray->value();
    Threshold(CurTestImg,&Region,curGray,curGray);
    GetRegionPoints(Region,&GrayRows,&GrayCols);
    GenEmptyRegion(&ResultRegion);
    for(int i=0;i<GrayRows.Length();i++)
    {
        HTuple isInside;
        int posY = GrayRows[i].I();
        int posX = GrayCols[i].I();
        TestRegionPoint(ResultRegion,posY,posX,&isInside);
        if(isInside == 1){
            continue;
        }
        else
        {
            HObject GrowRegion;
            QPoint pos(posX,posY);
            RegionGrowing(CurTestImg,GrowRegion,pos,arg1);
            Union2(GrowRegion,ResultRegion,&ResultRegion);
        }
    }
    FillUp(ResultRegion,&ResultRegion);
    UpdateImgWindow();

    ui->PicShow->Region_ShowBuf.clear();
    region_Info h_RegionInfo;
    h_RegionInfo.region = ResultRegion;
    h_RegionInfo.color = "#ff0000c0";
    h_RegionInfo.size = 1;
    ui->PicShow->Region_ShowBuf.push_back(h_RegionInfo);
    ui->PicShow->updateShowInfoOnWindow();
}

void RegionGrowDlg::on_spb_gray_valueChanged(int arg1)
{
    HObject Region,ResultRegion;
    HTuple GrayRows,GrayCols;
    Threshold(CurTestImg,&Region,arg1,arg1);
    GetRegionPoints(Region,&GrayRows,&GrayCols);
    GenEmptyRegion(&ResultRegion);
    int index = ui->spb_growIndex->value();
    for(int i=0;i<GrayRows.Length();i++)
    {
        HTuple isInside;
        int posY = GrayRows[i].I();
        int posX = GrayCols[i].I();
        TestRegionPoint(ResultRegion,posY,posX,&isInside);
        if(isInside == 1){
            continue;
        }
        else
        {
            HObject GrowRegion;
            QPoint pos(posX,posY);
            RegionGrowing(CurTestImg,GrowRegion,pos,index);
            Union2(GrowRegion,ResultRegion,&ResultRegion);
        }
    }
    FillUp(ResultRegion,&ResultRegion);
    UpdateImgWindow();

    ui->PicShow->Region_ShowBuf.clear();
    region_Info h_RegionInfo;
    h_RegionInfo.region = ResultRegion;
    h_RegionInfo.color = "#ff0000c0";
    h_RegionInfo.size = 1;
    ui->PicShow->Region_ShowBuf.push_back(h_RegionInfo);
    ui->PicShow->updateShowInfoOnWindow();
}

4 总结

区域生长算法的核心思想是将由相似性质的像素点合并到一个region区域,对于分割复杂的图像具有比较好的性能和效果,但其算法的迭代性,导致其在运算时的时间和内存的开销比较大,当噪声和灰度不均一的时候可能会出现过度分割,而且不太适合较大图像的运算场景。
项目代码下载

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,463评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,868评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,213评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,666评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,759评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,725评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,716评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,484评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,928评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,233评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,393评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,073评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,718评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,308评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,538评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,338评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,260评论 2 352

推荐阅读更多精彩内容