通过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获取视频设备名、