0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

英创信息技术Linux工控主板摄像头应用简介

英创信息技术 来源:英创信息技术 作者:英创信息技术 2020-02-03 09:01 次阅读

近年来,随着计算机、网络以及图像处理、传输技术的飞速发展,摄像头在工业控制领域的应用也越来越广泛了,目前市面上的摄像头可以分为两类,一种是符合UVC规范的摄像头,比如罗技的摄像头就是UVC摄像头。另一种是non-UVC摄像头,即不符合UVC规范。UVC全称为:USB video class (USB视频类)在Linux-2.6.4及以上的版本都已经集成了UCV设备的驱动,而non-UVC摄像头如果要使用,就需要硬件厂商提供专用的驱动。比如中星微的摄像头就是non-UVC设备,需要专用的驱动。

1、Linux内核配置

本文以英创嵌入式板卡EM335x 为例来介绍对于USB摄像头的支持,EM335x内核版本为Linux-3.12.10,USB摄像头选用中星微的ZC301摄像头,该摄像头以其高性价比得以广泛应用,同时在Linux内核中已经包括了对于ZC3XX系列摄像头的驱动支持。

内核配置如下:
<*> Multimedia support --->
[*] Cameras/video grabbers support
[*] Media USB Adapters --->
<*> USB Video Class (UVC)
[*] UVC input events device support
<*> GSPCA based webcams --->
ZC3XX USB Camera Driver

编译成功后,即可得到zc3xx系列USB摄像头驱动文件:gspca_zc3xx.ko。

在EM335x板卡上,该文件放置在根文件系统/lib/modules/3.12.10/目录下。应用时只需调用以下命令,即可完成对于USB摄像头的驱动加载。

insmod /lib/modules/3.12.10/gspca_zc3xx.ko

驱动加载成功后,会自动生成设备节点:“/dev/video0',应用程序可以操作该设备节点对摄像头进行图像的采集和控制。因为中星微的摄像头为non-UVC设备,所以需要再加专用的gspca_zc3xx.ko,如果是其他的UVC摄像头,内核中已经集成了驱动,插上后就可以识别出来,不用再加载其他驱动。

2、Qt摄像头应用程序简介

UVC和non-UVC摄像头都是用了V4L2驱动提供的API来操作摄像头。Video for Linux two简称V4L2,是V4L的改进版。V4L2是Linux操作系统下用于采集图片、视频音频数据的API接口,配合适当的视频采集设备和相应的驱动程序,可以实现图片、视频、音频等的采集。在视频监控系统和嵌入式多媒体终端中都有广泛的应用。V4L2支持两种方式来采集图像:内存映射方式(mmap)和直接读取方式(read)。在这里我们使用内存映射的方式来进行视频采集。应用程序通过V4L2接口采集视频数据可以分为五个步骤:

①打开视频设备文件,进行视频采集的参数初始化,通过V4L2接口设置视频图像的采集窗口、采集的点阵大小和格式;
②申请若干视频采集的帧缓冲区,并将这些帧缓冲区从内核空间映射到用户空间,便于应用程序读取/处理视频数据;
③将申请到的帧缓冲区在视频采集输入队列排队,并启动视频采集;
④驱动开始视频数据的采集,应用程序从视频采集输出队列取出帧缓冲区,处理完后,将帧缓冲区重新放入视频采集输入队列,循环往复采集连续的视频数据;
⑤停止视频采集。

可以参考下图:

可以看到每一个步骤都是通过ioctl这个接口去设置一些参数来实现的, 启动视频采集后,驱动程序开始采集数据,并把采集的数据放入视频采集输入队列的第一个帧缓冲区,当一帧数据采集完成,也就是第一个帧缓冲区存满数据以后,驱动程序将这一个缓冲区移至视频采集输出队列,等待应用程序取出。驱动程序接下来继续采集下一帧数据,并放入第二个帧缓冲区,同样帧缓冲区存满数据后,被放入视频采集输出队列。

应用程序从视频采集输出队列中取出含有视频数据的帧缓冲区,处理帧缓冲区中的视频数据,如存储或压缩。如果需要连续采集,应用程序需要将处理完数据的帧缓冲区重新放入视频采集输入队列,如图所示。

接下来结合程序来具体看一看通过V4L2接口来操作摄像头的一些重要的步骤:

打开设备文件:
int fd;
fd=open('/dev/video0',O_RDWR);

获取设备的基本信息,包括驱动版本号,设备支持操作等:
struct v4l2_capability cap;
ret=ioctl(fd,VIDIOC_QUERYCAP,&cap);
if(ret<0)
{
printf('failture VIDIOC_QUERYCAP ');
return -1;
}
printf('DriverName:%s Card Name:%s Bus info:%s DriverVersion:%u.%u.%u ',cap.driver,cap.card,cap.bus_info,(cap.version>>16)&0xFF,(cap.version>>8)&0xFF,cap.version&0xFF);

显示所支持的格式:
memset(&fmtdesc, 0, sizeof(fmtdesc));
fmtdesc.index = 0;
//数据流类型,必须永远是V4L2_BUF_TYPE_VIDEO_CAPTURE
fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
while(ioctl(fd,VIDIOC_ENUM_FMT,&fmtdesc)!=-1)
{
printf('/t%d.%s/n',fmtdesc.index+1,fmtdesc.description);
fmtdesc.index++;
}

设置视频的制式和帧格式,制式包括PAL,NTSC,帧的格式个包括宽度和高度等:
struct v4l2_format fmt;
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;//数据流类型,必须永远是V4L2_BUF_TYPE_VIDEO_CAPTURE
fmt.fmt.pix.width = 640;//宽,必须是16的倍数
fmt.fmt.pix.height = 480;//高,必须是16的倍数
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_JPEG;//视频数据存储类型//V4L2_PIX_FMT_YUYV;//V4L2_PIX_FMT_YVU420;//V4L2_PIX_FMT_YUYV;
fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
//设置当前驱动的频捕获格式
ret = ioctl (fd, VIDIOC_S_FMT, &fmt);
if(ret<0)
{
printf('failture VIDIOC_S_FMT ');
return -1;
}

向驱动申请帧缓冲,一般不超过五个:
struct v4l2_requestbuffers req;
req.count=1;
req.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory=V4L2_MEMORY_MMAP;
//申请帧缓冲
ret=ioctl(fd,VIDIOC_REQBUFS,&req);
if(ret<0)
{
printf('failture VIDIOC_REQBUFS ');
return -1;
}
if (req.count < 1)
{
printf('Insufficient buffer memory ');
return -1;
}

将申请到的帧缓冲映射到用户空间,这样就能够直接操作帧缓冲了:
buffers =(buffer*)calloc (req.count, sizeof (*buffers));
if (!buffers) {
fprintf (stderr,'Out of memory/n');
exit(EXIT_FAILURE);
}
for (n_buffers = 0; n_buffers < req.count; ++n_buffers)
{
struct v4l2_buffer buf;
memset(&buf,0,sizeof(buf));
buf.type =V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory =V4L2_MEMORY_MMAP;
buf.index =n_buffers;
//查询序号为n_buffers 的缓冲区,得到其起始物理地址和大小
if (-1 == ioctl(fd, VIDIOC_QUERYBUF, &buf))
{
printf('failture VIDIOC_QUERYBUF ');
return -1;
}
buffers[n_buffers].length= buf.length;
//映射内存
buffers[n_buffers].start=mmap (NULL,buf.length,PROT_READ | PROT_WRITE ,MAP_SHARED,fd, buf.m.offset);
if (MAP_FAILED == buffers[n_buffers].start)
{
printf('failture mmap ');
return -1;
}
}

将申请到的帧缓冲全部入队列,以便存放采集到的数据:
for (i = 0; i< req.count; ++i)
{
struct v4l2_buffer buffer;
buffer.type =V4L2_BUF_TYPE_VIDEO_CAPTURE;
buffer.memory =V4L2_MEMORY_MMAP;
buffer.index = i;
//将缓冲帧放入队列尾
ioctl (fd,VIDIOC_QBUF, &buffer);
}

开始视频的采集:
type =V4L2_BUF_TYPE_VIDEO_CAPTURE;
ioctl (fd,VIDIOC_STREAMON, &type);

取出队列中以取得采集数据的帧缓冲,获得原始采集数据,因为这个摄像头支持的格式为JPG,所以程序中将原始数据保存在新建的一个*.jpg文件中:
struct v4l2_buffer camera_buf;
CLEAR (camera_buf);
camera_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
camera_buf.memory = V4L2_MEMORY_MMAP;
//取出一个缓冲帧
i1 = ioctl (fd, VIDIOC_DQBUF, &camera_buf);
if(i1<0)
{
printf('failture ');
return -1;
}
fwrite(buffers[camera_buf.index].start, buffers[camera_buf.index].length, 1, file_fd);//将其写入文件中

将缓冲帧重新入队列尾,这样可以循环采集:
//将缓冲重新入队列尾
i1=ioctl (fd, VIDIOC_QBUF, &camera_buf);
if(i1<0)
{
printf('failture VIDIOC_QBUF ');
return -1;
}

如果需要关闭摄像头,先停止视屏采集,释放申请的帧缓冲,最后关闭设备节点:
//停止视频的采集。VIDIOC_STREAMOFF
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (-1 == ioctl(fd, VIDIOC_STREAMOFF, &type))
printf('VIDIOC_STREAMOFF');
for (i = 0; i < n_buffers; ++i)
if (-1 == munmap (buffers->start, buffers->length))
printf ('munmap error');
free(buffers);
//关闭视频设备
close (fd);

所以通过这一套通用的V4L2接口来操作摄像头的工作流程:

打开设备-> 检查和设置设备属性->设置帧格式-> 设置一种输入输出方法(缓冲区管理)-> 循环获取数据-> 关闭设备。通过这几个步骤已经可以操作摄像头来获取数据,下面来看看如何与Qt结合,将前面的代码与Qt界面结合起来。

在Qt中主要就是实现两个功能,一个是通过界面控制摄像头的数据获取,另一个是通过界面显示摄像头所拍摄下来的图片。摄像头的初始化设置,包括格式等参数的设置可以在Qt界面的构造函数中完成。

通过界面来控制摄像头,可以在Qt的界面上做一个按钮,在按钮的单击事件槽中调用摄像头采集数据的部分即可:
void MainWindow::on_init_camera_clicked()//按钮单击事件
{
for (;;)//这一段涉及到异步IO
{
fd_set fds;
struct timeval tv;
int r;
FD_ZERO (&fds);//将指定的文件描述符集清空
FD_SET (fd, &fds);//在文件描述符集合中增加新的文件描述符
tv.tv_sec = 0;
tv.tv_usec = 500000;
r = select (fd + 1, &fds, NULL, NULL, &tv);//判断是否可读(即摄像头是否准备好),tv是定时
if (-1 == r)
{
if (EINTR == errno)
continue;
printf ('select err ');
}
if (read_frame ())//如果可读,执行read_frame ()函数,并跳出循环
break;
else
{
QMessageBox::information(this, tr('失败'), tr('拍摄图片失败') , QMessageBox::Ok);
}
}
}

关于拍摄图片的显示问题,Qt中提供了很多实现的方法,比如可以在界面中采用一个label来显示,这里采用GraphicsView来显示,主要代码如下:
image=new QImage(pictrue_name);
image->load(pictrue_name);
scene = new QGraphicsScene;
scene->addPixmap(QPixmap::fromImage(*image));
ui->graphicsView->setScene(scene);
ui->graphicsView->setAlignment(Qt::AlignCenter);
ui->graphicsView->show();//显示

将摄像头获取的数据写入文件中,再通过GraphicsView显示出来。这样就实现了Qt程序和摄像头操作的结合,详细的代码请参考例程。

例程的效果如下图所示:

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • Linux
    +关注

    关注

    87

    文章

    11303

    浏览量

    209457
  • 嵌入式主板
    +关注

    关注

    7

    文章

    6085

    浏览量

    35326
收藏 人收藏

    评论

    相关推荐

    安防监控摄像头气密性测试案例-连拓精密#摄像头气密检测设备

    摄像头
    连拓精密科技
    发布于 :2024年12月11日 15:00:21

    多光谱火焰检测摄像头

    ,成为现代火灾监测领域的一项重要技术。多光谱火焰检测摄像头通过捕捉不同波段的光谱信息来识别火焰。与传统摄像头仅能获取可见光信息不同,多光谱
    的头像 发表于 12-11 10:50 125次阅读
    多光谱火焰检测<b class='flag-5'>摄像头</b>

    摄像头及红外成像的基本工作原理

    本文介绍了摄像头及红外成像的基本工作原理,摄像头可以将看到的图像真实的呈现出来,所见即所得! 摄像头如何工作? 摄像头可以将看到的图像真实的呈现出来,所见即所得。   比如人眼看到的一
    的头像 发表于 11-25 09:28 370次阅读
    <b class='flag-5'>摄像头</b>及红外成像的基本工作原理

    飞凌嵌入式-ELFBOARD-OV5640摄像头简介

    OV5640采用了CMOS图像传感器,也是我们ELF 1以及ELF 1S适配的摄像头。OV5640为500w像素级摄像头,最高支持2592x1944@15fps(QSXGA)【图像有效显示的区域
    发表于 11-18 11:14

    用于环视和CMS摄像头系统的四通道摄像头应用程序

    电子发烧友网站提供《用于环视和CMS摄像头系统的四通道摄像头应用程序.pdf》资料免费下载
    发表于 10-11 10:02 0次下载
    用于环视和CMS<b class='flag-5'>摄像头</b>系统的四通道<b class='flag-5'>摄像头</b>应用程序

    CANape Option DA中参考摄像头的标定演示#CANape

    摄像头
    北汇信息POLELINK
    发布于 :2024年07月30日 12:37:29

    基于FPGA的摄像头心率检测装置设计

    时间很长,且对环境要求较为严格。 基此,我们对其算法进行优化,设计出更快运算速度, 可在更复杂环境较准确测心率的摄像头心率检测装置。本系统着眼机器视觉,是集合图像处理技术、HDMI 显示技术的智能
    发表于 07-01 17:58

    esp32是如何与摄像头连接的呢?

    新手。看了esp32的模组中没有摄像头的硬件接口,请问它是如何与摄像头连接的呢
    发表于 06-28 15:01

    esp32-s2-soala-v1.2如何获取摄像头描述符?

    开发板:esp32-s2-soala-v1.2 开发环境:WIN10 + IDF4.4 我想使用uvc摄像头的例程,啥都没改测试初始化是成功的,但是获取图片后就会卡死 应该是摄像头没有配置
    发表于 06-27 06:48

    摄像头模组电路

    求助各位大佬,想问一下摄像头模组硬件电路大概需要怎么设计
    发表于 06-07 10:29

    智能摄像头抄表器是什么?

    1.概念理解:智能摄像头抄表器智能摄像头抄表器是一种融合了人工智能和物联网技术的创新设备,主要用于自动读取和记录各种计量仪表的数据,如水表、电表、燃气表等。它通过高清摄像头捕捉图像,然
    的头像 发表于 04-24 14:14 621次阅读
    智能<b class='flag-5'>摄像头</b>抄表器是什么?

    如何运用无人机摄像头改装成监控

    有个废旧无人机相机,零度xiro无人机。拆下来个摄像头。想着有没有办法能改装成电脑摄像头。 内部构造双层主板。安装摄像头那层有个双20插口,第二层有个20pin排线口。 请问大家有没有
    发表于 04-03 11:56

    用usb摄像头替换手机前置摄像头可以吗

    将从技术实现、可行性和使用体验三方面,探讨这个问题。 一、技术实现: USB摄像头的连接:USB摄像头通过USB接口与智能手机连接。目前,大部分智能手机都支持USB On-The-Go
    的头像 发表于 01-08 14:11 2766次阅读

    AHD摄像头与CVBS的区别

    随着科技的不断进步,摄像头作为监控领域中重要的设备之一,也在不断演化和改进。AHD(Analog High Definition,模拟高清)摄像头是近年来相对较新的一种技术,相对于传统的CVBS
    的头像 发表于 01-04 11:08 1.5w次阅读