注册 登录
查看: 577|回复: 16

请教摄像头有关问题之-------摄像头的采集与处理数据之间的实时性如何做到的?

[复制链接]
发表于 2014-2-19 11:37:09 | 显示全部楼层 |阅读模式
我想知道,在摄像采集的同时如何对采集的数据进行实时处理?例如我们常见的手机扫描二维码,图像一直在更新,同时也一直在识别。在程序中有何特别之处?我现在用K60在写一个实时识别数字的系统,可是无法实现实时行啊,图像就卡在一桢不动了,如何是好?
来自PC客户端 来自PC客户端
回复

使用道具 举报

发表于 2014-2-19 12:11:42 | 显示全部楼层
关键是代码识别算法问题了,图像数据尽可能小。例如一个文字模版为16*16
回复 支持 反对

使用道具 举报

发表于 2014-2-19 12:12:52 | 显示全部楼层
如果你加入的算法效率过低,那么就会出现这问题。
还有,一旦采集识别不了,那么就马上放弃,继续采集下一幅图像。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-2-19 12:38:59 | 显示全部楼层
风落小鱼 发表于 2014-2-19 12:12
如果你加入的算法效率过低,那么就会出现这问题。
还有,一旦采集识别不了,那么就马上放弃,继续采集下一 ...

我查了好多资料,一般的算法都是按点,按行扫描,这样的算法确实费时,由于之前从来没有弄过这种,希望得到高人的指点啊
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-2-19 12:40:22 | 显示全部楼层
风落小鱼 发表于 2014-2-19 12:11
关键是代码识别算法问题了,图像数据尽可能小。例如一个文字模版为16*16

太小就会使得图像不清楚,识别就更困难了。。。
回复 支持 反对

使用道具 举报

发表于 2014-2-19 14:18:15 | 显示全部楼层
zoro 发表于 2014-2-19 12:40
太小就会使得图像不清楚,识别就更困难了。。。

80*60应该是可以采集清晰的,从中间寻找字符,把他切割出来,归一化为16*16或者8*8。
换句话说,必须尽快把图像大小减小,不然处理速度很慢
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-2-19 14:31:04 | 显示全部楼层
山外メ雲ジ 发表于 2014-2-19 14:18
80*60应该是可以采集清晰的,从中间寻找字符,把他切割出来,归一化为16*16或者8*8。
换句话说,必须尽快 ...

山外,思路是这样的,可是我属菜鸟级别的,希望能给点详细的指教。
过程是:字符切割----归一化-----特征提取------比较对比
可是算法实在是不行啊,弄了好几天了,都快疯了。
回复 支持 反对

使用道具 举报

发表于 2014-2-19 14:32:44 | 显示全部楼层
zoro 发表于 2014-2-19 14:31
山外,思路是这样的,可是我属菜鸟级别的,希望能给点详细的指教。
过程是:字符切割----归一化-----特征 ...

我也没有现成的代码,我是三年前搞过而已,只懂思路,具体代码需要你自行实现。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-2-19 14:34:11 | 显示全部楼层
山外メ雲ジ 发表于 2014-2-19 14:32
我也没有现成的代码,我是三年前搞过而已,只懂思路,具体代码需要你自行实现。

只写了部分代码:看看能成不?
  1. /********************消除起始左右边界的阴影**************************/   
  2.   
  3.     for(i=0;i<320;i++)        //从左向右扫描
  4.     {
  5.         number=0;             //number为一列白色像素的点数
  6.         for(j=0;j<240;j++)    //从上到下扫描
  7.         {
  8.             if(img_buf[i][j]==0)
  9.                 number++;     //遇到白色点数number加 1
  10.         }
  11.         if(number>10)         
  12.         {
  13.             left0=i;          //稳定的起始边界--白色--左边
  14.             break;
  15.         }
  16.     }
  17.     for(i=320;j>0;j--)        //从右向左扫描
  18.     {
  19.         number=0;             //number为一列白色像素的点数
  20.         for(j=0;j<240;j++)    //从上到下扫描
  21.         {   
  22.             if(img_buf[i][j]==0);
  23.                 number++;
  24.         }
  25.         if(number>10)
  26.         {
  27.             right0=i;       //稳定的起始边界--白色--右边
  28.             break;
  29.         }
  30.     }
  31.     /*******************消除起始上下边界的阴影**************************/
  32.     for(j=0;j<240;j++)      //从上到下扫描
  33.     {
  34.         number=0;           
  35.         for(i=left0;j<=right0;i++)
  36.         {
  37.           if(img_buf[i][j]==0)
  38.               number++;
  39.         }
  40.         if(number>10)
  41.         {
  42.             top0=j;         //稳定的起始边界--白色--顶部
  43.             break;
  44.         }
  45.     }
  46.      for(j=240;j>0;j--)
  47.      {
  48.           number=0;
  49.           for(i=left0;i<right0;i++)
  50.           {
  51.                 if(img_buf[i][j]==0)
  52.                     number++;
  53.           }
  54.           if(number>10)
  55.           {
  56.                 bottom0=j;        //稳定的起始边界--白色--底部
  57.                 break;
  58.           }   
  59.      }
  60.      /*******************确定字符的上下边界*************************/
  61.    
  62.     for(j=top0;i<bottom0;i++)     //从上到下扫描(稳定边界)
  63.      {
  64.           count=0;                //count为一行中黑色像素的点数
  65.           for(i=left0;i<right0;i++)
  66.           {
  67.               if(img_buf[i][j]==1)
  68.                   count++;
  69.           }
  70.           if(count>5)
  71.           {
  72.               top1=j;
  73.               break;
  74.           }
  75.      }
  76.       for(j=bottom0;j>top0;j--)       //从下到上扫描(稳定边界)
  77.       {
  78.            count=0;                   //count为一行中黑色像素的点数
  79.            for(i=left0;i<right0;i++)
  80.            {
  81.                 if(img_buf[i][j]==0)
  82.                     count++;
  83.            }
  84.            if(count>5)
  85.            {
  86.                 bottom1=j;
  87.                 break;
  88.            }
  89.       }
  90.   
  91.   /*********************确定字符的左右边界****************/  
  92.       for(i=left0;i<right0;i++)
  93.       {
  94.             count=0;
  95.             for(j=top0;j<bottom0;j++)
  96.             {
  97.                   if(img_buf[i][j]==1)
  98.                       count++;
  99.             }
  100.             if(count>5)
  101.             {
  102.                   left1=i;
  103.                   break;
  104.             }
  105.       }
  106.      for(i=right0;i>left0;i--)
  107.      {
  108.      
  109.             count=0;
  110.             for(j=top0;j<bottom0;j++)
  111.             {
  112.                   if(img_buf[i][j]==1)
  113.                       count++;
  114.             }
  115.             if(count>5)
  116.             {
  117.                   right1=i;
  118.                   led(LED0, LED_ON);     
  119.                   break;
  120.             }
  121.      }
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-2-19 14:45:38 | 显示全部楼层
zoro 发表于 2014-2-19 14:34
只写了部分代码:看看能成不?

这样执行效率也太低了吧,早就卡住了,耗时啊。。
回复 支持 反对

使用道具 举报

发表于 2014-2-19 14:51:32 | 显示全部楼层
zoro 发表于 2014-2-19 14:34
只写了部分代码:看看能成不?

建议从中间往四周扫描,认为字体就放在中间,这样才能减少扫描时间。如果是整幅图片扫描,需要花费较长时间
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-2-19 14:56:05 | 显示全部楼层
山外メ雲ジ 发表于 2014-2-19 14:51
建议从中间往四周扫描,认为字体就放在中间,这样才能减少扫描时间。如果是整幅图片扫描,需要花费较长时 ...

这个函数这么耗时,放在程序的什么位置较为合适,while(1)里面是摄像头采集和lcd显示,需要中断还是顺序执行呢?
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-2-19 19:44:27 | 显示全部楼层
zoro 发表于 2014-2-19 14:34
只写了部分代码:看看能成不?
  1. /*!
  2. *     COPYRIGHT NOTICE
  3. *     Copyright (c) 2013,山外科技
  4. *     All rights reserved.
  5. *     技术讨论:山外我行论坛 http://www.vcan123.com
  6. *
  7. *     除注明出处外,以下所有内容版权均属山外科技所有,未经允许,不得用于商业用途,
  8. *     修改内容时必须保留山外科技的版权声明。
  9. *
  10. * @file       main.c
  11. * @brief      山外K60 平台主程序
  12. * @author     山外科技
  13. * @version    v5.0
  14. * @date       2013-08-28
  15. */

  16. #include "common.h"
  17. #include "include.h"


  18. uint8 imgbuff[CAMERA_SIZE];                             //定义存储接收图像的数组
  19. uint8 img[CAMERA_W*CAMERA_H];
  20. uint16 img_buf[CAMERA_W][CAMERA_H];
  21. uint8 bianyuan[CAMERA_W][CAMERA_H];

  22. //函数声明
  23. void PORTA_IRQHandler();
  24. void DMA0_IRQHandler();
  25. void sendimg(uint8 *imgaddr, uint32 imgsize);
  26. void img_extract(uint8 *dst, uint8 *src, uint32 srclen);
  27. void display();

  28. /*!
  29. *  @brief      main函数
  30. *  @since      v5.0
  31. *  @note       山外LCD flexbus测试实验
  32. */
  33. void  main(void)
  34. {
  35.     Site_t site     = {0, 0};                           //显示图像左上角位置
  36.     Size_t imgsize  = {CAMERA_W, CAMERA_H};             //图像大小
  37.     Size_t size;                   //显示区域图像大小

  38.     LCD_init();

  39.     site.x = 10;
  40.     site.y = 10;
  41.    
  42.    
  43.    

  44.     size.H = LCD_H;
  45.     size.W = LCD_W;
  46.     led_init(LED0);                         //初始化LED0
  47.     led_init(LED1);                         //初始化LED1
  48.     uint16 i,j;
  49.     uint16 number,flag,count,lab,num,left,right;
  50.     uint16 a_left,a_right,b_left,b_right,c_left,c_right;
  51.     uint16 a_top,a_bottom,b_top,b_bottom,c_top,c_bottom;
  52.     uint16 y_height,x_width;
  53.    

  54.     camera_init(imgbuff);
  55.     //配置中断复位函数
  56.     set_vector_handler(PORTA_VECTORn , PORTA_IRQHandler);   //设置LPTMR的中断复位函数为 PORTA_IRQHandler
  57.     set_vector_handler(DMA0_VECTORn , DMA0_IRQHandler);     //设置LPTMR的中断复位函数为 PORTA_IRQHandler
  58.     while(1)
  59.     {
  60.         camera_get_img();                                   //摄像头获取图像

  61. #if     ( CAMERA_COLOR == 1 )                                       //灰度摄像头
  62.         LCD_Img_gray_Z       (site, size, imgbuff, imgsize);
  63. #elif   ( CAMERA_COLOR == 0 )                                       //黑白摄像头
  64.        // LCD_Img_Binary_Z(site, size, imgbuff, imgsize);
  65.         /**************从中间向左扫描取数字边界*****************/
  66. for(i=40;i>10;i--)                                //中间坐标(40,30)
  67. {
  68.         number=0;                                //一列中白色像素的点数,初值为零
  69.         lab=0;
  70.         for(j=10;j<50;j++)
  71.         {
  72.                 if(img_buf[i][j]==0)
  73.                         number++;                //白色像素点数
  74.                         lab=1;                        //数字在中线左侧的标志
  75.         }
  76.         if(number==0)                                //此列没有白色像素点,意味着数字在中线上
  77.                 flag++;                                //一列中黑色像素的点数,一位中数字在中线位置
  78.         if(number>2 && flag>5 && lab==1 )        //意味着数字在中线左侧
  79.         {
  80.                 left=1;
  81.                 a_right=i;                        //找出数字的右边界
  82.                 break;
  83.         }
  84.         if(flag>5 && lab==0 && number>20)        //找出数字左边界
  85.         {
  86.                 b_left=i;
  87.                 break;
  88.         }
  89. }
  90. /****************从中间向右扫描取字符边界*********************/
  91. for(i=40;i<70;i++)                       
  92. {
  93.         number=0;                                //一列中白色像素的点数,初值为0
  94.         for(j=10;j<50;j++)
  95.         {
  96.                 if(img_buf[i][j]==0)
  97.                         number++;
  98.                         lab=1;                        //数字在中线右侧的标志
  99.         }
  100.         if(number==0)                                //起初数字在中线上
  101.                 flag++;
  102.         if(number>2 && flag>5 && lab==1)        //数字在中线右侧
  103.         {
  104.                 right=1;
  105.                 c_left=i;                        //找出数字左边界
  106.                 break;
  107.         }
  108.         if(flag>5 && lab==0 && number>20)
  109.         {
  110.                 b_right=i;                        //找出数字右边界
  111.                 break;
  112.         }
  113. }


  114. if(left==1)
  115. {        led(LED0,LED_ON);
  116.         /*******************确定位于中线左侧的数字左边界*******************/
  117.         for(i=5;i<a_right;i++)
  118.         {
  119.                 num=0;                                        //一列中黑色像素的点数
  120.                 for(j=10;j<50;j++)
  121.                 {
  122.                         if(img_buf[i][j]==1)
  123.                                 num++;
  124.                 }
  125.                 if(num>5)
  126.                 {
  127.                         a_left=i;                        //取位于中线左边数字的左边界
  128.                         break;
  129.                 }
  130.         }
  131.         /*********************确定字符的上下边界*********************************/       
  132.         for(j=10;j<50;j++)
  133.         {
  134.                 num=0;
  135.                 for(i=a_left;i<a_right;i++)
  136.                 {
  137.                         if(img_buf[i][j]==1)
  138.                                 num++;
  139.                 }
  140.                 if(num>5)
  141.                 {
  142.                         a_top=j;
  143.                         break;
  144.                 }
  145.         }
  146.         for(j=50;j>10;j--)
  147.         {
  148.                 num=0;
  149.                 for(i=a_left;i<a_right;i++)
  150.                 {
  151.                         if(img_buf[i][j]==1)
  152.                                 num++;
  153.                 }
  154.                 if(num>5)
  155.                 {
  156.                         a_bottom=j;
  157.                         break;
  158.                 }
  159.         }
  160.       
  161. }

  162. if(right==1)
  163. {
  164.         /********************确定位于中线右侧的数字左边界*********************/

  165.         for(i=70;i<c_left;i++)
  166.         {
  167.                 num=0;                                        //一列中黑色像素的点数
  168.                 for(j=10;j<50;j++)
  169.                 {
  170.                         if(img_buf[i][j]==1)
  171.                                 num++;
  172.                 }
  173.                 if(num>5)
  174.                 {
  175.                         c_right=i;                        //取位于中线左边数字的左边界
  176.                         break;
  177.                 }
  178.         }
  179.         /*********************确定字符的上下边界*********************************/       
  180.         for(j=10;j<50;j++)
  181.         {
  182.                 num=0;
  183.                 for(i=c_left;i<c_right;i++)
  184.                 {
  185.                         if(img_buf[i][j]==1)
  186.                                 num++;
  187.                 }
  188.                 if(num>5)
  189.                 {
  190.                         c_top=j;
  191.                         break;
  192.                 }
  193.         }
  194.         for(j=50;j>10;j--)
  195.         {
  196.                 num=0;
  197.                 for(i=c_left;i<c_right;i++)
  198.                 {
  199.                         if(img_buf[i][j]==1)
  200.                                 num++;
  201.                 }
  202.                 if(num>5)
  203.                 {
  204.                         c_bottom=j;
  205.                         break;
  206.                 }
  207.         }
  208.         
  209. }
  210. /*********************确定位于中线上的字符的上下边界*********************************/       
  211.         for(j=10;j<50;j++)
  212.         {
  213.                 num=0;
  214.                 for(i=b_left;i<b_right;i++)
  215.                 {
  216.                         if(img_buf[i][j]==1)
  217.                                 num++;
  218.                 }
  219.                 if(num>5)
  220.                 {
  221.                         b_top=j;
  222.                         break;
  223.                 }
  224.         }
  225.         for(j=50;j>10;j--)
  226.         {
  227.                 num=0;
  228.                 for(i=b_left;i<b_right;i++)
  229.                 {
  230.                         if(img_buf[i][j]==1)
  231.                                 num++;
  232.                 }
  233.                 if(num>5)
  234.                 {
  235.                         b_bottom=j;
  236.                         break;
  237.                 }
  238.         }
  239. }
  240. LCD_num_C(site, a_right, BLUE, RED);
  241. /***********************字符分割************************************/

  242.   
  243. #endif

  244. #if 0
  245.         /******************** 发送图像到上位机 ***********************/
  246.         img_extract(img_buf, imgbuff, CAMERA_SIZE);          //解压为灰度图像,方便发送到上位机显
  247.         sendimg(img, CAMERA_W * CAMERA_H);                    //发送到上位机
  248. #endif

  249.     }



  250. /*!
  251. *  @brief      PORTA中断服务函数
  252. *  @since      v5.0
  253. */
  254. void PORTA_IRQHandler()
  255. {
  256.     uint8  n;    //引脚号
  257.     uint32 flag;

  258.     while(!PORTA_ISFR);
  259.     flag = PORTA_ISFR;
  260.     PORTA_ISFR  = ~0;                                   //清中断标志位

  261.     n = 29;                                             //场中断
  262.     if(flag & (1 << n))                                 //PTA29触发中断
  263.     {
  264.         camera_vsync();
  265.     }
  266. #if ( CAMERA_USE_HREF == 1 )                            //使用行中断
  267.     n = 28;
  268.     if(flag & (1 << n))                                 //PTA28触发中断
  269.     {
  270.         camera_href();
  271.     }
  272. #endif


  273. }

  274. /*!
  275. *  @brief      DMA0中断服务函数
  276. *  @since      v5.0
  277. */
  278. void DMA0_IRQHandler()
  279. {
  280.     camera_dma();
  281. }


  282. //发送图像到上位机显示
  283. //不同的上位机,不同的命令,这里使用 yy_摄像头串口调试 软件
  284. //如果使用其他上位机,则需要修改代码
  285. void sendimg(uint8 *imgaddr, uint32 imgsize)
  286. {
  287.     uint8 cmd[4] = {0, 255, 1, 0 };    //yy_摄像头串口调试 使用的命令

  288.     uart_putbuff(FIRE_PORT, cmd, sizeof(cmd));    //先发送命令

  289.     uart_putbuff(FIRE_PORT, imgaddr, imgsize); //再发送图像
  290. }

  291. //压缩二值化图像解压(空间 换 时间 解压)
  292. //srclen 是二值化图像的占用空间大小
  293. void img_extract(uint8 *dst, uint8 *src, uint32 srclen)
  294. {
  295.     uint8 colour[2] = {255, 0}; //0 和 1 分别对应的颜色
  296.     //注:山外的摄像头 0 表示 白色,1表示 黑色
  297.     uint8 tmpsrc;
  298.     while(srclen --)
  299.     {
  300.         tmpsrc = *src++;
  301.         *dst++ = colour[ (tmpsrc >> 7 ) & 0x01 ];
  302.         *dst++ = colour[ (tmpsrc >> 6 ) & 0x01 ];
  303.         *dst++ = colour[ (tmpsrc >> 5 ) & 0x01 ];
  304.         *dst++ = colour[ (tmpsrc >> 4 ) & 0x01 ];
  305.         *dst++ = colour[ (tmpsrc >> 3 ) & 0x01 ];
  306.         *dst++ = colour[ (tmpsrc >> 2 ) & 0x01 ];
  307.         *dst++ = colour[ (tmpsrc >> 1 ) & 0x01 ];
  308.         *dst++ = colour[ (tmpsrc >> 0 ) & 0x01 ];
  309.     }
  310. }

  311. void display()
  312. {
  313.     uint16  i = 0;
  314.     Site_t site;
  315.     LCD_init();            //初始化

  316.     site.x = 10;
  317.     site.y = 10;
  318.    
  319.         
  320.   
  321.           for(i=0;i<100;i++)
  322.           {
  323.               LCD_num_C(site, i, BLUE, RED);
  324.               //i++;
  325.               //site.y=site.y+8;
  326.           }
  327.    
  328. }



  329.   
请指教指教,山外。。。。。。谢谢啦
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-2-19 19:47:34 | 显示全部楼层
zoro 发表于 2014-2-19 19:44
请指教指教,山外。。。。。。谢谢啦

这个图像解压数组里好像不是数字0,1组成,调试是值不对啊。。。。
回复 支持 反对

使用道具 举报

发表于 2014-2-19 20:01:30 | 显示全部楼层
zoro 发表于 2014-2-19 19:47
这个图像解压数组里好像不是数字0,1组成,调试是值不对啊。。。。

解压后的值为0和255,可根据自己需求修改我们的原函数啊!!!
img_extract函数里面
  1. uint8 colour[2] = {255, 0}; //0 和 1 分别对应的颜色
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-2-19 20:05:35 | 显示全部楼层
山外メ雲ジ 发表于 2014-2-19 20:01
解压后的值为0和255,可根据自己需求修改我们的原函数啊!!!
img_extract函数里面

能直接调用二值化的值吗?就是80x60个0或1的,一个黑色像素点就是1,白色像素点是0。。。。
回复 支持 反对

使用道具 举报

发表于 2014-2-20 11:58:52 | 显示全部楼层
zoro 发表于 2014-2-19 20:05
能直接调用二值化的值吗?就是80x60个0或1的,一个黑色像素点就是1,白色像素点是0。。。。

采集回来的是压缩后的图像,需要解压后才可以的,不然不利于处理。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回列表 返回顶部