基于Linux内核framebuffer的图像采集与显示系统设计

2018-03-27 06:29
计算机测量与控制 2018年3期
关键词:内核解码驱动

, ,

(东华大学 机械工程学院,上海 201620)

0 引言

手机屏幕作为最重要的信息输出部件,承担着人机交互的功能,它的质量好坏直接影响着用户体验,因此,在手机的生产过程中,屏幕的质量检测至关重要。目前国内手机屏幕检测的方法仍然是依靠人工检测,这种方式耗时耗力,并且不能够形成规模化、标准化。

本系统以手机屏幕缺陷采集为应用背景,旨在研究一种小型的低成本的能够实时的适用于手机液晶屏幕流水线生产的图像采集与图象处理的系统装置。基于嵌入式Linux平台,以S5PV210微控制器为主控单元,7寸LCD液晶屏为图像显示单元;UVC(USB video class)视频设备协议的usb摄像头为系统的图像采集单元,基于最优秀多路IO复用机制Epoll框架利用V4L2编程接口,进行多路图像采集,图像编解码显示,并为后续的图像缺陷检测做准备工作。

1 系统环境的搭建

1.1 系统的硬件平台

为了得到满足图像采集与显示系统需要的最小硬件平台。对S5PV210开发板的硬件资源进行裁剪,系统通过摄像头进行图像采集,并将采集数据送至 ARM 处理器进行图像处理,配载 512M 的 SDRAM 作为系统内存和 1G的Nand Flash为系统存储器以挂载嵌入式 Linux 操作系统和运行图形用户应用程序,期间通过 LCD 显示屏将采集图像实时显示给用户,处理结果既可以保存于掉电数据不丢失的 Flash 存储器中。为了调试程序、烧写系统以及与 PC 机的通信,保留了 USB 转串口和网线接口以连接到上位机 PC,最后加入电源管理,组成了整个硬件开发平台。

1.2 系统的软件框架

软件平台采用Linux,内核版本2.6.35,为针对目标平台S5PV210的硬件特性,首先将启动介质Uboot下载到了nandflash中,利用Busy box制作了ext3格式的根文件系统。由于程序开发的需要,本系统在uboot的命令行界面中设置了启动内核与挂载根文件的系统的方式。设置启动命令bootcmd,使开发板通过tftp下载镜像(zImage)。设置启动参数bootargs,使开发板从nfs去挂载rootfs(内核配置应使能nfs形式的rootfs)。考虑到内核版本与硬件的不兼容问题,本系统基于linux内核驱动框架,移植了framebuffer驱动程序。如图1所示,是系统的软件框架图。

图1 系统软件框架图

2 Framebuffer原理及驱动移植

framebuffer帧缓冲(简称fb)是Linux内核中虚拟出的一个设备,提供给用户态进程一个统一标准接口实现直接写屏操作。从驱动来看,framebuffer是一个典型的字符设备,而且创建了一个类/sys/class/graphics,用户可以把Framebuffer当作是显示内存的一个虚拟映像设备,将framebuffer映射到进程地址空间之后,就可以实现对LCD屏幕的直接读写操作,而这种写操作可以立刻反应在屏幕上。这种操作是统一的、抽象的,用户完全不必关心物理显存的位置、工作原理、刷新页面等具体细节,这些都是由 Framebuffer设备驱动来完成。

2.1 驱动框架部分

驱动框架部分,是内核开发人员编写,此部分不涉及具体硬件操作,主要包含4个文件。

1)fbmem.c此文件主要任务是:调用fbmem_init(void)此函数通过register_chrdev接口向系统注册一个framebuffer主设备号29即fb字符设备驱动,同时通过class_create创建graphics类, 配合mdev机制生成一个供给用户访问的设备文件(/dev目录下)。linux驱动设备中,所有的缓存显示设备都是由framebuffer子系统来管理,即linux设备驱动框架只需要知道一个主设备号为29的framebuffer设备即可。应用层如果要访问framebuffer均会被推送给fb_fops,统一由此结构体进行分发操作。register_framebuffer(struct fb_info *fb_info)此函数提供register_framebuffer接口给具体framebuffer驱动编写着来注册fb设备。

单独的显示缓存设备都被视作一个framebuffer从虚拟设备,必须要在驱动加载初始化时,通过register_framebuffer接口向framebuffer子系统注册自己,才能使自己能够被驱动程序接口调用。如此,当应用程序要访问该fb从设备时,才能方便framebuffer子系统进行有序操作和管理分发。

2)fbsys.c此文件中的函数将会被register_frame buffer接口调用,用来实现frame buffer在/sys目录下的一些属性文件bits_per_pixel、modes、stride、rotate…等。

3)modedb.c即显示模式库文件,此文件是管理显示模式,如分辨率,刷新率,VGA、720P等。

4)fb_notify.c其具体作用:被系统调用,它管理了一个链表,提供给linux内核管理,主要用来做一个反向唤醒机制。当注册了一个framebuffer驱动之后,系统将会通知这个链表中所有的驱动。

2.2 驱动部分

本系统中framebuffer驱动部分是被实现成为了platform平台总线驱动,这部分由驱动开发人员来编写,主要做一些硬件相关的工作,硬件初始化,初始化时钟,寄存器,GPIO,中断等等,包括如下4个文件。

1)s3cfb.c驱动主体。属于一个platform_driver,通过此文件中的s3cfb_probe()函数,调用操作硬件的函数接口,实现对硬件的操作算法。主要做的工作是:ioremap实现了寄存器地址的动态映射,分配frame buffer的缓存….等

2)s3cfb_fimd6x.c文件中定义了所有LCD硬件寄存器操作的函数,负责对硬件设备做一些具体的初始化,配置时钟,内存映射等。

3)mach-x210.c负责提供platform_device,platformdevices是在开机时,自动被注册,当platformdriver注册之后,二者将会配对。

4)devs.c为platform_device负责提供具体用到的硬件描述信息即resource资源数据,资源数据主要包括LCD有关的寄存器地址、IO资源、中断号等。

2.3 具体移植操作

开发Framebuffer设备驱动,存在几个重要结构体,需要重点研究,根据Framebuffer设备驱动程序的结构,驱动主要跟struct fb_info此结构体有关,此结构体记录了Framebuffer设备的几乎全部信息,具体包括设备的参数设置、状态信息和底层硬件操作的函数指针等。在Linuxkernel驱动中,每一个Framebuffer设备都对应一个fb_info才能完成驱动框架部分的接口函数。

1)struct fb_info此结构体定封装了frame buffer驱动的所有有效信息。

2)struct fb_ops,是fb_info成员结构体,fb_ops硬件操作接口集包含很多接口,如设置可变参数、设置颜色寄存器、清屏接口、画位图接口、内存映射等。

3)fb_fix_screeninf此结构体是fb_info成员结构体,填充用户不可修改的参数,包如显示内存的物理地址和长度等。

4)struct fb_var_screeninfo是fb_info成员结构体,填充用户可以修改的参数,包括屏幕分辨率、每个像素比特数等。

5)struct fb_fops,是Framebuffer属于字符设备,用户通过fb_fops结构中定义的文件操作接口函数可以操作Framebuffer设备。移植需要的具体操作如下:

1)打开kerneldriversvideoKconfig文件,添加代码:config FB_S3C_EK070TN93

bool "EK070TN93"

depends on MACH_SMDKV210 || MACH_SMDKC110

select BACKLIGHT_PWM

2)初始化LCD控制器。包括时钟信号的配置,信号的极性设置,VSYNC、HSYNC时序配置,像素配置,使能通道,LCD屏幕坐标设置,framebuffer始末位置设置,frame buffer在虚拟屏幕中的偏移量设置,输出模式等。

3)添加信息到设备devs.c中实现的加入控制器信息到device设备,如此,驱动框架才会认识新加入的设备名字,通过设备名字去查找相应的probe函数。

4)在系统初始化中增加对lcd的初始。即在系统初始化文件中添加:.init_machine = x210_lcd_init;5)make menuconfig配置,在console选项中还要加入frambuffer support选项。

6)最后make编译并执行,移植步骤完毕,如果移植完毕后,检测没有移植成功,可以在如下3个文中件排查问题,:menuconfig、Makefiel、Kconfig。

经过如上步骤,已经完成了framebuffer驱动在linux kernel中的移植工作,已经与S5PV210开发板的硬件完美兼容,接下来的只需要编写应用程序调用framebuffer驱动,将采集到的图像显示在开发板的LCD屏幕上。

3 基于Epoll框架的图像采集

Epoll是Linux内核为处理大批量文件描述符而作了改进的poll,是Linux下多路复用IO接口select/poll的增强版本,其工作原理如图2所示:在大量并发连接中只有少量活跃的情况下,能显著提高程序系统CPU利用率。获取事件的时,无须遍历整个被监听描述符集,只要遍历被内核IO事件异步唤醒而加入Ready队列的描述符集合。

图2 Epoll机制工作原理

V4L2(Video For Linux Two)是Linux操作系统下用于采集图片、视频和音频数据的API接口,配合适当的视频采集设备和相应的驱动程序,可以实现图像采集。在Linux操作系统中一切皆文件,在本系统中,摄像头设备文件是"/dev/video0"。V4L2支持两种方式来采集图像:内存映射方式(mmap)和直接读取方式(read)。V4L2在videodev.h文件中定义了一些重要的数据结构,在采集图像的过程中,通过对这些数据的操作来获得最终的图像数据。如图3所示是V4L2在linux中的驱动框架如图3所示。

图3 V4L2驱动框架图

如图4所示是epoll框架的V4L2图像采集流程:

第一步,打开视频设备文件,通过V4L2接口进行视频采集的参数初始化。

第二步,申请若干视频采集的帧缓冲区,并将这些帧缓冲区从内核空间映射到用户空间,便于应用程序读取并处理图像数据。

第三步,将申请到的帧缓冲区在视频采集输入队列排队,并启动视频采集。

第四步,开始视频数据的采集,应用程序从视频采集输出队列取出帧缓冲区,处理完后,将帧缓冲区重新放入视频采集输入队列,循环往复采集连续的视频数据。

第五步,在事件处理函数void cammer_handler(int fd,void *arg)里面保存图像数据。

第六步,由于次摄像头只支持YUVU格式图片采集,需要调用函数对图片格进行转化,最后采集到的图像数据image_jpeg.jpg和image_bmp.bmp。

4 基于framebuffer图像解码显示

4.1 framebuffer图像显示

framebuffer帧缓冲(简称fb)是Linux内核中虚拟出的一个设备,它向应用层提供一个统一的标准编程接口,它向应用层屏蔽了驱动层的一些细节,方便用户进行应用编程。从驱动来看,fb是一个典型的字符设备。如图4是frame buffer驱动框架图。本系统中基于framebuffer驱动,图像显示程序的关键如下:

(1)设备文件fbfd = open(FBDEVICE, O_RDWR);

(2)获取设备信息vinfo.xres, vinfo.yres,vinfo.bits_per_pixel

(3)mmap做映射pfb = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0);

(4)填充framebuffervoid fb_draw2(const struct pic_info *pPic)

由此可以直接利用 Video4Linux 采集的图像数据,映射到 Framebuffer 的内存区域中,便可以直接显示到 LCD上。也可将摄像头采集到的数据直接保存成 JPG 或BMP 等格式的图像文件后,利用jpeglib解码,映射到Framebuffer的内存区域中,同样可以显示到LCD上。

4.2 libjpeg库的移植及JPEG图片解码

JPEG静态图片压缩标准是一种被广泛认可的图像格式标准,JPEG 标准是在变换编码的基础上,综合应用了 DCT 和哈夫曼编码两种手段达到了很好的图像压缩效果, 基于 D C T 的编码方法是JPEG 算法的核心内容。JPEG算法的实现流程主要包括图像分割、颜色空间转换、DCT(Discrete cosine transform)、Quantization(数据量化)、Huffman coding(数据进行编码)。如图5是DCT基压缩解压框图。

图5 DCT压缩解压框图

如图5所示:图像压缩大致可以概括成3个步骤,原始图像经映射变换后的数据,经量化器和熵编码器后以码流的形式输出。

1)映射变换。通过映射改变图像像素的特性,更加有利于对图像进行压缩编码。

2)量化器。对映射后的数据进行量化,可分为标准量化和矢量量化。对映射后的数据进行逐个的量化,称标准量化,若对映射后的数据成组的进行量化,称矢量量化。量化必然会造成图像的某些信息丢失,导致失真,即量化失真或量化噪声。量化的精细程度与压缩比例始终是对立的,所以应选用适当的量化级数和量化曲线形状来平衡这对矛盾。量化器的使用是图像编码产生失真的根本原因,如果使用了量化器,不可能保证复原图像与原始图完全一致。

3)熵编码器。其作用是用来消除符号编码冗余度的,一般不导致失真,理论上,编出的码流的平均码长应该等于量化后数据的信息熵。

DCT变换就是利用傅立叶变换的特性.采用图像边界褶翻将像变换为偶函数形式,接着对图像数据进行二维傅立叶变换,变后就只包含余弦项。所以称之为离散余弦变换。

首先,将图像分割成8*8的小块,在JPEG压缩算法中,通常情况是将颜色空间转换成YCbCr空间,Y表示亮度,Cb和Cr分别表示蓝色和红色的色差值,其转换公式为:

Y=0.289R+0.589G+0.124B

Cr=(0.501R-0.4186G-0.0823B)+128

Cb=(-0.1687R+0.3313G+0.500B)+128

DCT变换的本质就是将原来的小块图像投影到新的空间中,经过DCT变换后,原本杂乱的数据将变得工整。如下是DCT变换的公式:

F=AfAT

在DCT变换之后,图像的数据信息并没有丢失,需要对其进行量化处理Quantization,根据图像中的数据元素的使用频率,调整元素的编码长度,以获最优压缩比,进行哈弗曼编码压缩,至此在保证不丢失信息的前提下,则可以实现数据的无损压缩。本系统通过上面的基于epoll框架的图片采集可以得到的是经过编码压缩后的jpg格式的图片,jpg格式的图片数据量比bmp格式图片小很多,有利于图片传输与保存。

4.3 libjpg解码显示具体实现

libjpeg是一个完全用C语言编写的库,被广泛应用于JPEG解码、JPEG编码等应用中。首先需要移植libjpeg到系统中,编写int is_jpg(const char *path)函数,判断是否是jpg图片。static int jpg_analyze(struct pic_info *pPic)此函数功能: 解码jpg图片,并将解码出来的数据存储;函数参数: pPic,记录源jpg图片,解码出来的图片宽高、图片数据缓冲区等信息。如图6所示,是本系统jpg图片解码显示软件流程图。具体实现如下:

第1步: 错误处理函数部分的绑定,给解码器做必要的内存分配和数据结构的初始化。

cinfo.err = jpeg_std_error(&jerr.pub);jerr.pub.error_exit = my_error_exit;

jpeg_create_decompress(&cinfo);

第2步: 将fopen打开的源jpg图片和解码器关联jpeg_stdio_src(&cinfo, infile);

第3步: 读jpg文件头;

jpeg_read_header(&cinfo, TRUE);

第4步: 启动解码器jpeg_start_decompress(&cinfo);

第5步: 逐行解码并将解码出的数据丢到缓冲区jpeg_read_scanlines(&cinfo, &buffer, 1);

第6步: 解码完了,做清理工作jpeg_destroy_decompress(&cinfo);

第7步:调用函数,从图片存放路径,递归检索图片,显示到LCD;

int display_jpg(const char *pathname);

fb_draw2(&picture);

图6 jpg图片解码显示软件流程图

本程序能够实现递归检索文件夹,bmp、jpg图片解码显示LCD屏幕上,同时还是实现了触摸屏播放显示。本系统选取了手机屏幕缺陷中的白屏黑点屏,黑屏亮点屏,绿屏黑点屏,花屏黑点屏进行实验测试,如图7所示,是jpeg解码显示测试图,本系统能够将摄像头采集到的手机液晶屏幕缺陷图像显示在开发板的LCD显示屏上。

图7 jpeg解码显示测试图

5 结论

本文设计了基于嵌入式Linux的图像采集与显示系统,能够实现多路摄像头实时采集图像,并且能够实时显示在LCD屏幕上,还实现了图像的BMP格式与JPEG格式保存,有利于后续对图片做一些图像检测,例如TFT手机屏幕缺陷检测,基于深度学习模式识别等应用。在大型工厂车间多条流水线快速作业的手机屏幕生产线上,可以利用此系统装置实时快速的对手机液晶屏幕总成缺陷进行自动检测,代替人工肉眼检测的同时,又避免了耗费大量的人力物力财力。不仅减少了人工的重复劳动和生产成本,节约了时间和空间,提高了生产效率,

而且提高了手机液晶屏生产线的自动化程度。本系统适合工业自动化领域,它成本低、功耗低、体积小,可以方便的应用到图像采集,图象处理,视频监控,安全防范等项目中。

[1]刘峥嵘,张晓薇,俞 辉,等编著.嵌入式Linux应用开发[M].北京:机械工业出版社,2004

[2]韦东山.嵌入式Linux应用开发完全手册[M].北京:人民邮电出版社,2008.

[3]刘 森.嵌入式系统接口设计与Linux驱动程序开发[M].北京:北京航空航天大学出版社,2006

[4]于殿泓.图像检测与处理技术[ M].西安: 西安电子科技大学出版社,2006.

[5]谭浩强.C语言程序设计[M].北京:清华大学出版社,1992.

[6] 许宏松.Linux 应用程序开发指南[M].北京:机械工业出版社, 2000.

[7] 杜春雷.ARM体系结构与编程[M]. 北京:清华大学出版社, 2003.

[8] 宋宝华.Linux设备驱动开发详解[M]. 北京:人民邮电出版社, 2008.

猜你喜欢
内核解码驱动
多内核操作系统综述①
数据驱动世界。你得懂它 精读
基于模糊PI控制的驱动防滑仿真系统分析
强化『高新』内核 打造农业『硅谷』
活化非遗文化 承启设计内核
屈宏斌:未来五年,双轮驱动,砥砺前行
文化解码
解码eUCP2.0
文化 解码
微软发布新Edge浏览器预览版下载换装Chrome内核