libjpeg-turbo介绍及测试代码
很多年之前在https://blog.csdn.net/fengbingchun/article/details/10171583 中簡單介紹過libjpeg-turbo的安裝,因為libjpeg-turbo一直在維護更新,較之前有了些變化,這里再次整理下,并增加更多的測試代碼。
libjpeg-turbo的主頁為https://libjpeg-turbo.org/ ,GitHub地址為https://github.com/libjpeg-turbo/libjpeg-turbo ,最新分布版本為2.0.2。
libjpeg-turbo是一個JPEG圖像編解碼器,它使用SIMD指令(MMX, SSE2, AVX2, NEON, AltiVec)來加速x86, x86-64, ARM和PowerPC系統上baseline JPEG壓縮和解壓縮,在x86和x86-64系統上還支持漸進式(progressive) JPEG壓縮。它的速度一般是libjpeg的2至6倍。在許多情況下,libjpeg-turbo的性能可以與專有的高速JPEG編解碼器相媲美。
libjpeg-turbo既實現了傳統的libjpeg API功能也有一些更直接但less powerful的TurboJPEG API。libjpeg-turbo還具有顏色空間擴展的特性,允許它壓縮/解壓縮到32位和大端(big-endian) 像素緩沖區(RGBX, XBGR等)。libjpeg-turbo也提供了功能齊全的Java接口。
因為libjpeg-turbo中有很多匯編文件,因此需要編譯器支持匯編編譯:
1. 在windows下通過vs編譯:
可以從https://www.nasm.us/ 中下載最新的NASM穩定版2.14.02,即nasm-2.14.02-installer-x64.exe,這里下載安裝的是64位的,也有對應32位的,安裝到D:\ProgramFiles\NASM目錄下,并將D:\ProgramFiles\NASM添加到系統環境變量中。將此目錄下的nasm.exe和ndisasm.exe拷貝到C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin中,即對應的vs版本是vs2013。
從https://www.codeproject.com/Articles/410776/Integrating-a-compiler-assembler-in-VS-Using-NASM 點擊下載” Download Property,Target,XML file - 3.8 KB”,即Target_Files_Collection.zip,解壓縮,然后將解壓后產生的3個文件nasm.props, nasm.targets, nasm.xml拷貝到C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V120\BuildCustomizations目錄下,此目錄下也有對應的masm的三個文件,masm.props, masm.targets, masm.xml。此3個配置文件用于控制自定義生成規則。
配置好后,打開任意一個工程:點擊右鍵 --> 生成依賴項(B) --> 生成自定義(B),可找到nasm(.targets),勾選nasm(.targets)。再右鍵 --> 屬性后,會發現多了一項Netwide Assmbler,如下圖所示:
新建一個空工程libjpeg-turbo,用于生成靜態庫,但是將匯編文件加入到該工程中一直有問題,因此先將通過CMake生成工程turbojpeg-static編譯生成的靜態庫用于測試。
2. 在Linux下通過GCC編譯:
首先在ubuntu上安裝nasm,有兩種方式,一種是從https://www.nasm.us/pub/nasm/releasebuilds/2.14.02/ 下載nasm-2.14.02.zip通過源碼安裝,一種是直接通過執行”sudo apt-get install nasm”來安裝。
build.sh內容如下:
#! /bin/bashreal_path=$(realpath $0)
dir_name=`dirname "${real_path}"`
echo "real_path: ${real_path}, dir_name: ${dir_name}"data_dir="test_data"
if [ -d ${dir_name}/${data_dir} ]; thenrm -rf ${dir_name}/${data_dir}
filn -s ${dir_name}/./../../${data_dir} ${dir_name}new_dir_name=${dir_name}/build
mkdir -p ${new_dir_name}
cd ${new_dir_name}
echo "pos: ${new_dir_name}"
if [ "$(ls -A ${new_dir_name})" ]; thenecho "directory is not empty: ${new_dir_name}"rm -r *
elseecho "directory is empty: ${new_dir_name}"
fi# build libjpeg-turbo
libjpeg_turbo_path=${dir_name}/../../src/libjpeg-turbo
cd ${libjpeg_turbo_path}
mkdir build
cd build
cmake ..
make
ln -s ${libjpeg_turbo_path}/build/libturbojpeg.a ${new_dir_name}cd -cd ${new_dir_name}
cmake ..
makecd -
CMakeList.txt內容如下:
PROJECT(Libjpeg-turbo_Test)
CMAKE_MINIMUM_REQUIRED(VERSION 3.0)# support C++11
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
# support C++14, when gcc version > 5.1, use -std=c++14 instead of c++1y
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++1y")SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -O2")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -O2")MESSAGE(STATUS "project source dir: ${PROJECT_SOURCE_DIR}")
SET(PATH_TEST_FILES ${PROJECT_SOURCE_DIR}/./../../demo/Libjpeg-turbo_Test)
SET(PATH_SRC_LIBJPEG_TURBO_FILES ${PROJECT_SOURCE_DIR}/./../../src/libjpeg-turbo)
MESSAGE(STATUS "path libjpeg-turbo src files: ${PATH_SRC_LIBJPEG_TURBO_FILES}")SET(PATH_OPENCV /opt/opencv3.4.2)
IF(EXISTS ${PATH_OPENCV})MESSAGE(STATUS "Found OpenCV: ${PATH_OPENCV}")
ELSE()MESSAGE(FATAL_ERROR "Can not find OpenCV in ${PATH_OPENCV}")
ENDIF()# head file search path
INCLUDE_DIRECTORIES(${PATH_TEST_FILES}${PATH_SRC_LIBJPEG_TURBO_FILES}${PATH_SRC_LIBJPEG_TURBO_FILES}/build${PATH_OPENCV}/include
)# find opencv library
FIND_LIBRARY(opencv_core NAMES opencv_core PATHS ${PATH_OPENCV}/lib NO_DEFAULT_PATH)
FIND_LIBRARY(opencv_imgproc NAMES opencv_imgproc PATHS ${PATH_OPENCV}/lib NO_DEFAULT_PATH)
FIND_LIBRARY(opencv_highgui NAMES opencv_highgui PATHS ${PATH_OPENCV}/lib NO_DEFAULT_PATH)
FIND_LIBRARY(opencv_imgcodecs NAMES opencv_imgcodecs PATHS ${PATH_OPENCV}/lib NO_DEFAULT_PATH)
FIND_LIBRARY(opencv_video NAMES opencv_video PATHS ${PATH_OPENCV}/lib NO_DEFAULT_PATH)
FIND_LIBRARY(opencv_videoio NAMES opencv_videoio PATHS ${PATH_OPENCV}/lib NO_DEFAULT_PATH)
FIND_LIBRARY(opencv_objdetect NAMES opencv_objdetect PATHS ${PATH_OPENCV}/lib NO_DEFAULT_PATH)
FIND_LIBRARY(opencv_ml NAMES opencv_ml PATHS ${PATH_OPENCV}/lib NO_DEFAULT_PATH)
MESSAGE(STATUS "opencv libraries: ${opencv_core} ${opencv_imgproc} ${opencv_highgui} ${opencv_imgcodecs} ${opencv_video}" ${opencv_videoio} ${opencv_objdetect} ${opencv_ml})# recursive query match files :*.cpp
FILE(GLOB_RECURSE TEST_CPP_LIST ${PATH_TEST_FILES}/*.cpp)# find library
FIND_LIBRARY(libturbojpeg NAMES turbojpeg PATHS ${PROJECT_SOURCE_DIR}/build NO_DEFAULT_PATH)
MESSAGE(STATUS "image libraries: ${libturbojpeg}")# build executable program
ADD_EXECUTABLE(Libjpeg-turbo_Test ${TEST_CPP_LIST})# add dependent library: static and dynamic
TARGET_LINK_LIBRARIES(Libjpeg-turbo_Test ${libturbojpeg} ${opencv_ml} ${opencv_core} ${opencv_imgproc} ${opencv_highgui} ${opencv_imgcodecs} ${opencv_video} ${opencv_videoio} ${opencv_objdetect} pthread)
測試代碼如下:
#include <string>
#include <memory>#include "funset.hpp"
#include <opencv2/opencv.hpp>int parse_jpeg_file(const char* name)
{FILE* infile = nullptr;if ((infile = fopen(name, "rb")) == nullptr) {fprintf(stderr, "can't open %s\n", name);return -1;}struct jpeg_decompress_struct cinfo;struct jpeg_error_mgr jerr;cinfo.err = jpeg_std_error(&jerr);/* Now we can initialize the JPEG decompression object. */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);fprintf(stdout, "image_width = %d\n", cinfo.image_width);fprintf(stdout, "image_height = %d\n", cinfo.image_height);fprintf(stdout, "num_components = %d\n", cinfo.num_components);/* Step 4: set parameters for decompression */cinfo.scale_num = 2;cinfo.scale_denom = 4;/* Step 5: Start decompressor */jpeg_start_decompress(&cinfo);fprintf(stdout, "output_width = %d\n", cinfo.output_width);fprintf(stdout, "output_height = %d\n", cinfo.output_height);fprintf(stdout, "output_components = %d\n", cinfo.output_components);/* JSAMPLEs per row in output buffer */int row_stride = cinfo.output_width * cinfo.output_components;/* Make a one-row-high sample array that will go away when done with image */JSAMPARRAY buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr)&cinfo, JPOOL_IMAGE, row_stride, 1);/* Step 6: while (scan lines remain to be read) */while (cinfo.output_scanline < cinfo.output_height) {jpeg_read_scanlines(&cinfo, buffer, 1);}/* Step 7: Finish decompression */jpeg_finish_decompress(&cinfo);/* Step 8: Release JPEG decompression object */jpeg_destroy_decompress(&cinfo);fclose(infile);return 0;
}int write_jpeg_file(const unsigned char* data, int width, int height, int channels, J_COLOR_SPACE color_space, int quality, const char* name)
{/* Step 1: allocate and initialize JPEG compression object */struct jpeg_compress_struct cinfo;struct jpeg_error_mgr jerr;cinfo.err = jpeg_std_error(&jerr);/* Now we can initialize the JPEG compression object. */jpeg_create_compress(&cinfo);/* Step 2: specify data destination (eg, a file) */FILE* outfile = nullptr;if ((outfile = fopen(name, "wb")) == nullptr) {fprintf(stderr, "can't open file: %s\n", name);return -1;}jpeg_stdio_dest(&cinfo, outfile);/* Step 3: set parameters for compression */cinfo.image_width = width;cinfo.image_height = height;cinfo.input_components = channels;cinfo.in_color_space = color_space;jpeg_set_defaults(&cinfo);jpeg_set_quality(&cinfo, quality, TRUE);/* Step 4: Start compressor */jpeg_start_compress(&cinfo, TRUE);/* Step 5: while (scan lines remain to be written) */int row_stride = width * channels;int line = 0;JSAMPROW row_pointer[1];while (line < cinfo.image_height) {row_pointer[0] = (JSAMPROW)&data[line * row_stride];jpeg_write_scanlines(&cinfo, row_pointer, 1);++line;}/* Step 6: Finish compression */jpeg_finish_compress(&cinfo);fclose(outfile);/* Step 7: release JPEG compression object */jpeg_destroy_compress(&cinfo);return 0;
}int get_jpeg_compress_data(const unsigned char* data, int width, int height, int channels, J_COLOR_SPACE color_space, int quality, unsigned char** out_buffer, unsigned long out_buffer_size, unsigned long& free_in_buffer)
{/* Step 1: allocate and initialize JPEG compression object */struct jpeg_compress_struct cinfo;struct jpeg_error_mgr jerr;cinfo.err = jpeg_std_error(&jerr);/* Now we can initialize the JPEG compression object. */jpeg_create_compress(&cinfo);/* Step 2: specify data destination (eg, a file) */jpeg_mem_dest(&cinfo, out_buffer, &out_buffer_size);/* Step 3: set parameters for compression */cinfo.image_width = width;cinfo.image_height = height;cinfo.input_components = channels;cinfo.in_color_space = color_space;jpeg_set_defaults(&cinfo);jpeg_set_quality(&cinfo, quality, TRUE);/* Step 4: Start compressor */jpeg_start_compress(&cinfo, TRUE);/* Step 5: while (scan lines remain to be written) */int row_stride = width * channels;int line = 0;JSAMPROW row_pointer[1];while (line < cinfo.image_height) {row_pointer[0] = (JSAMPROW)&data[line * row_stride];jpeg_write_scanlines(&cinfo, row_pointer, 1);++line;}/* Step 6: Finish compression */jpeg_finish_compress(&cinfo);free_in_buffer = cinfo.dest->free_in_buffer;/* Step 7: release JPEG compression object */jpeg_destroy_compress(&cinfo);return 0;
}int test_libjpeg_turbo()
{
#ifdef _MSC_VERstd::string image_path{ "E:/GitCode/OCR_Test/test_data/" };
#elsestd::string image_path{ "test_data/" };
#endifstd::string name1 = image_path + "tirg.jpg";parse_jpeg_file(name1.c_str());std::string name2 = image_path + "lena.png";std::string name3 = image_path + "lena.jpg";int quality = 80;cv::Mat mat = cv::imread(name2);if (!mat.data || mat.channels() != 3) {fprintf(stderr, "read image fail: %s\n", name2.c_str());return -1;}write_jpeg_file(mat.data, mat.cols, mat.rows, mat.channels(), JCS_EXT_BGR, quality, name3.c_str()); // bgr dataname3 = image_path + "lena2.jpg";cv::cvtColor(mat, mat, CV_BGR2RGB);write_jpeg_file(mat.data, mat.cols, mat.rows, mat.channels(), JCS_RGB, quality, name3.c_str()); // rgb dataname3 = image_path + "lena3.jpg";cv::cvtColor(mat, mat, CV_RGB2GRAY);write_jpeg_file(mat.data, mat.cols, mat.rows, mat.channels(), JCS_GRAYSCALE, quality, name3.c_str()); // gray dataint length = mat.cols * mat.rows;std::unique_ptr<unsigned char[]> data(new unsigned char[length]);unsigned char* p = data.get();unsigned long free_in_buffer;get_jpeg_compress_data(mat.data, mat.cols, mat.rows, mat.channels(), JCS_GRAYSCALE, quality, &p, length, free_in_buffer);name3 = image_path + "lena4.jpg";FILE* outfile = nullptr;if ((outfile = fopen(name3.c_str(), "wb")) == nullptr) {fprintf(stderr, "can't open file: %s\n", name3.c_str());return -1;}fwrite(data.get(), sizeof(unsigned char), length - free_in_buffer, outfile);fclose(outfile);return 0;
}
執行結果如下:
GitHub:?https://github.com/fengbingchun/OCR_Test?
總結
以上是生活随笔為你收集整理的libjpeg-turbo介绍及测试代码的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 程序员的自我修养--链接、装载与库笔记:
- 下一篇: 通过Python在Windows或Lin