我有一个图像分割输出,其中我得到了具有不同边界的不同对象。 即我可以在图像上有多个轮廓。 我想写一个算法,它将跟踪所有轮廓并以每个轮廓的连接像素点的形式给出输出。 是否有任何先前为此问题定义的算法?
答案 0 :(得分:0)
是的,在二进制图像处理库中
https://github.com/MalcolmMcLean/binaryimagelibrary
这是一大堆代码
#define CNT_TOPLEFT 0x80
#define CNT_TOPRIGHT 0x40
#define CNT_BOTTOMRIGHT 0x20
#define CNT_BOTTOMLEFT 0x10
#define CNT_RIGHT 1
#define CNT_DOWN 2
#define CNT_LEFT 3
#define CNT_UP 4
static int walkcontour(unsigned char *binary, int width, int height, int x, int y, int dir, double **cx,
double **cy, int *Nret);
/**
Go round a binary image, extracting the contours of the set pixels.
@param[in] binary - the image
@param width - image width
@param height - image height
@param[out] x - return for x co-ordinates of contours (malloced)
@param[out] y - return for y co-ordinates of contours (malloced)
@param[out] Nret - return for contour lengths (malloced)
@returns Number contours found, -1 on out of memory.
*/
int getcontours(unsigned char *binary, int width, int height, double ***x, double ***y, int **Nret)
{
int xi, yi;
int i;
unsigned char neighbours[9];
int N;
double *cx, *cy;
int cN;
void *temp;
double **contourx = 0;
double **contoury = 0;
int *contourN = 0;
int err;
int answer = 0;
int capacity = 0;
for(yi=0;yi<height;yi++)
{
for(xi=0;xi<width;xi++)
{
if(binary[yi*width + xi] & 0x01)
{
get2x2(neighbours, binary, width, height, xi, yi, 0);
N = 0;
for(i=0;i<4;i++)
N += neighbours[i] & 0x01;
if(N != 4)
{
if( (binary[yi*width+xi] & CNT_TOPLEFT) == 0 &&
(neighbours[0] & neighbours[1] & neighbours[3] &0x01) == 0)
{
err = walkcontour(binary, width, height, xi, yi, CNT_RIGHT, &cx, &cy, &cN);
if(err == 0)
{
if(answer >= capacity)
{
capacity = capacity + capacity/2 + 10;
temp = realloc(contourN, capacity * sizeof(int));
contourN = temp;
temp = realloc(contourx, capacity * sizeof(double *));
contourx = temp;
temp = realloc(contoury, capacity * sizeof(double *));
contoury = temp;
}
contourN[answer] = cN;
contourx[answer] = cx;
contoury[answer] = cy;
answer++;
}
}
/*
if( (binary[yi*width+xi] & CNT_TOPRIGHT) == 0 &&
(neighbours[1] & neighbours[2] & neighbours[5] &0x01) == 0)
{
walkcontour(binary, width, height, xi +1, yi, CNT_DOWN, &cx, &cy, &cN);
}
if( (binary[yi*width+xi] & CNT_BOTTOMRIGHT) == 0 &&
(neighbours[5] & neighbours[7] & neighbours[8] &0x01) == 0)
{
walkcontour(binary, width, height, xi, yi+1, CNT_LEFT, &cx, &cy, &cN);
}
if( (binary[yi*width+xi] & CNT_BOTTOMLEFT) == 0)
{
if( (binary[yi*width+xi] & CNT_BOTTOMRIGHT) == 0 &&
(neighbours[5] & neighbours[7] & neighbours[8] &0x01) == 0)
walkcontour(binary, width, height, xi+1, yi+1, CNT_UP, &cx, &cy, &cN);
}
*/
}
}
}
}
for(yi=0;yi<height;yi++)
{
for(xi=0;xi<width;xi++)
binary[yi*width+xi] &= 0x01;
}
*x = contourx;
*y = contoury;
*Nret = contourN;
return answer;
}
static int walkcontour(unsigned char *binary, int width, int height, int x, int y, int dir, double **cx,
double **cy, int *Nret)
{
int N = 0;
int advance;
int capacity = width + 3;
double *xwalk, *ywalk;
double *temp;
unsigned char neighbours[9];
int xi, yi;
int mask;
switch(dir)
{
case CNT_RIGHT: mask = CNT_TOPLEFT; break;
case CNT_DOWN: mask = CNT_TOPRIGHT; break;
case CNT_LEFT: mask = CNT_BOTTOMRIGHT; break;
case CNT_UP: mask = CNT_BOTTOMLEFT; break;
}
mask = CNT_TOPLEFT;
xwalk = malloc(capacity * sizeof(double));
ywalk = malloc(capacity * sizeof(double));
if(!xwalk || ! ywalk)
goto out_of_memory;
xi = x;
yi = y;
while(1)
{
get2x2(neighbours, binary, width, height, xi, yi, 0);
advance = 0;
while(advance == 0)
{
switch(dir)
{
case CNT_RIGHT:
if(neighbours[1] & 0x01)
dir = CNT_UP;
else
advance = 1;
break;
case CNT_DOWN:
if(neighbours[3] & 0x01)
dir = CNT_RIGHT;
else
advance = 1;
break;
case CNT_LEFT:
if(neighbours[2] & 0x01)
dir = CNT_DOWN;
else
advance = 1;
break;
case CNT_UP:
if(neighbours[0] & 0x01)
dir = CNT_LEFT;
else
advance = 1;
break;
}
}
xwalk[N] = xi;
ywalk[N] = yi;
N++;
if(N >= capacity)
{
capacity += capacity/2;
temp = realloc(xwalk, capacity * sizeof(double) );
if(!temp)
goto out_of_memory;
xwalk = temp;
temp = realloc(ywalk, capacity * sizeof(double) );
if(!temp)
goto out_of_memory;
ywalk = temp;
}
advance = 0;
if(yi < height && xi < width)
binary[yi*width+xi] |= CNT_TOPLEFT;
if(yi < height && xi > 0)
binary[yi*width+xi-1] |= CNT_TOPRIGHT;
if(yi > 0 && xi < width)
binary[(yi-1)*width+xi] |= CNT_BOTTOMLEFT;
if(xi > 0 && yi > 0)
binary[(yi-1)*width+xi-1] |= CNT_BOTTOMRIGHT;
switch(dir)
{
case CNT_RIGHT: xi++; break;
case CNT_DOWN: yi++; break;
case CNT_LEFT: xi--; break;
case CNT_UP: yi--; break;
}
get2x2(neighbours, binary, width, height, xi, yi, 0);
while(advance == 0)
{
switch(dir)
{
case CNT_RIGHT:
if( !(neighbours[3] & 0x01))
dir = CNT_DOWN;
else
advance = 1;
break;
case CNT_DOWN:
if(!(neighbours[2] & 0x01))
dir = CNT_LEFT;
else
advance = 1;
break;
case CNT_LEFT:
if(!(neighbours[0] & 0x01))
dir = CNT_UP;
else
advance = 1;
break;
case CNT_UP:
if(!(neighbours[1] & 0x01))
dir = CNT_RIGHT;
else
advance = 1;
break;
}
}
if(yi == y && xi == x && (binary[yi*width+xi] & mask) )
break;
}
*cx = xwalk;
*cy = ywalk;
*Nret = N;
return 0;
out_of_memory:
free(xwalk);
free(ywalk);
*cx = 0;
*cy =0;
*Nret = 0;
return -1;
}