基于ARM9的摄像头应用

项目简介

1.1实验目标重述

ARM架构的微处理器在追求低成本、低功耗和高性能的嵌入式系统领域占有主导地位,学习ARM微处理器的嵌入式系统设计对于未来的学习与实践都有重要的意义。本次实验,主要是基于KDLAB-I 嵌入式系统实验平台(核心为ARM9架构的S3C2440微处理器),在Linux系统下进行设计与编程,利用OV9650摄像头实现摄像、采集图片、分析图片、识别颜色的功能。
九层之台,起于垒土,整个实验跨度达两周,具体言之,又可以细分为以下几个目标:
1、 熟悉Linux虚拟机的安装和Linux系统的使用,掌握常见的命令,熟悉Linux系统下的操作逻辑;
2、 了解ARM嵌入式Linux系统的开发过程,掌握修改、编写、烧 写应用程序和驱动程序的方法;
3、 掌握嵌入式Linux系统开发交叉编译环境的建立和使用;
4、 熟悉实验台上常用外设的使用方法和连接方式;
5、 熟练掌握摄像头的应用程序的编写和调试;
6、 熟悉RGB-565、RGB-888和HSI等常见颜色空间的转换以及编程的实现;
7、 掌握位图的保存格式、数据格式和保存方法,并在Linux下编程实现;
8、 掌握八邻域生长算法的算法核心和编程实现,并能够在嵌入式 Linux系统中实现对拍摄图片的正确连通;
9、 熟悉嵌入式系统的编程和调试方法,学会利用输出来进行调试;

1.2作品功能分析

1、 摄像头能够实现实时监视功能,将拍摄到的图像实时显示在 LCD屏幕上;
2、 具备截图功能,能够定时或根据输入保存当时的实时画面并另存为图片;
3、 具备分析功能,能够判别图中是否存在面积达到一定大小的红色色块,并判定其形心和半径;
4、 具备结果可视化功能,可以将图片处理为除原图红色区域外均为黑色的图形,更加直观;

二、功能流程图

三、实验过程

准备:Linux平台下ARM嵌入式编程基本操作

主要包括基本文件操作、定制与修改内核、给开发板烧写定制的嵌入式Linux系统以及虚拟机与ARM9开发板的通讯。
其中,烧写系统或许是最重要的一项技能了,因为在实验的过程中几乎每天都会遇到莫名其妙的故障,甚至连重启都解决不了(比如无限自动重启),这时候我就采取了最笨的办法——重新安装系统。

例程学习——camtest.cpp

Trect类

例程将TRect用作屏幕显示的基类,定义了图像存储的起始地址Addr, 图像的尺寸Size、宽度Width、高度 Height、每行图像存储时占 用的字节数LineLen以及图像的位数BPP,并声明和定义了将缓存数据显示到屏幕上的DrawRect函数和清屏函数Clear。在这次实验中,完成bmp图像的存储和图像分析功能的SavePic函数都是通过在DrawRect基础上加以修改来实现的。

TFrameBuffer类

TFrameBuffer作为TRect类的派生类,主要作为缓存,将 TVideo存储的图片信息通过映射放到内存中,便于以后的直接读 写,也可以少用read()和write()这类读写函数,加快读写 速度,其他部分没有太大的改动。

TVideo类

TVideo同样是TRect类的派生类,这个派生类主要负责将摄像头拍摄到的图像存储在缓存区中,以待TFrameBuffer转存和显示。

主函数

Camtest的主函数比较简单,短短的几行却完成了很多事情,定义了一个TFrameBuffer对象和一个TVideo对象,调用FetchPicture函数存储图像之后,再调用DrawRect将图像显示到屏幕上。使用for结构无限循环此动作,并在最外层使用try-catch的结构来捕捉意外动作。

双线程

需求分析

最初并没有打算使用双线程,但是在仔细分析之后,如果需要加入按键来决定是否采集分析图像,那么久不能使用单线程,否则将会出现用户不按键,系统就一直等待的现象,这显然不是一个合格的系统所应有的样子。所以还是硬着头皮使用了双线程。一个线程负责键盘的检测,另一个线程负责实时拍摄和显示功能,并且,没有设置互斥量进行交互以保证完全的实时运行,设置了一个信息量以负责两个线程之间的信息传递。

双线程例程pthread学习

在双线程的例程pthread中,首先声明了互斥量pthread_tmutex,之后声明了主线程writer_function和子线程reader_function,在主函数中创建了子线程的进程,而主函数则运行主线程,两者通过互斥量进行交互,分别作为生产者和消费者增加和减少虚拟的缓存buffer_has_item,并在PC终端上对剩余的缓存产品进行显示。

双线程设计

基于之前的分析,将双线程例程中的互斥量去掉以保证两个线程能够完全独立地工作。当然在Makefile中还要在编译语句的最后加上-lpthread,把多线程的库链接上。在两个独立的线程中进一步添加功能。

颜色识别

什么是颜色空间

颜色通常用三个相对独立的属性来描述,三个独立变量综合作用,自然就构成一个空间坐标,这就是颜色空间。而颜色可以由不同的角度,用三个一组的不同属性加以描述,就产生了不同的颜色空间。虽然被描述的对象颜色是客观存在的,但是很明显这是多指标非线性的,由于不同场合的需求不同,因此不同的颜色空间仍有存在的必要。颜色空间按照基本结构可以分两大类:基色颜色空间和色、亮分离颜色空间。前者的典型是RGB;后者包括 YCC/YUV、Lab、以及一批“色相类颜色空间”。

RGB颜色空间

RGB颜色空间是一种大的分类,具体而言RGB空间还包含多种空间,其中sRGB是HP和Microsoft联合制定的标准RGB空间,除此之外还有Adobe RGB,Apple RGB,ColorMatch RGB等等,他们通过不同的方式表示RGB三种颜色,使得它们具有不同的色彩宽度,GAMMA值也是不一样的,但是在此处并不需要多加讨论。
本实验平台上摄像头OV9650回传的数据是RGB565格式的,相对RGB888格式(俗称24位真彩色)牺牲了一定的信息量,由于在想HSI空间转换的时候需要全部的RGB信息,因此还需要转化到RGB888格式,这其中更还涉及到补偿,会在后面叙述。

HSI颜色空间

HSI模型属于第二类色亮分离的颜色空间,其建立基于两个重要的事实: 1°L分量与图像的彩色信息无关;2°H和S分量与人感受颜色的方式是紧密相联的。这些特点使得HSI模型非常适合彩色特性检测与分析。


hsi-colour-palette2.png

HSI模型是美国色彩学家孟塞尔(H.A.Munseu)于1915年提出的,它反映了人的视觉系统感知彩色的方式,用色调(Hue)、色饱和度(Saturation或Chroma)和亮度 (Intensity或Brightness)来描述色彩其中,色调与光波的波长有关,它表示人的感官对不同颜色的感受,如红色、绿色、蓝色等,它也可表示一定范围的颜色,如暖色、冷色等。饱和度 表示颜色的纯度,纯光谱色是完全饱和的,加入白光会稀释饱和度。饱和度越大,颜色看起来就会越鲜艳,反之亦然。亮度 对应成像亮度和图像灰度,是颜色的明亮程度。HSI色彩空间可以用一个圆锥空间模型来描述。虽然这种圆锥模型相当复杂,但确能把色调、亮度和色饱和度的变化情形表现得很清楚。为了便于色彩处理和识别,人的视觉系统经常采用HSI色彩空间, 它比RGB色彩空间更符合人的视觉特性。在图像处理和计算机视觉中大量算法都可在HSI色彩空间中方便地使用,它们可以分开处理而且是相互独立的。因此,在HSI色彩空间可以大大简化图像分析和处理的工作量。HSI色彩空间和RGB色彩空间只是同一物理量的不同表示法,因而它们之间存在着转换关系。

RGB565->RGB888

将RGB565格式转换为RGB888以进行到HIS颜色空间的转换的必要性之前已经讲过。我们知道RGB565格式分别保存了色彩的RGB分量的高5位、6位、5位,那么,亟需做的一件事情就是决定如何添加低位信息,最直接的想法是低位补零,但是实践表明效果并不好,现在被广泛采用是是一种称为量化补偿的方法,有三个步骤:
  1. 将原数据填充至高位
  2. 对于低位,用原始数据的低位进行补偿
  3. 如果仍然有未填充的位,继续使用原始数据的低位进行循环补偿
  解释一下循环补偿的概念:
  16bit RGB565 -> 24bit RGB888 的转换
  8bit RGB565 R4 R3 R2 R1 R0 - - - G2 G1 G0 B1 B0
  24bit RGB888 R2 R1 R0 0 0 0 0 0 G2 G1 G0 0 0 0 0 0 B1 B0 0 0 0 0 0 0
  24bit RGB888 R2 R1 R0 R2 R1 R0 0 0 G2 G1 G0 G2 G1 G0 0 0 B1 B0 B1 B0 0 0 0 0
  24bit RGB888 R2 R1 R0 R2 R1 R0 R2 R1 G2 G1 G0 G2 G1 G0 G2 G1 B1 B0 B1 B0 B1 B0 0 0
  24bit RGB888 R2 R1 R0 R2 R1 R0 R2 R1 G2 G1 G0 G2 G1 G0 G2 G1 B1 B0 B1 B0 B1 B0 B1 B0

RGB颜色空间到HSI颜色空间的转换

** 红色界定**
量化补偿只是优化显示效果,并不能改变实际所观测的结果,所以,在编程的时候直接考虑从原始的RGB565格式的数据着手。
由于G是高6位,B是高5位参照网上资料,当G、B均小于10左右,R大于200,可以视为红色,故此处仅考虑G末位为000001/000000;
B为00000;红色为111**;
即只有这几种可能:
11100000 11101000 11110000 11111000 32+64+128+8+16=224,232,240,248
00000000 00100000 0/32

一些小Trick

宏与三目运算符嵌套

在进行RGB到HSI的转换的时候,有一个比较RGB三者大小的步骤,本来是写的if语句嵌套,但是想想貌似有点累赘,于是便选择了三目运算符的嵌套并写成了宏,效果还不错,减少了二十多行的代码量。

    #define MAX(a,b,c) ((a>b)?((a>c)?a:c):((b>c)?b:c))

实验记录

Segmentation Fault

在尝试进行更进一步的图像处理的时候,试图将图像数据写入数组再进行分析,但是出现了

=============
RESOURCE
今天在REVIEW代码的时候,发现了这样一个宏定义:

define COLOR_TO_MTK_COLOR_SIMUL(color) ((((color) >> 19) & 0x1f) << 11) \

                                        |((((color) >> 10) & 0x3f) << 5)  \
                                        |(((color) >> 3) & 0x1f)  

大家知道这个宏是用来干什么的吗?

仔细分析后,原来就是实现了RGB888到RGB565的转换,查阅相关资料后,发现网络上有一篇牛人写的东东,在此和大家分享。

讲一下量化压缩与量化补偿吧

在进行色彩格式转换的时候,经常会遇到色彩量化位数的改变,比如说从 24bit RGB888 到 16bit RGB565 的色彩转换。所谓量化压缩与量化补偿都是我个人所提出的概念,现说明如下。

量化压缩,举例:

24bit RGB888 -> 16bit RGB565 的转换

24ibt RGB888 R7 R6 R5 R4 R3 R2 R1 R0 G7 G6 G5 G4 G3 G2 G1 G0 B7 B6 B5 B4 B3 B2 B1 B0

16bit RGB656 R7 R6 R5 R4 R3 G7 G6 G5 G4 G3 G2 B7 B6 B5 B4 B3

量化位数从8bit到5bit或6bit,取原8bit的高位,量化上做了压缩,却损失了精度。

量化补偿,举例:

16bit RGB565 -> 24bit RGB888 的转换

16bit RGB656 R4 R3 R2 R1 R0 G5 G4 G3 G2 G1 G0 B4 B3 B2 B1 B0

24ibt RGB888 R4 R3 R2 R1 R0 0 0 0 G5 G4 G3 G2 G1 G0 0 0 B4 B3 B2 B1 B0 0 0 0

24ibt RGB888 R4 R3 R2 R1 R0 R2 R1 R0 G5 G4 G3 G2 G1 G0 G1 G0 B4 B3 B2 B1 B0 B2 B1 B0

说明:第二行的 24bit RGB888 数据为转换后,未进行补偿的数据,在精度上会有损失

第三行的 24bit RGB888 数据为经过量化补偿的数据,对低位做了量化补偿

可以很容易的证明,这样的补偿方法是一种合理的线性补偿。补偿的原理很简单,大家仔细想一下就明白了,因此不再详细说明。

总结一下:

量化压缩的方法:三个字取高位

量化补偿的方法:

1. 将原数据填充至高位

2. 对于低位,用原始数据的低位进行补偿

3. 如果仍然有未填充的位,继续使用原始数据的低位进行循环补偿

解释一下循环补偿的概念:

8bit RGB332 -> 24bit RGB888 的转换

8bit RGB332 R2 R1 R0 G2 G1 G0 B1 B0

24bit RGB888 R2 R1 R0 0 0 0 0 0 G2 G1 G0 0 0 0 0 0 B1 B0 0 0 0 0 0 0

24bit RGB888 R2 R1 R0 R2 R1 R0 0 0 G2 G1 G0 G2 G1 G0 0 0 B1 B0 B1 B0 0 0 0 0

24bit RGB888 R2 R1 R0 R2 R1 R0 R2 R1 G2 G1 G0 G2 G1 G0 G2 G1 B1 B0 B1 B0 B1 B0 0 0

24bit RGB888 R2 R1 R0 R2 R1 R0 R2 R1 G2 G1 G0 G2 G1 G0 G2 G1 B1 B0 B1 B0 B1 B0 B1 B0

看了这个,应该明白则么回事了吧,其中B分量,进行了四轮的补偿,达到要求。

量化补偿的必要性,从直觉上讲,我所提出的这种补偿方法是正确的(因为我并没有严格的去证明),进行这样的补偿,在做色彩各式转换的时候,能够明显的改善色彩效果,减少精度上的损失。

对256色调色板模式的认识和应用,顺便讲一下这个,因为量化压缩和量化补偿刚好可以应用到调色板模式下。大家都知道,很早以前就有人提过出256色的标准调色板的概念(有的人又称之为抖动调色板或者万能调色板),其实这样的调色板并不神秘。256色中,一个像素点用8bit表示,那么如果采用 8bit RGB332 的格式,一切问题都可以想通,并且可以进行很好的处理了。对于每个 RGB332 的颜色,都可以使用量化补偿的做法,将其转换为 24bit RGB888 的颜色格式,然后将其设置为调色板即可。这样,实质上是将256色调色板模式,转换为了 8bit RGB332 的像素格式。这样的调色板方式,更加利于某些方面的处理,比如调色板匹配、Alpha混合等。由于采用了这样的方法,一个像素点的颜色值,与其实际的RGB颜色值,可以很方便的通过量化补偿的方法转换出来,然后就可以对各个颜色分量进行计算,计算完毕,再使用量化压缩的方法,就可以生成最终需要的颜色值。而所谓的调色板匹配的问题,当然也更加好解决了。关键是要把问题想通,把握事物的本质,才能找到简单而优美的解决问题的方法。

以前我对标准调色板的认识也存在很多错误,导致在分析和解决问题上,没有能找到最好的方法。网上也有许多人写过有关256色模式下 Alpha Blending 的文章,但是都存在许多认识上的不足,导致最后给出的算法时间和空间的复杂度都太大。我也有过一篇有关256色Alpha混合的文章,但限于当时对事物的认知能力,因此现在看来以前的许多文章是惨不忍睹。大家都在进步,以后有机会再将新的认识写成文章,同大家分享。

hsi-colour-palette2.png

推荐阅读更多精彩内容