查找多个轮廓的连接像素点

时间:2017-02-15 02:30:33

标签: algorithm image-processing contour

我有一个图像分割输出,其中我得到了具有不同边界的不同对象。 即我可以在图像上有多个轮廓。 我想写一个算法,它将跟踪所有轮廓并以每个轮廓的连接像素点的形式给出输出。 是否有任何先前为此问题定义的算法?

1 个答案:

答案 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;

}