openjpeg:jpeg2000(j2k)图像内存压缩编码
来源:互联网 发布:光大炒股软件下载 编辑:程序博客网 时间:2024/05/16 11:32
上一篇博文实现了《jpeg2000(j2k)图像编码解码:c++实现openjpeg内存流接口(memory stream)》中实现了openjpeg的memory stream接口,本文介绍如何用memory stream实现jpeg2000图像的内存压缩。
create opj_image_t
openjpeg在处理图像是有定义自己的图像描述结构opj_image_t
,如果要对内存的中的图像进行压缩,就必须首先将内存图像数据转换成opj_image_t
。opj_image_t
中每个颜色通道的数据独立存储在opj_image_t.comps
数组中。 image_matrix_param
是我在《libjpeg:实现jpeg内存解压缩塈转换色彩空间/压缩分辨率》中定义的内存图像描述结构)每个像素所有通道的颜色值连续),下面的代码就是实现从image_matrix_param
创建一个opj_image_t
对象(代码实现参考了openjpeg/src/bin/jp2/convert.c中的bmptoimage
函数)
/* openjpeg编码解码异常类 */class opj_exception:public std::logic_error{public: // 继承基类构造函数 using std::logic_error::logic_error;};/* 从image_matrix_param创建 opj_image_t * 失败则抛出 opj_exception 异常 */opj_image_t* opj_image_create_from_matrix(const image_matrix_param& matrix, opj_cparameters_t* parameters) { if(nullptr==parameters) throw std::invalid_argument(string(__FILE__).append(" line:" + __LINE__).append("parameters is null")); auto subsampling_dx = parameters->subsampling_dx; auto subsampling_dy = parameters->subsampling_dy; auto color_space = jpeglib_to_opj_color_space(matrix.color_space); opj_image_cmptparm_t cmptparm[4]; /* maximum of 4 components */ opj_image_t * image = nullptr; /* initialize image components */ if(matrix.channels>4||0==matrix.channels) throw std::invalid_argument(string(__FILE__).append(" line:" + __LINE__).append("matrix.channels must be 1/2/3/4")); memset(cmptparm, 0, matrix.channels * sizeof(opj_image_cmptparm_t)); for (auto i = matrix.channels; i >0; --i) { cmptparm[i-1].prec = 8; cmptparm[i-1].bpp = 8; cmptparm[i-1].sgnd = 0; cmptparm[i-1].dx = (OPJ_UINT32) (subsampling_dx); cmptparm[i-1].dy = (OPJ_UINT32) (subsampling_dy); cmptparm[i-1].w = (OPJ_UINT32) (matrix.width); cmptparm[i-1].h = (OPJ_UINT32) (matrix.height); } /* create the image */ if (nullptr == (image = opj_image_create((OPJ_UINT32) (matrix.channels), cmptparm, color_space))) throw opj_exception("failed to create image: opj_image_create\n"); /* set image offset and reference grid */ image->x0 = (OPJ_UINT32) (parameters->image_offset_x0); image->y0 = (OPJ_UINT32) (parameters->image_offset_y0); image->x1 = image->x0 + (OPJ_UINT32) ((matrix.width - 1)) * (OPJ_UINT32) (subsampling_dx) + 1; image->y1 = image->y0 + (OPJ_UINT32) ((matrix.height - 1)) * (OPJ_UINT32) (subsampling_dy) + 1; auto index = 0; uint8_t*scanline,*pixel; decltype(matrix.height) y; decltype(matrix.width) x; decltype(matrix.channels) ch; auto row_stride=get_row_stride(matrix); //将image_matrix_param中按像素连续存储的通道数据依照opj_image_t的格式拆开到不同的comps中 for (y = 0; y <matrix.height; ++y) { scanline = const_cast<uint8_t*>(matrix.pixels.data())+ matrix.channels * row_stride * y; for (x = 0; x <matrix.width ; ++x) { pixel = scanline+matrix.channels * x; for (ch = 0; ch < matrix.channels; ++ch) { //image->comps[ch].data[index] = pixel[matrix.channels - ch]; image->comps[ch].data[index] = (OPJ_INT32)pixel[ch]; } ++index; } } return image;}
save_j2k
下面的代码将一个opj_image_t对象的图像数据压缩成jpeg2000格式输出到指定的opj_stream_interface对象
/** error callback expecting a FILE* client object */void error_callback(const char* msg, void* client_data) {// (void) (client_data); fprintf(stdout, "[ERROR] %s", msg); throw opj_exception(msg);}/** warning callback expecting a FILE* client object */void warning_callback(const char* msg, void* client_data) {// (void) (client_data); fprintf(stdout, "[WARNING] %s", msg);}/** debug callback expecting no client object */void info_callback(const char* msg, void* client_data) {#ifndef NDEBUG// (void) (client_data); fprintf(stdout, "[INFO] %s", msg);#endif}// 将opj_image_t对象的图像数据压缩成jpeg2000格式输出到opj_stream_interface对象void save_j2k(opj_image_t* image, opj_cparameters_t *parameters ,opj_stream_interface& dest) { if(nullptr==image) throw std::invalid_argument(string(__FILE__).append(" line:" + __LINE__).append("image is null")); if(nullptr==parameters) throw std::invalid_argument(string(__FILE__).append(" line:" + __LINE__).append("parameters is null")); bool set_comment = false; /* Create comment for codestream */ if (nullptr == parameters->cp_comment) { const char comment[] = "Created by OpenJPEG version "; const size_t clen = strlen(comment); const char* version = opj_version(); parameters->cp_comment = (char*) (malloc(clen + strlen(version) + 1)); sprintf(parameters->cp_comment, "%s%s", comment, version); set_comment = true; } opj_codec_t* l_codec = opj_create_compress((CODEC_FORMAT)parameters->cod_format); /* catch events using our callbacks and give a local context */ opj_set_info_handler(l_codec, info_callback, 00); opj_set_warning_handler(l_codec, warning_callback, 00); opj_set_error_handler(l_codec, error_callback, 00); opj_setup_encoder(l_codec, parameters, image); opj_stream_t* l_stream = opj_stream_create_default_si(dest); gdface::raii guard([&]() { /* close and free the byte stream */ opj_stream_destroy(l_stream); /* free remaining compression structures */ opj_destroy_codec(l_codec); if (set_comment) free(parameters->cp_comment); }); /* encode the image */ if (!opj_start_compress(l_codec, image, l_stream)) throw opj_exception("failed to encode image: opj_start_compress"); if (!opj_encode(l_codec, l_stream)) throw opj_exception("failed to encode image: opj_encode"); if (!opj_end_compress(l_codec, l_stream)) throw opj_exception("failed to encode image: opj_end_compress");}// 将一个image_matrix_param数据压缩成jpeg2000格式输出到opj_stream_interface对象// 默认压缩质量100// 默认压缩格式为OPJ_CODEC_JP2void save_j2k(const image_matrix_param& matrix, opj_stream_interface& dest, const unsigned int quality=100, OPJ_CODEC_FORMAT format=OPJ_CODEC_JP2) { opj_cparameters_t parameters; /* set encoding parameters to default values */ opj_set_default_encoder_parameters(¶meters); // 设置压缩图像质量参数 parameters.tcp_numlayers=1; parameters.tcp_distoratio[0]=(float)(quality>100?100:quality); parameters.cp_fixed_quality=1; parameters.cod_format=format; gdface::raii_var<opj_image_t*> raii_image([&]() { // 调用opj_image_create_from_matrix创建opj_image_t对象 return opj_image_create_from_matrix(matrix, ¶meters); }, [](opj_image_t*image) { /* free image data */ opj_image_destroy (image); }); save_j2k(*raii_image, ¶meters,dest);}// 将一个image_matrix_param数据压缩成jpeg2000格式输出到内存流对象(opj_stream_mem_output)// 默认压缩质量100// 默认压缩格式为OPJ_CODEC_JP2// 返回opj_stream_mem_output 对象opj_stream_mem_output save_j2k_mem(const image_matrix_param& matrix, const unsigned int quality=100, OPJ_CODEC_FORMAT format=OPJ_CODEC_JP2) { opj_stream_mem_output dest; save_j2k(matrix, dest,quality, format); return std::move(dest);}
sample
#include <iostream>#include <fstream>#include <string>#include <iostream>#include "j2k_mem.h"using namespace std;void save_binary_file(const char *filename,const uint8_t *img, size_t size){ std::ofstream ofs; ofs.open(filename, std::ofstream::binary); ofs.write((const char*)img, size); cout << filename << "saved,size=" << size << endl; ofs.close();}int main(){ const char *input_jpg_file = "D:/tmp/example-1.jpg"; const char *output4_jpg_file = "D:/tmp/example-1-out4.j2k"; try{ std::ifstream is (input_jpg_file, std::ifstream::binary); std::vector<uint8_t> jpeg_data; if (is) { // get length of file: is.seekg(0, is.end); auto length = is.tellg(); is.seekg(0, is.beg); jpeg_data = std::vector<uint8_t>(length); // read data as a block: is.read((char*) jpeg_data.data(), jpeg_data.size()); is.close(); } image_matrix_param mat=load_jpeg_mem(jpeg_data);// 加载一个jpeg图像 //将image_matrix_param 压缩成jp2k格式的内存数据,返opj_stream_mem_outputoutput对象 opj_stream_mem_outputoutput=save_j2k_mem(mat,35,OPJ_CODEC_J2K); // 从opj_stream_mem_outputoutput取出压缩后的图像数据保存成.j2k文件以方便查看结果 save_binary_file(output4_jpg_file,output.stream_data(),output.stream_length()); }catch (exception &e){ cout<<e.what()<<endl; }}
上面例子中保存的.j2k文件,用普通的看图软件是无法识别的,需要用支持jpeg2000格式的图片浏览器(比如XnView)才能查看压缩结果
0 0
- openjpeg:jpeg2000(j2k)图像内存压缩编码
- openjpeg:jpeg2000(j2k)图像内存解压缩(解码)
- jpeg2000(j2k)图像编码解码:c++实现openjpeg内存流接口(memory stream)
- 一个真实图像的JPEG2000压缩过程
- 《JPEG2000图像压缩基础、标准和实践》中两处错误
- 图像编码与压缩
- 图像压缩编码
- 图像压缩编码
- 图像压缩编码相关内容
- 图像压缩编码
- 图像压缩编码
- 图像压缩编码
- 图像压缩编码
- 图像压缩编码
- 图像压缩编码
- 图像压缩编码
- 图像压缩编码
- 图像压缩编码概述
- Android Studio你不知道的调试技巧
- Cc2540UART 串口透传 注意事项
- ubuntu14.04 libgtk-x11-2.0.so.0
- 使用javascript全局改变CSS样式(网页样式)
- ADB 使用
- openjpeg:jpeg2000(j2k)图像内存压缩编码
- SBT和Git 使用代理
- 如何编译nodemcu的源码?
- git 使用技巧
- 迅雷下载破解方法
- Android开发秘籍学习笔记(十四)
- 关于Map使用时的注意事项
- Linux SSH远程连接超时断开解决
- UISearchController搜索功能的简单使用