FPGA模式识别之数字检测

           从整体上来讲,就是车牌的一个检测,我仅仅做了数字的检测部分。

           首先第一个是基本理论,其实百度车牌识别的话,能收集到很多的方法,具体是怎么一个过程,具体的我不多说。大概就是,定位车牌,首先滤波后,进行边缘检测,边缘为长方形的,比例差不多的那个就是车牌。然后进行分割,矫正,最后才到了数字的检测。

                   第二个是前期的matlab验证。网上的主要方法是,让数字竖向投影到一条直线上,也就是说,分割后的数字,竖向相加。还有一个是横向投影到一条直线上,就是数字的横向相加。无论哪种方法,最主要的目的是把数字按照自己的数据特性分离开。       方法如下图。

                  

模式识别的最大要点,就是找到每个要检测的物体的差别特性。如果检测数字的时候,竖向投影,和横向投影,我用它的这两个特性依然检测不出数字是几的话,可能就要考虑斜向,或者连续点弯曲位置。用最大差异的特征去识别的话,效果就更好。

         我做的模型,或者说模拟检测的时候,只用了2个维度,就是竖向相加和横向相加。

 

这张图是竖向相加的结果。从1到0顺序。随便选的字体。

这张图是横向相加的结果。从1到0顺序。随便选的字体。

按照这两组matlab的分析图,能看出,两个维度差异比较大,基本可以检测出是什么数字了。可是如果有噪声的影响下,同一个数字能分离开吗??

从图上来看6和9和8,0和8差异并不是很大。在受到多大干扰的情况就检测不出来了呢???

这个是数据1到5的差异图。

这样图是这么来的,在不同的情况下,用了不同的数据样本(没有人为加扰,字体相同)。然后同样做竖向和横向相加,然后看看这些样本的差别。

当然其他的干扰测试还需要很多。6和9,8和0,他们能承受多大的误差。这张图的0,和有干扰图的0,之间的差异性。最后才能决定用什么检测方法。

前面这些都是matlab分析过程,其实要写最终的matlab验证程序的,我发现我偷懒了,没有写,就直接verilog开始写程序了。

最后的检测方案

             横向比较,允许偏差一个数字80个像素点的偏差(当然图的大小有差异,这个数据自然会有)。竖向比较,偏差60吧。如果没有找到,就把最前面的点(竖向相加,最第一个数据点)和最后一个点,去掉,在匹配。如果还没检测出来,把整个数据加10像素点,在匹配。下一步整体减少10个像素点,在匹配。如果检测不出来,报错。

FPGA实现:

 parameter  idle_state      = 64'b0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0001;
parameter  clear_memory_state    = 64'b0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0010;
parameter  receive_image_fifo_full  = 64'b0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0100;
parameter  receive_imagel9_state   = 64'b0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_1000;
parameter  receive_imageh9_state   = 64'b0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0001_0000;
parameter  selet_vertical_start   = 64'b0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0010_0000;
parameter  vertical_add_state    = 64'b0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0100_0000;
parameter  vertical_sum_save    = 64'b0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_1000_0000;
parameter  find_edge_read_start   = 64'b0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0001_0000_0000;
parameter  save_data_state     = 64'b0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0010_0000_0000;
parameter  competer_edge_state    = 64'b0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0100_0000_0000;
parameter  save_edge_value_state1   = 64'b0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_1000_0000_0000_0000;
parameter  save_edge_value_state2   = 64'b0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0001_0000_0000_0000_0000;
parameter  selet_horizontal_start   = 64'b0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0010_0000_0000_0000_0000;
parameter  horizontal_add_state   = 64'b0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0100_0000_0000_0000_0000;
parameter  horizontal_sum_save    = 64'b0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_1000_0000_0000_0000_0000;
parameter  read_save_data50_state   = 64'b0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0001_0000_0000_0000_0000_0000;
parameter  test_save_data50_state   = 64'b0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0010_0000_0000_0000_0000_0000;
parameter  read_rom_data_state    = 64'b0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0100_0000_0000_0000_0000_0000;
parameter  example_data_read_out   = 64'b0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_1000_0000_0000_0000_0000_0000;
parameter  data_compare_state    = 64'b0000_0000_0000_0000_0000_0000_0000_0000_0000_0001_0000_0000_0000_0000_0000_0000;
parameter  data_abs_state     = 64'b0000_0000_0000_0000_0000_0000_0000_0000_0000_0010_0000_0000_0000_0000_0000_0000;
parameter  shift_1time_register   = 64'b0000_0000_0000_0000_0000_0000_0000_0000_0000_0100_0000_0000_0000_0000_0000_0000;
parameter  num_big_two_state    = 64'b0000_0000_0000_0000_0000_0000_0000_0000_0000_1000_0000_0000_0000_0000_0000_0000;
parameter  test_counter_state    = 64'b0000_0000_0000_0000_0000_0000_0000_0000_0001_0000_0000_0000_0000_0000_0000_0000;
parameter  judge_code_test     = 64'b0000_0000_0000_0000_0000_0000_0000_0000_0010_0000_0000_0000_0000_0000_0000_0000;
parameter  read_ramh_data0     = 64'b0000_0000_0000_0000_0000_0000_0000_0000_0100_0000_0000_0000_0000_0000_0000_0000;
parameter  read_ramh_data1     = 64'b0000_0000_0000_0000_0000_0000_0000_0000_1000_0000_0000_0000_0000_0000_0000_0000;
parameter left_shift_one     = 64'b0000_0000_0000_0000_0000_0000_0000_0001_0000_0000_0000_0000_0000_0000_0000_0000;
parameter data_compare_two     = 64'b0000_0000_0000_0000_0000_0000_0000_0010_0000_0000_0000_0000_0000_0000_0000_0000;
parameter data_abs_two      = 64'b0000_0000_0000_0000_0000_0000_0000_0100_0000_0000_0000_0000_0000_0000_0000_0000;
parameter num_big_two_two     = 64'b0000_0000_0000_0000_0000_0000_0000_1000_0000_0000_0000_0000_0000_0000_0000_0000;
parameter test_counter_two     = 64'b0000_0000_0000_0000_0000_0000_0001_0000_0000_0000_0000_0000_0000_0000_0000_0000;
parameter data_compare_three    = 64'b0000_0000_0000_0000_0000_0000_0010_0000_0000_0000_0000_0000_0000_0000_0000_0000;
parameter set_send_state_add    = 64'b0000_0000_0000_0000_0000_0000_0100_0000_0000_0000_0000_0000_0000_0000_0000_0000;
parameter USB_send_emtry_state    = 64'b0000_0000_0000_0000_0000_0000_1000_0000_0000_0000_0000_0000_0000_0000_0000_0000;
parameter USB_send_l9_state    = 64'b0000_0000_0000_0000_0001_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000;
parameter USB_send_h9_state    = 64'b0000_0000_0000_0000_0010_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000;
parameter data_abs_three     = 64'b0000_0000_0000_0000_0100_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000;
parameter num_big_two_three    = 64'b0000_0000_0000_0000_1000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000;
parameter test_counter_three    = 64'b0000_0000_0000_0001_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000;
parameter image_num_time     = 64'b0000_0000_0000_0010_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000;
parameter save_one_cycle     = 64'b0000_0000_0000_0100_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000;
parameter shift_1time_three    = 64'b0000_0000_0000_1000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000;
parameter shift_1time_two     = 64'b0000_0000_0001_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000;

这个是我最后需要用的状态机数量。大概描述一下,状态机运行的顺序。

receive_imageh9_state状态前,都是在接收数字的图像,

好像一个一个状态解释,太多了。

大概顺序是这样的,1,接收到一个图像,5个数字。

2,分离,主要是2个数之间,有段没有数据,所以这个就是标志线。

3,竖向相加,求和。

4,第一次,进行比对。读rom,进行对比,对比如何误差过大,就进入下个数据,如果全没有,进入下个状态。

5,横向相加,求和。

6,第二次,进行比对。

7,看是什么数。如果没有回到第4部分。去掉头和尾,在比对。

8,最后就是整个竖向的和,都减10,和加10.在比对。

9,输出结果。

结果嘛。如果是相对标准的还好。只要换一种字体,就没法检测出来了。所以,如果需要实际用的话,还要有很多的改进,只能说大体思想和大体结构是这样的。

微笑本人能力有限,但是我努力做到,奉献我的技术,希望你们快速成长,希望中国的技术可以腾飞。

如果有好的想法,有些挑战性的话,可以给我留言,有兴趣我也会去学一下的。

原文地址:https://www.cnblogs.com/maohuawang/p/3807223.html