1. 系统概述
本设计采用NIOS2 32位处理器,通过SPI接口将SD/TF卡中的JPEG图片数据读取到内存中,SD/TF卡的文件系统为FAT32,NIOS2软件实现JPEG解码后,启动framereader和Clocked Video Output模块,最终在VGA显示器上显示JPEG图像,系统框图如下:
2. JPEG格式
JPEG(Joint Photographic Experts Group)是第一个国际图像压缩标准,提供了良好的压缩性能的同时,具有较好的图像质量,被广泛应用电子产品和芯片设计中。
JPEG文件格式有两种保存方式,分别是Baseline JPEG和Progressive JPEG。
Baseline JPEG:这种类型的JPEG文件存储方式是按从上到下的扫描方式,把每一行顺序的保存在JPEG文件中。显示时,数据将按照从上到下一行一行的被显示出来。
Progressive JPEG:包含多次扫描,这些扫描顺寻的存储在JPEG文件中。显示时,会先显示整个图片的模糊轮廓,随着扫描次数的增加,图片变得越来越清晰。
JPEG压缩算法过程如下:
3. Tiny JPEG Decompressor
TJpgDec是一个通用的JPEG图像解码模块,基于C语言开发且可以用于小型嵌入式系统中。
TJpgDec提供了两个API函数接口:
jd_prepare为图像解码准备足够的信息
jd_decomp执行解码任务
还提供了两个I/O函数接口:
Input function: 从输入流中读取JPEG文件数据
Output function: 将图像数据写入输出设备
开源的代码可以在http://elm-chan.org/fsw/tjpgd/00index.html下载。
3. 搭建Qsys
在博文NIOS2随笔——FAT32文件系统的基础上,在Qsys平台上添加framereader和Clocked Video Output组件,设置分辨率为640*480,VGA相关内容可以参考博文FPGA设计——VGA (Altera)。
搭好的Qsys平台如下图:
4. NIOS2软件设计
TTJpgDec是基于Baseline JPEG算法编写,需要以Baseline方式保存一幅JPEG图片到SD卡中,图像分辨率为640*480,文件名为desk.jpg,在电脑中打开如下:
在博文NIOS2随笔——FAT32文件系统的软件基础上,编写软件代码。
移植JPEG软件解码模块,主要是编写Input和Output函数。VGA显示部分,要对framereader组件初始化,然后存放在数组中的图像数据便会不停地被读取到Clocked Video Output模块,最后数据会被送到VGA编码芯片显示。编写好的Input、Output及main函数代码设计如下:
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
|
//============JPEG user function==============
/*------------------------------*/
/* User defined input funciton */
/*------------------------------*/
UINT
in_func (JDEC* jd,
BYTE
* buff,
UINT
nbyte)
{
u32 rb=0;
//number of byte read
f_read(&tf_jpeg,buff,nbyte,&rb);
return
rb;
}
/*------------------------------*/
/* User defined output funciton */
/*------------------------------*/
UINT
out_func (JDEC* jd,
void
* bitmap, JRECT* rect)
{
BYTE
*src, *dst;
UINT
y, bws, bwd;
if
(rect->left == 0) {
printf
(
"\r%lu%%"
, (rect->top << jd->scale) * 100UL / jd->height);
}
src = (
BYTE
*)bitmap;
dst = picture_buffer + 3 * (rect->top * FRAME_WIDTH+ rect->left);
bws = 3 * (rect->right - rect->left + 1);
bwd = 3 * FRAME_WIDTH;
for
(y = rect->top; y <= rect->bottom; y++) {
memcpy
(dst, src, bws);
src += bws; dst += bwd;
}
return
1;
}
FATFS fs;
FIL tf_jpeg;
BYTE
res=0;
int
main (
void
)
{
UINT
*work;
JDEC tjpeg_dev;
UINT
x=0;
UINT
y;
FrameRd_init();
f_mount(&fs,
""
,0);
//Open a JPEG file
res = f_open(&tf_jpeg,
"0:/desk.jpg"
,FA_READ);
work =
malloc
(3800);
//Prepare to decompress
res = jd_prepare(&tjpeg_dev, in_func, work, 3800, &tf_jpeg);
if
(res == JDR_OK) {
//Ready to dcompress. Image info is available here.
printf
(
"Image dimensions: %u by %u. %u bytes used.\n"
, tjpeg_dev.width, tjpeg_dev.height, 3800 - tjpeg_dev.sz_pool);
res = jd_decomp(&tjpeg_dev, out_func, 0);
// Start to decompress with 1/1 scaling
if
(res == JDR_OK) {
//Decompression succeeded. You have the decompressed image in the frame buffer here.
printf
(
"\nOK \n"
);
}
else
{
printf
(
"Failed to decompress: rc=%d\n"
, res);
}
}
else
{
printf
(
"Failed to prepare: rc=%d\n"
, res);
}
f_close(&tf_jpeg);
//Close the JPEG file
for
(y=0;y<FRAME_SIZE*3;y=y+3)
{
picture_buf[x] = picture_buffer[y]*65536+(picture_buffer[y+1])*256+(picture_buffer[y+2]);
x++;
}
printf
(
"image processed done\n"
);
while
(1);
return
0;
}
|
5. 编译运行
编译成功后,以Hardware方式运行,终端打印进度信息,最后显示:image processed done!
6. 最终结果
图片正常显示,和电脑上打开的desk.jpg一致,此图片还是博主4年前用Nokia手机在群租房里面拍的一张照片,满满的回忆啊。
本文转自 shugenyin 51CTO博客,原文链接:http://blog.51cto.com/shugenyin/1890239