openjpeg:jpeg2000(j2k)图像内存解压缩(解码)
2016-02-04 19:57
543 查看
我的上一篇博客《openjpeg:jpeg2000(j2k)图像内存压缩编码》详细讲述了调用openjpeg实现jpeg2000(j2k)图像的内存压缩过程。本文讲述如何调用openjpeg来将jpeg2000格式的内存图像数据解码。
因为有了《jpeg2000(j2k)图像编码解码:c++实现openjpeg内存流接口(memory stream)》实现的内存流接口,解压缩过程相对就比较简单了。
以下是jpeg2000内存解码的实现代码
代码中用到的
上面代码将内存图像解码返回解压后的
代码实现参考了openjpeg的源码
调用样例
因为有了《jpeg2000(j2k)图像编码解码:c++实现openjpeg内存流接口(memory stream)》实现的内存流接口,解压缩过程相对就比较简单了。
以下是jpeg2000内存解码的实现代码
代码中用到的
opj_stream_interface,
opj_stream_mem_input都在《jpeg2000(j2k)图像编码解码:c++实现openjpeg内存流接口(memory stream)》一文中实现。
raii_var,
raii对象在更早的《C++11实现模板化(通用化)RAII机制》文中实现。
info_callback,
warning_callback,
error_callback这三个用于解码过程中错误处理的函数在也在《openjpeg:jpeg2000(j2k)图像内存压缩编码》中有实现
// 表达式判断为true抛出invalid_argument异常 #define throw_if(expression,msg) \ if(expression)\ throw std::invalid_argument(std::string(__FILE__).append(" line:" + __LINE__).append(msg)); // 表达式判断为true抛出指定的except异常 #define throw_except_if(except,expression,msg) \ if(expression)\ throw except(std::string(__FILE__).append(" line:" + __LINE__).append(msg)); #define throw_except_if_null(except,p) throw_except_if(except,nullptr==p,#p" is null") #define throw_if_null(p) throw_if(nullptr==p,#p" is null") /* 从流对象(opj_stream_interface)中根据parameters提供的解码参数解码jpeg2000图像 * 返回 opj_image_t,出错则抛出opj_exception异常 */ opj_image_t* load_j2k(opj_stream_interface& src, opj_dparameters_t& parameters) { opj_image_t* image = nullptr; /* Handle to a image */ opj_codec_t* l_codec = nullptr; /* Handle to a decompressor */ // 创建stream对象 auto l_stream = opj_stream_create_default_si(src); /* Stream */ auto decompress_ok = false; // RAII资源对象,对象析构时自动释放资源 gdface::raii guard([&]() { /* close and free the byte stream */ opj_stream_destroy(l_stream); /* free remaining compression structures */ opj_destroy_codec(l_codec); if (!decompress_ok) { opj_image_destroy(image); image = nullptr; } }); /* decode the JPEG2000 stream */ /* ---------------------- */ switch (parameters.decod_format) { case OPJ_CODEC_J2K: /* JPEG-2000 codestream */ case OPJ_CODEC_JP2: /* JPEG 2000 compressed image data */ case OPJ_CODEC_JPT: /* JPEG 2000, JPIP */ { /* Get a decoder handle */ l_codec = opj_create_decompress((OPJ_CODEC_FORMAT) parameters.decod_format); break; } default: throw opj_exception(string(__FILE__).append(" line:" + __LINE__).append("invalid decod_format")); } /* 设信息/警告/错误处理函数 */ 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_dparameters_t参数对象设置解码器的解码参数 */ if (!opj_setup_decoder(l_codec, ¶meters)) { throw opj_exception("ERROR -> opj_compress: failed to setup the decoder"); } /* 读取图像格式头的基本信息*/ if (!opj_read_header(l_stream, l_codec, &image)) { throw opj_exception("ERROR -> opj_decompress: failed to read the header"); } if (!parameters.nb_tile_to_decode) { /* Optional if you want decode the entire image */ if (!opj_set_decode_area(l_codec, image, (OPJ_INT32) (parameters.DA_x0), (OPJ_INT32) (parameters.DA_y0), (OPJ_INT32) (parameters.DA_x1), (OPJ_INT32) (parameters.DA_y1))) throw opj_exception("ERROR -> opj_decompress: failed to set the decoded area"); /* Get the decoded image */ if (!(opj_decode(l_codec, l_stream, image) && opj_end_decompress(l_codec, l_stream))) throw opj_exception("ERROR -> opj_decompress: failed to decode image!"); } else { if (!opj_get_decoded_tile(l_codec, l_stream, image, parameters.tile_index)) throw opj_exception("ERROR -> opj_decompress: failed to decode tile!"); #ifndef NDEBUG printf("tile %d is decoded!\n", parameters.tile_index); #endif } decompress_ok = true; return image; } /* 从流对象(opj_stream_interface)中解码指定格式(format)的jpeg2000图像 * 返回 opj_image_t,出错则抛出opj_exception异常 */ opj_image_t* load_j2k(opj_stream_interface& src, OPJ_CODEC_FORMAT format) { opj_dparameters_t parameters; /* set decoding parameters to default values */ opj_set_default_decoder_parameters(¶meters); parameters.decod_format = format; return load_j2k(src, parameters); }
上面代码将内存图像解码返回解压后的
opj_image_t对象,
opj_image_t对象是按颜色通道存储每个像素的数据的,所以需要每像素颜色通道值连续存储,还需要做一些转换下面的代码将
opj_image_t转换为
image_matrix_param,
image_matrix_param中每个像素的各通道连续存储
/* 图像矩阵基本参数 */ typedef struct _image_matrix_param{ uint32_t width; // 图像宽度 uint32_t height; // 图像高度 uint8_t channels; // 通道数 J_COLOR_SPACE color_space; // 图像数据的色彩空间 uint8_t align; // 内存对齐方式 0为不对齐,>0为以2的n次幂对齐 std::vector <uint8_t> pixels; // 图像数据 }image_matrix_param,*image_matrix_param_ptr; inline uint32_t get_row_stride(const image_matrix_param&matrix){ return matrix.align?(matrix.width+(1 << matrix.align)-1)>>matrix.align<<matrix.align:matrix.width; } /* 从opj_image_t 创建 image_matrix_param * 失败则抛出 opj_exception 异常 */ image_matrix_param create_matrix_from_opj_image(opj_image_t* image) { throw_if_null(image); image_matrix_param matrix; throw_if(0 == image->numcomps, "image->numcomps must >0"); matrix.width = image->comps[0].w; matrix.height = image->comps[0].h; // 检查参数合法性 if (image->numcomps > 1) for (auto i = image->numcomps - 1; i > 0; --i) { throw_except_if(opj_exception,matrix.width != image->comps[i].w || matrix.height != image->comps[i].h||image->comps[i].prec>8||image->comps[i].bpp>8, "each components has different size"); } matrix.channels = (uint8_t) (image->numcomps); matrix.color_space = opj_to_jpeglib_color_space(image->color_space); matrix.align = 0; auto row_stride = get_row_stride(matrix); // 为image_matrix_param分配图像存储空间,失败则抛出opj_exception try{ matrix.pixels = std::vector<uint8_t>(row_stride * matrix.channels * matrix.height); }catch(exception &e){ throw opj_exception(string(__FILE__).append(" line:" + __LINE__).append(e.what())); }catch(...){ throw opj_exception(string(__FILE__).append(" line:" + __LINE__).append("fail to constructe std::vector")); } uint32_t index = 0; uint8_t* scanline,*pixel; decltype(matrix.height) y; decltype(matrix.width) x; decltype(matrix.channels) ch; for ( y = 0; y < matrix.height; ++y ) { scanline = matrix.pixels.data()+ matrix.channels * row_stride * y; for ( x = 0; x < matrix.height; ++x ) { pixel = scanline+matrix.channels * x; for (ch = 0; ch < matrix.channels; ++ch) { pixel[ch] = (uint8_t) (image->comps[ch].data[index]); } ++index; } } return std::move(matrix); } /* 从jpeg_data和size指定的内存数据中解码指定格式(format)的jpeg2000图像 * 返回 image_matrix_param对象,出错则抛出opj_exception异常 */ image_matrix_param load_j2k(const uint8_t* jpeg_data, size_t size, OPJ_CODEC_FORMAT format) { throw_if_null(jpeg_data) throw_if(0 == size, "jpeg_data is empty") opj_stream_mem_input src(jpeg_data, size); gdface::raii_var<opj_image_t*> raii_image([&]() { return load_j2k(src, format); }, [](opj_image_t* image) { /* free image data */ opj_image_destroy(image); }); return create_matrix_from_opj_image(*raii_image); } /* 从jpeg_data指定的内存数据中解码指定格式(format)的jpeg2000图像 * 返回 image_matrix_param对象,出错则抛出opj_exception异常 */ image_matrix_param load_j2k(const std::vector<uint8_t>&jpeg_data, OPJ_CODEC_FORMAT format){ return load_j2k(jpeg_data.data(),jpeg_data.size(),format); }
代码实现参考了openjpeg的源码
/src/bin/jp2/opj_decompress.c,部分代码是原样抄来的
调用样例
std::vector<uint8_t> load_binary_file(const char *input_jpg_file){ std::vector<uint8_t> jpeg_data; std::ifstream is (input_jpg_file, std::ifstream::binary); 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(); } return std::move(jpeg_data); } int main() { try { const char *output4_jpg_file = "D:/tmp/sample-1-out4.j2k"; auto j2k_data=load_binary_file(output4_jpg_file); load_j2k(j2k_data,OPJ_CODEC_J2K); }catch (exception &e){ cout<<e.what()<<endl; } return 0; }
相关文章推荐
- Android jp2(jpeg2000)图片的解码显示
- libjpeg:实现jpeg内存解压缩塈转换色彩空间/压缩分辨率
- mingw(gcc)编译openjpeg
- VS2015编译openjpeg(32/64位)
- openjpeg:解决静态链接时未定义引用错误:undefined reference to `__imp_opj_xxxxxxx'
- jpeg2000(j2k)图像编码解码:c++实现openjpeg内存流接口(memory stream)
- openjpeg:jpeg2000(j2k)图像内存压缩编码
- JPEG 2000学习笔记(1)
- Huffman编码字典构造
- Elias编码
- Hello JPEG 2000
- DCMTK3.5.4支持DCM图像JPEG2000压缩解压
- 基于DCT变换的JPEG图像压缩原理
- cmake设置msvc的运行库(runtime library)塈指定openjpeg使用静态库
- zlib库内存压缩解压缩函数的C++便利性封装
- JPEG2000 小波变换
- OpenJPEG在windows 10+VS 2013下的环境配置
- WebKitGTK 2.23.90增加了对JPEG2000及更多触摸板手势的支持
- Hadoop分布式文件系统——HDFS
- weka中的options