JPEG
编码之颜色空间变换
BMP
图转换为
JPEG
图,首先要进行颜色空间的转换。即把
RGB
转换为
YUV
或
YIQ
,并进行二次采样。因为亮度分量(
Y
)和色度分量(
U
、
V
或
I
、
Q
)用不同的比率。这是因为人眼对亮度比较敏感而对色度相对较弱。这些是我从书上看来的,但是,它没讲到底怎么二次采样,我只能以自己的理解来。
读取
BMP
图的像素数据(
24
色),用
unsigned char *
来存储。然后,是分块:
Y
用公式直接计算,与每个像素一一对应;而
U
、
V
则采用
4*4
的小块计算出
U
的平均、
V
的平均(我采用的是
4:2:0
)。
BMP
每行都是偶数(
4n
),但是并不是每个都存储满的,所以还是要用长、宽来处理颜色空间的色度转换。如果行
/
列不是偶数,那么就要进行边角料处理了。这是个很麻烦的东西。我想到是先偶数部分,然后对边角料处理:假设长宽都是奇数,那么则最后一列(
2*1
)进行处理(
/2
来求平均),同理对最后一行进行处理。最后,剩下一个像素(右下角的,
BMP
的存储坐标来看)。所以,如果行为奇数,则只要对最后一列进行处理,而列为奇数则对行进行处理,行列都为奇数则行、列处理完之后还有右下角的一个像素点要处理。
那么,
Y
、
U
、
V
是绑定存储还是分开存储呢?我看书上说是绑定存储的,比如
4:2:0
则存储为
4
个
Y
一个
U
和一个
V
,如此反复。
但是,我个人觉得是之后的
JPEG
的处理,是把
Y
和
U
、
V
分开的,可以简化操作。但是没有深入的思考过。这里,大家可以来讨论一下。
附注:
这里,还有写注意点。之前学习了一些处理
BMP
图的方法,用惯了
BYTE*
来存储像素值。在这里进行彩色空间转换的时候,许多都是
0
,后来才想起来,我进行的是
float
计算,用
BYTE
会使得精度损失比较大。另外,我试了一下,从
RGB
—
>YUV
—
>RGB
,发现有些失真(跟原来的颜色不大一样,绿色向黄色偏移)。
还发现一个东西,就是用
fstream
来写文件,写
BYTE*
的时候,如果多个数据中间有
0
,则会写到
0
后就不再写了。比如
BYTE* p={1
,
2
,
3
,
0
,
4
,
5
,
6}
;则写了
1
,
2
,
3
,
0
,就结束了。而
4
,
5
,
6
则没有写。
JPEG
编码之
DCT
变换
在
DCT
变换之前,先要进行分块处理。还是老问题:
8*8
之后像素矩阵的边角料处理。处理跟上面差不多,但是之前都是进行的
8*8
的
DCT
变换,所以要把它扩充为
8*8
的矩阵。那么,用什么数据来进行填充呢?我发现用
0
来填充是对原来的数据没有影响的。因为把
0
代入就是
* f ( i ,j )
就是
*0
;
之后就是
DCT
变换了。代入公式,是最适合计算机做的,问题是有没有更高效的方法。我看到一个,就是转换为一维的
DCT
变换——先行变换,再列变换。我还发现,各个
cos
的值,在行系数(或列系数)确定的时候,就只跟
i
相关(该行所在位置)。即每一行有
8
个
cos
值。那么,
8
行就是
8*8
的矩阵。
1 1 1 1 1 1 1 1
0.98 0.83 0.55 0.19 -0.19 -0.55 -0.83 -0.98
0.92 0.38 -0.38 -0.92 -0.92 -0.38 0.38 0.92
0.83 -0.19 -0.98 -0.5 0.55 0.98 0.19 -0.83
0.70 -0.70 -0.70 0.70 0.70 -0.70 -0.70 0.70
0.55 -0.98 0.19 0.83 -0.83 -0.19 0.98 -0.55
0.38 -0.92 0.92 -0.38 -0.38 0.92 -0.9 0.38
0.19 -0.55 0.83 -0.98 0.98 -0.83 0.55 -0.19
(以上的数据是我省略了一些位,为了清楚)
而各个像素值也是
8*8
的矩阵,所以
DCT
的行变换正好是两个
8*8
的矩阵相乘。
附注:
书上用的是蝶形变换,有些是直接代入傅里叶变换中进行,有些是列了很多的变量解决的,完全看不清楚。后来我查到了一些资料,见图
33
,
34
,
35
;