简体   繁体   中英

YUV420 to BGR image from pixel pointers

I am capturing raw output from a decoder which is YUV420. I have got three pointers: Y(1920*1080), U(960*540) and V(960*540) separately.

I want to save the image as JPEG using OpenCV. I tried using cvtcolor of opencv

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);

But, here is the output image which is saved:

图片

Can someone please suggest what is the proper way of saving the image?

YUV Binary files for reference

Following is the process to convert the provided YUV files into RGB image.

  • Read Y, U and V binary files into byte buffers
  • Create OpenCV Mat object from the created buffers.
  • Resize U and V Mats to the size of Y.
  • Merge Y and resized U and V.
  • Convert from YUV to BGR

Be advised that the resizing step is just an optimized way of repeating the values of U and V. This is only valid in the case where Y has twice the resolution of U and V in both dimensions. This approach should be invalid for arbitrary size images (not tested).

Here is the code for the above-mentioned process.

#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;
}

Compiled and tested with following command:

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

Following output image is generated by executing the above code:

YUV 到 BGR 输出

I think OpenCV matrix for your input yuv420 planar image should have 1 channel format instead of 3 channel. Place there Y channel, then U, then V. I found a very similar question HERE Planar YUV420 and NV12 is the same

For those who came here for YUV 420 to BGR/RGB Conversion (First Google search Result), Please refer to this code:

#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;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM