主页 > 软件开发  > 

yuv420并转为bgr

yuv420并转为bgr

文章目录 从视频通道获取yuv视频帧数据y和uv,读取合并成完整yuv并转为bgr。详细解释进一步封装ImageConverter.hImageConverter.cppmain.cpp

从视频通道获取yuv视频帧数据y和uv,读取合并成完整yuv并转为bgr。 #include <iostream> #include <fstream> #include <opencv2/opencv.hpp> int main() { const std::string yFile = "./Y.yuv";//自己替换 const std::string uvFile = "./UV.yuv";//自己替换 const int width = 1920;//自己替换 const int height = 1080;//自己替换 // 计算帧大小 const int frameSize = width * height * 3 / 2; // YUV420 图像每帧占用的字节数 // 打开 YUV420 图片文件 std::ifstream yfile(yFile, std::ios::binary); if (!yfile) { std::cerr << "Failed to open Y file." << std::endl; return 1; } std::ifstream uvfile(uvFile, std::ios::binary); if (!uvfile) { std::cerr << "Failed to open UV file." << std::endl; return 1; } // 读取 YUV 数据 std::vector<uint8_t> yData(frameSize); yfile.read(reinterpret_cast<char*>(yData.data()), frameSize); std::vector<uint8_t> uvData(frameSize); uvfile.read(reinterpret_cast<char*>(uvData.data()), frameSize); // 提取 Y、U、V 分量 std::vector<uint8_t> Y(width * height); std::vector<uint8_t> U(width * height / 4); std::vector<uint8_t> V(width * height / 4); std::copy_n(yData.begin(), width * height, Y.begin()); std::copy_n(uvData.begin(), width * height / 4, U.begin()); std::copy_n(uvData.begin() + width * height / 4, width * height / 4, V.begin()); cv::Mat yuvImage(height * 3 / 2, width, CV_8UC1); std::memcpy(yuvImage.data, Y.data(), width * height); std::memcpy(yuvImage.data + width * height, U.data(), width * height / 4); std::memcpy(yuvImage.data + width * height * 5 / 4, V.data(), width * height / 4); cv::Mat bgrImage; cv::cvtColor(yuvImage, bgrImage, cv::COLOR_YUV2BGR_NV12); // 显示图像 cv::imshow("YUV420 Image", bgrImage); cv::waitKey(6000); cv::destroyAllWindows(); return 0; } 详细解释

当然,我会逐行解释你的代码:

#include <iostream> #include <fstream> #include <opencv2/opencv.hpp>

这些是 C++ 头文件引入部分。<iostream> 用于标准输入和输出,<fstream> 用于文件操作,<opencv2/opencv.hpp> 是 OpenCV 库的头文件,允许你使用 OpenCV 功能。

int main() {

这是 main 函数的开始。

const std::string yFile = "./Y.yuv"; const std::string uvFile = "./UV.yuv";

这里定义了两个字符串变量 yFile 和 uvFile,用于存储 Y 和 UV 分量的文件路径。

const int width = 1920; const int height = 1080;

这里定义了图像的宽度和高度。

const int frameSize = width * height * 3 / 2;

这是计算每帧图像的大小,因为 YUV420 图像中,Y 分量占据一帧的大小,而 U 和 V 分量各占据一帧大小的四分之一。这是根据 YUV420 格式的存储方式计算的。

std::ifstream yfile(yFile, std::ios::binary); std::ifstream uvfile(uvFile, std::ios::binary);

这里打开了 Y 和 UV 分量的文件,使用了 ifstream 流,打开方式是二进制方式打开。

if (!yfile) { std::cerr << "Failed to open Y file." << std::endl; return 1; }

这个条件语句检查是否成功打开了 Y 分量的文件,如果失败,则输出错误信息并返回 1,表示程序出错。

std::vector<uint8_t> yData(frameSize); std::vector<uint8_t> uvData(frameSize);

这里定义了两个 std::vector,分别用于存储 Y 和 UV 分量的数据。它们的大小是一个帧的大小。

yfile.read(reinterpret_cast<char*>(yData.data()), frameSize); uvfile.read(reinterpret_cast<char*>(uvData.data()), frameSize);

这里使用 read 函数从文件中读取 Y 和 UV 数据,注意通过 reinterpret_cast 进行了类型转换,因为文件操作需要 char* 类型。

std::vector<uint8_t> Y(width * height); std::vector<uint8_t> U(width * height / 4); std::vector<uint8_t> V(width * height / 4);

这里定义了三个 std::vector,分别用于存储提取出的 Y、U 和 V 分量数据。

std::copy_n(yData.begin(), width * height, Y.begin()); std::copy_n(uvData.begin(), width * height / 4, U.begin()); std::copy_n(uvData.begin() + width * height / 4, width * height / 4, V.begin());

这三行代码分别从 yData 和 uvData 中复制数据到 Y、U 和 V 的 std::vector 中,确保正确提取了 Y、U、V 分量。

cv::Mat yuvImage(height * 3 / 2, width, CV_8UC1);

这里定义了一个 cv::Mat 对象 yuvImage,它将用于存储整个 YUV 图像,大小是 (height * 3 / 2) 行和 width 列,像素类型为 CV_8UC1(8 位无符号字符)。

std::memcpy(yuvImage.data, Y.data(), width * height); std::memcpy(yuvImage.data + width * height, U.data(), width * height / 4); std::memcpy(yuvImage.data + width * height * 5 / 4, V.data(), width * height / 4);

这三行代码使用 memcpy 函数将 Y、U、V 分量的数据复制到 yuvImage 中,确保它们按正确的顺序合并在一起。

cv::Mat bgrImage; cv::cvtColor(yuvImage, bgrImage, cv::COLOR_YUV2BGR_NV12);

这里定义了 bgrImage,用于存储 BGR 格式的图像。然后,使用 OpenCV 的 cvtColor 函数将 YUV 图像转换为 BGR 格式,cv::COLOR_YUV2BGR_NV12 表示从 NV12 YUV 格式转换到 BGR 格式。

cv::imshow("YUV420 Image", bgrImage); cv::waitKey(6000); cv::destroyAllWindows();

最后,这几行代码显示图像。imshow 用于显示图像窗口,waitKey 用于等待按键,destroyAllWindows 用于关闭所有窗口。

这就是你代码的逐行解释。它的主要功能是打开 YUV420 文件,提取 Y、U、V 分量,将它们合并成 YUV 图像,然后将其转换为 BGR 格式并在窗口中显示。如果你有任何问题或需要更多解释,请随时提问。

进一步封装 ImageConverter.h // ImageConverter.h #pragma once #include <opencv2/opencv.hpp> class ImageConverter { public: ImageConverter(const std::string& yFile, const std::string& uvFile, int width, int height); ~ImageConverter(); cv::Mat convertToBGR(); void displayBGRImage(); private: std::string yFile_; std::string uvFile_; int width_; int height_; cv::Mat yuvImage_; cv::Mat bgrImage_; }; #pragma once ImageConverter.cpp // ImageConverter.cpp #include "ImageConverter.h" #include <fstream> #include <iostream> ImageConverter::ImageConverter(const std::string& yFile, const std::string& uvFile, int width, int height) : yFile_(yFile), uvFile_(uvFile), width_(width), height_(height) { const int frameSize = width * height * 3 / 2; std::ifstream yfile(yFile_, std::ios::binary); std::ifstream uvfile(uvFile_, std::ios::binary); if (!yfile || !uvfile) { std::cerr << "Failed to open YUV files." << std::endl; return; } std::vector<uint8_t> yData(frameSize); yfile.read(reinterpret_cast<char*>(yData.data()), frameSize); std::vector<uint8_t> uvData(frameSize); uvfile.read(reinterpret_cast<char*>(uvData.data()), frameSize); std::vector<uint8_t> Y(width * height); std::vector<uint8_t> U(width * height / 4); std::vector<uint8_t> V(width * height / 4); std::copy_n(yData.begin(), width * height, Y.begin()); std::copy_n(uvData.begin(), width * height / 4, U.begin()); std::copy_n(uvData.begin() + width * height / 4, width * height / 4, V.begin()); yuvImage_ = cv::Mat(height * 3 / 2, width, CV_8UC1); std::memcpy(yuvImage_.data, Y.data(), width * height); std::memcpy(yuvImage_.data + width * height, U.data(), width * height / 4); std::memcpy(yuvImage_.data + width * height * 5 / 4, V.data(), width * height / 4); bgrImage_ = cv::Mat(height, width, CV_8UC3); cv::cvtColor(yuvImage_, bgrImage_, cv::COLOR_YUV2BGR_NV12); } ImageConverter::~ImageConverter() { // 可以在这里添加清理资源的代码 } cv::Mat ImageConverter::convertToBGR() { return bgrImage_.clone(); } void ImageConverter::displayBGRImage() { cv::imshow("BGR Image", bgrImage_); cv::waitKey(60000); cv::destroyAllWindows(); } main.cpp // main.cpp (用法示例) #include "ImageConverter.h" int main() { const std::string yFile = "./Y.yuv"; const std::string uvFile = "./UV.yuv"; const int width = 1920; const int height = 1080; ImageConverter converter(yFile, uvFile, width, height); cv::Mat bgrImage = converter.convertToBGR(); // 设置要保存的文件路径 std::string filePath = "./your_image.png"; // 替换为你的文件夹路径和文件名 // 保存BGR图像 bool success = cv::imwrite(filePath, bgrImage); if (success) { std::cout << "图像已成功保存到文件夹:" << filePath << std::endl; } else { std::cerr << "保存图像时出错." << std::endl; } converter.displayBGRImage(); return 0; }
标签:

yuv420并转为bgr由讯客互联软件开发栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“yuv420并转为bgr