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);
但是,这是保存的输出图像:
有人可以建议保存图像的正确方法是什么吗?
我认为输入 yuv420 平面图像的 OpenCV 矩阵应该具有 1 通道格式而不是 3 通道格式。放置Y通道,然后是U,然后是V。我发现了一个非常相似的问题HERE Planar YUV420 and NV12 is the same
以下是将提供的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
执行上述代码生成如下输出图像:
我正在从 YUV420 解码器捕获原始输出。我得到了三个指针:分别是 Y(1920*1080)、U(960*540) 和 V(960*540)。
我想使用 OpenCV 将图像保存为 JPEG。我尝试使用 opencv
的 cvtcolorcv::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);
但是,这是保存的输出图像:
有人可以建议保存图像的正确方法是什么吗?
我认为输入 yuv420 平面图像的 OpenCV 矩阵应该具有 1 通道格式而不是 3 通道格式。放置Y通道,然后是U,然后是V。我发现了一个非常相似的问题HERE Planar YUV420 and NV12 is the same
以下是将提供的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
执行上述代码生成如下输出图像: