当前位置: 首页> 文旅> 酒店 > 昇腾 - AscendCL C++应用开发 图像文件的解码时硬件对图像的宽度和高度的处理方式

昇腾 - AscendCL C++应用开发 图像文件的解码时硬件对图像的宽度和高度的处理方式

时间:2025/8/27 11:14:42来源:https://blog.csdn.net/flyfish1986/article/details/141421176 浏览次数:0次

昇腾 - AscendCL C++应用开发 图像文件的解码时硬件对图像的宽度和高度的处理方式

flyfish

假如是这样的

输入图片格式(YUV分量比例)

jpeg(420)

输出图片格式

YUV420SP NV12 8bit

输出图片宽、高对齐要求

宽2对齐
高2对齐

输出图片宽Stride、高Stride、内存大小要求

宽Stride为宽64对齐后的值。
高Stride为高16对齐后的值。
内存大小(单位Byte)≥ 宽Stride * 高Stride * 3/2

支持的硬件

Atlas 推理系列产品(Ascend 310P处理器)
Atlas 200/500 A2推理产品
Atlas A2训练系列产品

举例子

将ImageData 转cv::Mat格式
JPEGD(JPEG Decoder)对JPG图像文件的解码时,硬件对图像的宽度和高度存在对齐的要求

cv::Mat ImageDataToMat(const ImageData &imgData)
{// 确保图像格式是 YUV420SPif (imgData.format != PIXEL_FORMAT_YUV_SEMIPLANAR_420){throw std::invalid_argument("Unsupported image format");}std::cout << imgData.width << std::endl;std::cout << imgData.height << std::endl;// 创建 YUV420SP 的 cv::Matcv::Mat yuv420spMat(imgData.height + imgData.height / 2, imgData.width, CV_8UC1, imgData.data.get());// 将 YUV420SP 转换为 BGRcv::Mat bgrMat;cv::cvtColor(yuv420spMat, bgrMat, cv::COLOR_YUV2BGR_NV12);return bgrMat;
}

使用

string imgPath = "../data/1.jpg";
ImageProc imageProcess;
ImageData frame = imageProcess.Read(imgPath);cv::Mat bgrMat = ImageDataToMat(frame);
cv::imwrite("../data/2.jpg", bgrMat);

分析代码

ImageData 结构体
struct ImageData {std::shared_ptr<uint8_t> data = nullptr;uint32_t size = 0;uint32_t width = 0;uint32_t height = 0;uint32_t alignWidth = 0;uint32_t alignHeight = 0;acldvppPixelFormat format = PIXEL_FORMAT_YUV_SEMIPLANAR_420;ImageData() {}ImageData(std::shared_ptr<uint8_t> buf, uint32_t bufSize,uint32_t x, uint32_t y, acldvppPixelFormat fmt) : data(buf), size(bufSize),width(x), height(y), format(fmt) {}
};
ImageProc的读取图像文件

可以是jpg或者png,Read函数中调用了ReadBinFile函数

ImageData ImageProc::Read(const string& filePath, acldvppPixelFormat imgFormat)
{// read file to host void* hostDataBuf = nullptr;uint32_t hostDataSize = 0;ReadBinFile(filePath, hostDataBuf, hostDataSize);int splitPos = filePath.find_last_of('/');string fileName = filePath.substr(splitPos + 1);// get file typeint pos = fileName.find('.');string fileType = fileName.substr(pos + 1);if (fileType=="jpg" || fileType=="jpeg" || fileType=="JPG" || fileType=="JPEG") {return JpegD(hostDataBuf, hostDataSize, imgFormat);} else if (fileType=="png") {return PngD(hostDataBuf, hostDataSize, imgFormat);} else {LOG_PRINT("[ERROR] Read file type not supported.");ImageData dst;return dst;}
}bool ReadBinFile(const string& fileName, void*& data, uint32_t& size)
{struct stat sBuf;int fileStatus = stat(fileName.data(), &sBuf);CHECK_RET(fileStatus == 0, LOG_PRINT("[ERROR] Failed to get input file."); return false);CHECK_RET(S_ISREG(sBuf.st_mode) != 0, LOG_PRINT("[ERROR] %s is not a file, please enter a file.", fileName.c_str()); return false);std::ifstream binFile(fileName, std::ifstream::binary);CHECK_RET(binFile.is_open() == true, LOG_PRINT("[ERROR] Open file %s failed", fileName.c_str()); return false);binFile.seekg(0, binFile.end);uint32_t binFileBufferLen = binFile.tellg();CHECK_RET(binFileBufferLen != 0, LOG_PRINT("[ERROR] Binfile is empty, filename is %s", fileName.c_str()); return false);binFile.seekg(0, binFile.beg);uint8_t* binFileBufferData = new(std::nothrow) uint8_t[binFileBufferLen];CHECK_RET(binFileBufferData != nullptr, LOG_PRINT("[ERROR] Malloc binFileBufferData failed"); return false);binFile.read((char *)binFileBufferData, binFileBufferLen);binFile.close();data = binFileBufferData;size = binFileBufferLen;return true;
}

解释 YUV420SP 的 cv::Mat

变量 cv::Mat yuv420spMat(imgData.height + imgData.height / 2, imgData.width, CV_8UC1, imgData.data.get());

YUV420SP NV12 8bit 表示一种图像数据格式,其中:
图像数据使用YUV颜色空间。
色度抽样比是4:2:0(每4个亮度样本对应2个色度样本)。
数据以半平面的方式存储,Y分量单独存储,而UV交替存储在一起。
每个分量的数据用8位表示。

详细点说就是
YUV颜色空间

  • Y 代表亮度(Luminance),即图像的明暗信息。
  • UV 代表色度(Chrominance),分别存储蓝色差(Cb)和红色差(Cr)信息。U和V共同决定了图像的颜色。

4:2:0 表示色度抽样的比例。它表明色度(U和V)的分辨率是亮度(Y)的一半,也就是说,每4个Y样本(即亮度值)只存储2个U和2个V样本。这样可以减少存储空间,同时保持相对较好的图像质量。

  • 4 :代表每4个像素的亮度样本。
  • 2 :代表在水平方向上每2个像素共享一个色度样本。
  • 0 :代表在垂直方向上每2行像素共享一个色度样本。

SP (Semi-Planar) 表示Y、U、V数据的存储方式。在YUV420SP中,Y分量的数据存储在一块连续的内存区域中,而U和V分量的数据交替存储在另一块连续的内存区域中。即,首先是Y数据,然后紧接着是交替存储的UV数据(UVUVUV…)。

NV12 是YUV420SP格式的一种具体形式。它规定在存储时,Y分量紧跟着UV分量存储,其中U在V之前排列(即UVUVUV…的顺序)。因此,NV12格式的图像数据首先是一个单独的Y平面,后面跟着交错的UV平面。

8bit 表示每个像素的亮度(Y)和色度(U和V)分量用8位表示。具体来说,Y、U、V的每个分量都有256个可能的值(从0到255),分别表示不同的亮度或颜色信息。

图像数据的存储结构

在 NV12 格式下,图像的存储结构如下:
Y 平面:首先存储所有像素的亮度(Y)信息,占据了整个图像的高度和宽度的内存空间。
UV 平面:紧接在 Y 平面之后,存储交替的 U 和 V 色度信息。因为色度分辨率是亮度的四分之一(在4:2:0抽样中),所以 UV 平面高度是原始图像高度的一半。

计算方式

硬件对图像的宽度和高度存在对齐的要求,因此引入了宽Stride和高Stride两个概念。宽Stride用于表示对齐后的宽度,高Stride用于表示对齐后的高度。假设宽Stride按照宽度的64倍对齐,高Stride按照高度的16倍对齐。那么,内存大小(单位Byte)需要满足以下公式:内存大小 ≥ 宽Stride * 高Stride * 3/2。

例如,对于一个500 × 300(宽度 × 高度)的图像,对齐后的宽高分别为512 × 304。具体计算如下:

  • 500 / 64 = 7.8125,由于需要向上对齐到最近的64的倍数,所以结果为64 × 8 = 512。

  • 300 / 16 = 18.75,由于需要向上对齐到最近的16的倍数,所以结果为16 × 19 = 304。

同样,对于一个1920 × 1080(宽度 × 高度)的图像,对齐后的宽高分别为1920 × 1088。

  • 宽度对齐:1920 / 64 = 30,直接为64 × 30 = 1920,因为1920已经是64的倍数。

  • 高度对齐:1080 / 16 = 67.5,需要向上取整到16的倍数,所以结果为16 × 68 = 1088。

这样可视化结果会存在高8像素的绿边

原图
图片描述
保存后 (如果按照1920 * 1080 直接存储,不进行任何处理, 会有一个8像素的绿边)

图片描述

关于功能及约束说明的参考

关键字:昇腾 - AscendCL C++应用开发 图像文件的解码时硬件对图像的宽度和高度的处理方式

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: