这一节讲traceedge函数,从字面翻译,显然和边缘痕迹相关,也有人叫他染色嵌套函数,借用别人的指点,这种编程方法对图像中具有相同性质(灰度值等)的联通区域进行染色操作是很有用的。
是的,正是这个traceedge函数的启示,我领悟了找斑函数(findblob),因为我爷爷辈是染布的,后来自己的找斑函数就命名为染色函数,以兹纪念。
以下都是我调试成功,久经考验的函数:
网上traceedge函数的第一种表达(c++),
void TraceEdge(int y, int x, int nThrLow, BYTE *pResult, int *pMag, SIZE sz)
{ //TraceEdge(i(h), j(w), dThrLow, N, M, sz);sz.cx=w;sz.cy=h
//对8邻域像素进行查询
int xNum[8] = {1,1,0,-1,-1,-1,0,1};
int yNum[8] = {0,1,1,1,0,-1,-1,-1};
LONG yy,xx,k;
for(int k=0;k<8;k++)
{
yy = y+yNum[k];
xx = x+xNum[k];
if(pResult[(yy*sz.cx+xx)*4]==128 && pMag[yy*sz.cx+xx]>=nThrLow )
{
//该点设为边界点
pResult[(yy*sz.cx+xx)*4] = 255;
pResult[(yy*sz.cx+xx)*4+1] = 255;
pResult[(yy*sz.cx+xx)*4+2] = 255;
pResult[(yy*sz.cx+xx)*4+3] = 255;
//以该点为中心再进行跟踪
TraceEdge(yy,xx,nThrLow,pResult,pMag,sz);
}
}
}
网上traceedge函数的第二种表达(c++),
void TraceEdge(int y, int x, int nThrLow, BYTE *pResult, int *pMag, SIZE sz)
{ //TraceEdge(i(h), j(w), dThrLow, N, M, sz);sz.cx=w;sz.cy=h
//癸8綟办琩т
//int xNum[8] = {1,1,0,-1,-1,-1,0,1};
//int yNum[8] = {0,1,1,1,0,-1,-1,-1};
//LONG yy,xx/*,k*/;
//for(int k=0;k<8;k++)
//{
// yy = y+yNum[k];
// xx = x+xNum[k];
// if(pResult[(yy*sz.cx+xx)]==128 && pMag[yy*sz.cx+xx]>=nThrLow )
// {
// pResult[(yy*sz.cx+xx)] = 255;
// TraceEdge(yy,xx,nThrLow,pResult,pMag,sz);
// }
//}
int i,j;//2013.8.29
for(i=-1;i<2;i++)
for(j=-1;j<2;j++)//这里没考虑图像4边界情况,因为边界灰度都事先设为0。不可能是128
if(pResult[(y+i)*sz.cx+x+j]==128&&pMag[(y+i)*sz.cx+x+j]>nThrLow)
{
pResult[(y+i)*sz.cx+x+j]=255;
TraceEdge(y+i,x+j,nThrLow,pResult,pMag,sz);
}
}
这是我c#的改进算法:以上使用嵌套递归,这里使用堆栈。
private void TraceEdge(int y, int x, int nThrLow, ref byte[,] pResult, ref int[,] pMag)
{
Point start = new Point(x, y);
Stack<Point> s = new Stack<Point>();
int[] xNum = new int[8] { 1, 1, 0, -1, -1, -1, 0, 1 };
int[] yNum = new int[8] { 0, 1, 1, 1, 0, -1, -1, -1 };
long xx = 0, yy = 0;
s.Push(start);
do
{
//Point pt1 = s.ElementAt(0);
Point pt1 = s.Peek();
s.Pop();
for (int k = 0; k < 8; k++)
{
yy = y + yNum[k];
xx = x + xNum[k];
if (pResult[yy, xx] == 128 && pMag[yy, xx] >= nThrLow)
{
pResult[yy, xx] = 255;
Point pt = new Point((int)xx, (int)yy);
s.Push(pt);
}
}
} while (s.Count != 0);
}
以下是我的发展而来的findblob(找斑)函数(c++),C#博文中已经存在(染色函数),此处略去,但可以对比着看
void CBufferBase::FindBlob(BYTE *tempImage,int w,int h)//process binary image.8 bits one pixel.
{
for(int i=0;i<h;i++)
for(int j=0;j<w;j++)
{
if(tempImage[i*w+j]>128)
{
tempImage[i*w+j]=0;
}
else
{
tempImage[i*w+j]=128;
}
}
CPoint start;
for(int m=0;m<h;m++)
for(int n=0;n<w;n++)
{
if(tempImage[m*w+n]==128)
{
start.x=n;
start.y=m;
break;
}
}
stack<CPoint> s;
//癸8綟办琩т
int xNum[8] = {1,1,0,-1,-1,-1,0,1};
int yNum[8] = {0,1,1,1,0,-1,-1,-1};
LONG yy=0,xx=0;
tempImage[ start.y*w+start.x ]=255;
s.push(start);
do{
CPoint pt1=s.top();
s.pop();
for(int k=0;k<8;k++)
{
yy = pt1.y+yNum[k];
xx =pt1. x+xNum[k];
if(tempImage[(yy*w+xx)]==128)
{
tempImage[(yy*w+xx)] = 255;
CPoint pt(xx,yy);
s.push(pt);
}
}
}while(!s.empty());
}
没有谁能一次成功,只是跟着遛弯久了,自然就通透了。