首先还是得感谢CSDN上的众多博主的博客,在他们的博客中让我学到了很多。本篇第三篇主要是关于USB摄像头采集和图像压缩以及传输显示的问题,对于这方面我仍然是属于菜鸟部分,知道一些怎么用,然后写代码实现了应用层的使用而已,给大家分享的也是我的简单的思路,并不会去深入的剖析关于驱动呀什么的,望大家谅解。
进入正题,在linux下USB摄像头绝大部分都是统一了接口的,一种基于V4L2的框架机制,驱动部分不深究,嗯,首先感谢博主的这篇文章:https://blog.csdn.net/g_salamander/article/details/8107692 ;对ioctl接口做了详细的说明,以及这篇:https://blog.csdn.net/g_salamander/article/details/8189893 ;对驱动也做了介绍。下面将由代码来介绍怎样进行对摄像头的操作。代码我都是基于截图的方式,为了方便,如果需要的友友可以给我留言或者联系我邮箱skydearcheng@163.com联系我。
首先是头文件和几个结构体:
有些头文件可能没用就不管了;结构体后面再介绍;然后是摄像头初始化函数:
打开摄像头,传入路径一般是/dev/video0,然后定义struct v4l2_capability capway这个结构体,当然后面的名字随便取,看了我刚才推荐的博客就知道,这个结构体是拿来获取摄像头采集模式的,通过VIDIOC_QUERYCAP这个cmd获取;
然后是设置摄像头的捕捉格式:
通过struct v4l2_format fmt这个结构体设置;具体还是我推荐的博客有介绍,关于分辨率和格式具体摄像头来看,不过320*240和YUYV基本都支持,设置好了再把fmt清零再获取出来打印看下是不是。
然后是申请缓存队列:
通过struct v4l2_requestbuffers这个结构体定义然后申请主要三个参数,数量、类别、和内存方式;当然我用的是mmap映射的方式;
然后是映射用户空间和入队:
通过struct v4l2_buffer v4buf这个结构体来获取内核申请的缓存信息,然后映射用户空间然后进行全部入队操作;做完这些我们的摄像头基本就初始化成功了,当然跟不同的需求可以进行不同的设置。
然后是摄像头开始采集函数:
摄像头停止采集函数:
摄像头退出函数:
摄像头入队函数:
以上几个函数没有细讲是因为如果你看了关于那些结构体和cmd的话应该很好理解的;然后是摄像头出队函数,这个很重要了拿来获取图片了用了select:
重要的后面那一点,出队宏VIDIOC_DQBUF;
然后是自己封装给外部的获取图片函数:
循环的出队入队,至此关于摄像头操作部分的代码就完了,然后还有利用jpeg库对采集到的图像进行压缩的以及主函数使用套接字传输的;
先说主函数传输的吧:
主要就是创建套接字绑定监听不多说;然后是服务器:
也可以设置分离线程:
pthread_t tid;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pthread_create(&tid, &attr, THREAD_FUNCTION, arg);
服务器部分最简单的一种,当然也是最菜的一种,可以自己优化,然后是发送:
首先通过get_picture函数获取一张原始yuyv图片,然后通过转rgb函数转成rgb,再通过jpeg函数及库转成jpeg,再发送,先发大小,5个字节,然后跟着发一张图片的大小。写的差强人意,大家见谅,下面讲压缩函数;这里要感谢这位博主:https://www.cnblogs.com/eustoma/p/6664436.html ; 我的yuyv转grb函数就是用的他的,以前自己写的一个虚拟机内存大能用,跑64M的板子会死掉,然后就找到了这位博主的,能用,加上了flag:
注意是两张图,然后是yuyv_to_rgb:
然后是基于jpeg库的jpeg压缩函数:
当然我采集的图片格式是320*240的24位图,所以有些参数都是320*240的若是其他分辨率对应着改就可以了。
然后讲解怎样安装jpeg库:
首先自己去下包:我用的是jpegsrc.v8c.tar.gz
将jpegsrc.v8c.tar.gz包放在一个目录下,解压得到jpeg-8c文件夹;
这里说一下,如果先不用板子试,那么就先把库弄在虚拟机系统下,用pc机先测试,首先直接进入jpeg-8c对应的文件夹,然后执行./configure ,如果没有执行不成功注意权限问题或者是可执行的问题,然后直接make、make install,这样会在/usr/local/include和/usr/local/lib下生成对应的头文件和库,再编译的时候我们要指定 -L/usr/local/lib -ljpeg来链接,当然在pc下执行我们还需要将/usr/local/lib下的所有jpeg库文件拷贝一份到/usr/lib下,我的是这样,不然说找不到库,当然也可以建个链接过去,然后就可以在pc机上成功执行了。
然后是板子上的库,我需要新建一个目录比如jpeg;这里注意,先删掉编译过的jpeg-8cc目录,重新解压一份
然后进入解压目录jpeg-8c,然后执行:
./configure --host arm-linux --prefix=后面加上刚才拿来存库的目录的路径比如我的/root/tool/jpeg
就是./configure --host arm-linux --prefix=/root/tool/jpeg注意命令间的空格
然后make 再make install
然后进入到jpeg目录下也就是编译生成的目录下,将include文件夹下面的所有头文件拷贝到你交叉编译工具使用的头文件目录下,比如我的/root/tool/gcc-4.6.4/lib/gcc/arm-arm1176jzfssf-linux-gnueabi/4.6.4/include/ , 然后再拷贝一份到板子的根文件系统的/include/的目录下
然后拷贝库 将jpeg lib/下的所有文件拷贝到交叉编译工具对应目录,相比于就是上次拷头文件的上一层目录,比如我的
/root/tool/gcc-4.6.4/lib/gcc/arm-arm1176jzfssf-linux-gnueabi/4.6.4/ ,当然还要拷贝一份到板子根文件系统的/lib/目录下;
然后是编译链接的问题,不管是gcc还是arm-linux-gcc 都要加上-ljpeg来链接,注意前面要指定库目录。
至此整个摄像头采集部分就完成了。
然后是QT显示部分,对于QT显示部分在我另一篇博文中有介绍,不在赘述,但由于服务器传输的包不同,我这里也是用对应的接收方法,也就是那篇博文中说的第二种方法,如图对应收取代码:
注意是两张图片,到这里关于摄像头部分的传输和显示就完成了,至于代码的可行性那肯定是可以执行的,我这里就不在放执行结果的图了,毕竟我也不会拿我毕设开玩笑,如果需要或者我想放的时候会补上的,下面一篇讲一下对应板子的pwm控制直流点击的设计,毕竟要控制小车嘛。毕竟我也是初学者,有不足的地方请大牛多多指教,关于引用我看过的博文的作者的博文并没有经过作者本人的同意表示致歉,但只是引用推荐给大家看,应该没有问题吧。
还是放上板子上跑起来的图吧:
注意!!!大家可以看一下第六篇,以为这里jpeg格式转换那里少了一行代码,具体在第6篇里,抱歉了。