[原创] 图像处理能力评测之三--JPEG图片解码能力

ilovefengshulin   2016-12-14 09:48 楼主
图像处理能力评测之三--JPEG图片解码能力
硬件平台:STM32F769IDISCOVERY
软件开发平台:Keil 5.1
测试方法:
    1.采用SD卡,并把测试的图片存放到根目录中。SD卡的容量为8G,Class 4。选用3种色彩丰富程度差别较大的图片,并把每种图片裁剪成800X480、480X320、320X240大小,作为基准测试图片。
    2.配置系统时钟为200MHZ,SD卡时钟为25MHZ,SDRAM的时钟为100MHZ,使用FATFS文件系统。关闭LCD层0的显示,开启LCD层1的显示,使用RGB888显示。
    3.选用STM32自带的JPEG硬件编解码器、TjpgDEC解码库和LIBJPEG解码库,分别对图片进行测试,比较三者的解码能力。
LIBJPEG解码库简介:
    ibjpeg是一个完全用C语言编写的库,包含了被广泛使用的JPEG解码、JPEG编码和其他的JPEG功能的实现。目前最新的版本为9b。官网地址: http://www.ijg.org/。libjpeg具有稳定、兼容性强和解码速度较快等优点,但是使用这个库文件进行JPEG解码,消耗内存较大,对于内存不足的处理器来说,是一个很大的负担。在我们下载的STM32CUBEF7资源包里就有LIBJPEG库文件,因此不用去下载。库文件的存放路径如下图所示:
                                             1.jpg
                              
直接将整个文件夹复制到工程文件夹,然后添加文件,修改相应的配置参数即可使用。
TjpgDEC解码库简介:
    TJpgDec是一个通用的JPEG图像解压缩器模块,针对小型嵌入式系统进行了高度优化。它使用非常低的内存消耗,使其可以被并入微小的微控制器,如AVR,8051,PIC,Z80,Cortex-M0等。支持输出RGB888or RGB565,支持图片缩放。官网地址:http://elm-chan.org/fsw/tjpgd/00index.html。目前版本为R0.01B,作者基本上没有进行更新。
                                           2.jpg
JPEG硬件编解码器简介:
    这个是STM32自带的硬件解码器,目前只存在于STM32F7X7、 STM32F7X8和STM32F7X9这几个系列产品中。它提供了一个快速和简单的硬件压缩器和解压缩器。JPEG编解码器可以解码ISO / IEC 10918-1规范中定义的JPEG流,它可以选择性地解析JPEG头,并相应地更新JPEG编解码器寄存器的量化表和霍夫曼表。
JPEG编解码块主要特性:
    1.支持8位通道像素采样
    2.对每个像素数据进行编解码只需一个时钟周期
    3.支持JPEG图片头信息生成和解析,可以使能/禁止对JPEG图片头信息处理。
    4.拥有四个可编程量化表和完全可编程的霍夫曼表。
    5. 完全可编程的最小编码单元。
    6.支持编码/解码。
    7.数据传送支持DMA、中断和轮询。
    JPEG编解码器框图如下所示:
    3.jpg
从图中可以看出,JPEG编解码器拥有两个FIFO,一个为输入一个为输出,并且支持FIFO阈值中断。可以通过检测FIFO阈值中断是否产生,及时将数据送进FIFO或者从FIFO读出数据,从而使JPEG编解码操作维持连续性,使JPEG编解码器的性能得到最大的发挥。其中有一点需要注意,解码器输出的数据不是RGB数据,不能直接往LCD里送数据,需要进行数据转换算法,换算成RGB数据(就是这个问题,整整折腾了我一天的时间)。
下面是我选用的测试图片,按照图片色彩丰富程度从高到低进行排列:

    5.jpg
   
    4.jpg
   
    6.jpg
好了,现在我们开始进行测试。为了保证测试的一致性,我们选用同一块开发板,并使系统运行时的工作参数保持相同。解码时间的计算以毫秒为单位,配置系统滴答定时器每隔1ms产生中断,提供时间计数。当图片文件打开后,开始时间计数,到LCD显示图片完成后,停止时间计数。计算二者的时间差,就是图片的解码时间。
JPEG硬件解码器分别使用DMA、IT和轮询的方式对图片进行解码。同时对TjpgdDEC和LIBJPEG进行优化处理,使解码时间尽量最短,因为我们比较的是三种解码方式工作在最优模式下的解码速度(个人能力有限,已经尽最大努力优化TjpgDEC和LIBJPEG,以下的时间数据仅供参考。)。经过三天的移植和测试,最后的测试数据如下图所示:
图片像素800X480
  
图片质量
  
硬件JPEG 中断方式
硬件JPEG DMA方式
硬件JPEG轮询方式
TjpgDEC解码
LIBJPEG解码
89ms
62ms
87ms
238ms
148ms
151ms
121ms
148ms
316ms
213ms
189ms
158ms
185ms
413ms
271ms
图片像素480X320
  
图片质量
  
硬件JPEG 中断方式
硬件JPEG DMA方式
硬件JPEG轮询方式
TjpgDEC解码
LIBJPEG解码
39ms
28ms
37ms
102ms
64ms
80ms
69ms
78ms
151ms
107ms
97ms
85ms
95ms
196ms
133ms
图片像素320X240
  
图片质量
  
硬件JPEG 中断方式
硬件JPEG DMA方式
硬件JPEG轮询方式
TjpgDEC解码
LIBJPEG解码
21ms
15ms
20ms
55ms
34ms
54ms
48ms
54ms
93ms
70ms
63ms
57ms
62ms
116ms
82ms
从上述三张数据表中可以看出,使用DMA方式的JPEG硬件解码速度是最快的,而采用TjpgDEC库解码是速度最慢的。其中中断方式的JPEG硬件解码要和使用轮询方式的JPEG硬件解码二者的速度差不多,都比TjpgDEC解码和LIBJPEG解码来的快。但是使用轮询方式的JPEG硬件解码会占用整个CPU,不如中断来的灵活。当解码的图片越来越小时,LIBJPEG解码和JPEG硬件解码在速度上不会差太多.因此,当解码较大的图片时,JPEG硬件解码的优势就发挥出来了。
最后奉上几张800X600的图片在开发板上的显示:
      12.jpg
     
      11.jpg
     
      10.jpg

关于JPEG硬件编解码器使用的一些注意:
1.添加固件库文件stm32f7xx_hal_jpeg.c和stm32f7xx_hal_jpeg.h到项目工程。同时添加jpeg_utils.c、jpeg_utils.h和jpeg_utils_conf_template.h到项目工程,这三个是编解码数据格式转换相关的文件。
2.打开jpeg_utils_conf_template.h文件,修改第51行和52行的内容如下图所示:
    7.jpg
修改第72行和73行的内容,如果使用解码器,将73行的内容修改为:#define USE_JPEG_ENCODER    0如果使用编码器,将72行的内容修改为:#defineUSE_JPEG_DECODER     0。然后修改第75行的内容,这个是配置像素数据转换完成后的格式,根据屏幕像素的格式修改相应的值,比如我这里是RGB888,因此修改为:#define JPEG_RGB_FORMAT      JPEG_RGB888。最后修改第76行的内容,这个是配置是否需要交换RB,如果使能,那么经过转换后,像素的格式为BGR888。我这里不需要这个功能,设置为:#defineJPEG_SWAP_RB         0。
保存并关闭文件,将文件名修改为jpeg_utils_conf.h         
    3. 打开stm32f7xx_hal_conf.h文件,修改第96行如下图所示:
    8.jpg
    4.进行初始化,包括使能JPEG模组时钟,使能DMA2模组时钟,调用初始化函数对JPEG进行初始化,配置JPEG中断和DMA2中断。最后不要忘了,如果是进行解码操作,一定要调用JPEG_InitColorTables函数,初始化JPEG查找表。这个函数只能在初始化的时候调用,并且只能调用一次,后面不允许掉用,无论你有多少张JPEG图片要解码,都只在初始化的时候调用一次就够了。
    5.使用轮询方式解码图片时,会完全占用CPU,直到解码完成后者解码出错才会退出。采用DMA和中断,不会一直占用CPU。解码过程中会回调以下个函数:
HAL_JPEG_InfoReadyCallback:指示JPEG头解析完成,可以查看图片的宽度和高度,以及像素数据的组成方式。在这一步中通常调用JPEG_GetDecodeColorConvertFunc函数来设定转换完成后,数据格式转换的函数。
    HAL_JPEG_GetDataCallback:这个是请求数据输入的函数。参数NbDecodedData是指示解码器需要采集数据的字节数。
    HAL_JPEG_DataReadyCallback:解码器数据转换好的通知函数。注意如果是一次性将JPEG图片数据传送到解码器,那么这里出来的是全部的解码数据,否则为部分解码数据。参数pDataOut为数据存放区,参数OutDataLength为输出数据的字节数量。通常在里调用函数进行数据转换操作。
    HAL_JPEG_DecodeCpltCallback编解码完成的指示函数。
    HAL_JPEG_ErrorCallback编解码错误的指示函数。
关于我编写程序的使用注意事项:
    1.我已经将TjpgDEC和LIBJPEG都移植到工程项目中,编译完成后只会选用一种方式解码图片。要用其他的方式解码图片,需修改JpegDecode.h文件,如下图所示:
    9.jpg
    2.硬件JPEG、TjpgDEC和LIBJPEG的解码函数都存放在JpegDecode.c中。并且测试图片要存在放在SD卡的根目录中。

点击此处,查看STM32F769I开发板官方资源。

回复评论 (7)

很详细  加油
加油!在电子行业默默贡献自己的力量!:)
点赞  2016-12-14 10:16
多谢楼主分享啊 。
点赞  2016-12-14 16:59
引用: gxg1122 发表于 2016-12-14 16:59
多谢楼主分享啊 。

大家一起学习
点赞  2016-12-14 17:59
引用: soso 发表于 2016-12-14 10:16
很详细  加油

难得得到soso姐夸奖
点赞  2016-12-14 18:00
引用: ilovefengshulin 发表于 2016-12-14 18:00
难得得到soso姐夸奖

加油!在电子行业默默贡献自己的力量!:)
点赞  2016-12-15 09:11

我感觉像一只无头苍蝇不知道如何下手。

点赞  2019-6-12 08:27

厉害,我还没入门呢,感觉好难

gitee/casy
点赞  2023-6-24 17:30
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复