赞
踩
目录
设置当前摄像头的画面格式 比如说 设置 采集图像的宽度为640 高度 480
qt由于在arm qt版本下,没有多媒体库,所以,arm qt程序要访问摄像头,那么必须要使用linux操作系统v412(video for linux 2)机制
简单来说就是要在arm上安装v412框架就可以使用摄像头
#include <stropts.h>
int ioctl(int fildes,int request,.../* arg */);
- #include<stdio.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <sys/ioctl.h>
- #include <string.h>
- #include <linux/videodev2.h> //v4l2视频开发框架
- #include <sys/mman.h>
- //打开摄像头文件返回文件描述符
- int fd = open("/dev/video7",O_RDWR);
- if(fd == -1)
- {
- perror("open camera error");
- return -1;
- }
- //2、获取当前主机上(开发板)摄像头列表信息
- //#define VIDIOC_ENUM_FMT _IOWR('V', 2, struct v4l2_fmtdesc)
- struct v4l2_fmtdesc v4fmt; //定义一个结构体
- v4fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; //视频捕捉类型
- int i = 0;
- while(1)
- {
- v4fmt.index = i++;
- int ret = ioctl(fd,VIDIOC_ENUM_FMT,&v4fmt);
- if(ret < 0)
- {
- //perror("获取失败");
- break;
- }
- printf("index = %d\n",v4fmt.index);
- printf("flags = %d\n",v4fmt.flags);
- printf("description = %s\n",v4fmt.description);
- unsigned char*p = (unsigned char*)&v4fmt.pixelformat;
- printf("pixelformat = %c%c%c%c\n",p[0],p[1],p[2],p[3]);
- printf("reserved = %d\n",v4fmt.reserved[0]);
- }
- //3、设置当前摄像头的画面格式 比如说 设置 采集图像的宽度为640 高度 480
- //#define VIDIOC_S_FMT _IOWR('V', 5, struct v4l2_format)
- //发送VIDIOC_S_FMT命令需要定义struct v4l2_format结构体,
- //该结构体存放摄像头的画面格式,将摄像头设置为视频捕捉模式需要用到struct v4l2_format结构体
- struct v4l2_format vfmt;
- //设置为视频捕捉模式
- vfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- vfmt.fmt.pix.width = 640;// 设置宽(因为底层驱动已固定大小,不能任意改)
- vfmt.fmt.pix.height = 480;//设置高度
- vfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; //设置视频采集格式
- //将设置好的格式发送到摄像头
- ioctl(fd,VIDIOC_S_FMT,&vfmt);
- //设置完通过VIDIOC_G_FMT这个命令来查看格式有没有设置成功
- //#define VIDIOC_G_FMT _IOWR('V', 4, struct v4l2_format) //获取格式
- memset(&vfmt,0,sizeof(vfmt)); //清空结构体
- //设置为视频捕捉模式
- vfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- //获取的格式信息存放在该结构体中
- int ret = ioctl(fd,VIDIOC_G_FMT,&vfmt);
- if(ret < 0)
- {
- perror("获取格式失败");
- return -1;
- }
- //获取成功判断它的宽和高和模式
- if(vfmt.fmt.pix.width == 640 && vfmt.fmt.pix.height == 480 && vfmt.fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV )
- {
- printf("设置成功\n");
- }else{
- printf("设置失败\n");
- }
- //4、在内核空间中,申请一个缓冲区队列(队列中有4块缓冲区)
- //发送VIDIOC_REQBUFS命令需要struct v4l2_requestbuffers结构体
- struct v4l2_requestbuffers reqbuffers;
- reqbuffers.count = 4; //申请4个缓冲区
- reqbuffers.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;// 摄像头采集模式
- reqbuffers.memory = V4L2_MEMORY_MMAP; // mmap内存映射
- //向内核空间打一个报告,向你申请4个缓冲区队列,申请的方式为内存映射
- ret = ioctl(fd,VIDIOC_REQBUFS,&reqbuffers); //获取的信息存放在该结构体
- if(ret < 0)
- {
- perror("申请队列空间失败");
- return -1;
- }
- //5、将申请好的缓冲区队列映射到用户空间中
- //#define VIDIOC_QUERYBUF _IOWR('v',9,struct v4l2_buffer)
- //这个数组有4个元素,每个元素存储的是地址,存储的地址就是映射成功之后的地址
- unsigned char* mptr[4];
- unsigned int size[4];
- //发送VIDIOC_QUERYBUF命令需要struct v4l2_buffer结构体
- struct v4l2_buffer mapbuffer;
- mapbuffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;// 摄像头采集模式
-
- for(int i=0;i<4;i++){
- mapbuffer.index = i; //申请的缓冲区编号
- //发送VIDIOC_QUERYBUF命令来查询内核空间队列
- ret = ioctl(fd,VIDIOC_QUERYBUF,&mapbuffer);
- if(ret < 0) {
- perror("查询内核空间队列失败\n");
- return -1;
- }
- //mmap真正来实现内存映射 ,该函数的返回值是一个内存的首地址
- mptr[i] = (unsigned char*)mmap(NULL,mapbuffer.length,PROT_READ|PROT_WRITE,MAP_SHARED,fd,mapbuffer.m.offset);
- size[i] = mapbuffer.length;
-
- //通知使用完毕,----放回内核
- //#define VIDIOC_QBUF _IOWR('V', 15, struct v4l2_buffer)
- ret = ioctl(fd,VIDIOC_QBUF,&mapbuffer);
- if(ret < 0){
- perror("放回失败\n");
- return -1;
- }
- }
- //6、开启摄像头
- //#define VIDIOC_STREAMON _IOW('V', 18, int)
- int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;// 摄像头采集模式
- //发送VIDIOC_QUERYBUF命令来开启摄像头
- ioctl(fd,VIDIOC_STREAMON,&type);
- unsigned char buffer[640*480*3] = {0};//采集后的数据
- int size;
- //发送命令采集数据函数
- get_frame(buffer,&size);
-
- //获取图片
- void get_frame(unsigned char*buffer,int *size)
- {
- //1、先查询 当前帧数据 到底 在哪个 缓冲区中
- //采集数据 --VIDIOC_DQBUF:把数据从缓存中读取出来
- //#define VIDIOC_DQBUF _IOWR('V', 17, struct v4l2_buffer)
- //发送VIDIOC_DQBUF需要struct v4l2_buffer结构体
- struct v4l2_buffer readbuffer;
- readbuffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;//采集模式
- //发送VIDIOC_DQBUF采集数据放到结构体里
- int ret = ioctl(fd,VIDIOC_DQBUF,&readbuffer);
- if(ret < 0)
- {
- perror("提取数据失败");
- return -1 ;
- }
- //使用内存拷贝 -- void *memcpy(void *dest, const void *src, size_t n);
- memcpy(buffer,mptr[readbuffer.index],readbuffer.length);
- *size = readbuffer.length;
- //VIDIOC_QBUF:把数据放回缓存队列
- //通知内核已使用完毕
- //#define VIDIOC_QBUF _IOWR('V', 15, struct v4l2_buffer)
- ret = ioctl(fd,VIDIOC_QBUF,&readbuffer);
- if(ret < 0)
- {
- perror("放回队列失败");
- return -1 ;
- }
- }
- unsigned char rgb[640*480*3] = {0};//转换后的数据
- //8、将采集出来的yuyv格式的数据---转换成 rgb
- yuyv2rgb0(buffer, rgb, 640, 480);
- //将yuyv格式转为rgb格式
- int yuyv2rgb0(unsigned char *yuv, unsigned char *rgb, unsigned int width, unsigned int height)
- {
- unsigned int in, out;
- int y0, u, y1, v;
- unsigned int pixel24;
- unsigned char *pixel = (unsigned char *)&pixel24;
- unsigned int size = width*height*2;
-
- for(in = 0, out = 0; in < size; in += 4, out += 6)
- {
- y0 = yuv[in+0];
- u = yuv[in+1];
- y1 = yuv[in+2];
- v = yuv[in+3];
-
- sign3 = 1;
- pixel24 = yuyv2rgb(y0, u, v);
- rgb[out+0] = pixel[0];
- rgb[out+1] = pixel[1];
- rgb[out+2] = pixel[2];
-
- pixel24 = yuyv2rgb(y1, u, v);
- rgb[out+3] = pixel[0];
- rgb[out+4] = pixel[1];
- rgb[out+5] = pixel[2];
-
- }
- return 0;
- }
新建一个ui界面,布局一个两个按钮用于开启,停止,一个QLabel显示画面
通过定时器来调整帧数
新建一个MCamera摄像头类,将c代码移植进去
- extern "C"{
- #include<stdio.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <sys/ioctl.h>
- #include <string.h>
- #include <linux/videodev2.h> //v4l2视频开发框架
- #include <sys/mman.h>
- #include <unistd.h>
- }
- class MCamera
- {
- public:
- MCamera(const char*deviceName = "/dev/video7");
-
- void start();//启动摄像头
- void stop();//关闭摄像头
- void get_frame(unsigned char*buffer,int *size);//获取图像数据
- int yuyv2rgb0(unsigned char *buffer, unsigned char *rgbdata, int w, int h);//yuyv转为rgb
- private:
- int fd;//摄像头文件描述符
- unsigned char* mptr[4];//这个数组有4个元素,每个元素存储的是地址,存储的地址就是映射成功之后的地址
- unsigned int size[4];//图像的大小
- bool captrueFlag;//拍照标志位
- };
- MCamera::MCamera(const char*deviceName )
- {
- //1、打开摄像头文件
- //打开摄像头文件返回文件描述符
- fd = open(deviceName,O_RDWR);
- if(fd == -1)
- {
- perror("open camera error");
- return ;
- }
- //2、获取当前主机上(开发板)摄像头列表信息
- //#define VIDIOC_ENUM_FMT _IOWR('V', 2, struct v4l2_fmtdesc)
- struct v4l2_fmtdesc v4fmt; //定义一个结构体
- v4fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; //视频捕捉类型
- int i = 0;
- while(1)
- {
- v4fmt.index = i++;
- int ret = ioctl(fd,VIDIOC_ENUM_FMT,&v4fmt);
- if(ret < 0)
- {
- //perror("获取失败");
- break;
- }
- printf("index = %d\n",v4fmt.index);
- printf("flags = %d\n",v4fmt.flags);
- printf("description = %s\n",v4fmt.description);
- unsigned char*p = (unsigned char*)&v4fmt.pixelformat;
- printf("pixelformat = %c%c%c%c\n",p[0],p[1],p[2],p[3]);
- printf("reserved = %d\n",v4fmt.reserved[0]);
- }
-
- //3、设置当前摄像头的画面格式 比如说 设置 采集图像的宽度为640 高度 480
- //#define VIDIOC_S_FMT _IOWR('V', 5, struct v4l2_format)
- struct v4l2_format vfmt;
- vfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- vfmt.fmt.pix.width = 640;// 设置宽(因为底层驱动已固定大小,不能任意改)
- vfmt.fmt.pix.height = 480;//设置高度
- vfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; //设置视频采集格式
-
- ioctl(fd,VIDIOC_S_FMT,&vfmt);
-
- //#define VIDIOC_G_FMT _IOWR('V', 4, struct v4l2_format) //获取格式
- memset(&vfmt,0,sizeof(vfmt)); //清 零结构体
-
- vfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- int ret = ioctl(fd,VIDIOC_G_FMT,&vfmt); //获取的 信息存 放在该结构体
- if(ret < 0)
- {
- perror("获取格式失败");
- return ;
- }
- if(vfmt.fmt.pix.width == 640 && vfmt.fmt.pix.height == 480 && vfmt.fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV )
- {
- printf("设置成功\n");
- }else{
- printf("设置失败\n");
- }
- //4、在内核空间中,申请一个缓冲区队列(队列中有4块缓冲区)
- struct v4l2_requestbuffers reqbuffers;
- reqbuffers.count = 4; //申请4个缓冲区
- reqbuffers.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;// 摄像头采集
- reqbuffers.memory = V4L2_MEMORY_MMAP; // mmap
- //向内核空间打一个报告,向你申请4个缓冲区队列,申请的方式为内存映射
- ret = ioctl(fd,VIDIOC_REQBUFS,&reqbuffers); //获取的 信息存 放在该结构体
- if(ret < 0)
- {
- perror("申请队列空间失败");
- return ;
- }
- //5、将申请好的缓冲区队列 映射到 用户空间中
-
-
- struct v4l2_buffer mapbuffer;
- mapbuffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
- for(int i=0;i<4;i++){
- mapbuffer.index = i; //申请的缓冲区编号
- ret = ioctl(fd,VIDIOC_QUERYBUF,&mapbuffer);
- if(ret < 0) {
- perror("查询内核空间队列失败\n");
- return ;
- }
- //真正来实现内存映射 ,该函数的返回值是一个内存的首地址
- mptr[i] = (unsigned char*)mmap(NULL,mapbuffer.length,PROT_READ|PROT_WRITE,MAP_SHARED,fd,mapbuffer.m.offset);
- size[i] = mapbuffer.length;
-
- //通知使用完毕,----放回内核
- //#define VIDIOC_QBUF _IOWR('V', 15, struct v4l2_buffer)
- ret = ioctl(fd,VIDIOC_QBUF,&mapbuffer);
- if(ret < 0){
- perror("放回失败\n");
- return ;
- }
- }
- }
-
- void MCamera::start()
- {
- //6、开启摄像头
- //#define VIDIOC_STREAMON _IOW('V', 18, int)
- int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- ioctl(fd,VIDIOC_STREAMON,&type);
- }
-
- void MCamera::stop()
- {
- //[8] 停止采集
- int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- int ret = ioctl(fd,VIDIOC_STREAMOFF,&type);
- //释放内存 int munmap(void *addr, size_t length);
- for(int i=0;i<4;i++)
- {
- munmap(mptr[i],size[i]);
- }
- //[9] 关闭设备
- ::close(fd);
- }
-
- void MCamera::get_frame(unsigned char *buffer, int *size)
- {
- //采集数据 --VIDIOC_DQBUF:把数据从缓存中读取出来
- //#define VIDIOC_DQBUF _IOWR('V', 17, struct v4l2_buffer)
- //1、先查询 当前帧数据 到底 在哪个 缓冲区中
- struct v4l2_buffer readbuffer;
- readbuffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- int ret = ioctl(fd,VIDIOC_DQBUF,&readbuffer);
- if(ret < 0)
- {
- perror("提取数据失败");
- return ;
- }
- //使用内存拷贝 -- void *memcpy(void *dest, const void *src, size_t n);
- memcpy(buffer,mptr[readbuffer.index],readbuffer.length);
- *size = readbuffer.length;
- //VIDIOC_QBUF:把数据放回缓存队列
- //通知内核已使用完毕
- //#define VIDIOC_QBUF _IOWR('V', 15, struct v4l2_buffer)
- ret = ioctl(fd,VIDIOC_QBUF,&readbuffer);
- if(ret < 0)
- {
- perror("放回队列失败");
- return ;
- }
- }
-
- int MCamera::yuyv2rgb0(unsigned char *buffer, unsigned char *rgbdata, int w, int h)
- {
- int r1, g1, b1;
- int r2, g2, b2;
-
- for(int i=0; i<w*h/2; i++)
- {
- char data[4];
- memcpy(data, buffer+i*4, 4);
- //Y0U0Y1V1 -->[Y0 U0 V1] [Y1 U0 V1]
- unsigned char Y0=data[0];
- unsigned char U0=data[1];
- unsigned char Y1=data[2];
- unsigned char V1=data[3];
-
- r1 = Y0+1.4075*(V1-128); if(r1>255)r1=255; if(r1<0)r1=0;
- g1 =Y0- 0.3455 * (U0-128) - 0.7169*(V1-128); if(g1>255)g1=255; if(g1<0)g1=0;
- b1 = Y0 + 1.779 * (U0-128); if(b1>255)b1=255; if(b1<0)b1=0;
- r2 = Y1+1.4075*(V1-128);if(r2>255)r2=255; if(r2<0)r2=0;
- g2 = Y1- 0.3455 * (U0-128) - 0.7169*(V1-128); if(g2>255)g2=255; if(g2<0)g2=0;
- b2 = Y1 + 1.779 * (U0-128); if(b2>255)b2=255; if(b2<0)b2=0;
-
- rgbdata[i*6+0]=r1;
- rgbdata[i*6+1]=g1;
- rgbdata[i*6+2]=b1;
- rgbdata[i*6+3]=r2;
- rgbdata[i*6+4]=g2;
- rgbdata[i*6+5]=b2;
- }
- }
- #include <QTimer>
- #include "mcamera.h"
-
- private slots:
- void onUpdateCameraUi();
-
- private:
- MCamera *m_camera;//自定义摄像头类
- QTimer *m_timer;//定时器类
- m_camera = NULL;
-
- m_timer = new QTimer;
- connect(m_timer,&QTimer::timeout,this,&Widget::onUpdateCameraUi);
- if(m_camera == NULL)
- {
- m_camera = new MCamera;
- m_camera->start();
- //启动定时器,间隔时间采集图像数据
- m_timer->start(1); //1秒钟采集 一张画面(一帧画面)
- }
- if(m_camera != NULL)
- {
- m_timer->stop();
- m_camera->stop();
-
- delete m_camera;
-
- m_camera = NULL;
- }
captrueFlag=true;
- // 采集数据
- unsigned char buffer[640*480*3] = {0};
- unsigned char rgb[640*480*3] = {0};
- int size;
- m_camera->get_frame(buffer,&size);
-
- //yuyv转换rgb
- m_camera->yuyv2rgb0(buffer,rgb,640,480);
-
- //显示 源图像rgb --->pic对象
- QImage img = QImage(rgb,640,480,QImage::Format_RGB888);
- //保存为图片
- if(captrueFlag)
- {
- img.save("1.bmp");
- captrueFlag = false;
- }
- QPixmap pic = QPixmap::fromImage(img);
- ui->label->setPixmap(pic);
在linux中交叉编译放到开发板上运行
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。