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

coder_Alaric广东

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区域,对于分割复杂的图像具有比较好的性能和效果,但其算法的迭代性,导致其在运算时的时间和内存的开销比较大,当噪声和灰度不均一的时候可能会出现过度分割,而且不太适合较大图像的运算场景。
项目代码下载

阅读 183
4 声望
3 粉丝
0 条评论
4 声望
3 粉丝
宣传栏