使用libjpeg-turbo庫實(shí)現(xiàn)無損圖像到j(luò)pg壓縮圖像的內(nèi)存效果轉(zhuǎn)換

0.前言

深度學(xué)習(xí)訓(xùn)練的圖片大多是經(jīng)過壓縮的jpeg圖像,而深度學(xué)習(xí)推理過程面臨的圖像往往是內(nèi)存中的無損圖像妒牙,從而造成識別效果上的差異胖笛。解決差異的方法之一就是將無損的圖像進(jìn)行壓縮處理后再進(jìn)行深度學(xué)習(xí)推理巍实。此處并不是使用JPEG算法實(shí)現(xiàn)壓縮過程贺奠,而是使用的libjpeg-turbo第三方庫實(shí)現(xiàn)的,libjpeg-turbo是一個(gè)專門為 x86 和 x86-64 處理器優(yōu)化的高速 libjpeg 的改進(jìn)版本隆嗅,實(shí)現(xiàn)了libjpeg所有的API并且速度提高了2-6倍界阁。libjpeg是IJG(Independent JPEG Group,一個(gè)非正式團(tuán)體)發(fā)布用于JPEG圖像壓縮的廣泛使用的免費(fèi)庫胖喳,第一版于1991年10月7日發(fā)布泡躯。

1.libjpeg-turbo編譯安裝

step1:下載安裝NASM
NASM全稱The Netwide Assembler,是一款基于80x86和x86-64平臺(tái)的匯編語言編譯程序丽焊,其設(shè)計(jì)初衷是為了實(shí)現(xiàn)編譯器程序跨平臺(tái)和模塊化的特性较剃。編譯libjpeg-turbo時(shí)需要這個(gè)東西。
下載地址:https://www.nasm.us/index.php
下載對應(yīng)的安裝版本粹懒,雙擊安裝即可重付。
step2:安裝libjpeg-turbo-vc.exe
下載地址:https://sourceforge.net/projects/libjpeg-turbo
下載最新版本的exe,雙擊安裝凫乖,在安裝路徑上就有了include确垫、lib、bin等文件夾帽芽。但是這里面的東西除了include里面的頭文件是好用的其他的都不好用删掀。還是自己下載源碼編譯出來的能用。
step3:下載libjpeg-turbo源碼編譯
下載地址:https://github.com/libjpeg-turbo/libjpeg-turbo
使用cmake导街,vs進(jìn)行編譯披泪,選好兩個(gè)路徑就行,其他都默認(rèn)的搬瑰。


vs編譯后就會(huì)出現(xiàn)lib和bin了款票,并且也有靜態(tài)庫控硼。后面我用的都是turbojpeg-static.lib這個(gè)靜態(tài)庫。

2.參考example.txt實(shí)現(xiàn)功能艾少。

其實(shí)就是參考了example中的編碼過程和解碼過程卡乾,代碼直接復(fù)制過來就能用,我在里面加了一些opencv的操作缚够。另外幔妨,自定義的錯(cuò)誤處理代碼可參考example自行處理。
還有一點(diǎn)比較重要的是使用庫中提供的動(dòng)態(tài)分配內(nèi)存的函數(shù)jpeg_mem_dest代替example中的jpeg_stdio_dest函數(shù)谍椅。
函數(shù)原型:
jpeg_mem_dest(j_compress_ptr cinfo,unsigned char ** outbuffer,size_t * outsize);
參數(shù)說明:
oubuffer:壓縮后的Jpg圖像误堡,由函數(shù)返回,其內(nèi)存是在jpeg_mem_dest()函數(shù)中申請的雏吭,所以壓縮完之后需要釋放空間锁施,否則造成內(nèi)存泄露。
outSize:壓縮后圖像的字節(jié)數(shù)思恐,由函數(shù)返回沾谜。
outbuffer里面存放著壓縮后的數(shù)據(jù),只有jpeg_finish_compress(&cinfo)調(diào)用后outbuffer和outsize才是準(zhǔn)確的數(shù)據(jù)地址及數(shù)據(jù)大小胀莹。

#include<stdio.h>
#include "jpeglib.h"
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc/types_c.h>
typedef unsigned char uchar;
using namespace cv;
using namespace std;
void tojpg(cv::Mat &srcImg, cv::Mat &jpgImg, int quality)
{
    //**************壓縮編碼**************
    struct jpeg_compress_struct cinfo;
    struct jpeg_error_mgr jerr;
    JSAMPROW row_pointer[1];
    int row_stride;
    cinfo.err = jpeg_std_error(&jerr);
    jpeg_create_compress(&cinfo);
    uchar* outbuffer;
    outbuffer = NULL;
    unsigned long outSize = 0;
    jpeg_mem_dest(&cinfo, &outbuffer, &outSize);
    cinfo.image_width = srcImg.cols;
    cinfo.image_height = srcImg.rows;
    cinfo.input_components = 3;
    cinfo.in_color_space = JCS_RGB;
    jpeg_set_defaults(&cinfo);
    jpeg_set_quality(&cinfo, quality, TRUE);
    jpeg_start_compress(&cinfo, TRUE);
    row_stride = srcImg.cols * 3;
    cv::Mat RGBIMG(srcImg.rows, srcImg.cols, CV_8UC3);
    cvtColor(srcImg, RGBIMG, CV_BGR2RGB);
    JSAMPLE *image_buffer = RGBIMG.data;
    while (cinfo.next_scanline < cinfo.image_height) {
        row_pointer[0] = &image_buffer[cinfo.next_scanline * row_stride];
        (void)jpeg_write_scanlines(&cinfo, row_pointer, 1);
    }
    jpeg_finish_compress(&cinfo);
        //編碼后直接寫出來就是能打開的圖片
    /*FILE *f = fopen("outbuffer.jpg", "wb");
    fwrite(outbuffer, outSize, 1, f);
    fclose(f);*/
    //************解碼成圖像******************
    struct jpeg_decompress_struct cinfo2;
    struct my_error_mgr jerr2;
    JSAMPARRAY buffer;      /* Output row buffer */

    cinfo2.err = jpeg_std_error(&jerr2.pub);
    jerr2.pub.error_exit = my_error_exit;
    if (setjmp(jerr2.setjmp_buffer)) {
        jpeg_destroy_decompress(&cinfo2);
        return;
    }
    jpeg_create_decompress(&cinfo2);
    jpeg_mem_src(&cinfo2, outbuffer, outSize);
    (void)jpeg_read_header(&cinfo2, TRUE);
    (void)jpeg_start_decompress(&cinfo2);
    cinfo2.output_width = cinfo.image_width;
    cinfo2.output_height = cinfo.image_height;
    cinfo2.output_components = cinfo.input_components;
    row_stride = cinfo2.output_width * cinfo2.output_components;
    buffer = (*cinfo.mem->alloc_sarray)
        ((j_common_ptr)&cinfo, JPOOL_IMAGE, row_stride, 1);
    
    while (cinfo2.output_scanline < cinfo2.output_height) {
        (void)jpeg_read_scanlines(&cinfo2, buffer, 1);
        memcpy(jpgImg.data + (cinfo2.output_scanline - 1)*row_stride, buffer[0], row_stride);   
    }
    cvtColor(jpgImg, jpgImg, CV_RGB2BGR);
    /*****銷毀解碼******/
    (void)jpeg_finish_decompress(&cinfo2);
    /* Step 8: Release JPEG decompression object */
    jpeg_destroy_decompress(&cinfo2);

    /******銷毀編碼*******/
    if (NULL != outbuffer)
    {
        free(outbuffer);
        //delete outbuffer;
        outbuffer = NULL;
    }
    jpeg_destroy_compress(&cinfo);
    return;
}
void main()
{
    cv::Mat bmpimg = cv::imread("1.bmp");
    imshow("src", bmpimg);
    clock_t startTime, endTime;
    startTime = clock();
    Mat jpgImg(bmpimg.rows, bmpimg.cols, CV_8UC3, Scalar(0,0,0));
    tojpg(bmpimg, jpgImg, 10);
    endTime = clock();//計(jì)時(shí)結(jié)束
    double cTime = (double)(endTime - startTime) / CLOCKS_PER_SEC;
    cout << "total time is: " << cTime << "s" << endl;
    imshow("out", jpgImg);
    waitKey();
}

3.結(jié)論

一開始使用的是libjpeg,解碼一張大點(diǎn)的圖需要45ms婚温,換成libjpeg-turbo后同樣的圖解碼需要15ms描焰。這和halcon的用時(shí)就一樣了。

4.NASM栅螟、安裝版和源碼也可以在我的網(wǎng)盤中下載

https://pan.baidu.com/s/1k-_VW0spuRaQkCajR8ET2Q
提取碼:5gco

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
禁止轉(zhuǎn)載荆秦,如需轉(zhuǎn)載請通過簡信或評論聯(lián)系作者。
  • 序言:七十年代末力图,一起剝皮案震驚了整個(gè)濱河市步绸,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌吃媒,老刑警劉巖瓤介,帶你破解...
    沈念sama閱讀 212,718評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異赘那,居然都是意外死亡刑桑,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,683評論 3 385
  • 文/潘曉璐 我一進(jìn)店門募舟,熙熙樓的掌柜王于貴愁眉苦臉地迎上來祠斧,“玉大人,你說我怎么就攤上這事拱礁∽练妫” “怎么了辕漂?”我有些...
    開封第一講書人閱讀 158,207評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長吴超。 經(jīng)常有香客問我钮热,道長,這世上最難降的妖魔是什么烛芬? 我笑而不...
    開封第一講書人閱讀 56,755評論 1 284
  • 正文 為了忘掉前任隧期,我火速辦了婚禮,結(jié)果婚禮上赘娄,老公的妹妹穿的比我還像新娘仆潮。我一直安慰自己,他們只是感情好遣臼,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,862評論 6 386
  • 文/花漫 我一把揭開白布性置。 她就那樣靜靜地躺著,像睡著了一般揍堰。 火紅的嫁衣襯著肌膚如雪鹏浅。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,050評論 1 291
  • 那天屏歹,我揣著相機(jī)與錄音隐砸,去河邊找鬼。 笑死蝙眶,一個(gè)胖子當(dāng)著我的面吹牛季希,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播幽纷,決...
    沈念sama閱讀 39,136評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼式塌,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了友浸?” 一聲冷哼從身側(cè)響起峰尝,我...
    開封第一講書人閱讀 37,882評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎收恢,沒想到半個(gè)月后武学,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,330評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡派诬,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,651評論 2 327
  • 正文 我和宋清朗相戀三年劳淆,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片默赂。...
    茶點(diǎn)故事閱讀 38,789評論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡沛鸵,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情曲掰,我是刑警寧澤疾捍,帶...
    沈念sama閱讀 34,477評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站栏妖,受9級特大地震影響乱豆,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜吊趾,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,135評論 3 317
  • 文/蒙蒙 一宛裕、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧论泛,春花似錦揩尸、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,864評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至坟瓢,卻和暖如春勇边,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背折联。 一陣腳步聲響...
    開封第一講書人閱讀 32,099評論 1 267
  • 我被黑心中介騙來泰國打工粒褒, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人崭庸。 一個(gè)月前我還...
    沈念sama閱讀 46,598評論 2 362
  • 正文 我出身青樓怀浆,卻偏偏與公主長得像,于是被迫代替她去往敵國和親怕享。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,697評論 2 351