浮點數據有損壓縮演算法 附完整C代碼

來源:互聯網
上載者:User

標籤:ssi   類型   cte   dex   char   其他   image   res   體驗   

在幾年前的時候在做修圖APP演算法的時候,

曾經一度想過對3D Lut 預設資料進行壓縮,

主要用於提升使用者體驗。

關於3d lut演算法開源的資源也挺多的,就不多做科普了。

有興趣的朋友,可以去查閱下ffmepg項目相關實現代碼。

最早接觸3d lut演算法是2014年逆向 VSCO Cam 膠片演算法的時候,

當然一開始我也不知道它的演算法是3d lut,

是反反覆複編寫各個版本,演算法最佳化,

直到有一天我突然想起一個常量特別奇怪,

後來有一段時間在看3d lut演算法資料的時候,覺得演算法特別熟悉。

後來自然也就知道啥情況了。

那時候在做一款APP,考慮壓縮預設資源的時候,

當時由於項目匆忙,採用LZ壓縮演算法,自然壓縮比並不高。

導致預設檔案偏大,有點佔資源體積。

原來預想要做一下浮點類型的壓縮演算法的,這一拖,就沒後文了。

很多人很好奇膠片濾鏡演算法,是怎麼實現的,

網上流傳了很多個版本,作為一名資深安全研究員,我就說一下大概情況。

早期絕大數APP採用了 2d lut去類比 VSCO Cam的效果,

思路比較簡單,就是做一個2D顏色映射表進行插值實現,一般是512*512*3 的顏色表,

GPUImage裡面有具體實現,感興趣的可以去看下,這裡也不展開了。

我這邊還保留著當年原汁原味的VSCO Cam膠片演算法。

再到近些年,深度學習 神經網路大火,筆者在做手機端前向傳播的時候,

再一次碰到類似的問題。

模型量化,模型壓縮等等。

模型量化的思路其實也挺簡單的,例如32位量化到16位,

或者量化到8位,通過降低精度擷取一定的效能提升和資源壓縮。

就量化一個操作,就可以做到既提升效能又壓縮模型體積,

所以肯定是比較不錯的方案。

當然在IOS下還可以考慮採用記憶體映射的方式,

將物理空間映射為記憶體空間,以減少記憶體佔用之類的。

當然這種方式必須是作業系統的檔案類型支援。

毫無疑問,再一次碰到浮點數據的壓縮問題。

現在絕大多數深度學習模型都是採用32位浮點進行儲存權重的。

但是很奇怪,好像沒看到有誰針對浮點數據進行壓縮處理。

 

難不成浮點數據真的沒法壓縮了?!

 

不然,不然,在之前做映像演算法的時候,俺對頻域演算法特別感興趣,

因為這種轉換思維角度的處理方式,的確巧妙。

看了網上很多資料,感覺沒多少人能用通俗的語言解釋頻域。

我就大言不慚,大話一番。

其實頻域核心是頻,也就是符合一定的頻次規律。

有點像計數法,舉個例子:八個8 可以記為88888888 也可以記為88,也可以直接記為8.

這就是頻,而頻域是什嗎?

頻域或者說頻率,其實就是一種描述特定頻率波率機率乃至頻域的表達方式。

換句更通俗的話來說,就是 基於特定表達標準進行計數。

而傅裡葉變換也好,餘弦變換也好,這裡的變換其實就是指的一種表達方式。

有點像,你跟你女朋友約定一種暗號,例如拋個媚眼,表達的是,親愛的,你懂的。

好了,解釋暫告一段落,往下就有點兒童不宜了。

而最經典的壓縮演算法,莫過於jpeg,這個格式已經家喻戶曉了。

雖然也有後起之秀 WebP FLIF 等格式,

但jpeg跟mp3一樣成為一個時代的預設標記。

而jpeg就是一種基於dct8x8變換的壓縮演算法。

具體也不展開了,有興趣可以去看看jpeg編解碼相關。

例如:https://github.com/cpuimage/TinyJPEG

這鋪墊有點長,所以是不是可以基於dct 8x8 對浮點數據進行有損壓縮呢?

答案,沒錯就是這麼簡單粗暴。

 

 資料長度 :8*8*8

按照順序從 0 - 511 填充資料。

這裡給出一個參考資料:

zlib 壓縮:
miniz.c version: 10.0.2
Compressed from 2048 to 730 bytes
Decompressed from 730 to 2048 bytes
 

dct+ zlib 壓縮:
miniz.c version: 10.0.2
Compressed from 2048 to 116 bytes
Decompressed from 116 to 2048 bytes

如果符合一定的DCT 規律,dct+zlib 的壓縮比,極高。

如果填充的資料是沒有規律的隨機資料,大多數情況下zlib壓縮比高一些。

而jpeg編碼中有另一個技巧,就是採用色彩空間,

RGB轉換為YCBCR空間,來擷取更高的壓縮比。

當然也會有一定的資訊損失,好像說得有點多了。

打住打住。。

附上完整範例程式碼:

#ifdef __cplusplusextern "C" {#endif#include <stdio.h>#include <stdlib.h>#include <stdint.h>#include "miniz.h"#include "dct.h"#include <stdint.h>int test_miniz(const unsigned char *s_pStr, uLong data_len) {    int cmp_status;    uLong src_len = data_len;    uLong cmp_len = compressBound(src_len);    uLong uncomp_len = src_len;    uint8_t *pCmp, *pUncomp;    printf("miniz.c version: %s\n", MZ_VERSION);    // Allocate buffers to hold compressed and uncompressed data.    pCmp = (mz_uint8 *) malloc((size_t) cmp_len);    pUncomp = (mz_uint8 *) malloc((size_t) src_len);    if ((!pCmp) || (!pUncomp)) {        printf("Out of memory!\n");        return EXIT_FAILURE;    }    // Compress the string.    cmp_status = compress(pCmp, &cmp_len, (const unsigned char *) s_pStr, src_len);    if (cmp_status != Z_OK) {        printf("compress() failed!\n");        free(pCmp);        free(pUncomp);        return EXIT_FAILURE;    }    printf("Compressed from %u to %u bytes\n", (mz_uint32) src_len, (mz_uint32) cmp_len);    // Decompress.    cmp_status = uncompress(pUncomp, &uncomp_len, pCmp, cmp_len);    if (cmp_status != Z_OK) {        printf("uncompress failed!\n");        free(pCmp);        free(pUncomp);        return EXIT_FAILURE;    }    printf("Decompressed from %u to %u bytes\n", (mz_uint32) cmp_len, (mz_uint32) uncomp_len);    // Ensure uncompress() returned the expected data.    if ((uncomp_len != src_len) || (memcmp(pUncomp, s_pStr, (size_t) src_len))) {        printf("Decompression failed!\n");        free(pCmp);        free(pUncomp);        return EXIT_FAILURE;    }    free(pCmp);    free(pUncomp);    printf("Success.\n");    return EXIT_SUCCESS;}int test_dct_miniz(float *data, uLong len) {    uLong nCount = len / 64;    float *in_data = data;    for (int i = 0; i < nCount; i++) {        DCT(in_data, in_data);        in_data += 64;    }    test_miniz((const unsigned char *) data, len * sizeof(float));    float *out_data = data;    for (int i = 0; i < nCount; i++) {        IDCT(out_data, out_data);        out_data += 64;    }}int main(int argc, char *argv[]) {    printf("float data loss compression algorithm base DCT 8X8.\n");    printf("DCT implementation by Thomas G. Lane.\n");    printf("miniz implementation by Rich Geldreich.\n");    //http://developer.download.nvidia.com/SDK/9.5/Samples/vidimaging_samples.html#gpgpu_dct    printf("blog:http://cpuimage.cnblogs.com/\n");    int is_debug_output = 1;    const uLong data_len = 8 * 8* 8;// blocksize    float test_for_miniz[data_len];    float test_for_dct[data_len];    for (int i = 0; i < data_len; ++i) {        test_for_miniz[i] = i;    }    memcpy(test_for_dct, test_for_miniz, data_len * sizeof(float));    printf("\nonly miniz:\n");    test_miniz((const unsigned char *) test_for_miniz, data_len * sizeof(float));    printf("\nwith dct:\n");    test_dct_miniz(test_for_dct, data_len);    if (is_debug_output) {        for (int i = 0; i < data_len; ++i) {            if (test_for_miniz[i] != test_for_dct[i]) {                printf("index %d: %f != %f \n", i, test_for_miniz[i], test_for_dct[i]);            }        }    }    printf("\n press any key to exit.\n");    return EXIT_SUCCESS;}#ifdef __cplusplus}#endif

項目地址:https://github.com/cpuimage/DCT_8X8

 

另外感謝5.1節假日時,某位匿名 網友的一元人民幣打賞。

涓涓細流可成江河~

 

若有其他相關問題或者需求也可以郵件聯絡俺探討。

 

郵箱地址是: 
[email protected]

 

浮點數據有損壓縮演算法 附完整C代碼

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.