USB摄像头视频采集与QT界面显示解读.docx
- 文档编号:8626193
- 上传时间:2023-02-01
- 格式:DOCX
- 页数:21
- 大小:1.06MB
USB摄像头视频采集与QT界面显示解读.docx
《USB摄像头视频采集与QT界面显示解读.docx》由会员分享,可在线阅读,更多相关《USB摄像头视频采集与QT界面显示解读.docx(21页珍藏版)》请在冰豆网上搜索。
USB摄像头视频采集与QT界面显示解读
USB摄像头视频采集与Qt界面显示
一.Qt界面制作
1.新建Qt工程
启动QtCreator,新建一个QtGui应用。
单击File选择NewFileorProject出现以下界面:
选择QtGuiApplication,之后选择好工程与路径名,其他默认,一直到设置Classinformation(类信息)时,Classname设为Widget,Basename选择QWidget,其他默认。
设置好这些后,其他默认,直到工程设置结束。
如下图所示:
2.修改ui界面
打开Widget.ui,进入可视化设计界面。
默认情况中间的主设计区下只有一个Widget的对象。
由于USB摄像头采集到的图像需要显示到一个QLabel的部件上,从右侧的部件列表的“DisplayWidget”中选择“Label”部件拖动到中间;此外,我们需要两个按钮,一个用于启动和终止视频数据的保存,一个用于以后的视频文件的压缩。
从右侧的”Buttons”中两次选择”PushButtion”部件并拖动到Widget中。
从上图可以看出,对象Widget下已经添加了一个label部件,两个pushbutton部件。
右上角Object与Class的关系是:
Object对应的物体是属于Class对应的类,反映了Qt的继承关系。
接下来设置上面四种部件的属性,Widget的属性按照下面图示设置,其中geometry设置为[(0,0),650*550]说明界面左上角的坐标位于原点,大小为650*550;在windowname这一项设置的是你的界面的名字,我设置为USB_YUV_Camera。
注:
图片未提及的采用默认就行,其他三个部件见图示。
这些部件的objectName要特别注意,因为会在后面编写的程序中用到。
(Widget设置图示)(label设置图示1)(label设置图示2)
(Pushbutton1设置图示)(Pushbutton1设置图示)
(Pushbutton2设置图示)Pushbutton2设置图示)
最后生成的界面:
点击Debug会得到Debug文档,里面有你设置的信息。
编译运行后,会在建立的工程文件夹下生成很多文件,重要的是widget.ui文件,其他的文件要根据你具体的应用作出相应的修改。
Qt界面最终的效果图为:
二.USB摄像头视频采集与Qt界面显示源代码分析
源码包含:
common.hVideoDevice.hwidget.hVideoDevice.cppwidget.cppmain.cpp
common.h主要定义了USB采集到的图像的宽度,高度等信息;
Videodevice.h定义了VideoDevice类,使它继承于Qt的基类QObject,定义了VideoDevice的构造函数与析构函数,重要的是定义了实现V4L2视频架构的函数;
Videodevice.cpp具体实现了Videodevice.h定义的函数,完成了基于V4L2架构的视频采集;
widget.h定义了Widget窗口类,使它继承于Qt窗口类QWidget,并定义了YUV到RGB颜色转变的函数;QT界面按钮操作的实现函数,以及视频窗口的刷新时间painEvent函数;
widget.cpp实现了widget.h定义的函数。
下面介绍各文件的主要代码段:
(1)common.h
#ifndefCOMMON_H
#defineCOMMON_H
//……
#defineIMG_WIDTH640//定义视频的宽度为640
#defineIMG_HEIGTH480//定义视频的高度为480
#endif//COMMON_H
(2)Videodevice.h
#defineCLEAR(x)memset(&(x),0,sizeof(x))//定义CLEAR为内存清零
classVideoDevice:
publicQObject
{
Q_OBJECT//有了这条语句才能使用QT中的signal和slot机制
public:
VideoDevice(QStringdev_name);//构造函数定义,用于初始化
~VideoDevice();//析构函数用于释放内存
intget_frame(unsignedchar**yuv_buffer_pointer,size_t*len);//获取视频帧
intunget_frame();//释放视频帧,让出缓存空间准备新的视频帧数据
private:
intopen_device();//打开设备
intinit_device();//初始化设备
intstart_capturing();//启动视频采集
intinit_mmap();//内存映射初始化
intstop_capturing();//停止视频采集
intuninit_device();//注销设备
intclose_device();//关闭设备
structbuffer
{
void*start;//视频缓冲区的起始地址
size_tlength;//缓冲区的长度
};
QStringdev_name;
intfd;//video0file
buffer*buffers;
unsignedintn_buffers;
intindex;
signals:
//voiddisplay_error(QString);
};
#endif//VIDEODEVICE_H
(3)Videodevice.cpp
#defineFILE_VIDEO"/dev/video0"
VideoDevice:
:
VideoDevice(QStringdev_name)//VideoDevice的构造函数进行初始化
{
this->dev_name=dev_name;
this->fd=-1;
this->buffers=NULL;
this->n_buffers=0;
this->index=-1;
if(open_device()==FALSE)
{
close_device();
}
if(init_device()==FALSE)
{
close_device();
}
if(start_capturing()==FALSE)
{
stop_capturing();
close_device();
}
}
VideoDevice:
:
~VideoDevice()//VideoDevice的析构函数
{
if(stop_capturing()==FALSE)
{}
if(uninit_device()==FALSE)
{}
if(close_device()==FALSE)
{}
}
intVideoDevice:
:
init_device()//设备初始化
{
v4l2_capabilitycap;//设备能力结构体
v4l2_formatfmt;//设置视频像素
v4l2_streamparmsetfps;//设置采样率
v4l2_fmtdescfmtdesc;//查询摄像头支持像素格式
if(ioctl(fd,VIDIOC_QUERYCAP,&cap)==-1)
{
printf("Erroropeningdevice%s:
unabletoquerydevice.\n",FILE_VIDEO);
returnFALSE;
}
else
{
printf("driver:
\t\t%s\n",cap.driver);//驱动名
printf("card:
\t\t%s\n",cap.card);//摄像头信息
printf("bus_info:
\t%s\n",cap.bus_info);//PCI总线信息
printf("version:
\t%d\n",cap.version);//内核版本
printf("capabilities:
\t%x\n",cap.capabilities);
//以上打印信息详见设备能力结构体(structv4l2_capability)
if((cap.capabilities&V4L2_CAP_VIDEO_CAPTURE))
{
printf("Device%s:
supportscapture.\n",FILE_VIDEO);
}
if((cap.capabilities&V4L2_CAP_STREAMING))
{
printf("Device%s:
supportsstreaming.\n",FILE_VIDEO);
}
}
//列举摄像头所支持像素格式
fmtdesc.index=0;
fmtdesc.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
printf("Supportformat:
\n");
while(ioctl(fd,VIDIOC_ENUM_FMT,&fmtdesc)!
=-1)
{
printf("\t%d.%s\n",fmtdesc.index+1,fmtdesc.description);
fmtdesc.index++;
}
//setfmt
fmt.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;//恒为此项
fmt.fmt.pix.pixelformat=V4L2_PIX_FMT_YUYV;//视频数据存储类型
fmt.fmt.pix.height=480;
fmt.fmt.pix.width=640;
fmt.fmt.pix.field=V4L2_FIELD_INTERLACED;//隔行扫描
if(ioctl(fd,VIDIOC_S_FMT,&fmt)==-1)
{
printf("Unabletosetformat\n");
returnFALSE;
}
if(ioctl(fd,VIDIOC_G_FMT,&fmt)==-1)
{
printf("Unabletogetformat\n");
returnFALSE;
}
//setfps具体参考结构体v4l2_captureparm
setfps.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
/*timeperframe字段用于指定想要使用的帧频率,它是一个结构体:
numerator和denominator所描述的系数给出的是成功的帧之间的时间间隔。
numerator分子,denominator分母。
主要表达每次帧之间时间间隔。
numerator/denominator秒一帧。
*/
setfps.parm.capture.timeperframe.numerator=1;
setfps.parm.capture.timeperframe.denominator=30;//本摄像头帧频范围[5,30]帧/秒
if(ioctl(fd,VIDIOC_S_PARM,&setfps)==-1)
{
printf("Unabletosetframerate\n");
returnFALSE;
}
else
{
printf("setfpsOK!
\n");
}
if(ioctl(fd,VIDIOC_G_PARM,&setfps)==-1)
{
printf("Unabletogetframerate\n");
returnFALSE;
}
else
{
printf("getfpsOK!
\n");
printf("timeperframe.numerator:
\t%d\n",setfps.parm.capture.timeperframe.numerator);
printf("timeperframe.denominator:
\t%d\n",setfps.parm.capture.timeperframe.denominator);
}
//mmap
if(init_mmap()==FALSE)
{
printf("cannotmmap!
\n");
returnFALSE;
}
returnTRUE;
}
(4)widget.h
namespaceUi{
classWidget;
}
classWidget:
publicQWidget
{
Q_OBJECT//上面内容为固定格式
public:
explicitWidget(QWidget*parent=0);//explicit可以避免发生隐式类型转换
~Widget();
private:
Ui:
:
Widget*ui;
QImage*frame;
intrs;
unsignedintlen;
intconvert_yuv_to_rgb_buffer();
voidprint_quartet(unsignedinti);
VideoDevice*vd;
FILE*yuvfile;
unsignedcharrgb_buffer[640*480*3];
unsignedchar*yuv_buffer_pointer;
charY_frame[640*480];//存储亮度Y分量
charCr_frame[240*320];//存储蓝色浓度偏移量即U分量
charCb_frame[240*320];//存储红色浓度偏移量即V分量
intwrite420();//视频图像保存为YUV420,也可存储为YUV422
privateslots:
//定义槽
voidon_pushButton_start_clicked();//按钮按下对应的处理,不定义成槽,按钮将失效
voidpaintEvent(QPaintEvent*);//窗口刷新函数
};
#endif//WIDGET_H
(5)widget.cpp
charyuvfilename[11]={'s','a','v','e','0','0','.','y','u','v','\0'};//视频保存文件的名称
Widget:
:
Widget(QWidget*parent):
QWidget(parent),
ui(newUi:
:
Widget)
{
ui->setupUi(this);
vd=newVideoDevice(tr("/dev/video0"));
frame=newQImage(rgb_buffer,640,480,QImage:
:
Format_RGB888);
}
voidWidget:
:
paintEvent(QPaintEvent*)
{
rs=vd->get_frame(&yuv_buffer_pointer,&len);
if(last_state==2&&state==0)
{
yuvfile=fopen(yuvfilename,"wb+");
yuvfilename[5]++;
}
if(state==1)
{
rs=write420();
}
if(last_state==1&&state==2)
{
fclose(yuvfile);
}
intWidget:
:
write420()
{
intx,y;
longintindex1=0;
if(yuv_buffer_pointer[0]=='\0')
{
return-1;
}
for(x=0;x<640;x++)
{
for(y=0;y<480;y++)
{
Y_frame[index1]=yuv_buffer_pointer[2*index1];
index1++;
}
}
index1=0;
for(x=0;x<480;x++,x++)
{
for(y=0;y<640;y++,y++)
{
Cb_frame[index1]=yuv_buffer_pointer[(x*640+y)*2+1];
Cr_frame[index1]=yuv_buffer_pointer[(x*640+y)*2+3];
index1++;
}
}
//YUV422的程序
/*for(x=0;x<480;x++)
{
for(y=0;y<320;y++)
{
Y_frame[index]=yuv_buffer_pointer[(x*320+y)*4];
Cb_frame[index]=yuv_buffer_pointer[(x*320+y)*4+1];
Y_frame[index+1]=yuv_buffer_pointer[(x*320+y)*4+2];
Cr_frame[index]=yuv_buffer_pointer[(x*320+y)*4+3];
index++;
}
}*/
fwrite(Y_frame,307200,1,yuvfile);
fwrite(Cb_frame,76800,1,yuvfile);
fwrite(Cr_frame,76800,1,yuvfile);
framecnt++;
printf("writedframe%ld\n",framecnt);
}
intWidget:
:
convert_yuv_to_rgb_buffer()
{
unsignedlongin,out=0;
inty0,u,y1,v;
intr,g,b;
for(in=0;in { y0=yuv_buffer_pointer[in+0]; u=yuv_buffer_pointer[in+1]; y1=yuv_buffer_pointer[in+2]; v=yuv_buffer_pointer[in+3]; r=y0+(1.370705*(v-128)); g=y0-(0.698001*(v-128))-(0.337633*(u-128)); b=y0+(1.732446*(u-128)); /*r=y0+1.042*(v-128); g=y0-0.34414*(u-128)-0.71414*(v-128); b=y0+1.772*(u-128);*///YUV422程序 if(r>255)r=255; if(g>255)g=255; if(b>255)b=255; if(r<0)r=0; if(g<0)g=0; if(b<0)b=0; rgb_buffer[out++]=r; rgb_buffer[out++]=g; rgb_buffer[out++]=b; r=y1+(1.370705*(v-128)); g=y1-(0.698001*(v-128))-(0.337633*(u-128)); b=y1+(1.732446*(u-128)); /*r=y0+1.042*(v-128); g=y0-0.34414*(u-128)-0.71414*(v-128); b=y0+1.772*(u-128);*///YUV422程序 if(r>255)r=255; if(g>255)g=255; if(b>255)b=255; if(r<0)r=0; if(g<0)g=0; if(b<0)b=0; rgb_buffer[out++]=r; rgb_buffer[out++]=g; rgb_buffer[out++]=b; } return0; } voidWidget: : on_pushButton_start_clicked() { switch(state) { case0: { ui->pushButton_start->setText("stopsave"); state=1; break; } case1: { ui->pushButton_start->setText("saveagain"); state=2; break; } case2: { ui->pushButton_start->setText("startsave"); framecnt=0; state=0; break; } default: break; } (6)main.cpp #include #include"widget.h" intmain(intargc,char*argv[]) { QApplicationa(argc,argv); Widgetw; w.show(); returna.exec(); } 三.运行效果 点击保存按钮后存放视频的文件,当关闭时自动生成下一个save01.yuv文件已接受下次视频数据,以此类推。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- USB 摄像头 视频 采集 QT 界面 显示 解读