c++ 图像处理(十三)分水岭算法实现

分水岭算法实现

原理:以后再补

代码:

void* Watershed(QImage &image,QImage &gradiant)
{

    int width = image.width();
    int height = image.height();
    int all_size = height * width;
    int Num;
    int w,h;
    int p_conn[8][2] = {{0,-1},{-1,-1},{-1,0},{-1,1},{0,1},{1,1},{1,0},{1,-1}};
    bool p_condition[8];


    QVector<int> seedimage(all_size);
    QVector<int> labelimage(all_size);
    QVector<int> originalimage(all_size);


    QVector<queue<Point>*> vque;
    //QVector<int> vque(900 * all_size);


    queue<Point> *pque;

    queue<int>  qqp;


    queue<Point> qpt;  //队列


    //vector<int*>SeedCounts;//保持每个队列种子个数的数组
    QVector<QVector<int>> seedcounts;
    QVector<int> seed_array(256);


    Point temp;
    int x,y;


    int currindex;
    Num = 0;
    for(y = 0 ;y<height; y++)
    {
        for(x = 0; x<width; x++)
        {
            currindex = y*width + x;
            seedimage[currindex] = (qGray(image.pixel(x,y)) > 0) ? 255 : -1;
            labelimage[currindex] = 0;
            originalimage[currindex] = qGray(gradiant.pixel(x,y));
        }
    }




    int i,j;
    //初始连通盆地
    for(i = 0 ;i<height; i++)
    {
        for(j = 0; j<width; j++)
        {
            currindex = i*width + j;

            if(seedimage[currindex] == 255 && originalimage[currindex] == 0)
            {
                temp.x = j;
                temp.y = i;
                qpt.push(temp);

                Num ++;

                seedcounts.append(seed_array);

                pque = new queue<Point>[256];

                vque.push_back(pque);//加入到队列数组中,对应的是本标记号Num的

                seedimage[currindex] = 127;
                labelimage[currindex] = Num;

                cout<<"Num"<<Num<<endl;

                //种子
                while(!qpt.empty())
                {
                    temp = qpt.front();  //取种子

                    //保存取出来的种子
                    x = temp.x;
                    y = temp.y;

                    qpt.pop();  //删掉取出的种子

                    for(int k = 0; k<8; k++)
                    {
                        p_condition[k] = false;
                        h = y + p_conn[k][1];
                        w = x + p_conn[k][0];

                        currindex = h*width + w;
                        if(currindex>=0&&currindex<all_size)
                        {
                            if(seedimage[currindex] == 255 && originalimage[currindex] == 0)
                            {
                                temp.x = w;
                                temp.y = h;
                                qpt.push(temp);
                                seedimage[currindex] = 127 ;
                                labelimage[currindex] = Num ;
                            }else {
                                p_condition[k] = true;

                            }
                        }
                    }

                    //保存连通分量(盆地的所有点)
                    if(p_condition[0] || p_condition[1] || p_condition[2] || p_condition[3] || p_condition[4] || p_condition[5] || p_condition[6] || p_condition[7])
                    {

                        temp.x = x;
                        temp.y = y;


                        //Num-1 区的边界点,也就是Num-1盆地的周围的山的点与高度
                        //第一维度代表Num-1的盆地,第二维度代表的是灰度值的点集合,第三维度就是点空间坐标
                        //[区][灰度值队列].push就是相同灰度的坐标队列

                        currindex = y*width + x;
                        int grey = originalimage[currindex];
                        vque[Num-1][grey].push(temp);
                        seedcounts[Num-1][grey]++;//记录Num - 1区的每个灰度有多少个点,与上面对于

                    }

                }//while

            }//if

             }//forj
        }//fori




    int P_4[4][2] = {{-1,0},{0,-1},{1,0},{0,1}};
    int m,n;
    bool actives;//在某一水位处,所有标记的种子生长完的标志
    //int WaterLevel;
    //淹没过程开始,水位从零开始上升,水位对应灰度级,采用四连通法
    for(int WaterLevel = 0; WaterLevel < 256; WaterLevel++)//第二维,灰度值
    {
        actives = true;
        while(actives)
        {
           actives=false;

           for (int i = 0; i < Num; i++)//第一维,盆地区号
           {

               //对应的分水岭不为空集,i 表示区域号,waterlevel 表示灰阶
                if(!vque[i][WaterLevel].empty())
                {
                   actives = true;
                   while(seedcounts[i][WaterLevel]>0)
                   {
                       seedcounts[i][WaterLevel]--; //取出一个点,个数少一
                       temp=vque[i][WaterLevel].front();    //取出该区域的一个点,清空这个边缘点
                       //灰度级该像素已经处理掉了。
                       vque[i][WaterLevel].pop();

                       //当前的种子坐标
                       m = temp.x;
                       n = temp.y;


                       //四连通
                       for(int k = 0; k<4;k++)
                       {
                           h = n +P_4[k][0];
                           w = m +P_4[k][1];
                           currindex = h * width + w;

                           //不越界
                           if(currindex>=0 && currindex<all_size)
                           {
                               //不是盆地点
                               if(!labelimage[currindex])
                               {
                                   temp.x=w;
                                   temp.y=h;
                                   labelimage[currindex]=i+1;//上方点标记为已淹没区域

                                   if(originalimage[currindex]<=WaterLevel && seedimage[currindex] !=-1)//上方若为可生长点则加入当前队列,当前灰度的队列
                                   {
                                       vque[i][WaterLevel].push(temp);
                                       //SeedCounts[i][WaterLevel]++;
                                   }
                                   else
                                   {
                                       vque[i][originalimage[currindex]].push(temp);
                                       seedcounts[i][originalimage[currindex]]++;
                                   }
                               }
                           }

                       }

                    }//while

                    seedcounts[i][WaterLevel]=vque[i][WaterLevel].size();
                 }//if
            }//for j
        }//for i

    }//while
    /**/


    for(int i = 1;i<height-1; i++)
    {
        for(int j = 1; j<width-1;j++)
        {
           bool s = false,x_ = false,z = false,y_ = false;

           int mu = i*width + j;
           if(labelimage[mu] != labelimage[(i-1)*width +j])
               s = true;
           if(labelimage[mu] != labelimage[(i+1)*width + j])
               x_ = true;
           if(labelimage[mu] != labelimage[i*width + (j-1)])
                z= true;
           if(labelimage[mu] != labelimage[i*width + (j+1)])
               y_ = true;

           if(s || y_ ||x_ ||z)
           {
               image.setPixel(j,i,qRgb(255,0,0));
           }

        }

    }
    /**/
    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值