2009年8月23日星期日

JPEG 原理详细实例分析及其在嵌入式 Linux 中的应用

JPEG 原理详细实例分析及其在嵌入式 Linux 中的应用 - Video - Embeded Linux
   


JPEG 原理详细实例分析及其在嵌入式 Linux 中的应用
作为一个基本的图像压缩方式,JPEG 已经得到了广泛的运用,但 JPEG 相关的基本原理,却经常被忽视,或解释得很不确切。 这里我们详细讨论一下 JPEG 的编码原理,并结合实例来给出一个更加感性的认识。JPEG 编码的详细过程有着诸多的信息可以给我们巨大的启发,我们在这里讨论的就是要对这些信息做一个具体细致的分析,通过我们的讨论,大家会对 JPEG 编码过程中出现的内容有一个确切的了解,并且能了解到这些内容的来龙去脉。

一、系统架构

本文以一个实际的产品为例,来说明 JPEG 在其中的应用。


 

本系统为一个嵌入式 Linux 网络播放器,主要的功能为播放家庭网络中的多媒体文件,在家庭客厅等环境中有着大量的应用,它可以给用户提供更方便快捷的媒体文件的播放方式,并能充分利用家庭音响系统的巨大功能,而非 PC 环境下有限的外部设备,大大改善了媒体文件的播放体验。

系统主要的功能包括:


 

本系统架构如下图:


 

本系统是基于嵌入式 Linux 的一个应用,使用的是 ucLinux 2.4.22,并使用了 microwindows 作为 GUI 界面,底层使用了 Linux kernel 的 FrameBuffer 作为显示输出。

此系统在两个方面使用到了 JPEG 库:

1、 UI 的显示,即各种人机交互界面,考虑到用户体验,所以大量使用了贴图来美化 UI

2、 JPEG 图片文件的全屏播放,包括用户手中的各种照片等

二、JPEG 概述

JPEG 是 Joint Photographic Experts Group 的缩写,即 ISO 和 IEC 联合图像专家组,负责静态图像压缩标准的制定,这个专家组开发的算法就被称为 JPEG 算法,并且已经成为了大家通用的标准,即 JPEG 标准。 JPEG 压缩是有损压缩,但这个损失的部分是人的视觉不容易察觉到的部分,它充分利用了人眼对计算机色彩中的高频信息部分不敏感的特点,来大大节省了需要处理的数据信息。

人眼对构成图像的不同频率成分具有不同的敏感度,这个是由人眼的视觉生理特性所决定的。如人的眼睛含有对亮度敏感的柱状细胞1.8亿个,含有对色彩敏感的椎状细胞0.08亿个,由于柱状细胞的数量远大于椎状细胞,所以眼睛对亮度的敏感程度要大于对色彩的敏感程度。

总体来说,一个原始图像信息,要对其进行 JPEG 编码,过程分两大步:

1、 去除视觉上的多余信息,即空间冗余度

2、 去除数据本身的多余信息,即结构(静态)冗余度

1、去除视觉上的多余信息

当你拿到一个原始未经处理的图像,是由各种色彩组成的,即在一个平面上,有各种色彩,而这个平面是由水平和垂直方向上的很多点组成的。实际上,每个点的色彩,也即计算机能表示的每个像素点的色彩,能分解成红、绿、蓝,即 RGB 三元色来表示,即这三种颜色的一定比例的混合就能得到一个实际的色彩值。


 

所以,实际上,这个平面的图像,可以理解为除了水平 X 和垂直 Y 以外,还有一个色彩值的 Z 的三维的系统。Z 代表了三元色中各个分支 R/G/B 的混合时所占的具体数值大小,每个像素的 RGB 的混合值可能都有所不同,各个值有大有小,但临近的两个点的 R/G/B 三个值会比较接近。


 

由于这个原始图像是由很多个独立的像素点组成的,也就是说它们都是分散的,离散的。比如有些图像的尺寸为640X480,就表示水平有640个像素点,垂直有480个像素点。

从上面的内容,我们可以知道两个相邻的点,会有很多的色彩是很接近的,那么如何能在最后得到的图片中,尽量少得记录这些不需要的数据,也即达到了压缩的效果。

这个就要涉及到图像信号的频谱特性了。

图像信号的频谱线一般在0-6MHz范围内,而且一幅图像内,包含了各种频率的分量。但包含的大多数为低频频谱线,只在占图像区域比例很低的图像边缘的信号中才含有高频的谱线。这个是对 JPEG 图像压缩的理论依据。

因此具体的方法就是,在对图像做数字处理时,可根据频谱因素分配比特数:对包含信息量大的低频谱区域分配较多的比特数,对包含信息量低的高频谱区域分配较少的比特数,而图像质量并没有可察觉的损伤,达到数据压缩的目的。

将原始图像这个色彩空间域,转换为频谱域,怎么转呢,这个就用到了数学上的离散余弦变换,即 DCT(Discrete Cosine Transform) 变换。

DCT 是可逆的、离散的正交变换。变换过程本身虽然并不产生压缩作用,但是变换后的频率系数却非常有利于码率压缩。即这个变换过程得到一个 DCT 变换系数,而对这个系数可以再进行更进一步的处理,即所谓的量化。经过量化,就能达到数据压缩的作用了。

总体说来,这第一步,对图像进行编码,去除多余的信息,要用到 DCT 变换中的正向 DCT(FDCT),然后再对变换的系数做量化(Quantization),这个过程就是依据的经验值,来处理人眼视觉系统所不敏感的高频数据,从而极大地减少了需要处理的数据量,这个是结合数学方法与经验值而做的处理。

2、去除数据本身的多余信息

利用 Huffman 编码,来将最后的数据用无损的方式做压缩,这个是纯数学上的处理方式。

总体来说,上面的两步即:

如果处理的是彩色图像,JPEG 算法首先将 RGB 分量转化成亮度分量和色差分量,同时丢失一半的色彩信息(空间分辨率减半)。然后,用 DCT 来进行块变换编码,舍弃高频的系数,并对余下的系数进行量化以进一步减小数据量。最后,使用 RLE 行程编码和 Huffman 编码来完成压缩任务。

三、JPEG 原理详细分析

下面将更加详细地介绍这两步中的各个细节。

JPEG 编码中主要涉及到的内容主要包括:

1. Color Model Conversion (色彩模型)

2. DCT (Discrete Cosine Transform 离散余弦变换)

3. 重排列 DCT 结果

4. 量化

5. RLE 编码

6. 范式 Huffman 编码

7. DC 的编码


 

1、色彩空间 color space

在图像处理中,为了利用人的视角特性,从而降低数据量,通常把 RGB 空间表示的彩色图像变换到其他色彩空间。

现在采用的色彩空间变换有三种:YIQ,YUV 和 YCrCb。

每一种色彩空间都产生一种亮度分量信号和两种色度分量信号,而每一种变换使用的参数都是为了适应某种类型的显示设备。


 

YUV 不是哪个英文单词的缩写,而只是符号,Y 表示亮度,UV 用来表示色差,U、V 是构成彩色的两个分量;

YUV 表示法的重要性是它的亮度信号(Y)和色度信号(U、V)是相互独立的,也就是 Y 信号分量构成的黑白灰度图与用 U、V 信号构成的另外两幅单色图是相互独立的。由于 Y、U、V 是独立的,所以可以对这些单色图分别进行编码。此外,黑白电视能接收彩色电视信号也就是利用了 YUV 分量之间的独立性。

举例来说明一下:

要存储 RGB 8∶8∶8的彩色图像,即 R、G 和 B 分量都用8位二进制数(1个字节)表示,图像的大小为640×480像素,那么所需要的存储容量为640×480×(1+1+1)=921 600字节,即900KB,其中(1+1+1)表示 RGB 各占一个字节。


 

如果用 YUV 来表示同一幅彩色图像,Y 分量仍然为640×480,并且 Y 分量仍然用8位表示,而对每四个相邻像素(2×2)的 U、V 值分别用相同的一个值表示,那么存储同样的一幅图像所需的存储空间就减少到640×480×(1+1/(2*2)+1/(2*2))=460 800字节,即450KB。也就是把数据压缩了一半。


 

无论是用 YIQ、YUV 和 YCrCb 还是其他模型来表示的彩色图像,由于现在所有的显示器都采用 RGB 值来驱动,这就要求在显示每个像素之前,须要把彩色分量值转换成 RGB 值。

对电视机,在考虑人的视觉系统和电视阴极射线管(CRT)的非线性特性之后,RGB 和 YUV 的对应关系可以近似地用下面的方程式表示:


 

即:

Y=0.3R+0.59G+0.11B

U=B-Y

V=R-Y

对计算机而言,计算机用的数字域的色彩空间变换与电视模拟域的色彩空间变换不同,它们的分量使用 Y、Cr 和 Cb 来表示,与 RGB 空间的转换关系如下:


 

从这里,就可以看出,计算出来的 Y、Cr 和 Cb 分量,会出现大量的小数,即浮点数,从而导致了在 JPEG 编码过程中会出现大量的浮点数的运算,当然经过一定的优化,这些浮点数运算可以用移位与加法这些计算机能更快速处理的方式来对其进行编码。

RGB 与 YCrCb 之间的逆变换关系可写成如下的形式:


 

总体来说,上面讲的这些内容,主要就是对原始图片,可以先进行色彩空间的处理,使采集到的图像数据有所减少。

请注意,实际上,JPEG 算法与色彩空间无关,色彩空间是涉及到图像采样的问题,它和数据的压缩并没有直接的关系。

因此"RGB 到 YUV 变换"和"YUV 到 RGB 变换"不包含在 JPEG 算法中。JPEG 算法处理的彩色图像是单独的彩色分量图像,因此它可以压缩来自不同色彩空间的数据,如 RGB,YcbCr 和 CMYK。

2、色彩深度 color depth

在图像中,它是由很多个点来组成的,那么存储每个像素点所用的位数就叫做像素深度。对一个图片,这个值是可以有所不同的,从而会使得图片的数据有多和少的区别。

一幅彩色图像的每个像素用 R,G,B 三个分量表示,若每个分量用8位,那么一个像素共用3X8=24位表示,就说像素的深度为24 bit,每个像素可以是2的24次方=16 777 216种颜色中的一种。表示一个像素的位数越多,它能表达的颜色数目就越多。

在用二进制数表示彩色图像的像素时,除 R,G,B 分量用固定位数表示外,往往还增加1位或几位作为属性(Attribute)位。例如,RGB 5∶5∶5表示一个像素时,用2个字节共16位表示,其中 R,G,B 各占5位,剩下一位作为属性位。在这种情况下,像素深度为16位,而图像深度为15 位。

在用32位表示一个像素时,若 R,G,B 分别用8位表示,剩下的8位常称为 alpha 通道(alpha channel)位,或称为覆盖(overlay)位、中断位、属性位。它的用法可用一个预乘 α 通道(premultiplied alpha)的例子说明。假如一个像素(A,R,G,B)的四个分量都用归一化的数值表示,(A,R,G,B)为(1,1,0,0)时显示红色。当像素为 (0.5,1,0,0)时,预乘的结果就变成(0.5,0.5,0,0),这表示原来该像素显示的红色的强度为1,而现在显示的红色的强度降了一半。

这个 alpha 值,在这里就用来表示该像素如何产生特技效果。

总体来说,图像的宽高、分辨率越高,就是组成一幅图的像素越多,则图像文件越大;像素深度越深,就是表达单个像素的颜色和亮度的位数越多,图像文件就越大。

只有黑白两种颜色的图像称为单色图像(monochrome),每个像素的像素值用1位存储,它的值只有"0"或者"1",一幅640×480的单色图像需要占据37.5 KB的存储空间。

而灰度图像,即有色深的黑白图像,如果每个像素的像素值用一个字节表示,而不是仅仅只有一位,那么灰度值级数就等于256级,每个像素可以是0~255之间的任何一个值,一幅640×480的灰度图像就需要占用300 KB的存储空间,类似上面说到过的 Y 分量。

3、离散余弦变换 DCT

将图像从色彩域转换到频率域,常用的变换方法有:


 

DCT变换的公式为:


 

f(i,j) 经 DCT 变换之后,F(0,0) 是直流系数,其他为交流系数。

还是举例来说明一下。

8x8的原始图像:


 

推移128后,使其范围变为 -128~127:


 

使用离散余弦变换,并四舍五入取最接近的整数:


 

上图就是将取样块由时间域转换为频率域的 DCT 系数块。

DCT 将原始图像信息块转换成代表不同频率分量的系数集,这有两个优点:其一,信号常将其能量的大部分集中于频率域的一个小范围内,这样一来,描述不重要的分量只需要很少的比特数;其二,频率域分解映射了人类视觉系统的处理过程,并允许后继的量化过程满足其灵敏度的要求。

当u,v = 0 时,离散余弦正变换(DCT)后的系数若为F(0,0)=1,则离散余弦反变换(IDCT)后的重现函数 f(x,y)=1/8,是个常 数值,所以将 F(0,0) 称为直流(DC)系数;当 u,v≠0 时,正变换后的系数为 F(u,v)=0,则反变换后的重现函数 f(x,y) 不是常数,此时 正变换后的系数 F(u,v) 为交流(AC)系数。

DCT 后的64个 DCT 频率系数与 DCT 前的64个像素块相对应,DCT 过程的前后都是64个点,说明这个过程只是一个没有压缩作用的无损变换过程。

单独一个图像的全部 DCT 系数块的频谱几乎都集中在最左上角的系数块中。

DCT 输出的频率系数矩阵最左上角的直流 (DC)系数幅度最大,图中为-415;以 DC 系数为出发点向下、向右的其它 DCT 系数,离 DC 分量越远,频率越高,幅度值越小,图中最右下角为2,即图像信息的大部分集中于直流系数及其附近的低频频谱上,离 DC 系数越来越远的高频频谱几乎不含图像信息,甚至于只含杂波。

DCT 本身虽然没有压缩作用,却为以后压缩时的"取"、"舍" 奠定了必不可少的基础。

4、量化

量化过程实际上就是对 DCT 系数的一个优化过程。它是利用了人眼对高频部分不敏感的特性来实现数据的大幅简化。

量化过程实际上是简单地把频率领域上每个成份,除以一个对于该成份的常数,且接着四舍五入取最接近的整数。

这是整个过程中的主要有损运算。

以这个结果来说,经常会把很多高频率的成份四舍五入而接近0,且剩下很多会变成小的正或负数。

整个量化的目的是减小非"0"系数的幅度以及增加"0"值系数的数目。

量化是图像质量下降的最主要原因。

因为人眼对亮度信号比对色差信号更敏感,因此使用了两种量化表:亮度量化值和色差量化值。


 

使用这个量化矩阵与前面所得到的 DCT 系数矩阵:


 

如,使用−415(DC系数)且四舍五入得到最接近的整数


 

总体上来说,DCT 变换实际是空间域的低通滤波器。对 Y 分量采用细量化,对 UV 采用粗量化。

量化表是控制 JPEG 压缩比的关键,这个步骤除掉了一些高频量;另一个重要原因是所有图片的点与点之间会有一个色彩过渡的过程,大量的图像信息被包含在低频率中,经过量化处理后,在高频率段,将出现大量连续的零。

5、"Z"字形编排

量化后的数据,有一个很大的特点,就是直流分量相对于交流分量来说要大,而且交流分量中含有大量的0。这样,对这个量化后的数据如何来进行简化,从而再更大程度地进行压缩呢。

这就出现了"Z"字形编排,如图:


 

对于前面量化的系数所作的 "Z"字形编排结果就是:

底部 −26,−3,0,−3,−3,−6,2,−4,1 −4,1,1,5,1,2,−1,1,−1,2,0,0,0,0,0,−1,−1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 顶部

这样做的特点就是会连续出现多个0,这样很有利于使用简单而直观的行程编码(RLE:Run Length Coding)对它们进行编码。

8×8图像块经过 DCT 变换之后得到的 DC 直流系数有两个特点,一是系数的数值比较大,二是相邻8×8图像块的 DC 系数值变化不大。根据这个特点,JPEG 算法使用了差分脉冲调制编码(DPCM)技术,对相邻图像块之间量化 DC 系数的差值(Delta)进行编码。即充分利用相邻两图像块的特性,来再次简化数据。

即上面的 DC 分量-26,需要单独处理。

而对于其他63个元素采用zig-zag("Z"字形)行程编码,以增加行程中连续0的个数。

6、行程编码

Run Length Coding,行程编码又称"运行长度编码"或"游程编码",它是一种无损压缩编码。

例如:5555557777733322221111111

这个数据的一个特点是相同的内容会重复出现很多次,那么就可以用一种简化的方法来记录这一串数字,如

(5,6)(7,5)(3,3)(2,4)(l,7)

即为它的行程编码。

行程编码的位数会远远少于原始字符串的位数。

对经过"Z"字形编排过的数据,即可以用行程编码来对其进行大幅度的数据压缩。

我们来用一个简单的例子来详细说明一下:

57,45,0,0,0,0,23,0,-30,-16,0,0,1,0,0,0,0 ,0 ,0 ,0,..,0

可以表示为

(0,57) ; (0,45) ; (4,23) ; (1,-30) ; (0,-16) ; (2,1) ; EOB

即每组数字的头一个表示0的个数,而且为了能更有利于后续的处理,必须是 4 bit,就是说,只能是 0~15,这是的这个行程编码的一个特点。

7、范式 Huffman 编码

在直流 DC 系数经过上面的 DPCM 编码,交流 AC 系数经过 RLE 编码后,得到的数据,还可以再进一补压缩,即使用 Huffman 编码来处理。

范式 Huffman 编码即 Canonical Huffman Code,现在流行的很多压缩方法都使用了范式哈夫曼编码技术,如 GZIB、ZLIB、PNG、JPEG、MPEG 等。

对上面的例子中 RLC 后的结果,对它的存储,JPEG 里并不直接保存这个数值,这样主要是为了提高效率。


 

对上面的例子内容,就可以得到:

57 为第 6 组的,实际保存值为 111001,编码为 (6,111001)

45编码为 (6,101101)

23为(5,10111)

-30为(5,00001)

这个时候前面的例子就变为:

(0,6),111001 ; (0,6),101101 ; (4,5),10111; (1,5),00001; (0,4) ,0111 ; (2,1),1 ; (0,0)

这样,括号里的数值正好再合成一个字节,高4位是前面0的个数,低4位描述了后面数字的位数;后面被编码的数字表示范围是 -32767..32767。

使用上面这个表简化后的内容,再到 Huffman 编码表里去查询,从而得到最后的编码。

如06对应 Huffman 表的111000,那么

69 = (4,5) --- 1111111110011001 (69=0x45=4*16+5 )

21 = (1,5) --- 11111110110

从而得到最后的结果:

111000 111001 ; 111000 101101 ; 1111111110011001 10111 ; 11111110110 00001…

使用范式 Huffman 编码表的好处就是使得出现频率高的数字小于8位,而出现频率低的数字大于8位,这样对整体而言,就会极大地减少数据量。

需要注意的是,在 JPG 文件中,一般有两个 Huffman 表,一个是 DC 用,一个是 AC 用,它们是类似的。

对 DC 编码的部分是单独来处理的,并且是放在上面这个串的最前面。

总体来说,到目前为止,我们就得到了最后需要真正存储用的简化后,也即压缩后的数据了。

四、JPEG文件存储格式

介绍了 JPEG 的原理,我们再来结合一个具体的实例来详细讨论上面所涉及到的细节。

我们先来制作一个简单的8X8大小的像素图,然后把它存成JPEG格式。

方法是用 windows 的画图工具,定义一个8X8大小的图,用一些色块填充进去,然后另存为 JPEG 格式,如 test8x8.jpg。如下图所示:


 

保存成的文件后缀为 jpg,但按标准来说,它是一种 JFIF 格式标准的文件,里面的图像的压缩方式是 JPEG。

JFIF 是一个文件格式标准,JPEG 是一个压缩标准,总体来说它们不是一个概念。

JFIF 是 JPEG File Interchange Format 的缩写,也即 JPEG 文件交换格式。JFIF 是一个图片文件格式标准,它是一种使用 JPEG 图像压缩技术存储摄影图像的方法。JFIF 代表了一种"通用语言"文件格式,它是专门为方便用户在不同的计算机和应用程序间传输 JPEG 图像而设计的语言。

JFIF 文件格式定义了一些内容是 JPEG 压缩标准未定义的,如 resolution/aspect ratio,color space 等。


 

我们可以打开 JPEG 文件查看里面的内容,即可看到上面的各个标记段:


 

从图上可以看出:

在头部有 FFD8 ,表示图像的开始;结束部分有 FFD9 ,表示图像的结束。

在中间有两个量化表 DQT 对应的标记 FFDB ;

还有图像大小信息对应的 FFC0

再后面有四个 Haffman 表对应的 FFC4 ;

一般一个 JPG 文件里会有 2 类 Haffman 表:一个用于 DC 一个用于 AC ,也即实际有 4个表,亮度的 DC,AC 两个,色度的 DC,AC 两个。

然后是图像数据段标记 FFDA;

我们再来看看各个标记的细部,具体分析一下各个部分的含义。

1、图片的识别信息


 

上面的内容,在标记 FFE0 后,即为长度16。然后是5字节的 JFIF 标识符号,说明这是一个 JPEG 压缩的文件。然后是主/次版本号码。下一个为 XY 像素的单位,这里为1,表示单位为点数/英寸。然后是 XY 方向的像素密度,这里是 96DPI,最后是缩略图有关信息,这里为0。

2、量化表的实例


 

上面这个内容,FFDB 标记后的长度值为67,接下来的是 QT 信息,占一个字节;这里是0,表示这个 QT 表编号为0,并且精度是8bit。然后后面就是64个8x8的 QT 表的各个 item 了。

也即第一个 DQT 量化表的内容表示为十进制是:


 

这个表即为 JPEG 亮度量化表。

第二个量化表的内容为:


 

这个表的内容即为 JPEG 色度量化表。

当你打开不同的 JPEG 文件,你会看到这两个表可能也是会有区别的。这个主要是使用了不同的量化方式的结果。

3、图像信息段


 

上面这个内容,FFC0 标记后即是长度,为17,然后是一个字节的数据精度,通常是为8,代表样本位数。接下来是图片的高度,占两字节,这里即为8,然后是图片的宽度,也为8,这也就是我们定义的8x8的内容。然后是 component 的个数,这里是3,表示 YUV。接下来是三组数据,每组数据里,第一个是 component ID,第二个是采样系数,这里 Y 的采样系数为22,说明垂直是2,水平是2。再后面就是量化表的编号了。

4、Haffman 表的实例


 

上面这个内容,FFC4 标记后的内容为数据长度,再接着的1字节为 Huffman Table 的信息,低4位是 HT ID 号,第5位是 HT 表类型标记,再高三位是为0。

第一个 DHT 表,00,类型为 DC table,HT ID 号为 0;

第二个 DHT 表,10,类型为 AC table,HT ID 号也为 0;

第三个 DHT 表,01,类型为 DC table,HT ID 号为 1;

第四个 DHT 表,11,类型为 AC table,HT ID 号为 1;

即前两个表为Y亮度分量的 DC/AC 表,后两个为 UV 色度分量的 DC/AC 表。

以第一个表为例,因为长度只有 31,那么 00 后面的 16 字节,即绿色部分:


 

组号为 1 的组中,代码有 0 个;

组号为 2 的,代码有 1 个;

组号为 3 的代码有 5 个;

组号为 4/5/6/7/8/9 的代码各 1 个。

总共 12 个。

再看后续的数据:

00 01 02 03 04 05 06 07 08 09 0A 0B

即对应:


 

其他未出现的组号,对应的数据未使用到。也就是说前面提到过的范式 Huffman 编码里,目前只使用部分数据即可,原因是这个 8x8 的图像数据很小。

第二个 DHT 表就更复杂些了,长度有 181。

5、图像数据段


 

这里 SOS 段,长度为 12,后面所含有的 component 数量为 3 个,也即 Y UV。然后后面是各 component 的编号,及对应所使用的 Huffman 表的 ID 是多少。

在这个段的后面就是所有压缩后的数据。直到结束的问题,即 FFD9,EOI(End Of Image)。

五、JPEG 压缩过程的优化

JPEG 在目前的应用范围是非常广泛的,各种嵌入式系统中也大量地使用了 JPEG 压缩,如 IPCAM 摄像头、数字相机、移动存贮等。在这些领域由于传输数据的带宽限制或者是存贮数据的容量的限制,常常需要使用图像压缩技术来将原始大量的图像数据压缩后在进行传输或存贮,以充分利用带宽与存贮空间,达到更好的利用效率。这样,在嵌入系统中,就会使用到 JPEG 压缩。而且由于嵌入系统的资源有限的特点,在很多情况下,很需要再对 JPEG 编码压缩的过程做更进一步的优化,我们这里详细讨论一下如何实现这些优化。

浮点运算的优化

我们回头查看一下 JPEG 压缩中的 DCT 变换过程,公式:


 

由于公式中有两个 i/j=0~7 的部分,这样要获得一个 DCT 系数,需要做 8 x 8=64 次乘法和 8 x 8=64 次加法, 而完成整个 8 x 8 像素的 DCT 需要 8 x 8 x 8 x 8=4096 次乘法和 8 x 8 x 8 x 8=4096 次加法. 计算量是相当的大。

对于有些无浮点运算的嵌入式系统或无专门的数学运算协处理器的系统,会造成大量的运算,极大地占用CPU的资源。

上面的公式属于 DCT 的二维计算方式,经过简化,可以将其简化为两个一维的公式:


 

这样,上面的过程就可以简化为分别计算行和列的 DCT 变换。

对于一行来说需要计算的是 (8 x 8) 次乘法和 (8 x 8) 次加法,8 行就是 8 x (8 x 8) 次乘法和 8 x (8 x 8) 次加法,然后列也是相同,那么总数就为 2 x (8 x (8 x 8))=1024 次乘法和 2 x (8 x (8 x 8))=1024 次加法, 运算量变为二维计算的1/4。

但是这样的运算数量还是太大,还需要进一步优化。

在很多嵌入系统中,很多情况下需要不使用浮点运算,这样就需要再找出一维 DCT 的一些规律,然后对其进行进一步的优化。

在对一维 DCT 的运算中,还可以分为奇数列/行和偶数列/行


 

对上面的处理,就又出现了多种优化:ChenDCT,LeeDCT,AAN 算法和 LLM 算法。

其中 AAN 算法只需要 29 次加法和 5 次乘法。(注意,它是指每次一维运算要 29 次加法和 5 次乘法,一共是需要 29*8*2 次加法和 5*8*2 次乘法的)。


 

其中 Y[0]-Y[7] 都是 1*8 的矩阵,X[1]-X[7] 也都是 1*8 的矩阵。

{a, b, c, d, e, f, g} = 1/2 { cos(pi/4), cos(pi/16), cos(pi/8), cos(3pi/16), cos(5pi/16), cos(3pi/8), cos(7pi/16) }

再对上面的含有 pi 的系数进行整数优化,从而避免浮点运算,就会得到:


 

其中:

3/8=1/4+1/8

5/8=1/2+1/8

7/8=1-1/8

上面的除以 2,除以 8,都可以通过移位来实现,即右移一位和右移三位。即总数为 30 次加法,12 次移位即可。

这样就在很大程度上将原本需要使用乘法,浮点运算的过程全部转换成了简单的加法和移位处理了,这样使用数学的方法,用近似的值来完成整个转换过程,会有很好的性能和处理效果。

在处理上面的数据中,可以使用一些中间变量来记录中间结果,这样就可以减少反复计算中间值,而直接使用已经计算得到了的中间值。

tmp0 = x[0] + x[7];

tmp7 = x[0] - x[7];

tmp1 = x[1] + x[6];

tmp6 = x[1] - x[6];

tmp2 = x[2] + x[5];

tmp5 = x[2] - x[5];

tmp3 = x[3] + x[4];

tmp4 = x[3] - x[4];

tmp10 = tmp0 + tmp3;

tmp13 = tmp0 - tmp3;

tmp11 = tmp1 + tmp2;

tmp12 = tmp1 - tmp2;

/* 对偶数项进行运算 X 0,4,6,2 */

X[0]=tmp1+tmp11;

X[4]=tmp10 /2 - tmp11

X[6]=tmp12-(tmp13/4+ tmp13/8);

X[2]=tmp12/4+tmp12/8-tmp13;

其他的各个值也是类似处理的。

六、JPEG 在本嵌入式 Linux 应用中遇到的问题

在本系统中,提供给用户一些播放图片和预览图片的功能,在这个过程中就需要使用到对 JPEG 的处理。

1、JPEG 出错的处理

在对图片做预览处理的时候,有些图片原始尺寸很大,那么就需要将其转换成较小的缩略图,在转换为缩略图进行显示时,遇到了一个问题,即有时需要显示的图片,会导致系统无响应。

后来查找原因,定位到 JPEG 文件的数据不完整,才导致 jpeg decoder 出现无响应。

在前面的部分,有说到 JPEG 文件的格式中,JPEG 结束的标记 EOI (End Of Image) 为"FFD9"。

如果需要显示的图片,在传输过程中,或转换过程中,出现了没有 EOI 数据,那么应该在程序中,将其废弃,避免出现系统无响应。

2、JPEG 解码的效率优化

在解码 JPEG 时,可以使用 software decode 或 hardware decode 来处理。Hardware decode 的优点是充分利用 DSP 所提供的硬件解码功能,其解码速度会较 software decode 有数量级的提高。但有时使用 hardware decode 有一些限制,如各种 DSP 提供的 SDK 会是直接访问硬件,将 jpeg 直接输出到显示设备,从而会导致 hardware decode 与应用系统集成的麻烦。

而使用 software decode,就能在应用层完全掌握 jpeg decode 的数据缓冲结果,并可做一些图片的叠加效果或对其进行半透明混合处理,从而会有较高的灵活性。并且使用 decode buffer cache,来将已经解码的数据进行保存,在 UI 后续的使用中,就可不必反复去解码 JPEG 图片,从而也能有效提高绘图效率。





回页首


七、总结

上面的内容是本人对 JPEG 原理做的一个详细的实例分析,还介绍了 JPEG 编码过程中对浮点运算的优化处理,它特别适用于在资源有限的嵌入系统中避免大量的浮点运算。

在对 JPEG 原理做了一个详细的分析后,大家会对 JPEG 涉及到的各个细节有了一个更加明确的认识。当你自己动手结合 JPEG 编码过程来分析时,将会有一个清楚的全局观。

本文结合应用实例,对在嵌入式 Linux 应用中遇到的 JPEG 有关的问题,做了一个说明,大家在自己的设计过程中也可以作为参考。

现在,你如果再回头去看 JPEG 的原理,你现在应该能看懂它整个过程的来龙去脉了。


JPEG 原理详细实例分析及其在嵌入式 Linux 中的应用




















































作为一个基本的图像压缩方式,JPEG 已经得到了广泛的运用,但 JPEG 相关的基本原理,却经常被忽视,或解释得很不确切。 这里我们详细讨论一下 JPEG 的编码原理,并结合实例来给出一个更加感性的认识。JPEG 编码的详细过程有着诸多的信息可以给我们巨大的启发,我们在这里讨论的就是要对这些信息做一个具体细致的分析,通过我们的讨论,大家会对 JPEG 编码过程中出现的内容有一个确切的了解,并且能了解到这些内容的来龙去脉。

一、系统架构

本文以一个实际的产品为例,来说明 JPEG 在其中的应用。



本系统为一个嵌入式 Linux 网络播放器,主要的功能为播放家庭网络中的多媒体文件,在家庭客厅等环境中有着大量的应用,它可以给用户提供更方便快捷的媒体文件的播放方式,并能充分利用家庭音响系统的巨大功能,而非 PC 环境下有限的外部设备,大大改善了媒体文件的播放体验。

系统主要的功能包括:



本系统架构如下图:



本系统是基于嵌入式 Linux 的一个应用,使用的是 ucLinux 2.4.22,并使用了 microwindows 作为 GUI 界面,底层使用了 Linux kernel 的 FrameBuffer 作为显示输出。

此系统在两个方面使用到了 JPEG 库:

1、 UI 的显示,即各种人机交互界面,考虑到用户体验,所以大量使用了贴图来美化 UI

2、 JPEG 图片文件的全屏播放,包括用户手中的各种照片等

二、JPEG 概述

JPEG 是 Joint Photographic Experts Group 的缩写,即 ISO 和 IEC 联合图像专家组,负责静态图像压缩标准的制定,这个专家组开发的算法就被称为 JPEG 算法,并且已经成为了大家通用的标准,即 JPEG 标准。 JPEG 压缩是有损压缩,但这个损失的部分是人的视觉不容易察觉到的部分,它充分利用了人眼对计算机色彩中的高频信息部分不敏感的特点,来大大节省了需要处理的数据信息。

人眼对构成图像的不同频率成分具有不同的敏感度,这个是由人眼的视觉生理特性所决定的。如人的眼睛含有对亮度敏感的柱状细胞1.8亿个,含有对色彩敏感的椎状细胞0.08亿个,由于柱状细胞的数量远大于椎状细胞,所以眼睛对亮度的敏感程度要大于对色彩的敏感程度。

总体来说,一个原始图像信息,要对其进行 JPEG 编码,过程分两大步:

1、 去除视觉上的多余信息,即空间冗余度

2、 去除数据本身的多余信息,即结构(静态)冗余度

1、去除视觉上的多余信息

当你拿到一个原始未经处理的图像,是由各种色彩组成的,即在一个平面上,有各种色彩,而这个平面是由水平和垂直方向上的很多点组成的。实际上,每个点的色彩,也即计算机能表示的每个像素点的色彩,能分解成红、绿、蓝,即 RGB 三元色来表示,即这三种颜色的一定比例的混合就能得到一个实际的色彩值。



所以,实际上,这个平面的图像,可以理解为除了水平 X 和垂直 Y 以外,还有一个色彩值的 Z 的三维的系统。Z 代表了三元色中各个分支 R/G/B 的混合时所占的具体数值大小,每个像素的 RGB 的混合值可能都有所不同,各个值有大有小,但临近的两个点的 R/G/B 三个值会比较接近。



由于这个原始图像是由很多个独立的像素点组成的,也就是说它们都是分散的,离散的。比如有些图像的尺寸为640X480,就表示水平有640个像素点,垂直有480个像素点。

从上面的内容,我们可以知道两个相邻的点,会有很多的色彩是很接近的,那么如何能在最后得到的图片中,尽量少得记录这些不需要的数据,也即达到了压缩的效果。

这个就要涉及到图像信号的频谱特性了。

图像信号的频谱线一般在0-6MHz范围内,而且一幅图像内,包含了各种频率的分量。但包含的大多数为低频频谱线,只在占图像区域比例很低的图像边缘的信号中才含有高频的谱线。这个是对 JPEG 图像压缩的理论依据。

因此具体的方法就是,在对图像做数字处理时,可根据频谱因素分配比特数:对包含信息量大的低频谱区域分配较多的比特数,对包含信息量低的高频谱区域分配较少的比特数,而图像质量并没有可察觉的损伤,达到数据压缩的目的。

将原始图像这个色彩空间域,转换为频谱域,怎么转呢,这个就用到了数学上的离散余弦变换,即 DCT(Discrete Cosine Transform) 变换。

DCT 是可逆的、离散的正交变换。变换过程本身虽然并不产生压缩作用,但是变换后的频率系数却非常有利于码率压缩。即这个变换过程得到一个 DCT 变换系数,而对这个系数可以再进行更进一步的处理,即所谓的量化。经过量化,就能达到数据压缩的作用了。

总体说来,这第一步,对图像进行编码,去除多余的信息,要用到 DCT 变换中的正向 DCT(FDCT),然后再对变换的系数做量化(Quantization),这个过程就是依据的经验值,来处理人眼视觉系统所不敏感的高频数据,从而极大地减少了需要处理的数据量,这个是结合数学方法与经验值而做的处理。

2、去除数据本身的多余信息

利用 Huffman 编码,来将最后的数据用无损的方式做压缩,这个是纯数学上的处理方式。

总体来说,上面的两步即:

如果处理的是彩色图像,JPEG 算法首先将 RGB 分量转化成亮度分量和色差分量,同时丢失一半的色彩信息(空间分辨率减半)。然后,用 DCT 来进行块变换编码,舍弃高频的系数,并对余下的系数进行量化以进一步减小数据量。最后,使用 RLE 行程编码和 Huffman 编码来完成压缩任务。

三、JPEG 原理详细分析

下面将更加详细地介绍这两步中的各个细节。

JPEG 编码中主要涉及到的内容主要包括:

1. Color Model Conversion (色彩模型)

2. DCT (Discrete Cosine Transform 离散余弦变换)

3. 重排列 DCT 结果

4. 量化

5. RLE 编码

6. 范式 Huffman 编码

7. DC 的编码



1、色彩空间 color space

在图像处理中,为了利用人的视角特性,从而降低数据量,通常把 RGB 空间表示的彩色图像变换到其他色彩空间。

现在采用的色彩空间变换有三种:YIQ,YUV 和 YCrCb。

每一种色彩空间都产生一种亮度分量信号和两种色度分量信号,而每一种变换使用的参数都是为了适应某种类型的显示设备。



YUV 不是哪个英文单词的缩写,而只是符号,Y 表示亮度,UV 用来表示色差,U、V 是构成彩色的两个分量;

YUV 表示法的重要性是它的亮度信号(Y)和色度信号(U、V)是相互独立的,也就是 Y 信号分量构成的黑白灰度图与用 U、V 信号构成的另外两幅单色图是相互独立的。由于 Y、U、V 是独立的,所以可以对这些单色图分别进行编码。此外,黑白电视能接收彩色电视信号也就是利用了 YUV 分量之间的独立性。

举例来说明一下:

要存储 RGB 8∶8∶8的彩色图像,即 R、G 和 B 分量都用8位二进制数(1个字节)表示,图像的大小为640×480像素,那么所需要的存储容量为640×480×(1+1+1)=921 600字节,即900KB,其中(1+1+1)表示 RGB 各占一个字节。



如果用 YUV 来表示同一幅彩色图像,Y 分量仍然为640×480,并且 Y 分量仍然用8位表示,而对每四个相邻像素(2×2)的 U、V 值分别用相同的一个值表示,那么存储同样的一幅图像所需的存储空间就减少到640×480×(1+1/(2*2)+1/(2*2))=460 800字节,即450KB。也就是把数据压缩了一半。



无论是用 YIQ、YUV 和 YCrCb 还是其他模型来表示的彩色图像,由于现在所有的显示器都采用 RGB 值来驱动,这就要求在显示每个像素之前,须要把彩色分量值转换成 RGB 值。

对电视机,在考虑人的视觉系统和电视阴极射线管(CRT)的非线性特性之后,RGB 和 YUV 的对应关系可以近似地用下面的方程式表示:



即:

Y=0.3R+0.59G+0.11B

U=B-Y

V=R-Y

对计算机而言,计算机用的数字域的色彩空间变换与电视模拟域的色彩空间变换不同,它们的分量使用 Y、Cr 和 Cb 来表示,与 RGB 空间的转换关系如下:



从这里,就可以看出,计算出来的 Y、Cr 和 Cb 分量,会出现大量的小数,即浮点数,从而导致了在 JPEG 编码过程中会出现大量的浮点数的运算,当然经过一定的优化,这些浮点数运算可以用移位与加法这些计算机能更快速处理的方式来对其进行编码。

RGB 与 YCrCb 之间的逆变换关系可写成如下的形式:



总体来说,上面讲的这些内容,主要就是对原始图片,可以先进行色彩空间的处理,使采集到的图像数据有所减少。

请注意,实际上,JPEG 算法与色彩空间无关,色彩空间是涉及到图像采样的问题,它和数据的压缩并没有直接的关系。

因此“RGB 到 YUV 变换”和“YUV 到 RGB 变换”不包含在 JPEG 算法中。JPEG 算法处理的彩色图像是单独的彩色分量图像,因此它可以压缩来自不同色彩空间的数据,如 RGB,YcbCr 和 CMYK。

2、色彩深度 color depth

在图像中,它是由很多个点来组成的,那么存储每个像素点所用的位数就叫做像素深度。对一个图片,这个值是可以有所不同的,从而会使得图片的数据有多和少的区别。

一幅彩色图像的每个像素用 R,G,B 三个分量表示,若每个分量用8位,那么一个像素共用3X8=24位表示,就说像素的深度为24 bit,每个像素可以是2的24次方=16 777 216种颜色中的一种。表示一个像素的位数越多,它能表达的颜色数目就越多。

在用二进制数表示彩色图像的像素时,除 R,G,B 分量用固定位数表示外,往往还增加1位或几位作为属性(Attribute)位。例如,RGB 5∶5∶5表示一个像素时,用2个字节共16位表示,其中 R,G,B 各占5位,剩下一位作为属性位。在这种情况下,像素深度为16位,而图像深度为15 位。

在用32位表示一个像素时,若 R,G,B 分别用8位表示,剩下的8位常称为 alpha 通道(alpha channel)位,或称为覆盖(overlay)位、中断位、属性位。它的用法可用一个预乘 α 通道(premultiplied alpha)的例子说明。假如一个像素(A,R,G,B)的四个分量都用归一化的数值表示,(A,R,G,B)为(1,1,0,0)时显示红色。当像素为 (0.5,1,0,0)时,预乘的结果就变成(0.5,0.5,0,0),这表示原来该像素显示的红色的强度为1,而现在显示的红色的强度降了一半。

这个 alpha 值,在这里就用来表示该像素如何产生特技效果。

总体来说,图像的宽高、分辨率越高,就是组成一幅图的像素越多,则图像文件越大;像素深度越深,就是表达单个像素的颜色和亮度的位数越多,图像文件就越大。

只有黑白两种颜色的图像称为单色图像(monochrome),每个像素的像素值用1位存储,它的值只有“0”或者“1”,一幅640×480的单色图像需要占据37.5 KB的存储空间。

而灰度图像,即有色深的黑白图像,如果每个像素的像素值用一个字节表示,而不是仅仅只有一位,那么灰度值级数就等于256级,每个像素可以是0~255之间的任何一个值,一幅640×480的灰度图像就需要占用300 KB的存储空间,类似上面说到过的 Y 分量。

3、离散余弦变换 DCT

将图像从色彩域转换到频率域,常用的变换方法有:



DCT变换的公式为:



f(i,j) 经 DCT 变换之后,F(0,0) 是直流系数,其他为交流系数。

还是举例来说明一下。

8x8的原始图像:



推移128后,使其范围变为 -128~127:



使用离散余弦变换,并四舍五入取最接近的整数:



上图就是将取样块由时间域转换为频率域的 DCT 系数块。

DCT 将原始图像信息块转换成代表不同频率分量的系数集,这有两个优点:其一,信号常将其能量的大部分集中于频率域的一个小范围内,这样一来,描述不重要的分量只需要很少的比特数;其二,频率域分解映射了人类视觉系统的处理过程,并允许后继的量化过程满足其灵敏度的要求。

当u,v = 0 时,离散余弦正变换(DCT)后的系数若为F(0,0)=1,则离散余弦反变换(IDCT)后的重现函数 f(x,y)=1/8,是个常 数值,所以将 F(0,0) 称为直流(DC)系数;当 u,v≠0 时,正变换后的系数为 F(u,v)=0,则反变换后的重现函数 f(x,y) 不是常数,此时 正变换后的系数 F(u,v) 为交流(AC)系数。

DCT 后的64个 DCT 频率系数与 DCT 前的64个像素块相对应,DCT 过程的前后都是64个点,说明这个过程只是一个没有压缩作用的无损变换过程。

单独一个图像的全部 DCT 系数块的频谱几乎都集中在最左上角的系数块中。

DCT 输出的频率系数矩阵最左上角的直流 (DC)系数幅度最大,图中为-415;以 DC 系数为出发点向下、向右的其它 DCT 系数,离 DC 分量越远,频率越高,幅度值越小,图中最右下角为2,即图像信息的大部分集中于直流系数及其附近的低频频谱上,离 DC 系数越来越远的高频频谱几乎不含图像信息,甚至于只含杂波。

DCT 本身虽然没有压缩作用,却为以后压缩时的"取"、"舍" 奠定了必不可少的基础。

4、量化

量化过程实际上就是对 DCT 系数的一个优化过程。它是利用了人眼对高频部分不敏感的特性来实现数据的大幅简化。

量化过程实际上是简单地把频率领域上每个成份,除以一个对于该成份的常数,且接着四舍五入取最接近的整数。

这是整个过程中的主要有损运算。

以这个结果来说,经常会把很多高频率的成份四舍五入而接近0,且剩下很多会变成小的正或负数。

整个量化的目的是减小非“0”系数的幅度以及增加“0”值系数的数目。

量化是图像质量下降的最主要原因。

因为人眼对亮度信号比对色差信号更敏感,因此使用了两种量化表:亮度量化值和色差量化值。



使用这个量化矩阵与前面所得到的 DCT 系数矩阵:



如,使用−415(DC系数)且四舍五入得到最接近的整数



总体上来说,DCT 变换实际是空间域的低通滤波器。对 Y 分量采用细量化,对 UV 采用粗量化。

量化表是控制 JPEG 压缩比的关键,这个步骤除掉了一些高频量;另一个重要原因是所有图片的点与点之间会有一个色彩过渡的过程,大量的图像信息被包含在低频率中,经过量化处理后,在高频率段,将出现大量连续的零。

5、“Z”字形编排

量化后的数据,有一个很大的特点,就是直流分量相对于交流分量来说要大,而且交流分量中含有大量的0。这样,对这个量化后的数据如何来进行简化,从而再更大程度地进行压缩呢。

这就出现了“Z”字形编排,如图:



对于前面量化的系数所作的 “Z”字形编排结果就是:

底部 −26,−3,0,−3,−3,−6,2,−4,1 −4,1,1,5,1,2,−1,1,−1,2,0,0,0,0,0,−1,−1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 顶部

这样做的特点就是会连续出现多个0,这样很有利于使用简单而直观的行程编码(RLE:Run Length Coding)对它们进行编码。

8×8图像块经过 DCT 变换之后得到的 DC 直流系数有两个特点,一是系数的数值比较大,二是相邻8×8图像块的 DC 系数值变化不大。根据这个特点,JPEG 算法使用了差分脉冲调制编码(DPCM)技术,对相邻图像块之间量化 DC 系数的差值(Delta)进行编码。即充分利用相邻两图像块的特性,来再次简化数据。

即上面的 DC 分量-26,需要单独处理。

而对于其他63个元素采用zig-zag(“Z”字形)行程编码,以增加行程中连续0的个数。

6、行程编码

Run Length Coding,行程编码又称“运行长度编码”或“游程编码”,它是一种无损压缩编码。

例如:5555557777733322221111111

这个数据的一个特点是相同的内容会重复出现很多次,那么就可以用一种简化的方法来记录这一串数字,如

(5,6)(7,5)(3,3)(2,4)(l,7)

即为它的行程编码。

行程编码的位数会远远少于原始字符串的位数。

对经过“Z”字形编排过的数据,即可以用行程编码来对其进行大幅度的数据压缩。

我们来用一个简单的例子来详细说明一下:

57,45,0,0,0,0,23,0,-30,-16,0,0,1,0,0,0,0 ,0 ,0 ,0,..,0

可以表示为

(0,57) ; (0,45) ; (4,23) ; (1,-30) ; (0,-16) ; (2,1) ; EOB

即每组数字的头一个表示0的个数,而且为了能更有利于后续的处理,必须是 4 bit,就是说,只能是 0~15,这是的这个行程编码的一个特点。

7、范式 Huffman 编码

在直流 DC 系数经过上面的 DPCM 编码,交流 AC 系数经过 RLE 编码后,得到的数据,还可以再进一补压缩,即使用 Huffman 编码来处理。

范式 Huffman 编码即 Canonical Huffman Code,现在流行的很多压缩方法都使用了范式哈夫曼编码技术,如 GZIB、ZLIB、PNG、JPEG、MPEG 等。

对上面的例子中 RLC 后的结果,对它的存储,JPEG 里并不直接保存这个数值,这样主要是为了提高效率。



对上面的例子内容,就可以得到:

57 为第 6 组的,实际保存值为 111001,编码为 (6,111001)

45编码为 (6,101101)

23为(5,10111)

-30为(5,00001)

这个时候前面的例子就变为:

(0,6),111001 ; (0,6),101101 ; (4,5),10111; (1,5),00001; (0,4) ,0111 ; (2,1),1 ; (0,0)

这样,括号里的数值正好再合成一个字节,高4位是前面0的个数,低4位描述了后面数字的位数;后面被编码的数字表示范围是 -32767..32767。

使用上面这个表简化后的内容,再到 Huffman 编码表里去查询,从而得到最后的编码。

如06对应 Huffman 表的111000,那么

69 = (4,5) --- 1111111110011001 (69=0x45=4*16+5 )

21 = (1,5) --- 11111110110

从而得到最后的结果:

111000 111001 ; 111000 101101 ; 1111111110011001 10111 ; 11111110110 00001…

使用范式 Huffman 编码表的好处就是使得出现频率高的数字小于8位,而出现频率低的数字大于8位,这样对整体而言,就会极大地减少数据量。

需要注意的是,在 JPG 文件中,一般有两个 Huffman 表,一个是 DC 用,一个是 AC 用,它们是类似的。

对 DC 编码的部分是单独来处理的,并且是放在上面这个串的最前面。

总体来说,到目前为止,我们就得到了最后需要真正存储用的简化后,也即压缩后的数据了。

四、JPEG文件存储格式

介绍了 JPEG 的原理,我们再来结合一个具体的实例来详细讨论上面所涉及到的细节。

我们先来制作一个简单的8X8大小的像素图,然后把它存成JPEG格式。

方法是用 windows 的画图工具,定义一个8X8大小的图,用一些色块填充进去,然后另存为 JPEG 格式,如 test8x8.jpg。如下图所示:



保存成的文件后缀为 jpg,但按标准来说,它是一种 JFIF 格式标准的文件,里面的图像的压缩方式是 JPEG。

JFIF 是一个文件格式标准,JPEG 是一个压缩标准,总体来说它们不是一个概念。

JFIF 是 JPEG File Interchange Format 的缩写,也即 JPEG 文件交换格式。JFIF 是一个图片文件格式标准,它是一种使用 JPEG 图像压缩技术存储摄影图像的方法。JFIF 代表了一种"通用语言"文件格式,它是专门为方便用户在不同的计算机和应用程序间传输 JPEG 图像而设计的语言。

JFIF 文件格式定义了一些内容是 JPEG 压缩标准未定义的,如 resolution/aspect ratio,color space 等。



我们可以打开 JPEG 文件查看里面的内容,即可看到上面的各个标记段:



从图上可以看出:

在头部有 FFD8 ,表示图像的开始;结束部分有 FFD9 ,表示图像的结束。

在中间有两个量化表 DQT 对应的标记 FFDB ;

还有图像大小信息对应的 FFC0

再后面有四个 Haffman 表对应的 FFC4 ;

一般一个 JPG 文件里会有 2 类 Haffman 表:一个用于 DC 一个用于 AC ,也即实际有 4个表,亮度的 DC,AC 两个,色度的 DC,AC 两个。

然后是图像数据段标记 FFDA;

我们再来看看各个标记的细部,具体分析一下各个部分的含义。

1、图片的识别信息



上面的内容,在标记 FFE0 后,即为长度16。然后是5字节的 JFIF 标识符号,说明这是一个 JPEG 压缩的文件。然后是主/次版本号码。下一个为 XY 像素的单位,这里为1,表示单位为点数/英寸。然后是 XY 方向的像素密度,这里是 96DPI,最后是缩略图有关信息,这里为0。

2、量化表的实例



上面这个内容,FFDB 标记后的长度值为67,接下来的是 QT 信息,占一个字节;这里是0,表示这个 QT 表编号为0,并且精度是8bit。然后后面就是64个8x8的 QT 表的各个 item 了。

也即第一个 DQT 量化表的内容表示为十进制是:



这个表即为 JPEG 亮度量化表。

第二个量化表的内容为:



这个表的内容即为 JPEG 色度量化表。

当你打开不同的 JPEG 文件,你会看到这两个表可能也是会有区别的。这个主要是使用了不同的量化方式的结果。

3、图像信息段



上面这个内容,FFC0 标记后即是长度,为17,然后是一个字节的数据精度,通常是为8,代表样本位数。接下来是图片的高度,占两字节,这里即为8,然后是图片的宽度,也为8,这也就是我们定义的8x8的内容。然后是 component 的个数,这里是3,表示 YUV。接下来是三组数据,每组数据里,第一个是 component ID,第二个是采样系数,这里 Y 的采样系数为22,说明垂直是2,水平是2。再后面就是量化表的编号了。

4、Haffman 表的实例



上面这个内容,FFC4 标记后的内容为数据长度,再接着的1字节为 Huffman Table 的信息,低4位是 HT ID 号,第5位是 HT 表类型标记,再高三位是为0。

第一个 DHT 表,00,类型为 DC table,HT ID 号为 0;

第二个 DHT 表,10,类型为 AC table,HT ID 号也为 0;

第三个 DHT 表,01,类型为 DC table,HT ID 号为 1;

第四个 DHT 表,11,类型为 AC table,HT ID 号为 1;

即前两个表为Y亮度分量的 DC/AC 表,后两个为 UV 色度分量的 DC/AC 表。

以第一个表为例,因为长度只有 31,那么 00 后面的 16 字节,即绿色部分:



组号为 1 的组中,代码有 0 个;

组号为 2 的,代码有 1 个;

组号为 3 的代码有 5 个;

组号为 4/5/6/7/8/9 的代码各 1 个。

总共 12 个。

再看后续的数据:

00 01 02 03 04 05 06 07 08 09 0A 0B

即对应:



其他未出现的组号,对应的数据未使用到。也就是说前面提到过的范式 Huffman 编码里,目前只使用部分数据即可,原因是这个 8x8 的图像数据很小。

第二个 DHT 表就更复杂些了,长度有 181。

5、图像数据段



这里 SOS 段,长度为 12,后面所含有的 component 数量为 3 个,也即 Y UV。然后后面是各 component 的编号,及对应所使用的 Huffman 表的 ID 是多少。

在这个段的后面就是所有压缩后的数据。直到结束的问题,即 FFD9,EOI(End Of Image)。

五、JPEG 压缩过程的优化

JPEG 在目前的应用范围是非常广泛的,各种嵌入式系统中也大量地使用了 JPEG 压缩,如 IPCAM 摄像头、数字相机、移动存贮等。在这些领域由于传输数据的带宽限制或者是存贮数据的容量的限制,常常需要使用图像压缩技术来将原始大量的图像数据压缩后在进行传输或存贮,以充分利用带宽与存贮空间,达到更好的利用效率。这样,在嵌入系统中,就会使用到 JPEG 压缩。而且由于嵌入系统的资源有限的特点,在很多情况下,很需要再对 JPEG 编码压缩的过程做更进一步的优化,我们这里详细讨论一下如何实现这些优化。

浮点运算的优化

我们回头查看一下 JPEG 压缩中的 DCT 变换过程,公式:



由于公式中有两个 i/j=0~7 的部分,这样要获得一个 DCT 系数,需要做 8 x 8=64 次乘法和 8 x 8=64 次加法, 而完成整个 8 x 8 像素的 DCT 需要 8 x 8 x 8 x 8=4096 次乘法和 8 x 8 x 8 x 8=4096 次加法. 计算量是相当的大。

对于有些无浮点运算的嵌入式系统或无专门的数学运算协处理器的系统,会造成大量的运算,极大地占用CPU的资源。

上面的公式属于 DCT 的二维计算方式,经过简化,可以将其简化为两个一维的公式:



这样,上面的过程就可以简化为分别计算行和列的 DCT 变换。

对于一行来说需要计算的是 (8 x 8) 次乘法和 (8 x 8) 次加法,8 行就是 8 x (8 x 8) 次乘法和 8 x (8 x 8) 次加法,然后列也是相同,那么总数就为 2 x (8 x (8 x 8))=1024 次乘法和 2 x (8 x (8 x 8))=1024 次加法, 运算量变为二维计算的1/4。

但是这样的运算数量还是太大,还需要进一步优化。

在很多嵌入系统中,很多情况下需要不使用浮点运算,这样就需要再找出一维 DCT 的一些规律,然后对其进行进一步的优化。

在对一维 DCT 的运算中,还可以分为奇数列/行和偶数列/行



对上面的处理,就又出现了多种优化:ChenDCT,LeeDCT,AAN 算法和 LLM 算法。

其中 AAN 算法只需要 29 次加法和 5 次乘法。(注意,它是指每次一维运算要 29 次加法和 5 次乘法,一共是需要 29*8*2 次加法和 5*8*2 次乘法的)。



其中 Y[0]-Y[7] 都是 1*8 的矩阵,X[1]-X[7] 也都是 1*8 的矩阵。

{a, b, c, d, e, f, g} = 1/2 { cos(pi/4), cos(pi/16), cos(pi/8), cos(3pi/16), cos(5pi/16), cos(3pi/8), cos(7pi/16) }

再对上面的含有 pi 的系数进行整数优化,从而避免浮点运算,就会得到:



其中:

3/8=1/4+1/8

5/8=1/2+1/8

7/8=1-1/8

上面的除以 2,除以 8,都可以通过移位来实现,即右移一位和右移三位。即总数为 30 次加法,12 次移位即可。

这样就在很大程度上将原本需要使用乘法,浮点运算的过程全部转换成了简单的加法和移位处理了,这样使用数学的方法,用近似的值来完成整个转换过程,会有很好的性能和处理效果。

在处理上面的数据中,可以使用一些中间变量来记录中间结果,这样就可以减少反复计算中间值,而直接使用已经计算得到了的中间值。

tmp0 = x[0] + x[7];

tmp7 = x[0] - x[7];

tmp1 = x[1] + x[6];

tmp6 = x[1] - x[6];

tmp2 = x[2] + x[5];

tmp5 = x[2] - x[5];

tmp3 = x[3] + x[4];

tmp4 = x[3] - x[4];

tmp10 = tmp0 + tmp3;

tmp13 = tmp0 - tmp3;

tmp11 = tmp1 + tmp2;

tmp12 = tmp1 - tmp2;

/* 对偶数项进行运算 X 0,4,6,2 */

X[0]=tmp1+tmp11;

X[4]=tmp10 /2 - tmp11

X[6]=tmp12-(tmp13/4+ tmp13/8);

X[2]=tmp12/4+tmp12/8-tmp13;

其他的各个值也是类似处理的。

六、JPEG 在本嵌入式 Linux 应用中遇到的问题

在本系统中,提供给用户一些播放图片和预览图片的功能,在这个过程中就需要使用到对 JPEG 的处理。

1、JPEG 出错的处理

在对图片做预览处理的时候,有些图片原始尺寸很大,那么就需要将其转换成较小的缩略图,在转换为缩略图进行显示时,遇到了一个问题,即有时需要显示的图片,会导致系统无响应。

后来查找原因,定位到 JPEG 文件的数据不完整,才导致 jpeg decoder 出现无响应。

在前面的部分,有说到 JPEG 文件的格式中,JPEG 结束的标记 EOI (End Of Image) 为“FFD9”。

如果需要显示的图片,在传输过程中,或转换过程中,出现了没有 EOI 数据,那么应该在程序中,将其废弃,避免出现系统无响应。

2、JPEG 解码的效率优化

在解码 JPEG 时,可以使用 software decode 或 hardware decode 来处理。Hardware decode 的优点是充分利用 DSP 所提供的硬件解码功能,其解码速度会较 software decode 有数量级的提高。但有时使用 hardware decode 有一些限制,如各种 DSP 提供的 SDK 会是直接访问硬件,将 jpeg 直接输出到显示设备,从而会导致 hardware decode 与应用系统集成的麻烦。

而使用 software decode,就能在应用层完全掌握 jpeg decode 的数据缓冲结果,并可做一些图片的叠加效果或对其进行半透明混合处理,从而会有较高的灵活性。并且使用 decode buffer cache,来将已经解码的数据进行保存,在 UI 后续的使用中,就可不必反复去解码 JPEG 图片,从而也能有效提高绘图效率。





回页首


七、总结

上面的内容是本人对 JPEG 原理做的一个详细的实例分析,还介绍了 JPEG 编码过程中对浮点运算的优化处理,它特别适用于在资源有限的嵌入系统中避免大量的浮点运算。

在对 JPEG 原理做了一个详细的分析后,大家会对 JPEG 涉及到的各个细节有了一个更加明确的认识。当你自己动手结合 JPEG 编码过程来分析时,将会有一个清楚的全局观。

本文结合应用实例,对在嵌入式 Linux 应用中遇到的 JPEG 有关的问题,做了一个说明,大家在自己的设计过程中也可以作为参考。

现在,你如果再回头去看 JPEG 的原理,你现在应该能看懂它整个过程的来龙去脉了.























































2009年8月22日星期六

远 见

一九八五年,英国的牛津学院发生了一件「学校大事」。
校方们在工程检查后发现,有三百五十年历史的学校大会堂的安全性已经出了问题。二十根由巨大橡木制成的横梁,已经风干朽化,失去了支撑的力道,必然得抽换才行。
校方也请人估算了将梁木更新的价格,由于那么巨大的橡木已经很稀少了,预估每根横梁要花二十五万美元,才能完成修缮工程,但也没把握能找到那么大的橡树。
巨款一算出来,校方焦头烂额,若不募款,恐怕没有办法进行整修。这时,却有个天降 的好消息化解了危机,园艺所负责人前来报告:在三百五十年前,设计该大会堂的建筑师,已经想到后代会面临的困境,所以早早请园艺人员在学校所拥有的土地上 种植了一片橡树林,现在,每一棵橡树的尺寸,早就超过了横梁所需。
不知名的建筑师墓园已荒芜,但在三百五十年后,他的用心让人肃然起敬。这才是真正的远见。

助你成功的10个万能谈话技巧

要是你以为单靠熟练的技能和辛勤的工作就能在职场上出人头地,那你就有点无知了.当然,才干加上超时加班固然很重要,但懂得在关键时刻说适当的话,那也是成功与否的决定性因素.卓越的说话技巧,譬如讨好重要人物、避免麻烦事落到自己身上、处理棘手的事务等等,不仅能让你的工作生涯加倍轻松,更能让你名利双收.牢记以下十个句型,并在适当时刻派上用场,加薪与升职必然离你不远.
  
  1.以最婉约的方式传递坏消息句型:我们似乎碰到一些状况…
  你刚刚才得知,一件非常重要的案子出了问题,如果立刻冲到上司的办公室里报告这个坏消息,就算不干你的事,也只会让上司质疑你处理危机的能力,弄不好还惹来一顿骂,把气出在你头上.此时,你应该以不带情绪起伏的声调,从容不迫的说出本句型,千万别慌慌张张,也别使用"问题"或"麻烦"这一类的字眼;要让上司觉得事情并非无法解决,而"我们"听起来像是你将与上司站在同一阵线,并肩作战.
  
  2.上司传唤时责无旁贷句型:我马上处理.  
  冷静、迅速的做出这样的回答,会令上司直觉的认为你是名有效率、听话的好部属;相反,犹豫不决的态度只会惹得责任本就繁重的上司不快.夜里睡不好的时候,还可能迁怒到你头上呢!
  
  3.表现出团队精神句型:安琪的主意真不错! 
  安琪想出了一条连上司都赞赏的绝妙好计,你恨不得你的脑筋动得比人家快;与其拉长脸孔、暗自不爽,不如偷沾他的光.方法如下:趁着上司听得到的时刻说出本句型.在这个人人都想争着出头的社会里,一个不妒嫉同事的部属,会让上司觉得此人本性纯良、富有团队精神,因而另眼看待.
  
  4.说服同事帮忙句型:这个报告没有你不行啦! 
  有件棘手的工作,你无法独力完成,非得找个人帮忙不可;于是你找上了那个对这方面工作最拿手的同事.怎么开口才能让人家心甘情愿的助你一臂之力呢?送高帽、灌迷汤,并保证他日必定回报;而那位好心人为了不负自己在这方面的名声,通常会答应你的请求.不过,将来有功劳的时候别忘了记上人家一笔.
  
  5.巧妙闪避你不知道的事句型:让我再认真的想一想,三点以前给您答复好吗? 
  上司问了你某个与业务有关的问题,而你不知该如何做答,千万不可以说"不知道".本句型不仅暂时为你解危.也让上司认为你在这件事情上头很用心,一时之间竟不知该如何启齿.不过,事后可得做足功课,按时交出你的答复.
  
  6.智退性骚扰句型:这种话好像不大适合在办公室讲喔!
  如果有男同事的黄腔令你无法忍受,这句话保证让他们闭嘴.男人有时候确实喜欢开黄腔,但你很难判断他们是无心还是有意,这句话可以令无心的人明白,适可而止.如果他还没有闭嘴的意思,即构成了性骚扰,你可以向有关人士举发.
  
  7.不着痕迹的减轻工作量句型:我了解这件事很重要;我们能不能先查一查手头上的工作,把最重要的排出个优先顺序?
  不如当下就推辞.首先,强调你明白这件任务的重要性,然后请求上司的指示,为新任务与原有工作排出优先顺序不着痕迹的让上司知道你的工作量其实很重,若非你不可的话,有些事就得延后处理或转交他人.
  
  8.恰如其分的讨好句型:我很想您对某件案子的看法……  
  许多时候,你与高层要人共处一室,而你不得不说点话以避免冷清尴尬的局面.不过,这也是一个让你能够赢得高层青睐的绝佳时机.但说些什么好呢?每天的例行公事,绝不适合在这个时候被搬出来讲,谈天气嘛,又根本不会让高层对你留下印象.此时,最恰当的莫过于一个跟公司前景有关,而又发人深省的话题.问一个大老板关心又熟知的问题,但他滔滔不绝的诉说心得的时候,你不仅获益良多,也会让他对你的求知上进之心刮目相看.
  
  9.承认疏失但不引起上司不满句型:是我一时失察,不过幸好…… 
  犯错在所难免,但是你陈述过失的方式,却能影响上司心目中对你的看法.勇于承认自己的疏失非常重要,因为推卸责任只会让你看起来就像个讨人厌、软弱无能、不堪重用的人,不过这不表示你就得因此对每个人道歉,诀窍在于别让所有的矛头都指到自己身上,坦承却淡化你的过失,转移众人的焦点.
  
  10.面对批评要表现冷静句型:谢谢你告诉我,我会仔细考虑你的建议. 
  自己苦心的成果却遭人修正或批评时,的确是一件令人苦恼的事.不需要将不满的情绪写在脸上,但是却应该让批评你工作成果的人知道,你已接收到他传递的信息.不卑不亢的表现令你看起来更有自信、更值得人敬重,让人知道你并非一个刚愎自用、或是经不起挫折的人.

会讲话,可以少奋斗30年!

第一:不要认为停留在心灵的舒适区域内是可以原谅的。
每个人都有一个舒适区域,在这个区域内是很自我的,不愿意被打扰,不愿意被push,不愿意和陌生的面孔交谈,不愿意被人指责,不愿意按照规定的时限做事,不愿意主动的去关心别人,不愿意去思考别人还有什么没有想到。这在学生时代是很容易被理解的,有时候这样的同学还跟"冷酷""个性"这些字眼沾边,算作是褒义。然而相反,在工作之后,你要极力改变这一现状。否则,你会很快变成鸡尾酒会上唯一没有人理睬的对象,或是很快因为压力而内分泌失调。但是,如果你能很快打破之前学生期所处的舒适区域,比别人更快的处理好业务、人际、舆论之间的关系,那就能很快的脱颖而出。
在会议上,一个停留在心灵舒适区域的人会消极的听取领导的话语,消极的待命,很死的完成上级交给的事情,但从来不关心此事以外的任何事情,更不会想到多做一步,让接下来的别人的工作更加容易上手。而敢于打破这个舒适区域的人,敢于在适当的时候提出自己的看法和不理解,并在得到上级认可和指点之后把手头的工作尽快的完成,并随时接受别人的批评和调整。(注意:永远不要等待别人把你的想法说出来,这是典型的前者)


在工作上,当前者遇到一名新的同事,他会装作没有看见,继续自己的工作。殊不知新来的同事不久就变成了自己的上司。而后者则大方客气的自我介绍,并了解对方和自己的关系。
在聚会上,前者总是等待别人发言,并喜欢私下里评论对方的言语;如果这个桌子上没有人发言,那直到用餐结束,也没有人认识你。而后者是勇敢的和一同吃饭的开始介绍和闲谈,这看起来很困难,有时候会有失面子,但往往你会发现,对方是多么希望能和你说几句话。
以上只是很小的几个例子,但是要说明的是,大学生在走出校园的同时就要在工作上把校园中的"随意性"从身边赶走,尽早的冲出自己的舒适区域,开始做好和这个社会交流的准备。
开始工作之后的十个不要—-(二)
第二:不要把"好像";"有人会……";"大概";"晚些时候";"或者";"说不定"之类放在嘴边。尤其是和上级谈论工作的时候。
我十分痛恨听到的一句话是:"我晚些时候会把这个文件发给所有的人";因为这往往预示着我必须时刻提醒他不要忘记。同样,以下这些言辞也会让人觉得厌恶至极:
"到时候有人会把那些东西都准备好"
"大概是明天"
"明天或者后天客户会过来拜访"
"好像他说……"
一般是人都会这样说话的,因为这样第一给自己留下了广阔的余地,第二也不会给别人造成很大的压迫感,好像什么事情一定要弄个水落石出似的。说实话大学里面再用功的人都有一半是混的。一个人要么是在课堂上是混的,要么下课之后是混的。两个都没有带有混的色彩的人,要么是超级牛人,要么是神经病。所以,就因为人人都在混的,所以校园是一个浪漫的地方,校园也容易让人单纯。所以学生社团的工作往往是效率很低的,我现在回想起学校里做的工作,当时还觉得挺卖力的,但工作了之后才开始感觉到什么是效率。当你进入了用金钱计算时间的地方之后,你要尽可能的避免在学校里养成的这种习惯。如果上级问你什么时候能实施你给他的承诺,而你回答"今晚或者明天早上"这样的答案对于他来说完全等同于你没有回答,并且还给他留下了一个坏印象。(当然,这样的回答往往在学校社团,学生会工作中是常见的)
有一个寓言故事,一只小老鼠刚刚出世不久,老鼠妈妈问小老鼠:你现在能看见了吗? 小老鼠说:能。老鼠妈妈说:那你能看到那块红薯吗?小老鼠说:是的。老鼠妈妈说:那是一块石头,这说明你不但还看不见东西,你连嗅觉都还没有。
似是而非的应答往往一样会暴露出你更多的弱点。可能是以下中的一个或几个:
1.你之前没有想到这个工作,或者一直在拖延。
2.你没有责任心,认为这些并不重要。
3.你应付上级。
4.你不敢说真话。
5.你喜欢逞能,答应一些做不到的事情。
6.你不能独立工作。
当你的上级在以上选项中怀疑的时候,潜意识中你已经同时具备了以上所有的弱点了。
相反的看来,这样的回答,总是让上司恼火。
第一,他的问题没有得到回答,只是起到了提醒你的作用。
第二,他依然需要记住提醒你,因为他不知道你是否真正已经落实了工作。
第三,他不知道有多少你已经做了的事情中,都是这样没有落实的。(这点非常致命)
第四,往往因为没有得到满意的答案,上司自己的计划不得不被耽搁或推迟或不能给出明朗的结束时间。
所以———
甲问:你什么时候能把要这个漏洞修好?
乙说:我已经通知他们了,他们大概明天就会来修的。
一天后
甲问:维修公司什么时候回来,你找的是哪家维修公司?
乙说:好像他们说安排不出人来,如果可以的话,今天晚上或者明天下午就能过来。
一天后
甲问:漏洞怎么还没有修好?
乙说:我晚点再问问他们。
甲说:今天下午之前不解决,明天不用来上班了。
第三:不要拖延工作
很多人喜欢在学习和玩耍之间先选择后者,然后在最后时间一次性赶工把考试要复习的东西突击完成。但是在工作中请不要养成这样的习惯,因为工作是永远做不完的,容不得你"突击"。又或者,当你在徘徊和彷徨如何实施的时候,你的领导已经看不下去,自己去做了。—-这是一个危险的信号。
往往我们总是想把事情从头到尾全部想好了,才开始走第一步—–就摔倒了。
举个例子:我小学的时候第一次给我一个喜欢的女孩子打电话的时候,想象了各种情况——-1,她接电话的时候在做作业。2,她在做作业,她妈妈接的电话。3.她也很无聊,很想找人说话。4.她正在被父母训斥。 5.她正在想另外一个男孩。6.她父亲接电话。 7.她家正好来了什么亲戚,亲戚接了电话。 8.她接了电话,但父母就在身边,说话不方便。。。。。等等等等。我整整想了一个下午,想好了各种情况的心理准备和应对的策略。然后勇敢的拿起电话机,按下了那几个按钮。结果——-她不在家。
所以,当你徘徊不前而手足无措的时候,你要意识到你正在拖延工作。徘徊是因为害怕这个事情可能发生的后果需要自己承担或应付。工作的时候需要一种起码的自信,相信自己有能力,不管下一步是什么状况,我都能把它引导到我需要的那条线上去的。另外,告诉自己,不要想太多时间,如果不知道,就赶快求助,或想办法,苦恼和忧虑会给你更多的压力也会把剩下的时间蚕食殆尽。
另外,警告一下:永远不要想,我知道了,先把上级派的事情放一下,等这集《越狱》看完再说。—-90%的情况下,你会忘记,或者来不及,因为这件事需要比你原先想象要更多的时间。说做就做,一直是很好的习惯。
第四:不要认为理论上可以实施就大功告成了!
这点太重要了,往往当真正实施的人开始做了才会发现计划完全等于鬼话。如果不亲自实践,做计划的人会早晚被实施的鄙视。永远需要提升自己的办实事的能力,而不是空谈。
首先,如果你是做办公室工作的,或者做策划和计划的。请千万不要把你自己都认为不太可能或者很难做到的事情,让别人试试看。比如,用一个下午的时间在人流量很少的地方举办露天歌唱会。这会让执行的人觉得你在玩他,拿他做实验。没错,理论上,在任何地方都能举办歌唱会,但是,在不同的地方,执行的人的心情是不一样的。
其次,和执行的人讨论你的安排。比如,新来的你的下属,你可以安排她坐在任何地方,但是如果那是一个很难和大家接触的角落,这可能比你什么都不安排更差。的确,理论上一个人要坐下来,需要的只是空间。但事实上远远不止那些。
再次,不要奢望一切会随着你的计划进行。理论上这个会议会持续两个小时,但是,这是"不考虑在开场后的30分钟全场都在调试话筒",或者"场下没有提出如此尖锐的问题"的前提下的状态。大学生已经习惯了把事情做到 "理论上看上去很美"的程度了。 论文,ppt讲演,考试,辩论赛…… 这些校园智商大比拼,都是教我们如何完美的做好"纸上谈兵"的功夫。 你一定要相信自己能"搞定"事情的能力比想象的弱。
如果你是在学校的学生,测试一下自己,能否能搞定以下这些状况:
1.学校要制作一套校服,由你去寻找供应商,砍价,至少有三家公司的报价。
2.学校保安抓住一个学生偷窃,怎么处理?
3.学校的一个很重要路段的路灯坏了,你能否让它三天内继续亮起来。
4.食堂需要请一位专门烧清真菜的厨师,一周内到岗位。
当你开始思考以上这样的问题的时候,你会发现,他的思路和"看过去两年这个公司的业绩趋向,做出一个下个季度的市场策划方案"要相差极大。你会发现后者只要你做到"看上去很完美",没有人知道按照你这样做结果会怎样。而上述的工作你只要一想,就会体会到不少的压力。因为你不处理好,结果就是明显的失败更大的问题就会相继发生。
对了,这种感觉就是"工作"给你的感觉!这就是"工作"和"纸上谈兵"的差别!
第五:不要让别人等你
在任何情况下都不要让别人放下手头的工作来等你。在大学中可能只是同寝室的人的几句半开玩笑的抱怨,在工作上很可能导致你的潜在合作伙伴的丢失。
你在做一个工作的同时要知道别人的进度,而永远不要落后。
这不像是在考试,你比别人做的慢,别人可以先交卷,你到时间了做不完你自己承受扣分。在工作中的情况是这样的:这是一场没有人能做完的考试,所有的人,都分配做一张试卷的不同部分,有的人分到的是阅读理解,有的人做的是完形填空,有的人做的是语法…… 然后大家做完了相互抄,这样,所有人都做完了。如果大家都把各自的部分做完了,而你却还在没有做完,那么做得快的别人会开始做你的那部分题目,然后也是相互抄。慢慢地,大家会发现你的工作量完全可以由另外人来代替,整个团队中可以不需要你,这个时候,没有人从你这里得到试卷的答案,也没有人会给你他们的答案——–很不幸,你已经没有利用价值了。
请一定记住这个例子。
第六:不要认为细节不重要
在大学里,往往做事粗枝大叶,看看差不多就行了。相反,在企业里管理的精髓就在于将简单的事情做到细节。一个慌忙寻找保险箱钥匙的动作就很有可能丧失你晋升财务主管的机会。
公司的管理,其实需要的并不是把很难的事情做到90%—-比如,优化管理层的核心工作流程、改变公司在当地政府面前的形象,提高产品质量,改善工作环境…… 而管理要做的是把每个简单的事情做到100%—–比如,把公司的每个人的档案都按照一定的规律整齐的存放起来、在门卫设立一个外来人员的签到台、把会议室多余的椅子拿走、和电视台讲好下个礼拜三来公司做采访、把试用装送到客户手里、在生产的咖啡上加一个口子、给下一期的封面人物拍照……等等如此。如果你能把所有细节的问题都如实做到,那你才有开口升职的本钱。
很多人在毕业的时候不知道自己将来要做什么,于是就和自己说:我以后做管理吧!做管理?问一下自己,如果,公司资产被偷窃了,所有员工士气低下,办公室杂乱无章,公司电梯又坏了,打印机没墨了,采购计划超支了,产品滞销了,客户迟到了……你愿意解决这样的问题,并从小事开始做起吗?想好了这些再考虑是否把管理看得太空洞了。
第七:不要表现得消极,仅仅因为你所做的事情不是你的兴趣所在。
很显然,在学生时代,当做到自己喜欢的时候,我们会pay200%的精力去创造,但如果是枯燥的事务,我们便懒得理睬,最好能有办法应付过去。但在工作上 80%你所做的事情都是繁琐而看似机械的,如果仅仅为此而表现的闷闷不乐,那么你会郁闷更久。要知道你的上司已经为这个项目够烦恼了,你还想让他看到你的表情吗?
学会喜欢自己的工作,并把注意力放在日常工作能学到些什么上去。如果现在你努力的抱怨工作,那么接下来你就是努力的寻找工作。尽量少用"有趣","好奇"之类的词语来描述自己想要的工作,而是"充实","有成就感","乐意"
之类。
想想以下职位,你会发现生活中很多工作不是在等你有很好的状态下让你做的很有趣的事情:
1.高速公路收费口的收费员:一天都是面对一个小窗口,把一张卡片送出去,这样要持续好几年。
2.学校食堂厨师:永远在烧大排和鸡腿。烧一年。
3.作家:交稿期要到了,我还在孕育灵感,两个星期没吃早饭了。
4.外科医生:刚刚睡着,马上叫我做一个3小时的手术。这样至少一周一次。
5.门市部销售:产品不好卖,8点上班来就坐在店门口,一个人,坐到晚上6点,今天没有一个人来,和昨天一样。
6.公交司机:我开车不用你指挥。这条线路我开了三年了。
7.宠物商店店员:生意不好,还要一早就过来听着20条狗的叫声一整天,听一年。
8.公司职员:晚上两点下班,第二天还要8点上班。关键是路上还要一小时。这样已经一个月了。
再想想自己是不是只是接触了这个工作一个月或者才碰到没几个困难,这个时候抱怨的声音最大。
千万不要想着去选择一个有趣的职业,因为没有那样的工作存在。没有哪一"种"行业是开心的,因为如果有,那所有人都去干那个了。最多试着问问自己本身的兴趣吧。self exploration。
第八:绝对不要把改善工作能力仅寄托在公司培训上
人绝对不可能经过一次培训就脱胎换骨。相反,集体培训上学到的东西往往是最用不上的信息。就像食堂烧大锅菜一样,总没有你最想吃的菜,因为这样做容易,并且不容易得罪人。
很多学生很看重所选的公司有没有培训,这说明,你不但不知道这个公司做什么,你甚至不知道怎样学习这些技能。
我的感悟是如果你不知道怎么学你想要的知识,也不知道你想要的知识是什么,你只会做出两种行为:1。等待别人来教你,并且等待别人发现你不知道的地方。2.寻找现成的答案并且拷贝。期待公司培训的人,就很大概率上是第一种人(不排除极少真正优秀的公司培训)
许多的同学有这样的习惯思维:
因为,这个公司的培训能结束达到多少多少的程度
又因为,这个程度正好是我想达到的
所以我尽力进这家公司
因为我进了这家公司
所以它自然会使我达到了这个期望的程度。
我们把参加培训和达到效果很幼稚的画上了等号。其实往往集体培训上所得到的信息是最没有实际操作价值的。永远不要期望单靠听课,靠老师把同样的东西给所有的人,你会得到比别人更多。把更多的心思放在观察和思考自己的需要上,找到问题的所在再通过观察和实践得到的答案才是真正的知识。
所以,刚刚开始工作,什么都不会,不要认为那样是正常的,因为公司还没有培训过呢!等我接受培训了之后,我就全都会了。如果你一无所知还等待别人会可怜你的无知而施舍你知识,那你会为你的无知而付出更多的智商。
第九:不要推卸责任
推卸责任是害怕的条件反射。不要认为别人看不出这点。
我记得我小学里的一件事情。我一次作业没有带来,老师要训斥我,说:你怎么老是作业不带?
我当时说:不是。。。。 当我正要支支吾吾时候,老师说:什么不是?你带来了没有?
我说:没有
老师说:那不就是没有带!什么不是!就是!
之后我就发现,我只是害怕承担责任而条件反射似的就说了"不是",仔细观察一下周围,你会发现,身边有无数的人在用"不是"作为被责问之后的第一反应。
其实现在很多人面对工作也是这样,当上级责问的时候,很条件反射的就做出了推卸动作,然而这样的动作,接下来往往是无力的辩解,以及一些很粗糙的借口。这样会让上司感到你这个人很难沟通,并且很不真实。
另外一种情况,就是无论什么情况下,我指责一个人,他永远是强调客观。其实这点才是学生最典型的特征。这说明他太容易受到其他事物的影响,并受它们决定。如果你和上司之间会出现以下类型的对话,想想是不是需要改一下你的处事方法。
甲:为什么到现在还没有给副总看你的报告!
乙:刚才c在打印,我在等他结束,现在他大概好了吧,我去看看
乙:还有点东西要修改
乙:b也要把东西给副总,我因为等他
乙:a他说我报告不用给副总看(a是乙的同级同事)
乙:不知道副总在不在哦,他的门关着。
乙:d他叫我帮他打印文件!怪他!(d是乙的同级同事)
乙:我的杯子突然找不到了,在找杯子。
不愿意负责任的人的不利在于他会让上司怀疑他的忠诚程度,因为上司给他的命令往往会因为一个小事情而被搁置或者打折执行,转而被他人的意识所改变。
第十:不要对自己说"我是大学生"
这点包涵了很多信息。
1.不要认为自己有多清高
2.不要仍然以学生的标准要求自己
3.不要感觉低人一等
4.不要等待别人的关怀
5.不要把这个作为犯错误自我安慰的借口
6.不要忘记搞清楚,公司究竟给自己的待遇是多少,老练些,这不是在做志愿者。
品格是处理好人际关系的基础,也是确保人际关系质量的关键。除此之外,人际交往的技巧也是尤为重要的。有些人做好事会让人感激一辈子,而有些人帮了别人却可能费力不讨好,不但得不到感激和回报,还让人心存嫉恨。将同样的产品以相同的价格推销给同一个客户,有些业务员可能被粗暴地赶出门,有些业务员却可能签到大单,甚至被客户奉为上宾。
人际交往的技巧是一个非常庞杂的话题,囿于篇幅,在这里只能结合我的切身体会做一些简单的列举,挂一漏万在所难免了。
1. 多给别人鼓励和表扬,尽量避免批评、指责和抱怨,不要逼别人认错。
2. 要学会倾听。不要说得太多,想办法让别人多说。
3. 如果你要加入别人的交谈,先要弄清楚别人究竟在说什么。
4. 交谈之前尽量保持中立、客观。表明自己的倾向之前先要弄清楚对方真实的倾向。
5. 注意对方的社交习惯并适当加以模仿。
6. 不要轻易打断、纠正、补充别人的谈话。
7. 别人有困难时,主动帮助,多多鼓励。
8. 不要因为对方是亲朋好友而不注意礼节。
9. 尽可能谈论别人想要的,教他怎样去得到他想要的。
10. 始终以微笑待人。
11. 做一个有幽默感的人。但是在讲笑话的时候千万不要只顾着自己笑。
12. 做一个脱离低级趣味的人。
13. 跟别人说话的时候尽量看着对方的眼睛,不管你是在说还是在听。
14. 转移话题要尽量不着痕迹。
15. 要学会聆听对方的弦外之音。也要学会通过弦外之音来委婉地表达自己的意思。
16. 拜访别人一定要事先通知。
17. 不要在别人可能忙于工作或者休息的时候打电话过去。除非是非常紧急的事情。
18. 给别人打电话的时候,先问对方是否方便通话。
19. 一件事情让两个人知道就不再是秘密。
20. 你在背后说任何人的坏话都迟早有一天传入这个人的耳朵。
21. 不要说尖酸刻薄的话。
22. 牢记他人的名字。养成偶尔翻看名片簿、电话本的习惯。
23. 尝试着跟你讨厌的人交往。
24. 一定要尊重对方的隐私,不管是朋友还是夫妻。
25. 很多人在一起的时候,当你与其中某个人交谈,请不要无视其他人的存在。
26. 要勇于认错。
27. 以谦卑的姿态面对身边的每一个人。
28. 给予他人同情和谅解。
29. 尽可能用"建议"取代"命令"。
30. 不要轻易做出承诺。承诺的事情就一定要尽可能做到