历史上的今天

今天是:2025年10月12日(星期日)

正在发生

2022年10月12日 | 基于mini2440的USB视频采集

发布者:SerendipityDawn 来源: csdn关键字:mini2440  USB  视频采集 手机看文章 扫描二维码
随时随地手机看文章

嵌入式系统中,视频采集主要采用两种接口:一种是标准摄像头接口,一种是USB接口(USB1.1)。标准的摄像头接口,接口复杂,但传输速度快,适合高质量视频采集,而USB接口,接口简单,但有性能瓶颈,只能用于低质量的视频采集。mini2440开发板采用的是S3C2440芯片,S3C2440自带了一个OHCI的USB1.1主机接口和一个CMOS摄像头标准接口。所以mini2440开发板的两种视频采集方式都可以,这里主要介绍基于USB接口的视频采集。因为前一段时间编写了主机上基于GTK的USB视频采集程序,现在需要将其移植到开发板上。


根据主机与开发板环境的不同,需要移植的部分主要就是视频显示部分。在主机上视频显示程序是调用GTK的库函数,而在开发板上有众多的UI可以选择,可以基于QT或者基于minigui 做显示界面,但是最简单最直接的方式就是操作frambuffer设备显示,因为这样可以避免GUI函数带来的性能损失,直接看到采集的实际效果,但这种方式只适用于实验程序没有太大的实用价值,我的采集程序程序就是采用了这种方式。USB摄像头采用和主机程序测试一样的摄像头(十几块钱的山寨摄像头),视频输出格式为YUYV,接口为USB2.0接口兼容USB1.1。为了避免线程切换带来的性能损失,在程序中我去掉了显示以及采集线程,主程序采用大循环的结构。下面简单的介绍一下程序:


1 主函数

int main(int argc, const char* argv[])

{

int fp = 0;

unsigned int i;

/*

* init struct camera 

*/

struct camera *cam;

//这个是我自定义的结构,代表一个摄像头,定义在v4l2.h中

struct timeval tpstart,tpend;

        float timeuse;

//以上变量是为了统计每帧采集的时间

unsigned short *pbuf;

//帧缓存地址

 

  cam = malloc(sizeof(struct camera));

  if (!cam) { 

printf("malloc camera failure!n");

exit(1);

}

        cam->device_name = "/dev/video0";

cam->buffers = NULL;

cam->width = IMAGE_WIDTH;

cam->height = IMAGE_HEIGHT;

cam->display_depth = 3;  /* RGB24 */

cam->rgbbuf = malloc(cam->width * cam->height * cam->display_depth);

 

if (!cam->rgbbuf) { 

printf("malloc rgbbuf failure!n");

exit(1);

}

open_camera(cam);

get_cam_cap(cam);

get_cam_pic(cam);

get_cam_win(cam);

cam->video_win.width = cam->width;

cam->video_win.height = cam->height;

set_cam_win(cam);

close_camera(cam);

open_camera(cam);

get_cam_win(cam);

        init_camera(cam);

        start_capturing (cam);

//以上初始化摄像头,设置采集图像格式为YUYV,采集图像大小为IMAGE_WIDTH×IMAGE_HEIGHT,mmap方式读取数据

  fp = fb_init ("/dev/fb0");

//打开初始化frambuffer设备,用mmap映射帧缓存地址为fbbuf

if (fp < 0){

printf("Error : Can not open framebuffer devicen");

exit(1);

}

 

pbuf = (unsigned short *)fbbuf;

for (i = 0; i < 320 *240; i++) {

pbuf[i] = make_pixel(0, 0x0, 0x0, 0xff);

}

//清屏成蓝色       

#ifdef DEBUG_GTIME

gettimeofday(&tpstart,NULL);

#endif

        for (;;) {

if (read_frame (cam)) {

draw_image(pbuf, cam->rgbbuf);

//将采集的数据显示到屏幕上

#ifdef DEBUG_GTIME

gettimeofday(&tpend,NULL);

                timeuse = 1000000 * (tpend.tv_sec - tpstart.tv_sec) + (tpend.tv_usec - tpstart.tv_usec);

                timeuse /= 1000000;

                printf("Used Time:%10f sn",timeuse);

                gettimeofday(&tpstart,NULL);

#endif

//以上用gettimeofday函数统计采集一帧的时间

}

        }

       return 0;

}


主函数主要初始化摄像头,分配数据结构,为视频采集做准备。然后初始化frambuffer设备,映射帧缓存,为视频显示做准备。主函数调用的v4l2接口函数与主机测试程序几乎一样。与主机测试程序不同的是显示程序draw_image,它用来显示一帧图像。


2 draw_image 函数

static void draw_image(unsigned short *pbuf, unsigned char *buf)

{

unsigned int x,y;

unsigned int pixel_num;

if (WINDOW_W <= 240) {

for (y = WINDOW_Y; y < WINDOW_Y + WINDOW_H; y++) {

for (x = WINDOW_X; x < WINDOW_X + WINDOW_W; x++) {

pixel_num = ((y - WINDOW_Y) * IMAGE_WIDTH + x - WINDOW_X) * 3;

pbuf[y * 240 + x] = make_pixel(0, (unsigned int)buf[pixel_num], 

(unsigned int)buf[pixel_num + 1], (unsigned int)buf[pixel_num + 2]);

}

}

} else { /* reverse */

for (x = 0; x < WINDOW_W; x++) {

for (y = 0; y < WINDOW_H; y++) {

pixel_num = (y * IMAGE_WIDTH + x) * 3;

pbuf[x * 240 + y] = make_pixel(0, (unsigned int)buf[pixel_num], 

(unsigned int)buf[pixel_num + 1], (unsigned int)buf[pixel_num + 2]);

}

}

}

}


这个函数作用就是显示一帧图像,因为在程序初始化阶段已经映射了帧缓存fbbuf,所以只需要将一帧图像的数据capy到帧缓存处就可以显示到lcd上了。在程序的开始处定义了一组宏。

#define IMAGE_WIDTH 320    //采集视频的宽度

#define IMAGE_HEIGHT 240    //采集视频的高度

#define WINDOW_W 176    //显示视频的宽度

#define WINDOW_H 144    //显示视频的高度

#define WINDOW_X 40     //显示起始横坐标

#define WINDOW_Y 60     //显示起始纵坐标


这样通过这一组宏就可以调整显示图像的大小与位置,因为mini2440的lcd为240 × 320 的竖屏,而摄像头采集回来的最大图像大小为320 × 240 ,所以这里用了一个技巧。如果显示的图像宽度大于240,那么就将屏幕翻转,这样可以更好的显示。因为在yuv422转rgb的函数中,转换出的RGB格式为RGB24,而mini2440的屏幕为RGB16的,所以需要做一个颜色转换。

static inline int  make_pixel(unsigned int a, unsigned int r, unsigned int g, unsigned int b)

{

    return (unsigned int)(((r >> 3) << 11) | ((g >> 2) << 5 | (b >> 3)));

}


这个函数就是将RGB24格式转换成RGB16的格式。


3 性能分析

以上程序可以正确的进行摄像头的视频采集与显示,但是最大只能采集到176 × 144 的低质量图像,如果采集分辨里达到320 * 240 图像会非常卡,有明显的延迟与丢帧现象,这种原因是USB1.1每秒所传的帧数有限造成的。USB1.1最大每秒可传的帧数由图像大小和USB速度共同决定。下面以320×240 YUYV格式的图像为例,计算USB1.1最大每秒可传的帧数。

    (1)每帧需要传输的数据量为 320 × 240 × 2 × 8 = 1228800bit = 1.2288Mbit

    (2)USB协议规定:USB1.1的最大传输比特率为12M也就是每秒传12Mbit。这只是理论上的数据,实际传输也就10M左右。我们以10Mbps为例

    (3)USB协议规定:同步传输不得超过总线的带宽的90%,所以传播速度还得乘以0.9,为9Mbps。

    (4)USB传输速度包括了协议相关的位,USB协议规定USB同步传输包,每个包的协议信息为9个字节。每秒帧数还与每个USB帧(1mS)传输的包的数量有关系,这与同步端点的最大数据有关系,我的摄像头同步端点最大数据为8字节。所以每个包的数据与协议数据比就是 8 : 9, 这样一来带宽还得乘以一个 8/17,为4.2353Mbps

    (5) 最后算出每秒帧数据就是 4.2353 / 1.2288 = 3.4


以上计算没有考虑SOF包,以及USB位填充,以及其他的因素,粗略的算出,对于320×240的一幅YUYV格式的图像,USB1.1最大每秒传输3.4帧。可谓是非常小了,但这只是理论的值,实际我用gettimeofday测出的只有每秒一帧多,这样的速度不卡才怪。所以最后得出的结论就是:由于USB1.1的速度限制,采用USB1.1做图像采集,在USB摄像头输出格式为未压缩的原始数据(如:RGB,YUV)的前提下只能采集到低分辨率,低质量的画面。基本上不能用于产品,我查了一些资料,USB1.1数据采集的系统,USB摄像头采集出来的数据格式大多是已经压缩过的,如JPEG格式,这样可大大减轻USB传输的负担,提高视频采集的采集质量。但是这样也有弊端,采集回的数据不是原始数据,不方便对数据的二次处理。所以这种压缩输出格式的USB摄像头基本上都是USB1.1的,USB2.0的摄像头输出格式基本上都是未经处理的原始数据,因为2.0的速度已经足够快,理论480Mbps的速度绝对满足需要。


实验代码在我的资源里: http://download.csdn.net/detail/yaozhenguo2006/3925480


关键字:mini2440  USB  视频采集 引用地址:基于mini2440的USB视频采集

上一篇:arm-linux-gcc 裸机程序开发(二)
下一篇:S3C2440 USB 设备控制器

推荐阅读

5G 网络的忠实拥趸们相信,这项新技术不但能提供比 4G 网络更快的连接和数据下载能力,还能处理更为海量的通信任务,而正在一步步走向成熟的自动驾驶汽车,未来也需要 5G 网络的“辅佐”。 不过,自动驾驶汽车缺了 5G 就真的“活不下去”吗? 一直以来,电信业都对未来有一个预设,那就是用传感器武装到牙齿的自动驾驶汽车会通过网络采集并接收信...
第一、盐酸流量计具有的功能特色1.测量不受流体密度、粘度、温度、压力和电导率变化的影响。2.测量管内无阻碍流动部件,无压损,直管段要求较低。3.系列公称通径DN15~DN3000。传感器衬里和电极材料有多种选择。4.转换器采用新颖励磁方式,功耗低、零点稳定、度高。流量范围度可达1500:1。5.转换器可与传感器组成一体型或分离型。6.转换器采用16位高性能...
在网上看了不少与卡尔曼滤波相关的博客、论文,要么是只谈理论、缺乏感性,或者有感性认识,缺乏理论推导。能兼顾二者的少之又少,直到我看到了国外的一篇博文,真的惊艳到我了,不得不佩服作者这种细致入微的精神,翻译过来跟大家分享一下。 我不得不说说卡尔曼滤波,因为它能做到的事情简直让人惊叹!意外的是很少有软件工程师和科学家对对它有所了解,这...
Atomrobot|用技术解放双手第三届中国(华南)国际机器人与自动化展览会(以下简称华南展)是中国国际工业博览会优势展(机器人展与自动化展)在华南地区的首个异地展,是继2018年武汉国际自动化与机器人展览会后第二站。主办单位东浩兰生会展集团将继续携手工博会的机器人展(RS)与自动化展(IAS)的优质展商落地“华南工业展览之都”广东省东莞市,结合...

史海拾趣

小广播
最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

厂商技术中心

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

 
机器人开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2026 EEWORLD.com.cn, Inc. All rights reserved