• yuv420并转为bgr


    从视频通道获取yuv视频帧数据y和uv,读取合并成完整yuv并转为bgr。

    #include 
    #include 
    #include 
    
    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62

    详细解释

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

    #include 
    #include 
    #include 
    
    • 1
    • 2
    • 3

    这些是 C++ 头文件引入部分。 用于标准输入和输出, 用于文件操作OpenCV 库的头文件,允许你使用 OpenCV 功能。

    int main() {
    
    • 1

    这是 main 函数的开始。

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

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

    const int width = 1920;
    const int height = 1080;
    
    • 1
    • 2

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

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

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

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

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

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

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

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

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

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

    这里使用 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);
    
    • 1
    • 2
    • 3

    这里定义了三个 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());
    
    • 1
    • 2
    • 3

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

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

    这里定义了一个 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);
    
    • 1
    • 2
    • 3

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

    cv::Mat bgrImage;
    cv::cvtColor(yuvImage, bgrImage, cv::COLOR_YUV2BGR_NV12);
    
    • 1
    • 2

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

    cv::imshow("YUV420 Image", bgrImage);
    cv::waitKey(6000);
    cv::destroyAllWindows();
    
    • 1
    • 2
    • 3

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

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

    进一步封装

    ImageConverter.h

    // ImageConverter.h
    #pragma once
    
    #include 
    
    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
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    ImageConverter.cpp

    // ImageConverter.cpp
    #include "ImageConverter.h"
    #include 
    #include 
    
    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();
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    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;
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
  • 相关阅读:
    Hbase解决ERROR: KeeperErrorCode = ConnectionLoss for /hbase/master报错
    科目二试题
    Flink Watermark详解
    实时备案查询易语言代码
    windows、ubuntu双系统安装教程
    Docker核心知识手册
    精品基于SpringCloud实现的高校招生信息管理系统-微服务-分布式
    android学习day1
    从0搭建Vue3组件库之Icon组件
    IDEA中的神仙插件——Smart Input (自动切换输入法)
  • 原文地址:https://blog.csdn.net/qq_45865950/article/details/134272835