#include "images.h"
uint8 l_border[MT9V03X_H];//左线数组
uint8 r_border[MT9V03X_H];//右线数组
uint8 center_line[MT9V03X_H];//中线数组
/*变量声明*/
//uint8 original_image[MT9V03X_H][MT9V03X_W];
uint8 bin_image[MT9V03X_H][MT9V03X_W];//图像数组
uint8 image_thereshold_last = 0;//
uint8 image_thereshold;//图像分割阈值
//------------------------------------------------------------------------------------------------------------------
// @函数功能 求绝对值
// @函数返回 绝对值
//------------------------------------------------------------------------------------------------------------------
int my_abs(int value)
{
if(value>=0) return value;
else return -value;
}
//数值范围限制
int16 limit_a_b(int16 x, int a, int b)
{
if(x<a) x = a;
if(x>b) x = b;
return x;
}
//------------------------------------------------------------------------------------------------------------------
// @函数功能 求x,y中的最小值
// @函数返回 两值中的最小值
//------------------------------------------------------------------------------------------------------------------
int16 limit1(int16 x, int16 y)
{
if (x > y) return y;
else if (x < -y) return -y;
else return x;
}
//------------------------------------------------------------------------------------------------------------------
// @函数功能 获得一副灰度图像
// @函数返回 灰度图像数组original_image
//------------------------------------------------------------------------------------------------------------------
void Get_image(uint8(*mt9v03x_image)[MT9V03X_W])
{
uint8 i = 0, j = 0;
for (i = 0; i < MT9V03X_H; i += 1)
{
for (j = 0; j <MT9V03X_W; j += 1)
{
bin_image[i][j] = mt9v03x_image[i][j];
}
}
}
//将原始图像复制到bin_image数组
//------------------------------------------------------------------------------------------------------------------
// @函数功能 大津法求动态阈值
// @函数返回 动态阈值Threshold
//------------------------------------------------------------------------------------------------------------------
uint8 OtsuThreshold(uint8 *image)
{
uint8 Pixel_Max = 0;
uint8 Pixel_Min = 255;
//uint16 width = MT9V03X_W / use_num;
//uint16 height = MT9V03X_H / use_num;
int pixelCount[GrayScale]; //各像素GrayScale的个数pixelCount 一维数组
float pixelPro[GrayScale]; //各像素GrayScale所占百分比pixelPro 一维数组
int16 i = 0;
int16 j = 0;
int16 pixelSum = MT9V03X_W * MT9V03X_H / 4; //pixelSum是获取总的图像像素个数的1/4,相应下面轮询时高和宽都是以2为单位自增
uint8 threshold = 0;
uint8* data = image; //指向像素数据的指针
for(i = 0;i < GrayScale;i++)
{
pixelCount[i] = 0;
pixelPro[i] = 0;
}
uint32 gray_sum = 0;
//统计灰度图中每个像素在整幅图像中的个数
for(i = 0;i < MT9V03X_H;i += 2)
{
for(j = 0;j < MT9V03X_W; j += 2)
{
pixelCount[(int)data[i * MT9V03X_W + j]]++; //将当前的点的像素值作为计数数组的下标
gray_sum += (int)data[i * MT9V03X_W + j]; //灰度值总和
if(data[i * MT9V03X_W + j] > Pixel_Max)
{
Pixel_Max = data[i * MT9V03X_W + j];
}
if(data[i * MT9V03X_W + j] < Pixel_Min)
{
Pixel_Min = data[i * MT9V03X_W + j];
}
}
}
//计算每个像素值的点在整幅图像中的比例
for(i = Pixel_Min;i < Pixel_Max;i++)
{
pixelPro[i] = (float)pixelCount[i] / pixelSum;
}
//遍历灰度值
float w0,w1,u0tmp,u1tmp,u0,u1,deltaTmp,deltaMax = 0;
w0 = w1 = u0tmp = u1tmp = u0 = u1 = deltaTmp = 0;
for(j = Pixel_Min;j < Pixel_Max;j++)
{
w0 += pixelPro[j]; //背景部分每个灰度值的像素点所占比例之和 即背景部分的比例
u0tmp += j * pixelPro[j]; //背景部分 每个灰度值的点的比例 *灰度值
w1 = 1 - w0;
u1tmp = gray_sum / pixelSum-u0tmp;
u0 = u0tmp / w0; //背景平均灰度
u1 = u1tmp / w1; //前景平均灰度
deltaTmp = (float)(w0 * w1 * (u0 - u1) * (u0 - u1));
if(deltaTmp > deltaMax)
{
deltaMax = deltaTmp;
threshold = (uint8)j;
}
if(deltaTmp < deltaMax)
{
break;
}
}
//限幅
if(threshold > 25 && threshold < 235)
{
image_thereshold_last = threshold;
}
else
{
threshold = image_thereshold_last;
}
return threshold;
}
//------------------------------------------------------------------------------------------------------------------
// @函数功能 图像二值化,大津法
// @函数返回 二值化图像数组bin_image
//------------------------------------------------------------------------------------------------------------------
void turn_to_bin(void)
{
uint8 i,j;
image_thereshold = OtsuThreshold(bin_image[0]);
//ips114_show_int(189,0,image_thereshold,5);
for(i = 0;i < MT9V03X_H;i++)
{
for(j = 0;j < MT9V03X_W;j++)
{
if(bin_image[i][j] > image_thereshold)
{
bin_image[i][j] = 255;
}
else
{
bin_image[i][j] = 0;
}
}
}
/* for(i = 40;i < MT9V03X_H;i++)
{
for(j = 0;j < MT9V03X_W;j++)
{
if(bin_image[i][j] < image_thereshold)
{
bin_image[i][j] = 0;
}
else
{
bin_image[i][j] =255;
}
}
}*/
}
//------------------------------------------------------------------------------------------------------------------
// @函数功能 寻找两个边界的边界点作为八邻域循环的起始点
// @参数说明 输入任意行数
// @函数返回 无
//------------------------------------------------------------------------------------------------------------------
uint8 start_point_l[2] = { 0 };//左边起点的x,y值
uint8 start_point_r[2] = { 0 };//右边起点的x,y值
uint8 get_start_point(uint8 start_row)
{
uint8 i = 0,j = MT9V03X_W/2,l_found = 0,r_found = 0,num = 0;
//清零
start_point_l[0] = 0;//左x
start_point_l[1] = 0;//左y
start_point_r[0] = 0;//右x
start_point_r[1] = 0;//右y
//大致定位白线
for(num = 0;num < MT9V03X_W/2 - 15;num = num + 10)
{
if(bin_image[start_row][j + num] == 255)
{
j = j + num;
break;
}
if(bin_image[start_row][j - num] == 255)
{
j = j - num;
break;
}
}
//从中间往左边,先找起点
for (i = j; i > border_min; i--)
{
start_point_l[0] = i;//x
start_point_l[1] = start_row;//y
if (bin_image[start_row][i] == 255 && bin_image[start_row][i - 1] == 0)
{
//printf("找到左边起点image[%d][%d]\n", start_row,i);
l_found = 1;
break;
}
}
for (i = j; i < border_max; i++)
{
start_point_r[0] = i;//x
start_point_r[1] = start_row;//y
if (bin_image[start_row][i] == 255 && bin_image[start_row][i + 1] == 0)
{
//printf("找到右边起点image[%d][%d]\n",start_row, i);
r_found = 1;
break;
}
}
if(l_found&&r_found)
{
return 1;
}
else
{
//printf("未找到起点\n");
return 0;
}
}
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// @函数功能 八邻域正式开始找右边点的函数,左右线一次性找完。 Tip:特别注意,不要拿宏定义名字作为输入参数,否则数据可能无法传递过来
// @参数说明
// break_flag_r 最多需要循环的次数
// (*image)[image_w] 需要进行找点的图像数组,必须是二值图,填入数组名称即可
// *l_stastic 统计左边数据,用来输入初始数组成员的序号和取出循环次数
// *r_stastic 统计右边数据,用来输入初始数组成员的序号和取出循环次数
// l_start_x 左边起点横坐标
// l_start_y 左边起点纵坐标
// r_start_x 右边起点横坐标
// r_start_y 右边起点纵坐标
// hightest 循环结束所得到的最高高度
// @函数返回 无
// @备 注:
//example:search_l_r((uint16)USE_num,image,&data_stastics_l, &data_stastics_r,start_point_l[0],start_point_l[1], start_point_r[0], start_point_r[1],&hightest);
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
#define USE_num MT9V03X_H*3 //定义找点的数组成员个数按理说300个点能放下,但是有些特殊情况确实难顶,多定义了一点
//存放点的x,y坐标
uint16 points_l[(uint16)USE_num][2] = { { 0 } };//左线
uint16 points_r[(uint16)USE_num][2] = { { 0 } };//右线
uint16 dir_r[(uint16)USE_num] = { 0 };//用来存储右边生长方向
uint16 dir_l[(uint16)USE_num] = { 0 };//用来存储左边生长方向
uint16 data_stastics_l = 0;//统计左边找到点的个数
uint16 data_stastics_r = 0;//统计右边找到点的个数
uint8 hightest = 0;//最高点
void search_l_r(uint16 break_flag, uint8(*image)[MT9V03X_W], uint16 *l_stastic, uint16 *r_stastic, uint8 l_start_x, uint8 l_start_y, uint8 r_start_x, uint8 r_start_y, uint8*hightest)
{
uint8 i = 0, j = 0;
//左边变量
uint8 search_filds_l[8][2] = { { 0 } };
uint8 index_l = 0;
uint8 temp_l[8][2] = { { 0 } };
uint8 center_point_l[2] = { 0 };
uint16 l_data_statics;//统计左边
//定义八个邻域
static int8 seeds_l[8][2] = {{0,1},{-1,1},{-1,0},{-1,-1},{0,-1},{1,-1},{1,0},{1,1},};
//{-1,-1} {0,-1} {+1,-1}
//{-1, 0} {+1, 0}
//{-1,+1} {0,+1} {+1,+1}
//顺时针
//右边变量
uint8 search_filds_r[8][2] = { { 0 } };
uint8 center_point_r[2] = { 0 };//中心坐标点
uint8 index_r = 0;//索引下标
uint8 temp_r[8][2] = { { 0 } };
uint16 r_data_statics;//统计右边
//定义八个邻域
static int8 seeds_r[8][2] = { {0,1},{1,1},{1,0}, {1,-1},{0,-1},{-1,-1}, {-1,0},{-1,1}, };
//{-1,-1} {0,-1} {+1,-1},
//{-1, 0} {+1, 0}
//{-1,+1} {0,+1} {+1,+1}
//这个是逆时针
l_data_statics = *l_stastic;//统计找到了多少个点,方便后续把点全部画出来
r_data_statics = *r_stastic;//统计找到了多少个点,方便后续把点全部画出来
//第一次更新坐标点 将找到的起点值传进来
center_point_l[0] = l_start_x;//x
center_point_l[1] = l_start_y;//y
center_point_r[0] = r_start_x;//x
center_point_r[1] = r_start_y;//y
//开启邻域循环
while (break_flag--)
{
//左边
for (i = 0; i < 8; i++)//传递8F坐标
{
search_filds_l[i][0] = center_point_l[0] + seeds_l[i][0];//x
search_filds_l[i][1] = center_point_l[1] + seeds_l[i][1];//y
}
//中心坐标点填充到已经找到的点内
points_l[l_data_statics][0] = center_point_l[0];//x
points_l[l_data_statics][1] = center_point_l[1];//y
l_data_statics++;//索引加一
//右边
for (i = 0; i < 8; i++)//传递8F坐标
{
search_filds_r[i][0] = center_point_r[0] + seeds_r[i][0];//x
search_filds_r[i][1] = center_point_r[1] + seeds_r[i][1];//y
}
//中心坐标点填充到已经找到的点内
points_r[r_data_statics][0] = center_point_r[0];//x
points_r[r_data_statics][1] = center_point_r[1];//y
index_l = 0;//先清零,后使用
for (i = 0; i < 8; i++)
{
temp_l[i][0] = 0;//先清零,后使用
temp_l[i][1] = 0;//先清零,后使用
}
//左边判断
for (i = 0; i < 8; i++)
{
if (image[search_filds_l[i][1]][search_filds_l[i][0]] == 0 && image[search_filds_l[(i + 1) & 7][1]][search_filds_l[(i + 1) & 7][0]] == 255)
{
temp_l[index_l][0] = search_filds_l[(i)][0];
temp_l[index_l][1] = search_filds_l[(i)][1];
index_l++;
dir_l[l_data_statics - 1] = (i);//记录生长方向
}
if (index_l)
{
//更新坐标点
center_point_l[0] = temp_l[0][0];//x
center_point_l[1] = temp_l[0][1];//y
for (j = 0; j < index_l; j++)
{
if (center_point_l[1] > temp_l[j][1])
{
center_point_l[0] = temp_l[j][0];//x
center_point_l[1] = temp_l[j][1];//y
}
}
}
}
if ((points_r[r_data_statics][0]== points_r[r_data_statics-1][0]&& points_r[r_data_statics][0] == points_r[r_data_statics - 2][0] && points_r[r_data_statics][1] == points_r[r_data_statics - 1][1] && points_r[r_data_statics][1] == points_r[r_data_statics - 2][1]) ||(points_l[l_data_statics-1][0] == points_l[l_data_statics - 2][0] && points_l[l_data_statics-1][0] == points_l[l_data_statics - 3][0] && points_l[l_data_statics-1][1] == points_l[l_data_statics - 2][1] && points_l[l_data_statics-1][1] == points_l[l_data_statics - 3][1]))
{
//printf("三次进入同一个点,退出\n");
break;
}
if (my_abs(points_r[r_data_statics][0] - points_l[l_data_statics - 1][0]) < 2 && my_abs(points_r[r_data_statics][1] - points_l[l_data_statics - 1][1] < 2))
{
//printf("\n左右相遇退出\n");
*hightest = (points_r[r_data_statics][1] + points_l[l_data_statics - 1][1]) >> 1;//取出最高点
//printf("\n在y=%d处退出\n",*hightest);
break;
}
if ((points_r[r_data_statics][1] < points_l[l_data_statics - 1][1]))
{
//printf("\n如果左边比右边高了,左边等待右边\n");
continue;//如果左边比右边高了,左边等待右边
}
if (dir_l[l_data_statics - 1] == 7 && (points_r[r_data_statics][1] > points_l[l_data_statics - 1][1]))//左边比右边高且已经向下生长了
{
//printf("\n左边开始向下了,等待右边,等待中... \n");
center_point_l[0] = points_l[l_data_statics - 1][0];//x
center_point_l[1] = points_l[l_data_statics - 1][1];//y
l_data_statics--;
}
r_data_statics++;//索引加一
index_r = 0;//先清零,后使用
for (i = 0; i < 8; i++)
{
temp_r[i][0] = 0;//先清零,后使用
temp_r[i][1] = 0;//先清零,后使用
}
//右边判断
for (i = 0; i < 8; i++)
{
if (image[search_filds_r[i][1]][search_filds_r[i][0]] == 0 && image[search_filds_r[(i + 1) & 7][1]][search_filds_r[(i + 1) & 7][0]] == 255)
{
temp_r[index_r][0] = search_filds_r[(i)][0];
temp_r[index_r][1] = search_filds_r[(i)][1];
index_r++;//索引加一
dir_r[r_data_statics - 1] = (i);//记录生长方向
//printf("dir[%d]:%d\n", r_data_statics - 1, dir_r[r_data_statics - 1]);
}
if (index_r)
{
//更新坐标点
center_point_r[0] = temp_r[0][0];//x
center_point_r[1] = temp_r[0][1];//y
for (j = 0; j < index_r; j++)
{
if (center_point_r[1] > temp_r[j][1])
{
center_point_r[0] = temp_r[j][0];//x
center_point_r[1] = temp_r[j][1];//y
}
}
}
}
}
//取出循环次数
*l_stastic = l_data_statics;
*r_stastic = r_data_statics;
}
//------------------------------------------------------------------------------------------------------------------
// @函数功能 从八邻域边界里提取需要的左边线
// @参数说明 total_L :找到的点的总数
// @函数返回 左边线数组l_border
//------------------------------------------------------------------------------------------------------------------
uint16 border_to_edge_l[MT9V03X_H];//存放左边border和edge的映射关系的数组
void get_left(uint16 total_L)
{
uint8 i = 0;
uint16 j = 0;
uint8 h = 0;
//初始化
for (i = 0;i<MT9V03X_H;i++)
{
l_border[i] = border_min;
}
h = MT9V03X_H - 2;
//左边
for (j = 0; j < total_L; j++)
{
//printf("%d\n", j);
if (points_l[j][1] == h)
{
l_border[h] = points_l[j][0]+1;
border_to_edge_l[h] = j;
}
else continue; //每行只取一个点,没到下一行就不记录
h--;
if (h == 0)
{
break;//到最后一行退出
}
}
}
//------------------------------------------------------------------------------------------------------------------
// @函数功能 从八邻域边界里提取需要的右边线
// @参数说明 total_R :找到的点的总数
// @函数返回 右边线数组r_border
//------------------------------------------------------------------------------------------------------------------
uint16 border_to_edge_r[MT9V03X_H];//存放右边border和edge的映射关系的数组
void get_right(uint16 total_R)
{
uint8 i = 0;
uint16 j = 0;
uint8 h = 0;
for (i = 0; i < MT9V03X_H; i++)
{
r_border[i] = border_max;//右边线初始化放到最右边,左边线放到最左边,这样八邻域闭合区域外的中线就会在中间,不会干扰得到的数据
}
h = MT9V03X_H - 2;
//右边
for (j = 0; j < total_R; j++)
{
if (points_r[j][1] == h)
{
r_border[h] = points_r[j][0] - 1;
border_to_edge_r[h] = j;
}
else continue;//每行只取一个点,没到下一行就不记录
h--;
if (h == 0)break;//到最后一行退出
}
}
//------------------------------------------------------------------------------------------------------------------
// @函数功能 滤波减少噪声
// @函数返回 经过滤波的图像数组bin_image
//------------------------------------------------------------------------------------------------------------------
#define threshold_max 255*5//定义膨胀的阈值区间
#define threshold_min 255*2//定义腐蚀的阈值区间
void image_filter(uint8(*bin_image)[MT9V03X_W])//形态学滤波,膨胀和腐蚀
{
uint16 i, j;
uint32 num = 0;
for (i = 1; i < MT9V03X_H - 1; i++)
{
for (j = 1; j < (MT9V03X_W - 1); j++)
{
//统计八个方向的像素值
num = bin_image[i - 1][j - 1] + bin_image[i - 1][j] + bin_image[i - 1][j + 1] + bin_image[i][j - 1] + bin_image[i][j + 1] + bin_image[i + 1][j - 1] + bin_image[i + 1][j] + bin_image[i + 1][j + 1];
if (num >= threshold_max && bin_image[i][j] == 0)
{
bin_image[i][j] = 255;//白
}
if (num <= threshold_min && bin_image[i][j] == 255)
{
bin_image[i][j] = 0;//黑
}
}
}
}
//------------------------------------------------------------------------------------------------------------------
// @函数功能 给图像画一个黑框
// @函数返回 带有黑框的图像数组bin_image
//------------------------------------------------------------------------------------------------------------------
void image_draw_rectan(uint8(*image)[MT9V03X_W])
{
uint8 i = 0;
for (i = 0; i < MT9V03X_H; i++)
{
image[i][0] = 0;
image[i][1] = 0;
image[i][MT9V03X_W - 1] = 0;
image[i][MT9V03X_W - 2] = 0;
}
for (i = 0; i < MT9V03X_W; i++)
{
image[0][i] = 0;
image[1][i] = 0;
//image[image_h-1][i] = 0;
}
}
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// @函数功能 环岛元素识别处理
// @函数返回 无
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//全局状态变量
IslandState current_state = NORMAL;
uint8_t island_type = 0; // 0:未确定 1:左环岛 2:右环岛
uint8 target_h = 0;//存放断裂点行数
uint16 A_edge = 0;
uint16 V_edge = 0;
uint8 A_point = 0;
uint8 P_point = 0;
uint8 V_point = 0;
//------------------------------------------------------------------------------------------------------------------
// @函数功能 边界连续性判断
// @参数说明 需要寻找的边线
// @函数返回 有断裂返回0,无断裂返回1
//------------------------------------------------------------------------------------------------------------------
uint8 border_continuous(uint8 *border)
{
for(uint8 i = MT9V03X_H-1;i > 0;i--)
{
int8 diff = border[i] - border[i - 1];
if(diff < -4 || diff > 4)
{
target_h = i;
return 0;//有断裂
}
}
return 1;//无断裂
}
//------------------------------------------------------------------------------------------------------------------
// @函数功能 寻找A点
// @函数返回 A点
//------------------------------------------------------------------------------------------------------------------
//左圆环时寻找左边界A点
uint8 find_point_A_l(void)
{
uint16 j = border_to_edge_l[target_h];//映射
int16 search_min = j - search_range;//遍历点的最小编号
int16 search_max = j + search_range;//遍历点的最大编号
//限定查找区间
if(search_min < 3)
{
search_min = 3;
}
if(search_max > data_stastics_l - 2)
{
search_max = data_stastics_l - 2;
}
//遍历寻找A点
for(j = search_min;j <= search_max;j++)
{
if(points_l[j+2][0]<points_l[j][0] && points_l[j+2][1]<points_l[j][1] && points_l[j-2][1] < points_l[j][1])
{
A_edge = j;
return 1;//找到A点
}
}
return 0;//未找到A点
}
//右圆环时寻找右边界A点
uint8 find_point_A_r(void)
{
uint16 j = border_to_edge_r[target_h];//映射
int16 search_min = j - search_range;//遍历点的最小编号
int16 search_max = j + search_range;//遍历点的最大编号
//限定查找区间
if(search_min < 3)
{
search_min = 3;
}
if(search_max > data_stastics_r - 2)
{
search_max = data_stastics_r - 2;
}
//遍历寻找A点
for(j = search_min;j <= search_max;j++)
{
if(points_l[j+2][0]>points_l[j][0] && points_l[j+2][1]<points_l[j][1] && points_l[j-2][1] < points_l[j][1])
{
A_edge = j;
return 1;//找到A点
}
}
return 0;//未找到A点
}
//------------------------------------------------------------------------------------------------------------------
// @函数功能 寻找P点
// @函数返回 P点
//------------------------------------------------------------------------------------------------------------------
//左圆环时寻找左边界P点
uint8 find_point_P_l(void)
{
for(uint8 i = MT9V03X_H - 2;i > 1;i++)
{
if(l_border[i-2] < l_border[i] && l_border[i+2] < l_border[i])
{
P_point = i;
return 1;//找到P点
}
}
return 0;//未找到P点
}
//右圆环时寻找左边界P点
uint8 find_point_P_r(void)
{
for(uint8 i = MT9V03X_H - 2;i > 1;i++)
{
if(l_border[i-2] > l_border[i] && l_border[i+2] > l_border[i])
{
P_point = i;
return 1;//找到P点
}
}
return 0;//未找到P点
}
//------------------------------------------------------------------------------------------------------------------
// @函数功能 寻找V点
// @函数返回 V点
//------------------------------------------------------------------------------------------------------------------
//左边V点
uint8 find_point_V_l(void)
{
uint16 j = border_to_edge_l[target_h];//映射
int16 search_min = j - search_range;//遍历点的最小编号
int16 search_max = j + search_range;//遍历点的最大编号
//限定查找区间
if(search_min < 3)
{
search_min = 3;
}
if(search_max > data_stastics_l - 2)
{
search_max = data_stastics_l - 2;
}
//遍历寻找V点
for(j = search_min;j <= search_max;j++)
{
if(points_l[j+2][1]<points_l[j][1] && points_l[j-2][1] < points_l[j][1])
{
V_edge = j;
return 1;//找到V点
}
}
return 0;//未找到V点
}
//右边V点
uint8 find_point_V_r(void)
{
uint16 j = border_to_edge_r[target_h];//映射
int16 search_min = j - search_range;//遍历点的最小编号
int16 search_max = j + search_range;//遍历点的最大编号
//限定查找区间
if(search_min < 3)
{
search_min = 3;
}
if(search_max > data_stastics_r - 2)
{
search_max = data_stastics_r - 2;
}
//遍历寻找V点
for(j = search_min;j <= search_max;j++)
{
if(points_l[j+2][1]<points_l[j][1] && points_l[j-2][1] < points_l[j][1])
{
V_edge = j;
return 1;//找到V点
}
}
return 0;//未找到V点
}
//------------------------------------------------------------------------------------------------------------------
// @函数功能 补线
// @参数说明 m补线下方点,n补线上方点,border需要补线的边线数组,end_point需要补到的高度
// @函数返回 无
//------------------------------------------------------------------------------------------------------------------
void patching_line(uint8 m,uint8 n,uint8 *border,uint8 end_point)
{
float k = (float)( (m - n) / (border[n] - border[m]) );
for(uint8 h = m - 1;h > end_point;h--)
{
border[h] = (uint8)(border[m] + (m - h) / k);
}
}
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// @函数功能 总环岛识别处理函数
// @函数返回 无
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void island_handler(void)
{
switch(current_state)
{
case NORMAL:
//判断初见环岛条件
if(border_continuous(r_border) && !border_continuous(l_border) && find_point_A_l() && find_point_P_l())//判断是否为左环岛
{
current_state = SEE_ISLAND;
island_type = 1;//左环岛
}
if(!border_continuous(r_border) && border_continuous(l_border) && find_point_A_r() && find_point_P_r())//判断是否为右环岛
{
current_state = SEE_ISLAND;
island_type = 2;//右环岛
}
break;
case SEE_ISLAND://初见环岛
if(island_type == 1)//左环岛
{
//找A,P点
border_continuous(l_border);
find_point_A_l();
find_point_P_l();
//补线
A_point = points_l[A_edge][1];
l_border[A_point] = points_l[A_edge][0];
patching_line(A_point,P_point,l_border,P_point);
//判断初入环岛条件
if(l_border[MT9V03X_H-1] == border_min && l_border[MT9V03X_H-2] == border_min)
{
current_state = ENTER_ISLAND;
}
}
if(island_type == 2)//右环岛
{
//找A,P点
border_continuous(r_border);
find_point_A_r();
find_point_P_r();
//补线
A_point = points_r[A_edge][1];
r_border[A_point] = points_r[A_edge][0];
patching_line(A_point,P_point,r_border,P_point);
//判断初入环岛条件
if(r_border[MT9V03X_H-1] == border_max && r_border[MT9V03X_H-2] == border_max)
{
current_state = ENTER_ISLAND;
}
}
break;
case ENTER_ISLAND://初入环岛
if(island_type == 1)//左环岛
{
//找P点
find_point_P_l();
//补线
A_point = MT9V03X_H-1;
patching_line(A_point,P_point,l_border,P_point);
//判断第一次到环岛出口条件
if(!border_continuous(l_border) && border_continuous(r_border) && find_point_V_l())
{
current_state = EXIT_ISLAND1;
}
}
if(island_type == 2)//右环岛
{
//找P点
find_point_P_r();
//补线
A_point = MT9V03X_H-1;
patching_line(A_point,P_point,r_border,P_point);
//判断第一次到环岛出口条件
if(border_continuous(l_border) && !border_continuous(r_border) && find_point_V_r())
{
current_state = EXIT_ISLAND1;
}
}
break;
case EXIT_ISLAND1://第一次到环岛出口
if(island_type == 1)//左环岛
{
//找V点
border_continuous(l_border);
find_point_V_l();
//补线
V_point = points_l[V_edge][1];
r_border[V_point] = points_l[A_edge][0];
patching_line(119,V_point,r_border,0);
//判断即将入环条件
if(!border_continuous(r_border) && find_point_V_r())
{
current_state = IN_ISLAND;
}
}
if(island_type == 2)//右环岛
{
//找V点
border_continuous(r_border);
find_point_V_r();
//补线
V_point = points_r[V_edge][1];
l_border[V_point] = points_r[A_edge][0];
patching_line(119,V_point,l_border,0);
//判断即将入环条件
if(!border_continuous(l_border) && find_point_V_l())
{
current_state = IN_ISLAND;
}
}
break;
case PRE_ENTER://即将入环
if(island_type == 1)//左环岛
{
//找V点
border_continuous(r_border);
find_point_V_r();
//补线
V_point = points_r[V_edge][1];
r_border[V_point] = points_r[A_edge][0];
patching_line(119,V_point,r_border,0);
//判断完全入环条件
if(border_continuous(r_border) && border_continuous(l_border))
{
current_state = IN_ISLAND;
}
}
if(island_type == 2)//右环岛
{
//找V点
border_continuous(l_border);
find_point_V_l();
//补线
V_point = points_l[V_edge][1];
l_border[V_point] = points_l[A_edge][0];
patching_line(119,V_point,l_border,0);
//判断完全入环条件
if(border_continuous(r_border) && border_continuous(l_border))
{
current_state = IN_ISLAND;
}
}
break;
case IN_ISLAND://完全入环
if(island_type == 1)//左环岛
{
//条件补线
if(!border_continuous(r_border) && border_continuous(l_border))
{
r_border[0] = border_min;
patching_line(target_h,0,r_border,0);
}
//判断第二次到环岛出口条件
if( l_border[MT9V03X_H-1]>border_min && l_border[MT9V03X_H-2]>border_min && r_border[MT9V03X_H-1]==border_max && r_border[MT9V03X_H-1]==border_max)
{
current_state = EXIT_ISLAND2;
}
}
if(island_type == 2)//右环岛
{
//条件补线
if(!border_continuous(l_border) && border_continuous(r_border))
{
l_border[0] = border_max;
patching_line(target_h,0,l_border,0);
}
//判断第二次到环岛出口条件
if( l_border[MT9V03X_H-1]==border_min && l_border[MT9V03X_H-2]==border_min && r_border[MT9V03X_H-1]<border_max && r_border[MT9V03X_H-1]<border_max)
{
current_state = EXIT_ISLAND2;
}
}
break;
case EXIT_ISLAND2://第二次到环岛出口
if(island_type == 1)//左环岛
{
//判断最终出环条件
if(!border_continuous(l_border) && border_continuous(r_border))
{
current_state = FINAL_EXIT;
}
}
if(island_type == 2)//右环岛
{
//判断最终出环条件
if(border_continuous(l_border) && !border_continuous(r_border))
{
current_state = FINAL_EXIT;
}
}
break;
case FINAL_EXIT://最终出环
if(island_type == 1)//左环岛
{
//补线
border_continuous(l_border);
patching_line(119,target_h,l_border,target_h);
//结束条件
if(border_continuous(l_border) && border_continuous(r_border))
{
current_state = NORMAL;
island_type = 0;
}
}
if(island_type == 2)//右环岛
{
//补线
border_continuous(r_border);
patching_line(119,target_h,r_border,target_h);
//结束条件
if(border_continuous(l_border) && border_continuous(r_border))
{
current_state = NORMAL;
island_type = 0;
}
}
break;
}
}
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// @函数功能 获取车身偏差
// @函数返回 车身偏差error
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
int16 error = 1000; //误差100
int16 error_last = 0; //上次误差
void car_error(void)
{
uint8 i = 0;
int32 num = 0; //int16 num = 0
for(i = 1;i < MT9V03X_H;i++)
{
num += (center_line[i] - (MT9V03X_W / 2));
}
error_last = error;
error = num;
}
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// @函数功能 最终处理函数
// @函数返回 无
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
uint8 change = 0;
uint8 change_last = 0;
void image_process(void)
{
uint16 i;
uint8 hightest = 0;//定义一个最高行,tip:这里的最高指的是y值的最小
Get_image(mt9v03x_image);//获得一副灰度图像
turn_to_bin();//大津法二值化。
//提取赛道边界
image_filter(bin_image);//滤波减少噪声
image_draw_rectan(bin_image);//给图像画黑框为八领域做准备
//清零
data_stastics_l = 0;
data_stastics_r = 0;
if (get_start_point(MT9V03X_H - 2))//找到起点了,再执行八领域,没找到就一直找
{
navigation_flag = 0;
//判断直角弯
uint8 m = 0,n = 0, j = 0;
for(j = 1;j < MT9V03X_W;j++)
{
if(bin_image[60][j] == 255)
{
break;
}
if(bin_image[62][j] == 255)
{
break;
}
}
if(j == MT9V03X_W)
{
for(j = 119;j > 55;j--)
{
if(bin_image[j][5] == 255 && bin_image[j][7] == 255)
{
m = 1;
}
if(bin_image[j][115] == 255 && bin_image[j][113] == 255)
{
n = 1;
}
}
}
if(m == 1 && n == 0)
{
navigation_flag = 1;
}
if(m == 0 && n == 1)
{
navigation_flag = 2;
}
//八领域处理
search_l_r((uint16)USE_num, bin_image, &data_stastics_l, &data_stastics_r, start_point_l[0], start_point_l[1], start_point_r[0], start_point_r[1], &hightest);
// 从爬取的边界线内提取边线 , 这个才是最终有用的边线
get_left(data_stastics_l);
get_right(data_stastics_r);
//处理函数
island_handler();//环岛元素识别处理
}
else
{
navigation_flag = 3;
}
for (i = hightest; i < MT9V03X_H-1; i++)
{
center_line[i] = (l_border[i] + r_border[i]) >> 1;//求中线
}
if(bin_image[118][8] == 0 && bin_image[118][40] == 255 && bin_image[118][100] == 255 && bin_image[118][148] == 255 && bin_image[118][180] == 0 && bin_image[118][94] == 255)
{
change_last = change;
change = 1;
}
else
{
change = 0;
}
if(change == 1 && change_last == 0)
{
stop++;
}
以上代码如何调整参数来降低曝光问题
最新发布