一些基本函数
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, ¢er);
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;
}
下载链接: