作者:星隕
來源:
音視訊開發進階 說到圖像解碼庫,最容易想起的就是libpng
和 libjpeg
這兩個老牌圖像解碼庫了。 libpng
libjpeg
分别各自對應 png
jpeg
兩種圖像格式。這兩種格式的差別如下: png
支援清晰度,無損壓縮的圖檔格式,能在保證不失真的情況下重新壓縮壓縮圖像檔案的大小,是以圖像品質高,在一些貼紙應用中也大部分用的是png圖檔。 jpg
不支援垂直,有損壓縮的圖檔格式,有損壓縮會和原始圖檔資料品質下載下傳,也是以它占用的記憶體小,在網頁應用中加速速度快。
要想在工程中同時解碼
png
jpeg
格式圖檔,就必須同時引用這兩個庫,而且還得通過分段編譯步驟才行。
在這裡,介紹一個簡單易用的圖像庫:
stb_image
。Github位址為:https://github.com/nothings/stb,目前已經有了9600+ Star。它的使用非常簡單,看看README可能你就會了。
看看它的源碼,會你發現全的英文
.h
頭檔案。這就是它的強大之處了,僅需在工程中加入頭檔案就可以解析圖像了(實際上是函數實作等内容都放在頭檔案了而已)。
重點關注如下三個頭檔案:
- stb_image.h
-
- 用于圖像加載
- stb_image_write.h
-
- 用于寫入圖像檔案
- stb_image_resize.h
-
- 用于改變圖像尺寸
下面就開始實踐吧,先稱為一個完整的例子:
1#include <iostream>
2
3#define STB_IMAGE_IMPLEMENTATION
4#include "stb_image.h"
5#define STB_IMAGE_WRITE_IMPLEMENTATION
6#include "stb_image_write.h"
7#define STB_IMAGE_RESIZE_IMPLEMENTATION
8#include "stb_image_resize.h"
9#include <string>
10#include <stdio.h>
11#include <stdlib.h>
12#include <vector>
13
14using namespace std;
15
16int main() {
17 std::cout << "Hello, STB_Image" << std::endl;
18
19 string inputPath = "/Users/glumes/Pictures/input.png";
20 int iw, ih, n;
21
22 // 加載圖檔擷取寬、高、顔色通道資訊
23 unsigned char *idata = stbi_load(inputPath.c_str(), &iw, &ih, &n, 0);
24
25 int ow = iw / 2;
26 int oh = ih / 2;
27 auto *odata = (unsigned char *) malloc(ow * oh * n);
28
29 // 改變圖檔尺寸
30 stbir_resize(idata, iw, ih, 0, odata, ow, oh, 0, STBIR_TYPE_UINT8, n, STBIR_ALPHA_CHANNEL_NONE, 0,
31 STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP,
32 STBIR_FILTER_BOX, STBIR_FILTER_BOX,
33 STBIR_COLORSPACE_SRGB, nullptr
34 );
35
36 string outputPath = "/Users/glumes/Pictures/output.png";
37 // 寫入圖檔
38 stbi_write_png(outputPath.c_str(), ow, oh, n, odata, 0);
39
40 stbi_image_free(idata);
41 stbi_image_free(odata);
42 return 0;
43}
這個例子很簡單也很全面,主要就是加載了一張圖檔,變成它的寬高都縮小一倍,并儲存縮小後圖檔。
stb_image
首先是調用
stbi_load
方法去加載圖像資料,并擷取相關資訊。初始的參數除了圖檔檔案位址,還有寬,高,顔色通道資訊的引用。
變量
n
就代表圖檔的顔色通道值,通常有如下的情況:
- 1:灰色圖
- 2:灰色圖加雙邊
- 3:紅綠藍RGB三色圖
- 4:紅綠藍加同軸RGBA圖
傳回的結果就是圖檔預期資料的指針了。
stbi_load
不僅僅支援
png
格式,把上面的例子中的圖檔改成
jpg
格式字尾的依舊可行。
它支援的所有格式如下:
- png
- jpg
- ga
- bmp
- psd
- gif
- 人類發展報告
- 圖檔
格式雖然多,不過一般用到png和jpg就好了。
除了從檔案加載圖檔,stb_image還支援從記憶體中加載圖檔,通過該方法
stbi_load_from_memory
,在後續文章中會用到它的。
加載完圖檔之後,stb_image還提供了相應的釋放方法
stbi_image_free
,實際上就是把
free
封裝了一下而已。
sbt_image_resize
加載完圖檔估計資料之後,就可以通過
stbir_resize
方法更改圖檔的尺寸。
stbir_resize
方法參數有很多:
1STBIRDEF int stbir_resize(const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
2 void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
3 stbir_datatype datatype,
4 int num_channels, int alpha_channel, int flags,
5 // stb 中提供了多種模式,但是修改後并沒有見很明顯的效果
6 stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
7 stbir_filter filter_horizontal, stbir_filter filter_vertical,
8 stbir_colorspace space, void *alloc_context)
9
stbir_edge
stbir_filter
類型的參數,stb_image_resize提供了多種類型:
1typedef enum
2{
3 STBIR_EDGE_CLAMP = 1,
4 STBIR_EDGE_REFLECT = 2,
5 STBIR_EDGE_WRAP = 3,
6 STBIR_EDGE_ZERO = 4,
7} stbir_edge;
8
9typedef enum
10{
11 STBIR_FILTER_DEFAULT = 0, // use same filter type that easy-to-use API chooses
12 STBIR_FILTER_BOX = 1, // A trapezoid w/1-pixel wide ramps, same result as box for integer scale ratios
13 STBIR_FILTER_TRIANGLE = 2, // On upsampling, produces same results as bilinear texture filtering
14 STBIR_FILTER_CUBICBSPLINE = 3, // The cubic b-spline (aka Mitchell-Netrevalli with B=1,C=0), gaussian-esque
15 STBIR_FILTER_CATMULLROM = 4, // An interpolating cubic spline
16 STBIR_FILTER_MITCHELL = 5, // Mitchell-Netrevalli filter with B=1/3, C=1/3
17} stbir_filter;
但實際上調整不同類型組合得到的圖檔并沒有太多的變化┑( ̄Д  ̄)┍。
真正有用的可能還是前面那幾個參數,指定了預期的圖檔縮放後的寬高資料。
stb_image_write
最後就是調用
stbi_write_png
方法将資料寫入檔案中,另外,stb_image_write還提供了
stbi_write_jpg
方法來儲存jpg格式圖檔。
根據兩者格式的不同,方法調用的參數也是不一樣的。
1int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality)
2
3int stbi_write_png(char const *filename, int x, int y, int comp, const void *data, int stride_bytes)
4
總結
以上就是關于stb_image圖像解碼庫的小介紹。
總的來說,它還是挺簡單易用的,在平常做一些Demo以及需要快速實作,驗證功能的情況下都可以考慮考慮。
但是在一些大型的項目中,還是要深思熟慮一些,從性能方面考慮,它肯定不如老牌的圖像解碼庫了,像
libjpeg-turbo
解碼用到了
NEON
這樣SIMD(單指令流多資料流)的操作,才是大型項目的首選了。
參考
關于stb_image在Android中的使用實踐,可以參考我的項目:
https://github.com/glumes/InstantGLSL安卓以及音視訊雜談
「視訊雲技術」你最值得關注的音視訊技術公衆号,每周推送來自阿裡雲一線的實踐技術文章,在這裡與音視訊領域一流工程師交流切磋。