先看对比图,第一张图是轮廓线间太离散,
第二张图,使用二邻域插值后,离散轮廓基本已经连接起来了,我给这个技术起了个名字,相邻感知,如果你知道草履虫,草履虫全身长满纵行排列的纤毛,这些纤毛有感知周围事物的能力,如果上面的每一个离散的轮廓线是有感知的草履虫,那么这些离散的轮廓就能连起来。一样东西能有感知能力,是多么神奇的事情!
以前,我们常用的技术是,用8邻域去找轮廓,找斑(blob),以中心为主的九宫格,3*3的模板用了不计多少。
其实,这个技术也没什么创新,扩展了九宫格,关键是他有了感知能力,这却是非凡的。我们常用的如下:
int[] xNum = new int[] { 1, 1, 0, -1, -1, -1, 0, 1 };
int[] yNum = new int[] { 0, 1, 1, 1, 0, -1, -1, -1 };
我们扩展后是这样的:
int[] xNum = new int[] { -2, -1, 0, 1, 2, 2, 2, 2,2,1,0,-1,-2,-2,-2,-2 };
int[] yNum = new int[] { -2, -2, -2, -2, -2, -1, 0, 1,2,2,2,2,2,1,0,-1 };
当我们有了一些离散的轮廓短线,我们让这个二邻域感知器,顺着轮廓短线的每个像素爬虫般,探测外围16个点,如果有感知,即标记出来,并且把断开的点插入,插入点一定是上面八邻域其中一个,比如,感知到(-2,2)点,断开了,要连起来,必须插入的点是(-2/2,2/2),如果是自己轮廓短线的点,掠过,遍历完短线,继续下一个轮廓短线,这样整图处理完,相当多的轮廓短线就变得连续了。
这种处理,很多离散的特征就可以连成一个完整的特征,很方便找斑点(blob)的工作。
bool 点在序列中(Point cur, List<Point> hello)
{
for (int i = 0; i < hello.Count; i++)
{
if (hello[i].X == cur.X && hello[i].Y == cur.Y)
{
return true;
}
}
return false;
}
下面是c#示范代码:(图像是白中黑,255是背景,0是特征线条,插入值为0)
int[] xNum = new int[] { -2, -1, 0, 1, 2, 2, 2, 2,2,1,0,-1,-2,-2,-2,-2 };
int[] yNum = new int[] { -2, -2, -2, -2, -2, -1, 0, 1,2,2,2,2,2,1,0,-1 };
List<Point> jilu = new List<Point>();
int yy = 0, xx = 0;
for (int x = 0; x < 离散短线.Count; x++)
{
List<Point> 实验 = 离散短线[x];// List<List<Point>>
for (int i = 0; i < 实验.Count; i++)
for (int j = 0; j < 16; j++)//一周二邻域内
{
xx = 实验[i].X + xNum[j];
yy = 实验[i].Y + yNum[j];
int nn = yy * 图像宽度 + xx;
int grayValue = outimgN[nn];
//如果感知到不在短线上,又在二邻域范围内,记录并插值
if (!点在序列中(new Point(xx, yy), 实验) && grayValue == 0)//白底黑斑
{
if (jilu.Count == 0)
{
jilu.Add(new Point(xx, yy));//植入中间空缺的点在outimgN202210131636
int 插入点位置 = (实验[i].Y + (int)(yNum[j] / 2f)) * 图像宽度 + 实验[i].X + (int)(xNum[j] / 2f);
outimgN[插入点位置] = 0;//白底黑斑
}
else
{
if (jilu[jilu.Count - 1].X != xx && jilu[jilu.Count - 1].Y != yy)
{
jilu.Add(new Point(xx, yy));//有重复记录的情况,很少,影响不大
int 插入点位置 = (实验[i].Y + (int)(yNum[j] / 2f)) * 图像宽度 + 实验[i].X + (int)(xNum[j] / 2f);
outimgN[插入点位置] = 0;//白底黑斑
}
}
}
}
}