【问题标题】:YUV420 to BGR image from pixel pointersYUV420 从像素指针到 BGR 图像
【发布时间】:2018-10-18 04:52:47
【问题描述】:

我正在捕获来自 YUV420 解码器的原始输出。我得到了三个指针:分别是 Y(1920*1080)、U(960*540) 和 V(960*540)。

我想使用 OpenCV 将图像保存为 JPEG。我尝试使用opencv的cvtcolor

cv::Mat i_image(cv::Size(columns, rows), CV_8UC3, dataBuffer);
cv::Mat i_image_BGR(cv::Size(columns, rows), CV_8UC3);
cvtColor(i_image, i_image_BGR, cv::COLOR_YCrCb2BGR);
cv::imwrite("/data/data/org.myproject.debug/files/pic1.jpg", i_image_BGR);

但是,这是保存的输出图像:

有人可以建议保存图像的正确方法是什么吗?

YUV Binary files for reference

【问题讨论】:

  • 可以分享完整的代码吗?好像您没有正确地将 YUV420 转换为 YUV444。
  • 我们直接尝试从YUV420转换为BGR。上面的 sn-p 是函数内部使用的全部内容。您能否分享更多关于如何将 YUV420 转换为 YUV444 的信息?
  • 您说您有 3 个指针,但您只提供了一个指向 i_image 的指针。
  • 看起来 U 和 V 分量必须为 4 个 Y 分量复制。如果您可以共享单个输入图像(或dataBuffer 的值),我将能够测试示例代码。
  • @zindarod... 是的,我认为 OP 错误解释了dataBuffer 中的像素值。

标签: c++ opencv vlc yuv encoder-decoder


【解决方案1】:

以下是将提供的 YUV 文件转换为 RGB 图像的过程。

  • 将 Y、U 和 V 二进制文件读入字节缓冲区
  • 从创建的缓冲区创建 OpenCV Mat 对象。
  • 将 U 和 V 垫调整为 Y 的大小。
  • 合并 Y 并调整 U 和 V 的大小。
  • 从 YUV 转换为 BGR

请注意,调整大小步骤只是重复 U 和 V 值的优化方式。这仅适用于 Y 在两个维度上的分辨率是 U 和 V 的两倍的情况.这种方法对于任意尺寸的图片应该是无效的(未测试)。

这是上述过程的代码。

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

std::vector<unsigned char> readBytesFromFile(const char* filename)
{
    std::vector<unsigned char> result;

    FILE* f = fopen(filename, "rb");

    fseek(f, 0, SEEK_END);  // Jump to the end of the file
    long length = ftell(f); // Get the current byte offset in the file
    rewind(f);              // Jump back to the beginning of the file

    result.resize(length);

    char* ptr = reinterpret_cast<char*>(&(result[0]));
    fread(ptr, length, 1, f); // Read in the entire file
    fclose(f); // Close the file

    return result;
}

int main(int argc, char** argv)
{
    cv::Size actual_size(1920, 1080);
    cv::Size half_size(960, 540);

    //Read y, u and v in bytes arrays
    auto y_buffer = readBytesFromFile("ypixel.bin");
    auto u_buffer = readBytesFromFile("upixel.bin");
    auto v_buffer = readBytesFromFile("vpixel.bin");


    cv::Mat y(actual_size, CV_8UC1, y_buffer.data());
    cv::Mat u(half_size, CV_8UC1, u_buffer.data());
    cv::Mat v(half_size, CV_8UC1, v_buffer.data());

    cv::Mat u_resized, v_resized;
    cv::resize(u, u_resized, actual_size, 0, 0, cv::INTER_NEAREST); //repeat u values 4 times
    cv::resize(v, v_resized, actual_size, 0, 0, cv::INTER_NEAREST); //repeat v values 4 times

    cv::Mat yuv;

    std::vector<cv::Mat> yuv_channels = { y, u_resized, v_resized };
    cv::merge(yuv_channels, yuv);

    cv::Mat bgr;
    cv::cvtColor(yuv, bgr, cv::COLOR_YUV2BGR);
    cv::imwrite("bgr.jpg", bgr);

    return 0;
}

使用以下命令编译和测试:

g++ -o yuv2rgb -std=c++11 yuv2rgb.cpp -L/usr/local/lib -lopencv_core -lopencv_imgcodecs -lopencv_highgui -lopencv_imgproc

执行上述代码生成如下输出图像:

【讨论】:

  • 像魅力一样工作。非常感谢 sgarizvi。
【解决方案2】:

我认为输入 yuv420 平面图像的 OpenCV 矩阵应该有 1 通道格式而不是 3 通道。放在那里 Y 通道,然后是 U,然后是 V。我发现了一个非常相似的问题 HEREPlanar YUV420 和 NV12 是一样的

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-07-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多