图像处理之轮廓跟踪算法及圆提取-代码

 一些基本函数


int icvCodeDeltas[][2] = {{1, 0}, {1, -1}, {0, -1}, {-1, -1}, {-1, 0}, {-1, 1}, {0, 1}, {1, 1}};

int DeltasChangeTab[] = {4, 5, 6, 7, 0, 1, 2, 3};


typedef struct
{
    short i;
    short j;
    short DeltasNum;
} _Point;



inline _Point GetPoint8(int i, int j, int num)
{
    _Point p;
    p.i = i + icvCodeDeltas[num][0];
    p.j = j + icvCodeDeltas[num][1];
    p.DeltasNum = num;
    return p;
}

inline int GetPoint8NBD(char data[][WIDTH], int i, int j, int num)
{
    int _i = i + icvCodeDeltas[num][0];
    int _j = j + icvCodeDeltas[num][1];
    if (_i < 0 || _j < 0)
        return 0;
    if (_i >= HEIGHT || _j >= WIDTH)
        return 0;

    return data[_i][_j];
}

inline int Get8Pos(_Point *cent, _Point *p)
{
    int di = p->i - cent->i;
    int dj = p->j - cent->j;
    for (int n = 0; n < 8; n++)
    {
        if (di == icvCodeDeltas[n][0] && dj == icvCodeDeltas[n][1])
        {
            return n;
        }
    }

    return -1;
}

 查找内外轮廓

//p 二维二值化图片
int findContour(char *p, float d_error, int min, int max, int log_show)
{
    bool object = false;
    bool flag = false;
    int circle_cnt = 0;

    //用于查找单条轮廓的临时变量

    // uint16_t contour_i[CONTOUR_MAX_LENGTH];
    // uint16_t contour_j[CONTOUR_MAX_LENGTH];

    uint16_t contour_len = 0;

    char(*nbd)[WIDTH] = (char(*)[WIDTH])p;
    //查找起点
    _Point I0; //轮廓起点
    _Point I1; //轮廓的终点
    _Point I2; //轮廓 上一个点
    _Point I3; //轮廓 8领域中点
    _Point I4; // 8领域找到的下一个点

    for (int i = 1; i < HEIGHT - 1; i++)
    {
        for (int j = 1; j < WIDTH - 1; j++)
        {
            if (nbd[i][j] == 1 && nbd[i][j - 1] == 0) //找到轮廓起点
            {
                nbd[i][j] |= 2;
                I0.i = i;
                I0.j = j;

                // log("find outer %d\t[%d,%d]\r\n", contour_outr++, i, j);

                contour_init;
                contour_app(i, j);
                //找终点 I1

                if (GetPoint8NBD(nbd, i, j, 6) != 0)
                {
                    I1 = GetPoint8(i, j, 6);
                }
                else if (GetPoint8NBD(nbd, i, j, 7) != 0)
                {
                    I1 = (GetPoint8(i, j, 7));
                }
                else if (GetPoint8NBD(nbd, i, j, 0) != 0)
                {
                    I1 = (GetPoint8(i, j, 0));
                }
                else if (GetPoint8NBD(nbd, i, j, 1) != 0)
                {
                    I1 = (GetPoint8(i, j, 1));
                }
                else
                {
                    // nbd[i][j] = 0; //删除
                    //无效的起始点
                    continue;
                }

                nbd[I1.i][I1.j] |= 2;

                flag = false;
                //查找I2
                int deltas = I1.DeltasNum;
                for (int n = 0; n < 8; n++)
                {
                    deltas = (deltas - 1) & 7;
                    if (GetPoint8NBD(nbd, I0.i, I0.j, deltas) >= 1)
                    {
                        I2 = (GetPoint8(I0.i, I0.j, deltas));
                        flag = true;
                        break;
                    }
                }

                // printf("I0(%d,%d)  I1(%d,%d)%d  I2(%d,%d)%d",I0.i,I0.j,I1.i,I1.j,I1.DeltasNum,I2.i,I2.j,I2.DeltasNum);

                if (flag == false)
                {
                    // printf("I2 invalid\r\n");
                    continue; //位置无效
                }

                nbd[I2.i][I2.j] |= 2;
                contour_app(I2.i, I2.j);

                //设置I3
                if (I2.DeltasNum == I1.DeltasNum) //独立的两个点 I0 I1 , I1 I2未同一个点
                {
                    I2 = I0;
                    I3 = I1;                                      //交换中心点
                    I2.DeltasNum = DeltasChangeTab[I1.DeltasNum]; //交互相对位置
                                                                  // single_list_flag = true;
                                                                  //	contour_init;
                }
                else
                {
                    I3 = I2;
                    I2 = I0;
                    I2.DeltasNum = DeltasChangeTab[I3.DeltasNum];
                }

                //起点过后 开始查找链表
                // printf("# i,j=%d,%d\r\n", i, j);
                // DeltasNum 已针对I3中点更新
                while (true)
                {
                    //  vTaskDelay(2);
                    flag = false;
                    //查找I4 下一个目标点
                    deltas = I2.DeltasNum;
                    for (int n = 0; n < 8; n++)
                    {
                        deltas = (deltas - 1) & 7;
                        int tmp = GetPoint8NBD(nbd, I3.i, I3.j, deltas);
                        if ((tmp & 0x01) == 0x01)
                        {
                            I4 = GetPoint8(I3.i, I3.j, deltas); //找到下一个点
                            flag = true;
                            break;
                        }
                    }

                    if (flag == false)
                    {
                        break; //位置无效
                    }
                    if (I4.i == I0.i && I4.j == I0.j)
                    {
                        break;
                        // return;
                    }
                    //交换 I2 I3
                    if (I4.DeltasNum == I2.DeltasNum) // 找到孤立点
                    {
                        //饶了一圈回来了 说明该点是端点 结束继续查找
                        nbd[I4.i][I4.j] |= 2;

                        contour_app(I4.i, I4.j);

                        I2 = I3;
                        I3 = I4;
                        I2.DeltasNum = DeltasChangeTab[I4.DeltasNum];
                    }
                    else
                    {
                        nbd[I4.i][I4.j] |= 2;

                        contour_app(I4.i, I4.j); //单链不算入链条长度里面
                        I2 = I3;
                        I3 = I4;
                        I2.DeltasNum = DeltasChangeTab[I4.DeltasNum];
                    }
                }
            }
            else if (nbd[i][j] == 1 && nbd[i][j + 1] == 0) //内边界
            {
                //  log("find iner%d\t[%d,%d]\r\n", contour_iner++, i, j);

                nbd[i][j] |= 4;
                I0.i = i;
                I0.j = j;
                contour_init;
                contour_app(i, j);

                int cou_length = 0;
                //找终点 I1

                if (GetPoint8NBD(nbd, i, j, 6) != 0)
                {
                    I1 = (GetPoint8(i, j, 6));
                }
                else if (GetPoint8NBD(nbd, i, j, 5) != 0)
                {
                    I1 = (GetPoint8(i, j, 5));
                }
                else if (GetPoint8NBD(nbd, i, j, 4) != 0)
                {
                    I1 = (GetPoint8(i, j, 4));
                }
                else if (GetPoint8NBD(nbd, i, j, 3) != 0)
                {
                    I1 = (GetPoint8(i, j, 3));
                }
                else
                {
                    // nbd[i][j] = 0; //删除
                    //无效的起始点
                    continue;
                }
                flag = false;
                //查找I2
                int deltas = I1.DeltasNum;
                for (int n = 0; n < 8; n++)
                {
                    deltas = (deltas + 1) & 7;
                    if (GetPoint8NBD(nbd, I0.i, I0.j, deltas) != 0)
                    {
                        I2 = (GetPoint8(I0.i, I0.j, deltas));
                        flag = true;
                        break;
                    }
                }

                if (flag == false)
                {
                    // printf("-I2 invalid\r\n");
                    continue; //位置无效
                }

                nbd[I2.i][I2.j] |= 4;
                contour_app(I2.i, I2.j);

                //设置I3
                if (I2.DeltasNum == I1.DeltasNum) //独立的两个点 I0 I1 , I1 I2未同一个点
                {
                    I2 = (I0);
                    I3 = (I1);                                    //交换中心点
                    I2.DeltasNum = DeltasChangeTab[I1.DeltasNum]; //交互相对位置
                }
                else
                {
                    I3 = (I2);
                    I2 = (I0);
                    I2.DeltasNum = DeltasChangeTab[I3.DeltasNum];
                }

                //起点过后 开始查找链表
                //  printf("o i,j=%d,%d\r\n", i, j);
                // DeltasNum 已针对I3中点更新
                while (true)
                {
                    // vTaskDelay(2);
                    flag = false;
                    //查找I4 下一个目标点
                    deltas = I2.DeltasNum;
                    for (int n = 0; n < 8; n++)
                    {
                        deltas = (deltas + 1) & 7;
                        if (GetPoint8NBD(nbd, I3.i, I3.j, deltas) != 0)
                        {
                            I4 = (GetPoint8(I3.i, I3.j, deltas)); //找到下一个点
                            flag = true;
                            break;
                        }
                    }
                    if (flag == false)
                    {
                        break; //位置无效
                    }

                    // printf("* I4 i,j=%d,%d\r\n", I4.i, I4.j);
                    cou_length++;

                    if (I4.i == I0.i && I4.j == I0.j)
                    {
                        // printf("outer %d len %d\r\n", contour_iner, cou_length);

                        // contour_signal_clear(nbd, contour_i, contour_j, contour_len);

#if 1
                        contour_len = contour_signal_clear(nbd, contour_i, contour_j, contour_len);
                        if (contour_len > FILTER_CONTOUR)
                        {
                            _Point center;
                            printf("\r\n");
                            int area = getContourArea(contour_i, contour_j, contour_vaild, contour_len, &center);
                            if (area > 10)
                            {
                                int length = getContourLength(contour_i, contour_j, contour_vaild, contour_len);
                                float d1 = 2 * sqrt(area / PARAM_PI);
                                float d2 = length / PARAM_PI;
                                float error = fabs(d2 - d1) / d1;
                                // printf("contour >  %d   %d %.2f %.2f (%d %d)\r\n", area, length, d1, d2, center.j, center.i);
                                if (error < d_error)
                                {
                                    contour_set_circle; //圆形外轮廓
                                                        // getCirclePoint(contour_i, contour_j, contour_vaild, contour_len);

                                    nbd[center.i][center.j] |= 0x40; //圆心坐标

                                    if (d1 >= min && d1 <= max)
                                    {
                                        printf(">circle:%d d:%.2f (%d,%d) e:%.2f\r\n", circle_cnt, d1, center.i, center.j, error);
                                        circle_cnt++;
                                    }
                                    if (log_show)
                                        printf("error= %.2f area=%d length=%d d1=%.2f d2=%.2f [%d]\t<<<YES>>>(%d,%d)\r\n", error, area, length, d1, d2, contour_len, center.i, center.j);
                                }
                                else
                                {
                                    if (log_show)
                                        printf("error= %.2f area=%d length=%d d1=%.2f d2=%.2f [%d]\r\n", error, area, length, d1, d2, contour_len);
                                }
                            }
                        }
#endif

                        break;
                    }

                    //交换 I2 I3
                    if (I4.DeltasNum == I2.DeltasNum) //独同一个点 那说明找完了整条轮廓
                    {
                        //饶了一圈回来了 说明该点是端点 结束继续查找

                        contour_app(I4.i, I4.j);
                        I2 = (I3);
                        I3 = (I4);
                        I2.DeltasNum = DeltasChangeTab[I4.DeltasNum];
                    }
                    else
                    {
                        nbd[I4.i][I4.j] |= 4;
                        contour_app(I4.i, I4.j);
                        I2 = (I3);
                        I3 = (I4);
                        I2.DeltasNum = DeltasChangeTab[I4.DeltasNum];
                    }
                }
            }
        }
    }
    printf(">circle end %d\r\n", circle_cnt);
    return circle_cnt;
}

下载链接:

https://download.csdn.net/download/ai5945fei/85800131

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值