一种优化的 JPEG 剪裁、缩小图片的解码方法

2022-07-11 19:04:40 +08:00
 picone
libjpeg-turbo 是一个优秀的,JPEG 解码加速库。但是在程序使用上其实可以更进一步优化。具体为:

# 图片剪裁

JPEG 图片是逐个 MCU(Minimum Coded Unit) 从左到右,从上到下地编码出来的,因此解码可以只解码感兴趣的部分而不用解码整个图片,JPEG 库提供了相对应的操作,`jpeg_skip_scanlines` 可以跳过行,`jpeg_crop_scanline` 可以只解码感兴趣的像素列所在的 MCU ,经过上层封装后能减少 MCU 解码的个数,对于只剪裁很小一部分像素的程序来说会有很大的性能提升。

# 图片缩小

同上,基于 JEPG 的 MCU 特性,每个 MCU 涉及重采样。简单且一般来说,抽样一般是 4:2:0 ,这意味着 16x16 像素大小的 MCU ,Y 通道会被编码成 16x16 ,而 Cb 和 Cr 通道会被编码成 8x8 大小(实际没有这么简单,但先可以这么理解)。在解码时,明显地 Cb 、Cr 通道需要升采样。这时候如果进行图片缩小操作就很浪费 CPU 和内存了,因为 Cb 和 Cr 通道进行了升采样,然后再被缩小,实际上可以不升采样。在 libjepg 里面也提供了这样的接口,只需要在解码时传入 `scale_num` 和 `scale_denom` 就可以控制解码时升降采样大小了。

下面是安利时间,这是我 Golang 上已实现的库,已经实现了主流格式的兼容了,附上 benchmark 。
https://github.com/picone/gojpegturbo
1630 次点击
所在节点    程序员
7 条回复
iamzuoxinyu
2022-07-11 19:16:53 +08:00
在前司也用 jpeg-turbo ,原本的 C 接口就很简单易用了,cgo 只要简单包一层就行。
picone
2022-07-11 19:23:47 +08:00
@iamzuoxinyu #1 这取决于需求,如果你的需求是剪裁图片,或者缩放图片,可以考虑一下我说的方法能大大提高性能。
daimaosix
2022-07-11 22:48:47 +08:00
大可不必! http://www.thumbor.org
picone
2022-07-11 22:53:04 +08:00
@daimaosix #3 没在一个频道,这里讨论的是业务里常用的剪裁和缩放逻辑怎么做到性能极致
mikewang
2022-07-12 00:22:40 +08:00
写过 JPEG 编码器,能理解 OP 的想法。
libjpeg-turbo 是在 libjpeg 基础上在汇编层面上使用 SIMD 指令加速计算,快。
补充一点:裁剪方面如果是粗略的操作,还可以不解码 MCU 本身,利用 MCU 边长整数倍直接裁,免去 DCT 计算,更快。
wsph123
2022-07-12 06:33:00 +08:00
这个妙啊
picone
2022-07-12 08:37:02 +08:00
@mikewang 貌似不行,除非需求的大小都是整数倍。往往要求的剪裁大小都是部分的 MCU ,需要 copy 一次内存然后重新编码。。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/865498

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX