使用 C++ 将 RGBA 转换为 YUV422 格式 - 没有得到正确的输出
Converting RGBA to YUV422 format using c++ - not getting proper output
我想将图像从 RGBA 格式转换为 YUV422 格式。下面是我的代码:
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace cv;
using namespace std;
#define CLIP(X) ( (X) > 255 ? 255 : (X) < 0 ? 0 : X)
#define RGB2Y(R, G, B) CLIP(( ( 66 * (R) + 129 * (G) + 25 * (B) + 128) >> 8) + 16)
#define RGB2U(R, G, B) CLIP(( ( -38 * (R) - 74 * (G) + 112 * (B) + 128) >> 8) + 128)
#define RGB2V(R, G, B) CLIP(( ( 112 * (R) - 94 * (G) - 18 * (B) + 128) >> 8) + 128)
int main(int argc, char *argv[])
{
Mat in_img, in_RGB, out_yuv;
in_img = imread(argv[1],1);
if(!in_img.data)
{
printf("Failed to load the image ... %s\n!", argv[1]);
return -1;
}
short imgwidth = in_img.cols;
short imgheight = in_img.rows;
cvtColor(in_img, in_RGB, CV_BGR2RGB);
out_yuv.create(imgheight, imgwidth, CV_16U);
imwrite("RGB.jpg",in_RGB);
for(int i = 0; i< imgheight; i++)
for(int j = 0; j< imgwidth; j = j+2) {
unsigned int val = in_RGB.at<unsigned int>(i,j);
/*********** for 1st pixel ***********/
unsigned int tmp = val;
unsigned char B = (unsigned char)(((tmp<<16) >> 24) | 0x000000ff ); //Extracting B channel data
tmp = val;
unsigned char G = (unsigned char)(((tmp<<8) >> 24) | 0x000000ff ); //Extracting G channel data
tmp = val;
unsigned char R = (unsigned char)((tmp >> 24) | 0x000000ff ); //Extracting R channel data
unsigned char Y1 = RGB2Y(R, G, B);
unsigned char U = RGB2U(R, G, B);
unsigned char V = RGB2V(R, G, B);
/*********** for 2nd pixel ***********/
unsigned int val1 = in_RGB.at<unsigned int>(i,j+1);
unsigned int tmp1 = val1;
unsigned char B1 = (unsigned char)(((tmp1<<16) >> 24) | 0x000000ff );
tmp1 = val1;
unsigned char G1 = (unsigned char)(((tmp1<<8) >> 24) | 0x000000ff );
tmp1 = val1;
unsigned char R1 = (unsigned char)((tmp1 >> 24) | 0x000000ff );
unsigned char Y2 = RGB2Y(R, G, B);
/********** writing into out image in U-Y1-V-Y2 format *********************/
unsigned short p1 = ((U << 8) | Y1) ;
unsigned short p2 = ((V << 8) | Y2) ;
out_yuv.at<unsigned short>(i,j) = p1;
out_yuv.at<unsigned short>(i,j+1) = p2;
}
imwrite("YUV422.png",out_yuv);
return 0;
}
但是我没有得到正确的输出图像。我也尝试用 Y1-U-Y2-V 格式编写它,输出仍然相同。上面的代码可能有什么问题,或者是创建问题的输出图像格式(.png/.jpg)? (cv::imwrite 不允许以 .yuv 格式保存)
out_yuv.create(imgheight, imgwidth, CV_16U);
...
imwrite("YUV422.png",out_yuv);
这里有几个问题:
imwrite
考虑 CV_16U
to be mono channel。
- 你不能在png里面写yuv。您必须转储原始数据,并使用特殊的 yuv 查看器,例如 raw yuvplayer 以确保您的数据正确。
编辑:
请注意,原始像素首字母缩略词有点大端,即最左边的值是内存中的最低有效字节(大多数时候,视频人们喜欢混乱)
- RGBA 表示
R = RGB[0]
、G = RGB[1]
、B = RGB[2]
、A = RGB[3]
- YUYV 表示在缓冲区中
p
表示 p[0]
是 Y0,p[1]
是 U,p[2]
是 Y1,p[3]
是 V
你的轮班正好相反:)
编辑 2:
如果你的图像仍然是乱码,你似乎愿意按照平面格式(YUV422P akaYV16
)来写。平面格式意味着每个通道都在一个单独的、连续的平面上。对目标数据使用普通的旧缓冲区(unsigned char*
,或std::vector<unsigned char>
)更清晰。
unsigned char* out_yuv_ptr = new unsigned char[imgwidth*imgheight*2];
unsigned char* y_ptr = out_yuv_ptr;
unsigned char* u_ptr = y_ptr + imgwidth*imgheight;
unsigned char* v_ptr = u_ptr + imgwidth*imgheight/2;
...
*y_ptr = Y1;
++y_ptr
*y_ptr = Y2;
++y_ptr
*u_ptr = U;
++u_ptr;
*v_ptr = V;
++v_ptr;
我想将图像从 RGBA 格式转换为 YUV422 格式。下面是我的代码:
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace cv;
using namespace std;
#define CLIP(X) ( (X) > 255 ? 255 : (X) < 0 ? 0 : X)
#define RGB2Y(R, G, B) CLIP(( ( 66 * (R) + 129 * (G) + 25 * (B) + 128) >> 8) + 16)
#define RGB2U(R, G, B) CLIP(( ( -38 * (R) - 74 * (G) + 112 * (B) + 128) >> 8) + 128)
#define RGB2V(R, G, B) CLIP(( ( 112 * (R) - 94 * (G) - 18 * (B) + 128) >> 8) + 128)
int main(int argc, char *argv[])
{
Mat in_img, in_RGB, out_yuv;
in_img = imread(argv[1],1);
if(!in_img.data)
{
printf("Failed to load the image ... %s\n!", argv[1]);
return -1;
}
short imgwidth = in_img.cols;
short imgheight = in_img.rows;
cvtColor(in_img, in_RGB, CV_BGR2RGB);
out_yuv.create(imgheight, imgwidth, CV_16U);
imwrite("RGB.jpg",in_RGB);
for(int i = 0; i< imgheight; i++)
for(int j = 0; j< imgwidth; j = j+2) {
unsigned int val = in_RGB.at<unsigned int>(i,j);
/*********** for 1st pixel ***********/
unsigned int tmp = val;
unsigned char B = (unsigned char)(((tmp<<16) >> 24) | 0x000000ff ); //Extracting B channel data
tmp = val;
unsigned char G = (unsigned char)(((tmp<<8) >> 24) | 0x000000ff ); //Extracting G channel data
tmp = val;
unsigned char R = (unsigned char)((tmp >> 24) | 0x000000ff ); //Extracting R channel data
unsigned char Y1 = RGB2Y(R, G, B);
unsigned char U = RGB2U(R, G, B);
unsigned char V = RGB2V(R, G, B);
/*********** for 2nd pixel ***********/
unsigned int val1 = in_RGB.at<unsigned int>(i,j+1);
unsigned int tmp1 = val1;
unsigned char B1 = (unsigned char)(((tmp1<<16) >> 24) | 0x000000ff );
tmp1 = val1;
unsigned char G1 = (unsigned char)(((tmp1<<8) >> 24) | 0x000000ff );
tmp1 = val1;
unsigned char R1 = (unsigned char)((tmp1 >> 24) | 0x000000ff );
unsigned char Y2 = RGB2Y(R, G, B);
/********** writing into out image in U-Y1-V-Y2 format *********************/
unsigned short p1 = ((U << 8) | Y1) ;
unsigned short p2 = ((V << 8) | Y2) ;
out_yuv.at<unsigned short>(i,j) = p1;
out_yuv.at<unsigned short>(i,j+1) = p2;
}
imwrite("YUV422.png",out_yuv);
return 0;
}
但是我没有得到正确的输出图像。我也尝试用 Y1-U-Y2-V 格式编写它,输出仍然相同。上面的代码可能有什么问题,或者是创建问题的输出图像格式(.png/.jpg)? (cv::imwrite 不允许以 .yuv 格式保存)
out_yuv.create(imgheight, imgwidth, CV_16U);
...
imwrite("YUV422.png",out_yuv);
这里有几个问题:
imwrite
考虑CV_16U
to be mono channel。- 你不能在png里面写yuv。您必须转储原始数据,并使用特殊的 yuv 查看器,例如 raw yuvplayer 以确保您的数据正确。
编辑:
请注意,原始像素首字母缩略词有点大端,即最左边的值是内存中的最低有效字节(大多数时候,视频人们喜欢混乱)
- RGBA 表示
R = RGB[0]
、G = RGB[1]
、B = RGB[2]
、A = RGB[3]
- YUYV 表示在缓冲区中
p
表示p[0]
是 Y0,p[1]
是 U,p[2]
是 Y1,p[3]
是 V
你的轮班正好相反:)
编辑 2:
如果你的图像仍然是乱码,你似乎愿意按照平面格式(YUV422P akaYV16
)来写。平面格式意味着每个通道都在一个单独的、连续的平面上。对目标数据使用普通的旧缓冲区(unsigned char*
,或std::vector<unsigned char>
)更清晰。
unsigned char* out_yuv_ptr = new unsigned char[imgwidth*imgheight*2];
unsigned char* y_ptr = out_yuv_ptr;
unsigned char* u_ptr = y_ptr + imgwidth*imgheight;
unsigned char* v_ptr = u_ptr + imgwidth*imgheight/2;
...
*y_ptr = Y1;
++y_ptr
*y_ptr = Y2;
++y_ptr
*u_ptr = U;
++u_ptr;
*v_ptr = V;
++v_ptr;