我的上一篇博客《openjpeg:jpeg2000(j2k)图像内存压缩编码》详细讲述了调用openjpeg实现jpeg2000(j2k)图像的内存压缩过程。本文讲述如何调用openjpeg来将jpeg2000格式的内存图像数据解码。

因为有了《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, &parameters)) {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 NDEBUGprintf("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(&parameters);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_exceptiontry{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;
}

完整代码

完整代码参见gitee仓库:

https://gitee.com/l0km/jpegwrapper

openjpeg:jpeg2000(j2k)图像内存解压缩(解码)相关推荐

  1. openjpeg:jpeg2000(j2k)图像内存压缩编码

    上一篇博文实现了<jpeg2000(j2k)图像编码解码:c++实现openjpeg内存流接口(memory stream)>中实现了openjpeg的memory stream接口,本文 ...

  2. CImg:插件(plugin)使用说明塈实现JPEG图像内存编码/解码

    杀鸡用牛刀? 如果你想对图像进行简单处理,你一般会想到用什么?可能多数人想到的是OpenCV. 对,OpenCV是个非常强大的图像视觉工具库,用途非常广泛.简单的图像处理用它肯定是可以的. 但Open ...

  3. jpeg2000(j2k)图像编码解码:c++实现openjpeg内存流接口(memory stream)

    前阵子用libjpeg-turbo实现jpeg图像在内存中编码与解码 参见<libjpeg:实现jpeg内存解压缩塈转换色彩空间/压缩分辨率>,<libjpeg:实现jpeg内存压缩 ...

  4. GDAL读取Jpeg2000格式图像

    JPEG-2000标准支持无损和有损压缩,并且支持单图像分量(如灰度图像)和多图像分量(如彩色图像).除了基本的图像压缩功能外,还支持其他的功能:1)对图像进行按精度或者按分辨率来渐进显示.2)感兴趣 ...

  5. 中科大的AI图像/视频编解码综述

    [前言] 长论文ptsd犯病了,这次是一篇35页的AI编解码器的综述,犯病了犯病了. 首先还是保命时刻,以下解读与见解均为我的个人理解,要是我有哪里曲解了,造成了不必要的麻烦,可以联系我删除文章,也可 ...

  6. h.264参考图像列表、解码图像缓存

    1.参考图像列表(reference picture list) 一般来说,h.264会把需要编码的图像分为三种类型:I.P.B,其中的B.P类型的图像由于采用了帧间编码的这种编码方式,而帧间编码又是 ...

  7. 多媒体技术与应用之图像Huffman编解码

    多媒体技术与应用之图像Huffman编解码 一.实验内容 1.了解BMP图像的格式,实现BMP图片格式的数据域及文件头的分离 2.熟悉Huffman编码原理 3.使用Huffman编码算法对给定图像文 ...

  8. 图像深度和图像内存的计算

    图像深度和图像内存的计算 1.图像的深度 对于单通道图像,图像深度表示图像能够显示的最大的图像的灰度的级数:对于三通道图像,图像深度表示图像颜色的种类数: 用位来表示: 例如对于一个三通道图像,图像深 ...

  9. JPEG图像的解压缩操作

    一.解压缩操作过程 为JPEG对象分配空间并初始化 指定解压缩数据源 获取文件信息 为解压缩设定参数,包括图像大小,颜色空间 开始解压缩 取出数据 解压缩完毕 释放资源 1.1 为JPEG对象分配空间 ...

最新文章

  1. private 的访问权限
  2. 拉格朗日乘子法(Lagrange Multiplier)和KKT条件
  3. stm32 不断的重新启动的原因
  4. pheonix从入门到进阶
  5. ActionScript3学习笔记2-包
  6. VC编辑框(EDIT)的自动换行、自动滚屏 、到指定行数自动清空
  7. P1547 Out of Hay
  8. c 高级语言,C作为高级语言?
  9. python打乱列表的方法_python打乱列表
  10. PHP 根据年月返回这个月的第一天时间戳和这个月的最后一天时间戳
  11. 20155338《网络对抗》Web安全基础实践
  12. python给一个不多于5位的正整数 要求_python作业题2 给一个不多于5位的正整数,要求:一、求它是几位数,二、逆序打印出各位数字。...
  13. 2020-02-27
  14. c语言烟花表白程序代码,表白神器-七彩烟花源码
  15. c语言试题库 文库,C语言试题库
  16. STM8系列芯使用STVP烧写程序设定读保护和如何解除读保护操作
  17. jvm-垃圾回收(垃圾收集器)
  18. Accelerate Activity Tracker隐私政策
  19. 网站建设服务器拼租服务器好还是独立服务器好
  20. 移动硬盘不被系统识别的处理

热门文章

  1. JiaoZiVideoPlayer饺子视频播放器
  2. AutoCAD 定义 AutoLISP 函数
  3. 工商银行 U盾 -100003 数据签名错误
  4. 2020年高教社杯全国大学生数学建模竞赛赛题 C题分析与思路!(持续更新)
  5. codeblocks安装
  6. htc touch pro2 新手入门及进阶
  7. 思科 Cisco Packet Tracer 标准ACL的配置
  8. 计算机清理垃圾文件丢失怎么恢复,电脑管家清理的文件怎么恢复
  9. killall -9的危害
  10. sourceInsight4.0 安装-pojie