基于STM32F407图片显示实验(有代码)

本文档介绍如何使用STM32F407微控制器解码和显示BMP、JPG、JPEG、GIF等图片格式,涉及图像格式介绍、硬件设计、软件设计和下载验证流程,适用于嵌入式开发人员。
摘要由CSDN通过智能技术生成

一、实验目的

在开发产品的时候,很多时候,我们都会用到图片解码,本次实验介绍如何通过 STM32F4 来解码 BMP/JPG/JPEG/GIF 等图片,并在 LCD 上显示出来。

二、图片格式简介

我们常用的图片格式有很多,一般最常用的有三种: JPEG(或 JPG)、 BMP 和 GIF

其中JPEG(或 JPG)和 BMP 是静态图片,而 GIF 则是可以实现动态图片。

首先,我们来看看 BMP 图片格式。 BMP(全称 Bitmap)是 Window 操作系统中的标准图像文件格式,文件后缀名为“.bmp”, 使用非常广。它采用位映射存储格式,除了图像深度可选以外,不采用其他任何压缩,因此, BMP 文件所占用的空间很大,但是没有失真。 BMP 文件的图像深度可选 lbit、 4bit、 8bit、 16bit、 24bit 及 32bit。 BMP 文件存储数据时,图像的扫描方式是按从左到右、从下到上的顺序。
典型的 BMP 图像文件由四部分组成:
1, 位图头文件数据结构,它包含 BMP 图像文件的类型、显示内容等信息;
2, 位图信息数据结构,它包含有 BMP 图像的宽、高、压缩方法,以及定义颜色等信息
3, 调色板,这个部分是可选的,有些位图需要调色板,有些位图,比如真彩色图(24 位
的 BMP)就不需要调色板;
4, 位图数据,这部分的内容根据 BMP 位图使用的位数不同而不同,在 24 位图中直接使
用 RGB,而其他的小于 24 位的使用调色板中颜色索引值。
关于 BMP 的详细介绍,请参考光盘的《BMP 图片文件详解.pdf》。接下来我们看看 JPEG
文件格式。

JPEG 是 Joint Photographic Experts Group(联合图像专家组)的缩写,文件后辍名为“. jpg”或“. jpeg”,是最常用的图像文件格式,由一个软件开发联合会组织制定, 同 BMP 格式不同,JPEG 是一种有损压缩格式,能够将图像压缩在很小的储存空间,图像中重复或不重要的资料会被丢失,因此容易造成图像数据的损伤(BMP 不会,但是 BMP 占用空间大)。

尤其是使用过高的压缩比例,将使最终解压缩后恢复的图像质量明显降低,如果追求高品质图像,不宜采用过高压缩比例。 但是 JPEG 压缩技术十分先进,它用有损压缩方式去除冗余的图像数据,在获得极高的压缩率的同时能展现十分丰富生动的图像,换句话说,就是可以用最少的磁盘空间得到较好的图像品质。而且 JPEG 是一种很灵活的格式,具有调节图像质量的功能,允许用不同的压缩比例对文件进行压缩,支持多种压缩级别,压缩比率通常在 10: 1 到 40: 1 之间,压缩比越大,品质就越低;相反地,压缩比越小,品质就越好。比如可以把 1. 37Mb 的 BMP 位图文件压缩至 20. 3KB。当然也可以在图像质量和文件尺寸之间找到平衡点。 JPEG 格式压缩的主要是高频信息,对色彩的信息保留较好,适合应用于互联网,可减少图像的传输时间,可以支持 24bit 真彩色,也普遍应用于需要连续色调的图像。

JPEG/JPG 的解码过程可以简单的概述为如下几个部分:
1、从文件头读出文件的相关信息。JPEG 文件数据分为文件头和图像数据两大部分,其中文件头记录了图像的版本、长宽、采样因子、量化表、哈夫曼表等重要信息。所以解码前必须将文件头信息读出,以备图像数据解码过程之用。
2、从图像数据流读取一个最小编码单元(MCU) ,并提取出里边的各个颜色分量单元。
3、将颜色分量单元从数据流恢复成矩阵数据。
使用文件头给出的哈夫曼表,对分割出来的颜色分量单元进行解码,把其恢复成 8×8
的数据矩阵。
4、 8×8 的数据矩阵进一步解码。此部分解码工作以 8×8 的数据矩阵为单位, 其中包括相邻矩阵的直流系数差分解码、使用文件头给出的量化表反量化数据、反 Zig- zag 编码、隔行正负纠正、反向离散余弦变换等 5 个步骤, 最终输出仍然是一个 8×8 的数据矩阵。
5、颜色系统 YCrCb 向 RGB 转换。
将一个 MCU 的各个颜色分量单元解码结果整合起来,将图像颜色系统从 YCrCb 向
RGB 转换。
6、排列整合各个 MCU 的解码数据。
不断读取数据流中的 MCU 并对其解码,直至读完所有 MCU 为止,将各 MCU 解码后的数据正确排列成完整的图像。JPEG 的解码本身是比较复杂的, 这里 FATFS 的作者,提供了一个轻量级的 JPG/JPEG 解码库: TjpgDec,最少仅需 3KB 的 RAM 和 3.5KB 的 FLASH 即可实现 JPG/JPEG 解码,本例程采用 TjpgDec 作为 JPG/JPEG 的解码库,关于 TjpgDec 的详细使用,请参考光盘: 6,软件资料\图片编解码\TjpgDec 技术手册 这个文档。BMP 和 JPEG 这两种图片格式均不支持动态效果,而 GIF 则是可以支持动态效果。最后,我们来看看 GIF 图片格式。

GIF(Graphics Interchange Format)是 CompuServe 公司开发的图像文件存储格式, 1987 年开发的 GIF 文件格式版本号是 GIF87a, 1989 年进行了扩充,扩充后的版本号定义为 GIF89a。GIF 图像文件以数据块(block)为单位来存储图像的相关信息。一个 GIF 文件由表示图形/图像的数据块、数据子块以及显示图形/图像的控制信息块组成,称为 GIF 数据流(Data Stream)。数据流中的所有控制信息块和数据块都必须在文件头(Header)和文件结束块(Trailer)之间。

GIF 文件格式采用了 LZW(Lempel-Ziv Walch)压缩算法来存储图像数据,定义了允许用户为图像设置背景的透明(transparency)属性。此外, GIF 文件格式可在一个文件中存放多幅彩色图形/图像。如果在 GIF 文件中存放有多幅图,它们可以像演幻灯片那样显示或者像动画那样演示。
一个 GIF 文件的结构可分为文件头(File Header)、 GIF 数据流(GIF Data Stream)和文件终结器(Trailer)三个部分。文件头包含 GIF 文件署名(Signature)和版本号(Version); GIF 数据流由控制标识符、图象块(Image Block)和其他的一些扩展块组成;文件终结器只有一个值为 0x3B 的字符(’;’)表示文件结束。

关于 GIF 的详细介绍,我们就介绍到这里。

三、硬件设计

本章实验功能简介:开机的时候先检测字库,然后检测 SD 卡是否存在,如果 SD 卡存在,则开始查找 SD 卡根目录下的 PICTURE 文件夹,如果找到则显示该文件夹下面的图片文件(支持 bmp、 jpg、 jpeg 或 gif 格式) ,循环显示,通过按 KEY0 和 KEY2 可以快速浏览下一张和上一张, KEY_UP 按键用于暂停/继续播放, DS1 用于指示当前是否处于暂停状态。如果未找PICTURE 文件夹/任何图片文件,则提示错误。同样我们也是用 DS0 来指示程序正在运行。
所要用到的硬件资源如下:
1) 指示灯 DS0 和 DS1
2) KEY0、 KEY2 和 KEY_UP 三个按键
3) 串口
4) TFTLCD 模块
5) SD 卡
6) SPI FLASH
这几部分,在之前的实例中都介绍过了,我们在此就不介绍了。需要注意的是,我们在 SD卡根目录下要建一个 PICTURE 的文件夹,用来存放 JPEG、 JPG、 BMP 或 GIF 等图片。

四、软件设计

打开本章实验工程目录可以看到, 我们在工程根目录下面新建了一个 PICTURE 文件夹。
在该文件夹里面新建了 bmp.c、 bmp.h、 tjpgd.c、 tjpgd.h、 integer.h、 gif.c、 gif.h、 piclib.c 和 piclib.h等 9 个文件。 打开实验工程可以看到,我们在工程中新建了 PICTURE 分组,添加了相关源文件到工程,同时将 PICTURE 文件夹加入头文件包含路径。

对于这些文件, 其中 bmp.c 和 bmp.h 用于实现对 bmp 文件的解码; tjpgd.c 和 tjpgd.h 用于实现对 jpeg/jpg 文件的解码; gif.c 和 gif.h 用于实现对 gif 文件的解码;这几个代码太长了,所以我们在这里不贴出来,请大家参考光盘本例程的源码,我们打开 piclib.c,代码如下:

_pic_info picinfo; //图片信息
_pic_phy pic_phy; //图片显示物理接口
//lcd.h 没有提供划横线函数,需要自己实现
void piclib_draw_hline(u16 x0,u16 y0,u16 len,u16 color)
{
   
if((len==0)||(x0>lcddev.width)||(y0>lcddev.height))return;
LCD_Fill(x0,y0,x0+len-1,y0,color);
}
//填充颜色
//x,y:起始坐标
//width, height:宽度和高度。
//*color:颜色数组
void piclib_fill_color(u16 x,u16 y,u16 width,u16 height,u16 *color)
{
   
LCD_Color_Fill(x,y,x+width-1,y+height-1,color);
}
//画图初始化,在画图之前,必须先调用此函数
//指定画点/读点
void piclib_init(void)
{
   
pic_phy.read_point=LCD_ReadPoint; //读点函数实现,仅 BMP 需要
pic_phy.draw_point=LCD_Fast_DrawPoint; //画点函数实现
pic_phy.fill=LCD_Fill; //填充函数实现,仅 GIF 需要
pic_phy.draw_hline=piclib_draw_hline; //画线函数实现,仅 GIF 需要
pic_phy.fillcolor=piclib_fill_color; //颜色填充函数实现,仅 TJPGD 需要
picinfo.lcdwidth=lcddev.width; //得到 LCD 的宽度像素
picinfo.lcdheight=lcddev.height; //得到 LCD 的高度像素
picinfo.ImgWidth=0; //初始化宽度为 0
picinfo.ImgHeight=0; //初始化高度为 0
picinfo.Div_Fac=0; //初始化缩放系数为 0
picinfo.S_Height=0; //初始化设定的高度为 0
picinfo.S_Width=0; //初始化设定的宽度为 0
picinfo.S_XOFF=0; //初始化 x 轴的偏移量为 0
picinfo.S_YOFF=0; //初始化 y 轴的偏移量为 0
picinfo.staticx=0; //初始化当前显示到的 x 坐标为 0
picinfo.staticy=0; //初始化当前显示到的 y 坐标为 0
}
//快速 ALPHA BLENDING 算法.
//src:源颜色
//dst:目标颜色
//alpha:透明程度(0~32)
//返回值:混合后的颜色.
u16 piclib_alpha_blend(u16 src,u16 dst,u8 alpha)
{
   
u32 src2;u32 dst2;
//Convert to 32bit |-----GGGGGG-----RRRRR------BBBBB|
src2=((src<<16)|src)&0x07E0F81F;
dst2=((dst<<16)|dst)&0x07E0F81F;
//Perform blending R:G:B with alpha in range 0..32
//Note that the reason that alpha may not exceed 32 is that there are only
//5bits of space between each R:G:B value, any higher value will overflow
//into the next component and deliver ugly result.
dst2=((((dst2-src2)*alpha)>>5)+src2)&0x07E0F81F;
return (dst2>>16)|dst2;
}
//初始化智能画点
//内部调用
void ai_draw_init(void)
{
   
float temp,temp1;
temp=(float)picinfo.S_Width/picinfo.ImgWidth
  • 14
    点赞
  • 55
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值