通过libjpeg-turbo实现对jpeg图像的解码
生活随笔
收集整理的這篇文章主要介紹了
通过libjpeg-turbo实现对jpeg图像的解码
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
之前在https://blog.csdn.net/fengbingchun/article/details/89715416中介紹過通過libjpeg-turbo接口實現將數據編碼或壓縮成jpeg數據并通過FILE的fwrite接口將其直接保存成*.jpg圖像,當時用的是libjpeg的接口,其實還可以使用turbojpeg api的接口即tjCompress2實現對數據的編碼,見下面的code:
int get_jpeg_compress_data2(const unsigned char* data, int width, int height, int pixelFormat, unsigned char** jpegBuf, unsigned long* jpegSize, int jpegSubsamp, int jpegQual, int flags)
{tjhandle handle = tjInitCompress();int ret = tjCompress2(handle, data, width, 0, height, pixelFormat, jpegBuf, jpegSize, jpegSubsamp, jpegQual, flags);tjDestroy(handle);return 0;
}
相對應的實現圖像的解碼或解壓縮也有兩套接口,一套是libjpeg的,即頭文件為jpeglib.h,一套是turbojpeg的,即頭文件為turbojpeg.h。測試代碼如下:
#include <string>
#include <memory>#include "funset.hpp"
#include <opencv2/opencv.hpp>int test_libjpeg_turbo_decompress()
{
#ifdef _MSC_VERstd::string image_path{ "E:/GitCode/OCR_Test/test_data/" };
#elsestd::string image_path{ "test_data/" };
#endifstd::string image_name = image_path + "tirg.jpg";int width, height, channels;long long t1 = Timer::getNowTime();std::unique_ptr<unsigned char[]> data = get_jpeg_decompress_data(image_name.c_str(), width, height, channels);long long t2 = Timer::getNowTime();if (data == nullptr) {fprintf(stderr, "fail to decompress: %s\n", image_name.c_str());return -1;}fprintf(stdout, "decompress time 1: %lldms, width: %d, height: %d, channels: %d\n", t2 - t1, width, height, channels);std::string result_image = image_path + "result_tirg.png";cv::Mat mat(height, width, CV_8UC3, data.get());cv::cvtColor(mat, mat, CV_RGB2BGR);cv::imwrite(result_image, mat); // save *.jpg will crash in linuxint width2, height2, channels2;t1 = Timer::getNowTime();std::unique_ptr<unsigned char[]> data2 = get_jpeg_decompress_data2(image_name.c_str(), width2, height2, channels2);t2 = Timer::getNowTime();if (data2 == nullptr) {fprintf(stderr, "fail to decompress: %s\n", image_name.c_str());return -1;}fprintf(stdout, "decompress time 2: %lldms, width2: %d, height2: %d, channels2: %d\n", t2 - t1, width2, height2, channels2);std::string result_image2 = image_path + "result_tirg2.png";cv::Mat mat2(height2, width2, CV_8UC3, data2.get());cv::cvtColor(mat2, mat2, CV_RGB2BGR);cv::imwrite(result_image2, mat2);return 0;
}std::unique_ptr<unsigned char[]> get_jpeg_decompress_data2(const char* image_name, int& width, int& height, int& channels)
{FILE* infile = fopen(image_name, "rb");if (infile == nullptr) {fprintf(stderr, "can't open %s\n", image_name);return nullptr;}fseek(infile, 0, SEEK_END);unsigned long srcSize = ftell(infile);std::unique_ptr<unsigned char[]> srcBuf(new unsigned char[srcSize]);fseek(infile, 0, SEEK_SET);fread(srcBuf.get(), srcSize, 1, infile);fclose(infile);tjhandle handle = tjInitDecompress();int subsamp, cs;int ret = tjDecompressHeader3(handle, srcBuf.get(), srcSize, &width, &height, &subsamp, &cs);if (cs == TJCS_GRAY) channels = 1;else channels = 3;int pf = TJCS_RGB;int ps = tjPixelSize[pf];std::unique_ptr<unsigned char[]> data(new unsigned char[width * height * channels]);ret = tjDecompress2(handle, srcBuf.get(), srcSize, data.get(), width, width * channels, height, TJPF_RGB, TJFLAG_NOREALLOC);tjDestroy(handle);return data;
}std::unique_ptr<unsigned char[]> get_jpeg_decompress_data(const char* image_name, int& width, int& height, int& channels)
{FILE* infile = fopen(image_name, "rb");if (infile == nullptr) {fprintf(stderr, "can't open %s\n", image_name);return nullptr;}struct jpeg_decompress_struct cinfo;struct jpeg_error_mgr jerr;/* Step 1: allocate and initialize JPEG decompression object */cinfo.err = jpeg_std_error(&jerr);jpeg_create_decompress(&cinfo);/* Step 2: specify data source (eg, a file) */jpeg_stdio_src(&cinfo, infile);/* Step 3: read file parameters with jpeg_read_header() */jpeg_read_header(&cinfo, TRUE);/* Step 4: set parameters for decompression *//* Step 5: Start decompressor */jpeg_start_decompress(&cinfo);cinfo.out_color_space = JCS_RGB; //JCS_EXT_BGR;int row_stride = cinfo.output_width * cinfo.output_components;/* Output row buffer */JSAMPARRAY buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr)&cinfo, JPOOL_IMAGE, row_stride, 1);width = cinfo.output_width;height = cinfo.output_height;channels = cinfo.output_components;std::unique_ptr<unsigned char[]> data(new unsigned char[width * height * channels]);/* Step 6: while (scan lines remain to be read) */for (int j = 0; j < cinfo.output_height; ++j) {jpeg_read_scanlines(&cinfo, buffer, 1);unsigned char* p = data.get() + j * row_stride;memcpy(p, buffer[0], row_stride);}/* Step 7: Finish decompression */jpeg_finish_decompress(&cinfo);/* Step 8: Release JPEG decompression object */jpeg_destroy_decompress(&cinfo);fclose(infile);return data;
}
執行結果如下:對于小圖來說,兩套接口執行時間上差不多,對于400*330*3的圖像,兩種方式都大約在3ms至5ms之間;對于大圖來說,反復測試多次,大多數turbojpeg.h的接口要比jpeglib.h的接口耗時更少一些。而且turbojpeg.h的實現要不jpeglib.h代碼量更少一些。因此推薦直接使用turbojpeg.h中的接口。
GitHub:https://github.com//fengbingchun/OCR_Test
總結
以上是生活随笔為你收集整理的通过libjpeg-turbo实现对jpeg图像的解码的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 通过Windows DShow获取设备名
- 下一篇: Linux下通过v4l2获取视频设备名、