怎样搭建一个企业网站,免费域名空间虚拟主机,网站到期域名怎么解决,wordpress手机底部目录
跟内核进行数据通信的函数
编程步骤
c代码
头文件
打开摄像头文件 /dev/videox
获取当前主机上#xff08;开发板#xff09;摄像头列表信息
设置当前摄像头的画面格式 比如说 设置 采集图像的宽度为640 高度 480
在内核空间中#xff0c;申请一个缓冲区队列…目录
跟内核进行数据通信的函数
编程步骤
c代码
头文件
打开摄像头文件 /dev/videox
获取当前主机上开发板摄像头列表信息
设置当前摄像头的画面格式 比如说 设置 采集图像的宽度为640 高度 480
在内核空间中申请一个缓冲区队列队列中有4块缓冲区
将申请好的缓冲区队列 映射到 用户空间中
开启摄像头
采集数据 yuyv
将采集出来的yuyv格式的数据---转换成 rgb
将c代码移植到qt代码中在qt的界面显示摄像头画面
MCamera摄像头类添加头文件成员函数接口
实现MCamera摄像头类函数接口
在主ui界面类加入头文件成员函数接口
在构造函数中初始化摄像头类和定时器类并关联定时器的槽函数
开启摄像头按钮点击事件
关闭摄像头按钮点击事件
拍照按钮点击事件
定时器槽函数实现 qt由于在arm qt版本下没有多媒体库所以arm qt程序要访问摄像头那么必须要使用linux操作系统v412(video for linux 2)机制
简单来说就是要在arm上安装v412框架就可以使用摄像头
跟内核进行数据通信的函数
#include stropts.h
int ioctl(int fildes,int request,.../* arg */);
第一个参数fd文件描述符第二个参数要发送的命令 VIDIOC_REQBUFS:分配内存VIDIOC_QUERYBUF:把 VIDIOC_REQBUFS 中分配的数据缓存转换成物理地址VIDIOC_QUERYCAP:查询驱动功能VIDIOC_ENUM_FMT:获取当前驱动支持的视频格式VIDIOC_S_FMT:设置当前驱动的频捕获格式VIDIOC_G_FMT:读取当前驱动的频捕获格式VIDIOC_TRY_FMT:验证当前驱动的显示格式VIDIOC_CROPCAP:查询驱动的修剪能力VIDIOC_S_CROP:设置视频信号的边框VIDIOC_G_CROP:读取视频信号的边框VIDIOC _QBUF:把数据放回缓存队列VIDIOC_DQBUF:把数据从缓存中读取出来VIDIOC_$TREAMON:开始视频显示函数VIDIOC_STREAMOFF:结束视频显示函数VIDIOC_QUERYSTD:检查当前视频设备支持的标准例如 PAL或NTSC。....变参接口根据第二个参数来决定
编程步骤
打开摄像头文件 /dev/videox获取当前主机上的摄像头列表信息 #define VIDIOC_ENUM_FMT _IOWR(V,2,struct v412_fmtdesc) struct v412_fmtdesc fmt;ioctl(fd,VIDIOC_ENUM_FMT,fmt);设置当前视频捕捉格式 也就是设置摄像头采集画面的宽度、高度、格式VIDIOC_S_FMT:设置当前驱动的视频捕捉格式#define VIDIOC_S_FMT _IOWR(V,5,struct v412_format) struct v412_format format;format.宽度 640;format.高度 400;ioctl(fd,VIDIOC_S_FMT,format);申请内核缓冲区队列VIDIOC_REQBUFS 一般会将摄像头获取到的数据放到4块内存空间---一次性存储4帧画面数据将申请的内核缓冲区队列映射到用户空间VIDIOC_QUERYBUF开启摄像头VIDIOC_STREAMON 将开启摄像头的命令从应用层发送到内核层中内核层就会驱动这个摄像头开始工作while(1) 采集数据 --yuyv格式 注意;摄像头采集出来的图像数据格式组成是yuyv将采集出来的一帧画面yuyv格式的数据转为rgb格式将转换好rgb格式数据显示到ui控件上
c代码
头文件
#includestdio.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打开摄像头文件 /dev/videox //打开摄像头文件返回文件描述符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]);}
设置当前摄像头的画面格式 比如说 设置 采集图像的宽度为640 高度 480 //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、在内核空间中申请一个缓冲区队列队列中有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 i0;i4;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);
采集数据 yuyv 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 ;}
}
将采集出来的yuyv格式的数据---转换成 rgb unsigned char rgb[640*480*3] {0};//转换后的数据//8、将采集出来的yuyv格式的数据---转换成 rgbyuyv2rgb0(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[in0];u yuv[in1];y1 yuv[in2];v yuv[in3];sign3 1;pixel24 yuyv2rgb(y0, u, v);rgb[out0] pixel[0];rgb[out1] pixel[1];rgb[out2] pixel[2];pixel24 yuyv2rgb(y1, u, v);rgb[out3] pixel[0];rgb[out4] pixel[1];rgb[out5] pixel[2];}return 0;
}
将c代码移植到qt代码中在qt的界面显示摄像头画面
新建一个ui界面布局一个两个按钮用于开启停止一个QLabel显示画面
通过定时器来调整帧数
新建一个MCamera摄像头类将c代码移植进去
MCamera摄像头类添加头文件成员函数接口
extern C{#includestdio.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::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 i0;i4;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 i0;i4;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 i0; iw*h/2; i){char data[4];memcpy(data, bufferi*4, 4);//Y0U0Y1V1 --[Y0 U0 V1] [Y1 U0 V1]unsigned char Y0data[0];unsigned char U0data[1];unsigned char Y1data[2];unsigned char V1data[3];r1 Y01.4075*(V1-128); if(r1255)r1255; if(r10)r10;g1 Y0- 0.3455 * (U0-128) - 0.7169*(V1-128); if(g1255)g1255; if(g10)g10;b1 Y0 1.779 * (U0-128); if(b1255)b1255; if(b10)b10;r2 Y11.4075*(V1-128);if(r2255)r2255; if(r20)r20;g2 Y1- 0.3455 * (U0-128) - 0.7169*(V1-128); if(g2255)g2255; if(g20)g20;b2 Y1 1.779 * (U0-128); if(b2255)b2255; if(b20)b20;rgbdata[i*60]r1;rgbdata[i*61]g1;rgbdata[i*62]b1;rgbdata[i*63]r2;rgbdata[i*64]g2;rgbdata[i*65]b2;}
}在主ui界面类加入头文件成员函数接口
#include QTimer
#include mcamera.hprivate 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;}
拍照按钮点击事件
captrueFlagtrue;
定时器槽函数实现 // 采集数据unsigned char buffer[640*480*3] {0};unsigned char rgb[640*480*3] {0};int size;m_camera-get_frame(buffer,size);//yuyv转换rgbm_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中交叉编译放到开发板上运行