图像分割之区域生长算法

时间:2020-12-07

1. 流程简述

算法流程:

  1. 选取种子点p(x0,y0),用堆栈表示种子区域,将种子点push到种子堆栈中;
  2. 将种子堆栈中第一个种子点pop出堆栈,并以该点为中心,遍历该中心8邻域像素;
  3. 判断遍历像素点是否已经在种子区域中
    3.1 是,continue
    3.2 否,检查点p(x,y)和种子区域的均值refAvg灰度差是否满足阈值;若满足,将p(x, y) push到堆栈中;若不满足,continue
  4. 计算新的种子区域的均值refAvg,找出离上一个种子"最近"的seed,更新堆栈顺序;
  5. 重复步骤 2-3-4,直至种子堆栈为空。

3. 源码

源码v1.0,目前存在的问题是:

  • 生长过程中,以下代码只会寻找下一个种子(仅一个),取决于迭代的顺序。最终,可能导致分割效果不同。

  • 另一个问题是阈值的选择问题。

修改策略:自适应阈值?全局迭代?后续补充v2.0

int negihborRegionCheck(
    unsigned char   *pSrc,
    unsigned char   *pDst,
    seedInfo_t      *seedPts,
    unsigned int    *seedCnt,
    imageSize_t     srcSize,
    unsigned char   threshold
) {

    if (nullptr == pSrc || nullptr == pDst || nullptr == seedPts || nullptr == seedCnt ||
        srcSize.width <= 0 || srcSize.height <= 0) {
        // input err.
        return -1;
    }

    // malloc buffer for seed list.
    seedInfo_t *listSeedPts = (seedInfo_t *)malloc(sizeof(seedInfo_t) * MAX_SEED_NUM);

    // get seedPts[]
    memcpy(listSeedPts, seedPts, sizeof(seedInfo_t) * (*seedCnt));

    // get 1-st seed pts.
    int numRegSeedList = *seedCnt;
    
    int resBoundary = 0;
    int nbPts[8][2] = { {-1, -1},
                        { 0, -1},
                        { 1, -1},
                        {-1,  0},
                        { 1,  0},
                        {-1,  1},
                        { 0,  1},
                        { 1,  1} };

    // get region mean.
    float refAvg = listSeedPts[0].var;

    while (numRegSeedList > 0) {
#ifdef ENABLE_OPENCV
        cv::Mat ori(srcSize.height, srcSize.width, CV_8UC1, (void *)pSrc);
        cv::Mat dst(srcSize.height, srcSize.width, CV_8UC1, (void *)pDst);
#endif
        // pop a seed.
        int x = listSeedPts[0].pts.x;
        int y = listSeedPts[0].pts.y;
        pDst[y * srcSize.width + x] = 255;  // mark seed.
        
        // iter stack.
        for (int k = numRegSeedList - 1; k > 0; k--) {
            listSeedPts[k - 1] = listSeedPts[k];
        }

        listSeedPts[numRegSeedList - 1].pts.x = 0;
        listSeedPts[numRegSeedList - 1].pts.y = 0;
        listSeedPts[numRegSeedList - 1].var = 0;

        numRegSeedList -= 1;

        for (int i = 0; i < 8; i++) {
            unsigned int xn = x + nbPts[i][0];
            unsigned int yn = y + nbPts[i][1];

            resBoundary = ((xn >= 0) && (xn <= srcSize.width - 1) &&
                           (yn >= 0) && (yn <= srcSize.height - 1));

            if (resBoundary && pDst[yn * srcSize.width + xn] == 0) {
                if (fabs(pSrc[yn * srcSize.width + xn] - refAvg) <= threshold) {
                    pDst[yn * srcSize.width + xn] = 255;
                    
                    // add seed to list, push pts in stack.
                    listSeedPts[numRegSeedList].pts.x = xn;
                    listSeedPts[numRegSeedList].pts.y = yn;
                    listSeedPts[numRegSeedList].var = pSrc[yn * srcSize.width + xn];

                    numRegSeedList += 1;
                }
            }
        }

        // find next seed.
        int idx = 0;
        int minVar = 255;
        float sumReg = pSrc[y * srcSize.width + x];

        for (int i = 0; i < numRegSeedList; i++) {
            if (minVar >= fabs(pSrc[y * srcSize.width + x] - listSeedPts[i].var)) {
                minVar = fabs(pSrc[y * srcSize.width + x] - listSeedPts[i].var);
                idx = i;
            }
            sumReg += listSeedPts[i].var;
        }

        if (sumReg > 0 && numRegSeedList > 0) {
            refAvg = sumReg / (numRegSeedList + 1);
        }

        // update list (swap element).
        if (idx > 0) {
            int tempVar = listSeedPts[0].var;
            int tempX = listSeedPts[0].pts.x;
            int tempY = listSeedPts[0].pts.y;

            listSeedPts[0].var = listSeedPts[idx].var;
            listSeedPts[0].pts.x = listSeedPts[idx].pts.x;
            listSeedPts[0].pts.y = listSeedPts[idx].pts.y;

            listSeedPts[idx].var = tempVar;
            listSeedPts[idx].pts.x = tempX;
            listSeedPts[idx].pts.y = tempY;
        }
    }


    if (listSeedPts) {
        free(listSeedPts);
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值