时间:2020-12-07
1. 流程简述
算法流程:
- 选取种子点
p(x0,y0)
,用堆栈表示种子区域,将种子点push
到种子堆栈中; - 将种子堆栈中第一个种子点
pop
出堆栈,并以该点为中心,遍历该中心8邻域像素; - 判断遍历像素点是否已经在种子区域中
3.1 是,continue
;
3.2 否,检查点p(x,y)
和种子区域的均值refAvg
灰度差是否满足阈值;若满足,将p(x, y)
push
到堆栈中;若不满足,continue
; - 计算新的种子区域的均值
refAvg
,找出离上一个种子"最近"的seed
,更新堆栈顺序; - 重复步骤 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;
}