簡體   English   中英

YUV420 從像素指針到 BGR 圖像

[英]YUV420 to BGR image from pixel pointers

我正在捕獲來自 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 二進制文件供參考

以下是將提供的 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

通過執行上述代碼生成以下輸出圖像:

YUV 到 BGR 輸出

我認為您輸入的 yuv420 平面圖像的 OpenCV 矩陣應該有 1 通道格式而不是 3 通道。 放在那里 Y 通道,然后是 U,然后是 V。我發現了一個非常相似的問題HERE Planar YUV420 and NV12 is the same

對於那些來這里進行YUV 420 到 BGR/RGB 轉換(第一個谷歌搜索結果)的人,請參考此代碼:

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

using namespace cv;
using namespace std;

int main(int argc, char** argv)
{
    Size iSize(512,512);
    int iYUV_Size = iSize.width * (iSize.height + iSize.height / 2);
    
    Mat mSrc_YUV420(cv::Size(iSize.width,iSize.height+ iSize.height / 2),CV_8UC1);

    ifstream FileIn;
    FileIn.open("Sample_YUV420_512x512.yuv", ios::binary | ios::in);

    if (FileIn.is_open())
    {
        FileIn.read((char*)mSrc_YUV420.data, iYUV_Size);
        FileIn.close();
    }
    else
    {
        printf("[Error] Unable to Read the Input File! \n");
    }

    Mat mSrc_BGR(cv::Size(iSize.width, iSize.height), CV_8UC1);

    cv::cvtColor(mSrc_YUV420, mSrc_BGR, COLOR_YUV2BGR_I420);

    imshow("Input YUV Image", mSrc_YUV420);

在此處輸入圖像描述

    imshow("Input RGB Image", mSrc_BGR);

在此處輸入圖像描述

    cv::waitKey();

    return 0;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM