opencv Mat To Heif
高效率图像文件格式(英语:High Efficiency Image File Format, HEIF;也称高效图像文件格式)是一个用于单张图像或图像序列的文件格式。它由运动图像专家组(MPEG)开发,并在MPEG-H Part 12(ISO/IEC 23008-12)中定义。
HEIF规范也定义了高效率视频编码(HEVC)编码的内嵌图像和HEVC编码的图像序列的存储方式,其中以受约束的方式应用帧间预测。
HEIF文件与ISO基本媒体文件格式(ISOBMFF,ISO/IEC 14496-12)兼容,并且还可以包括其他媒体流,例如定时的文本和音频。
环境配置:
相关资源:https://github.com/strukturag/libheif
Windows(最简单、快捷方式,自行编译容易出错)
You can build and install libheif using the vcpkg dependency manager:
git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.bat
./vcpkg integrate install
./vcpkg install libheif
Linux/macOS(或参考上述相关资源链接)
1. Install dependencies with Homebrew
brew install cmake make pkg-config x265 libde265 libjpeg libtool
2. Configure and build project (–preset argument needs CMake >= 3.21):
mkdir build
cd build
cmake --preset=release ..
./configure
make
功能:cv::Mat 转 HEIF文件, HEIF文件转cv::Mat
```cpp
#include <libheif/heif.h>
#include <opencv2/opencv.hpp>
#include <iostream>
bool RGBMatToHeif(cv::Mat& mat, const char* filename)
{
if (mat.empty() || mat.type() != CV_8UC3)
{
std::cerr << "Invalid Mat format. Expected 8UC3." << std::endl;
return false;
}
struct heif_image* image;
struct heif_context* ctx = heif_context_alloc();
struct heif_error err;
int width = mat.cols;
int height = mat.rows;
// 创建HEIF图像
err = heif_image_create(width, height, heif_colorspace_RGB, heif_chroma_interleaved_RGB, &image);
if (err.code != heif_error_Ok)
{
std::cerr << "Error adding plane to HEIF image:" << err.message << std::endl;
heif_image_release(image);
heif_context_free(ctx);
return false;
}
// 添加一个用于交错 RGB 通道的图像平面
err = heif_image_add_plane(image, heif_channel_interleaved, width, height, 8);
if (err.code != heif_error_Ok) {
std::cerr << "Error adding plane to HEIF image: " << err.message << std::endl;
heif_image_release(image);
heif_context_free(ctx);
return false;
}
// 获取指向HEIF图像数据的指针
int stride;
uint8_t* p = heif_image_get_plane(image, heif_channel_interleaved, &stride);
// 将 cv::Mat 数据复制到 HEIF 图像中
for (int y = 0; y < height; y++) {
memcpy(p + y * stride, mat.ptr(y), width * 3); // 每行的像素数据都是 width * 3 个字节
}
//for (int y = 0; y < height; y++) {
// // 使用 size_t 来安全地计算偏移量
// size_t rowOffset = static_cast<size_t>(y) * stride;
// // 将偏移量转换为 char* 类型的指针偏移
// char* rowPtr = reinterpret_cast<char*>(p) + rowOffset;
// // 使用 memcpy 复制数据
// memcpy(rowPtr, mat.ptr<uchar>(y), width * 3); // 注意:这里假设 mat.ptr 返回 uchar*
// // 注意:如果 mat.ptr 实际上返回的是其他类型的指针(如 RGB 像素的 struct 或类),
// // 你可能需要调整 memcpy 的第三个参数来匹配实际的字节大小。
//}
创建并初始化heif_encoding_options结构体
//struct heif_encoding_options encoding_options = { 0 };
//encoding_options.version = 0;
//encoding_options.save_alpha_channel = false;
//encoding_options.image_orientation = heif_orientation_normal; // 例如:设置图像方向为正常
// 创建HEIF编码器
struct heif_encoder* encoder;
err = heif_context_get_encoder_for_format(ctx, heif_compression_HEVC, &encoder);
if (err.code != heif_error_Ok)
{
std::cerr << "Error getting HEIF encoder: " << err.message << std::endl;
heif_image_release(image);
heif_context_free(ctx);
return false;
}
heif_encoder_set_lossy_quality(encoder, 80); //0-100 压缩比例
heif_encoder_set_lossless(encoder, true); // True / False
heif_encoder_set_logging_level(encoder, 4); // log信息详细程度0-4
err = heif_context_encode_image(ctx, image, encoder, nullptr, nullptr);
if (err.code != heif_error_Ok) {
std::cerr << "Error encoding HEIF image: " << err.message << std::endl;
heif_encoder_release(encoder);
heif_image_release(image);
heif_context_free(ctx);
return false;
}
err = heif_context_write_to_file(ctx, filename);
if (err.code != heif_error_Ok) {
std::cerr << "Error writing HEIF file: " << err.message << std::endl;
heif_encoder_release(encoder);
heif_image_release(image);
heif_context_free(ctx);
return false;
}
heif_encoder_release(encoder);
heif_image_release(image);
heif_context_free(ctx);
return true;
}
bool GRAYMatToHeif(cv::Mat& mat, const char* filename)
{
// 确保输入的cv::Mat 是8位深度,单通道的灰度图
if (mat.empty() || mat.type() != CV_8UC1) {
std::cerr << "Invalid Mat format. Expected 8UC1." << std::endl;
return false;
}
struct heif_image* image;
struct heif_context* ctx = heif_context_alloc();
struct heif_error err;
int width = mat.cols;
int height = mat.rows;
// 创建HEIF图像
err = heif_image_create(width, height, heif_colorspace_monochrome, heif_chroma_monochrome, &image);
if (err.code != heif_error_Ok) {
std::cerr << "Error creating HEIF image: " << err.message << std::endl;
heif_context_free(ctx);
return false;
}
// 添加一个用于灰度通道的图像平面
err = heif_image_add_plane(image, heif_channel_Y, width, height, 8);
if (err.code != heif_error_Ok) {
std::cerr << "Error adding plane to HEIF image: " << err.message << std::endl;
heif_image_release(image);
heif_context_free(ctx);
return false;
}
// 获取指向HEIF图像灰度数据的指针
int stride;
uint8_t* p = heif_image_get_plane(image, heif_channel_Y, &stride);
// 将cv::Mat 的灰度数据复制到HEIF图像中
for (int y = 0; y < height; y++) {
memcpy(p + y * stride, mat.ptr(y), width); // 每行的像素数据是 width 个字节
}
// 创建HEIF编码器
struct heif_encoder* encoder;
err = heif_context_get_encoder_for_format(ctx, heif_compression_HEVC, &encoder);
if (err.code != heif_error_Ok) {
std::cerr << "Error getting HEIF encoder: " << err.message << std::endl;
heif_image_release(image);
heif_context_free(ctx);
return false;
}
heif_encoder_set_lossy_quality(encoder, 80); //0-100 压缩比例
heif_encoder_set_lossless(encoder, true); // True / False
heif_encoder_set_logging_level(encoder, 4); // log信息详细程度0-4
err = heif_context_encode_image(ctx, image, encoder, nullptr, nullptr);
if (err.code != heif_error_Ok) {
std::cerr << "Error encoding HEIF image: " << err.message << std::endl;
heif_encoder_release(encoder);
heif_image_release(image);
heif_context_free(ctx);
return false;
}
err = heif_context_write_to_file(ctx, filename);
if (err.code != heif_error_Ok) {
std::cerr << "Error writing HEIF file: " << err.message << std::endl;
heif_encoder_release(encoder);
heif_image_release(image);
heif_context_free(ctx);
return false;
}
heif_encoder_release(encoder);
heif_image_release(image);
heif_context_free(ctx);
return true;
}
cv::Mat HeifToRGBMat(const char* filename)
{
// 创建HEIF上下文
heif_context* ctx = heif_context_alloc();
heif_error error = heif_context_read_from_file(ctx, filename, nullptr);
if (error.code != heif_error_Ok)
{
std::cerr << "读取heif文件失败:" << error.message << std::endl;
heif_context_free(ctx);
return cv::Mat();
}
// 获取图像句柄
heif_image_handle* handle;
error = heif_context_get_primary_image_handle(ctx, &handle);
if (error.code != heif_error_Ok)
{
std::cerr << "获取图像句柄失败:" << error.message << std::endl;
heif_context_free(ctx);
return cv::Mat();
}
// 解码图像
heif_image* image;
error = heif_decode_image(handle, &image, heif_colorspace_RGB, heif_chroma_interleaved_RGB, nullptr);
if (error.code != heif_error_Ok)
{
std::cerr << "解码图像失败:" << error.message << std::endl;
heif_image_handle_release(handle);
heif_context_free(ctx);
return cv::Mat();
}
// 获取图像宽度、高度和数据
int width = heif_image_get_width(image, heif_channel_interleaved);
int height = heif_image_get_height(image, heif_channel_interleaved);
int stride;
const uint8_t* data = heif_image_get_plane_readonly(image, heif_channel_interleaved, &stride);
// 将图像数据复制到cv::Mat
cv::Mat mat(height, width, CV_8UC3);
for (int y = 0; y < height; y++) {
memcpy(mat.ptr(y), data + y * stride, width * 3);
}
cv::cvtColor(mat, mat, cv::COLOR_BGR2RGB);
//释放资源
heif_image_release(image);
heif_image_handle_release(handle);
heif_context_free(ctx);
return mat;
}
cv::Mat HeifToGRAYMat(const char* filename)
{
// 创建HEIF上下文
heif_context* ctx = heif_context_alloc();
heif_error error = heif_context_read_from_file(ctx, filename, nullptr);
if (error.code != heif_error_Ok) {
std::cerr << "读取HEIF文件失败: " << error.message << std::endl;
heif_context_free(ctx);
return cv::Mat();
}
// 获取第一个图像句柄
heif_image_handle* handle;
error = heif_context_get_primary_image_handle(ctx, &handle);
if (error.code != heif_error_Ok) {
std::cerr << "获取图像句柄失败:" << error.message << std::endl;
heif_context_free(ctx);
return cv::Mat();
}
// 解码图像
heif_image* image;
error = heif_decode_image(handle, &image, heif_colorspace_monochrome, heif_chroma_monochrome, nullptr);
if (error.code != heif_error_Ok) {
std::cerr << "解码图像失败: " << error.message << std::endl;
heif_image_handle_release(handle);
heif_context_free(ctx);
return cv::Mat();
}
// 获取图像宽度、高度和数据
int width = heif_image_get_width(image, heif_channel_Y);
int height = heif_image_get_height(image, heif_channel_Y);
int stride;
const uint8_t* data = heif_image_get_plane_readonly(image, heif_channel_Y, &stride);
// 将图像数据复制到 cv::Mat
cv::Mat mat(height, width, CV_8UC1);
for (int y = 0; y < height; y++) {
memcpy(mat.ptr(y), data + y * stride, width);
}
cv::imwrite("C:\\Users\\Lenovo\\Desktop\\opencv_decode.png", mat);
// 释放资源
heif_image_release(image);
heif_image_handle_release(handle);
heif_context_free(ctx);
return mat;
}
int main()
{
// RGB
cv::Mat matRGB;
cv::Mat matBGR = cv::imread("C:\\Users\\Lenovo\\Desktop\\opencv.png");
const char* rgbFilename = "C:\\Users\\Lenovo\\Desktop\\opencv.heif";
const char* dstRgbFilename = "C:\\Users\\Lenovo\\Desktop\\opencv_decode.png";
cv::cvtColor(matBGR, matRGB, cv::COLOR_BGR2RGB);
bool isRGB = RGBMatToHeif(matRGB, rgbFilename);
matBGR = HeifToRGBMat(rgbFilename);
cv::imwrite(dstRgbFilename, matBGR);
// GRAY
cv::Mat matGRAY = cv::imread("C:\\Users\\Lenovo\\Desktop\\opencv_gray.png", cv::IMREAD_GRAYSCALE);
const char* grayFilename = "C:\\Users\\Lenovo\\Desktop\\opencv_gray.heif";
const char* dstGrayFilename = "C:\\Users\\Lenovo\\Desktop\\opencv_gray_decode.png";
bool isGRAY = GRAYMatToHeif(matGRAY, grayFilename);
cv::Mat dstMatGRAY = HeifToGRAYMat(grayFilename);
cv::imwrite(dstGrayFilename, dstMatGRAY);
return 0;
}
原文地址:https://blog.csdn.net/weixin_50918736/article/details/144226320
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!