怎样做摄影网站,免费网站加速服务,wordpress那种路径格式容易收录,myeclipse做网站更改名字元素识别是摄像头部分中难度最大的一部分#xff0c;也是我花时间最长的一部分#xff0c;前前后后画了很长时间#xff0c;最后还是勉勉强强完成了。
基础的元素识别主要有两个#xff1a;十字#xff0c;圆环#xff0c;和斑马线。十字要求直行#xff0c;圆环需要进…元素识别是摄像头部分中难度最大的一部分也是我花时间最长的一部分前前后后画了很长时间最后还是勉勉强强完成了。
基础的元素识别主要有两个十字圆环和斑马线。十字要求直行圆环需要进圆环。我们的车在完全不写的情况下十字可以猛冲过去只是会非常抖。圆环不能进。
如果十字不能走直线的话是直接判失败的因为你抄了近路。圆环不能进入的话是罚时30s的我们这一年华南赛区一等奖是要在10s之内的区2也要15s左右。所以如果你吃了这个罚时基本上与区二无缘了。
前面我的推文提到过我们在搜线搜完之后会额外出现两个数组一个是左右边线的丢线数组另一个是赛道宽度的数组。我们先对左右边线丢线数组进行处理 loss_pointer_L -1;loss_pointer_R -1;if (loss_array[IMG_H - 1][0] 1) {loss_array_L[loss_pointer_L] IMG_H - 1;}if (loss_array[IMG_H - 1][1] 1) {loss_array_R[loss_pointer_R] IMG_H - 1;}for (int j IMG_H - 1; j IMG_H - max_length; j--) {if (loss_array[j - 1][0] 1 loss_array[j][0] 0) { // headloss_array_L[loss_pointer_L] j;}if (loss_array[j - 1][0] 0 loss_array[j][0] 1) { // endloss_array_L[loss_pointer_L] j - 1;loss_counter_L[loss_pointer_L / 2] loss_array_L[loss_pointer_L - 1] - loss_array_L[loss_pointer_L];}if (loss_array[j - 1][1] 1 loss_array[j][1] 0) { // headloss_array_R[loss_pointer_R] j;}if (loss_array[j - 1][1] 0 loss_array[j][1] 1) { // endloss_array_R[loss_pointer_R] j - 1;loss_counter_R[loss_pointer_R / 2] loss_array_R[loss_pointer_R - 1] - loss_array_R[loss_pointer_R];}}
这其中loss_array[IMG_H][2]中存的是丢线的数据比如左边线的第100行丢线了则loss_array[100][0] 1。
这串代码的意图是把这个loss_array分成四个一维数组分别为loss_array_Lloss_array_Rloss_counter_Lloss_counter_R。loss_array_L[]这个数组偶数存放的是左边线丢线的开始奇数存放的是 左边线丢线的结束loss_counter_L[]这个数组存放的是左边线丢线的个数。便于之后辨别元素。例如loss_array_L[0] 75, loss_array_L[1] 55,那么说明左边线的55行-75行存在丢线的情况那么 loss_counter_L[0]的值则为20。
所需要的另一个数组则为宽度的计算
我们首先需要计算在大直道的情况下如果把车至于赛道中央顶端和最低端赛道的像素数量
for (i IMG_H - 1; i 0; i--) {compared_array[i] (HEAD_LENGTH (END_LENGTH - HEAD_LENGTH) * (float)i / IMG_H) * ELEMENT_RATE;if (boundary_length[i] compared_array[i]) {elem_array[i] 1;}else {elem_array[i] 0;}}
这样我们可以计算出大直道上理论上的赛道宽度如果大于这个宽度*ELEMENT_RATE则有进元素的嫌疑。
之后我们还是像刚刚处理丢线的方式来把丢线的长度入栈 for (int j ELEM_SEARCH_BEGIN; j IMG_H - max_length; j--) {if (elem_array[j - 1] 1 elem_array[j] 0) { // 开始elem[elem_pointer] j;line_L[elem_pointer] abs(boundary[j][LEFT] - boundary[j - 1][LEFT]);line_R[elem_pointer] abs(boundary[j][RIGHT] - boundary[j - 1][RIGHT]);}if (elem_array[j - 1] 0 elem_array[j] 1) { // 结束elem[elem_pointer] j - 1;//结尾入栈elem_counter[elem_pointer / 2] elem[elem_pointer - 1] - elem[elem_pointer];line_L[elem_pointer] abs(boundary[j - 1][LEFT] - boundary[j][LEFT]);line_R[elem_pointer] abs(boundary[j - 1][RIGHT] - boundary[j][RIGHT]);}}if (elem_array[1] 1) { //如果图象底部缺线 则将底部入栈elem[elem_pointer] 1;elem_counter[elem_pointer / 2] elem[elem_pointer - 1] - elem[elem_pointer];line_L[elem_pointer] abs(boundary[1][LEFT] - boundary[0][LEFT]);line_R[elem_pointer] abs(boundary[1][RIGHT] - boundary[0][RIGHT]);}
这样我们就完成了数据的预处理。
我们来具体分析下十字和圆环的特征。
图片是选用逐飞对ccd组进行讲解的图对上面的标号对镜头组其实不适用可以忽略
我们可以看出临近十字有一条很长的直线圆环的一侧是一条很长的直线我们可以用这个来辅助判断圆环和十字的特征
然后圆环的入口和出口会有一个很大的丢线区域十字中也会有一个很大的丢线区域
所以我们需要一个函数来判断是否为直线
unsigned char is_straight(unsigned char begin, unsigned char end, line_type line);//直线判断函数 我们的函数接受三个数据读取boundary数组的line行也就是确定左边线还是右边线。其他的有begin end 返回值是1或者0。
现在我们来开始元素判断 if (mode NORMAL max_length 95) {if (elem_pointer 0) {i 0;while (i elem_pointer i 10) {int lc 0, rc 0, llc 0, rlc 0, lcbegin 0, rcbegin 0;//l counter(long), l loss counterif(elem[i] - elem[i 1] 20) return;for(int a 0; a loss_pointer_L; a 2){llc loss_counter_L[a / 2];if(loss_counter_L[a / 2] 25){lc;lcbegin loss_array_L[a];}}for(int b 0; b loss_pointer_R; b 2){rlc loss_counter_R[b / 2];if(loss_counter_R[b / 2] 25){rc;rcbegin loss_array_R[b];}}
这部分是基础的判断把丢线再次分为了长丢线和短丢线这是一个很方便的分辨圆环和十字的方式即圆环为一边的长丢线十字为两边都有长丢线。
先来进行圆环的判断前面有提到圆环的一个很显著的特征是一侧边线为直线但是实际你的图象不可能特别完美比如可能会出现这样的情况 显然 左边线的处理会比较困难另外可能由于光照之类的因素左边线并不是非常的完整的直线所以需要将左边线简单的做一下分割分段判断是否为直线方式和前文提到的数据预处理相差不大
if(loss_array_R[0] IMG_H - 1){//在底部丢线的情况下 排除底部for(int j 1; j loss_pointer_R; j 2){straight_judge_array[straight_pointer] loss_array_R[j];straight_judge_array[straight_pointer] loss_array_R[j 1];if(loss_array_R[j 1] 20){straight_judge_array[straight_pointer] 20;break;}}
}
else
{straight_judge_array[straight_pointer] IMG_H - 1;straight_judge_array[straight_pointer] loss_array_R[0];for(int j 1; j loss_pointer_R; j 2){straight_judge_array[straight_pointer] loss_array_R[j];straight_judge_array[straight_pointer] loss_array_R[j 1];if(loss_array_R[j 1] 20){straight_judge_array[straight_pointer] 20;break;}}
}
然后进行数据的筛除把那些特别小的段进行剔除之后可以进行直线判断
for(int j 1; j straight_pointer; j){if(straight_pointer 2) break;if(straight_judge_array[j 1] - straight_judge_array[j] 5) flag 0;if(abs(boundary[straight_judge_array[j 1]][RIGHT] - boundary[straight_judge_array[j]][RIGHT]) 5) flag 0;}
for(int j 0; j straight_pointer; j 2){if(!is_straight(straight_judge_array[j], straight_judge_array[j 1], RIGHT)){flag 0;break;}
}
这样判断后圆环基本上可以实现识别到圆环了
if(flag 1){if(system_time - last_elem_finish_flag 200) return;if(circle_num_L 0){return;}else{mode FAR_CIRCLE_L;}
}
一种比较鸡贼的避免误判的方式 就是把根据赛道把圆环数量写死也就是代码中的circle_num_L需要注意每一次发车的时候都需要重置这个值
当然还有一些比较特殊的情况需要另外加判断去屏蔽这些需要大家跑车的时候多去试试。
圆环是误判最麻烦的一部分因为圆环分成了好几个状态每个状态都需要不同的补线方式我们采用的出圆环的方式是陀螺仪的积分这样就要求小车必须转一圈才会出圆环所以一旦误判圆环就会造成直接的错误。
接下去是十字识别
if(lc rc){if(abs(lcbegin - rcbegin) 20) return;l_down elem[i]; r_down elem[i];l_up elem[i 1]; r_up elem[i 1];for(int k 10; k 0; k k - 2){if(k loss_pointer_L) continue;if(elem[i] - 3 loss_array_L[k] loss_counter_L[k / 2] 5 loss_array_L[k] ! IMG_H - 1){l_down loss_array_L[k] 3;l_up loss_array_L[k 1] - 7;break;}}for(int k 10; k 0; k k - 2){if(k loss_pointer_R) continue;if(elem[i] - 3 loss_array_R[k] loss_counter_R[k / 2] 5 loss_array_R[k] ! IMG_H - 1){int a;r_down loss_array_R[k] 3;for(int b 7; b 13; b){if(boundary[loss_array_R[k 1] - b][RIGHT] IMG_W - 5){r_up loss_array_R[k 1] - b;break;}}break;}}if(is_straight( l_down, l_down 15, LEFT) is_straight( r_down, r_down 15, RIGHT)){mode FAR_CROSS;return;}}
十字识别相对来说简单些两边都有长丢线两边丢线到底端都是直线而且直线误判也没关系状态机会很快的恢复到正常模式也不用单独调整权重。所以我们并没有在直线判断上下很多功夫