Reputation: 83
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
Upvotes: 8
Views: 9359
Reputation: 1845
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;
}
Upvotes: 4
Reputation: 16796
Following is the process to convert the provided YUV files into RGB image.
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:
Upvotes: 9
Reputation: 556
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
Upvotes: 3