一:灰度图转YUV
由于工作需要,经常接触12bit灰度数据,因此在这里将数据的处理记录下来。
经常接触的是sensor输出的12bit灰度数据,按照需求经常会将这份数据转换成其他格式,如16bit灰度数据(高4bit为0),YUV数据等,其中在转成YUV之前需要先把每个piel的12bit数据变成8bit,即将低4bit舍弃,然后补齐UV数据。
以下代码为将16bit的灰度数据转成YUV格式,由于UV数据都置为128,因此对于YUV420的各种格式的处理也都是相同的了。
#include <stdio.h>
unsigned short grayraw[640*480]; //输入的16bit 灰度数据
unsigned char gray_8bit[640*480]; //输出的8bit 灰度数据
unsigned char gray_yuv[640*480*3/2];//输出的YUV数据,NV12或者NV21等
int main()
{
int i = 0;
unsigned short pixel;
unsigned short temp;
char gray_file[256];
sprintf(gray_file, "gray_raw");
FILE *file_grayraw = fopen(gray_file, "rb");
fread(grayraw, 1, 640 * 480 * 2 , file_grayraw);
fclose(file_grayraw);
for(i = 0; i < 640*480; i++)
{
pixel = grayraw[i];
temp = (pixel << 4) >> 8;
gray_8bit[i] = (unsigned char)temp;
gray_yuv[i] = (unsigned char)temp;
}
//to 8bit
char gray_out[256];
sprintf(gray_out, "grayout.raw");
FILE *grayout_file = fopen(gray_out, "wb+");
fwrite((void*)gray_8bit, 1, 640*480, grayout_file);
fclose(grayout_file);
//to yuv
memset(gray_yuv+640*480, 128, 640*480/2);
char gray_yuv_out[256];
sprintf(gray_yuv_out, "640_480.yuv");
FILE *grayyuv_file = fopen(gray_yuv_out, "wb+");
fwrite((void*)gray_yuv, 1, 640*480*3/2, grayyuv_file);
fclose(grayyuv_file);
return 0;
}
二:NV12转YUV422(UYVY)
NV12格式属于YUV420 即 YYYYYYYYYYYYYYY.....UVUVUVUVUVUV
下面的代码用于将1920*1080的NV12数据转换成UYVY的YUV422格式
原理是将YUV420的由上下两行相邻的共4个Y共享一个U转变为YUV422每行相邻的两个Y共享一个U,具体方式为将YUV420的第一行的Y对应的U(第二行Y也对应着这个U)复制一行,也就是两行的U,其中一行对应YUV422第一行的Y,另一行对应YUV422第二行的Y,如此类推,那么YUV420的第3,4行的Y对应的960个U也是复制成为1920个,分别用于对应YUV422的3,4行的Y。同理,V也是如此。
#include <stdio.h>
char image_buffer[460800];
char image_big_buffer[3110400];
char image_yuv422_buffer[4147200];
static void NV12_to_UYVY(char* src, char* dst, int width, int height)
{
char *yuv420_y = src;
char *yuv420_u = src + width * height;
char *yuv420_v = src + width * height + 1;
char *yuv422 = dst;
int i = 0;
int j = 0;
char u_buf[518400];
char v_buf[518400];
memset((void*)u_buf, 0, 518400);
memset((void*)v_buf, 0, 518400);
for(i = 0, j = 0; i < 518400; i++)
{
u_buf[i] = *(yuv420_u + j);
j+=2;
}
for(i = 0, j = 0; i < 518400; i++)
{
v_buf[i] = *(yuv420_v + j);
j+=2;
}
char uu_buf[1036800];
char vv_buf[1036800];
memset((void*)uu_buf, 0, 1036800);
memset((void*)vv_buf, 0, 1036800);
int uWidth = width / 2;
int uHeight = height / 2;
for(i = 0; i < uHeight; i++)
{
memcpy((void*)uu_buf + i * 2 * uWidth, u_buf + i * uWidth, uWidth);
memcpy((void*)uu_buf + i * 2 * uWidth + uWidth, u_buf + i * uWidth, uWidth);
}
for(i = 0; i < uHeight; i++)
{
memcpy((void*)vv_buf + i * 2 * uWidth, v_buf + i * uWidth, uWidth);
memcpy((void*)vv_buf + i * 2 * uWidth + uWidth, v_buf + i * uWidth, uWidth);
}
for(i = 1; i < width * height * 2;)
{
*(yuv422 + i) = *yuv420_y++;
i += 2;
}
for(i = 0, j = 0; i < width * height * 2;)
{
*(yuv422 + i) = uu_buf[j];
i += 4;
j++;
}
for(i = 0, j = 0; i < width * height * 2;)
{
*(yuv422 + i + 2) = vv_buf[j];
i += 4;
j++;
}
}
int main()
{
char *originimage = "yuv420_19201080.bin";
FILE *imagefile = fopen(originimage,"a+");
if(NULL == imagefile)
{
printf("open file[%s] failed!\n", originimage);
return -1;
}
memset((void*)image_big_buffer,0,3110400);
fread((void*)image_big_buffer, 1, 3110400, imagefile);
fclose(imagefile);
memset((void*)image_yuv422_buffer,128,4147200);
NV12_to_UYVY(image_big_buffer, image_yuv422_buffer, 1920, 1080);
char *big422image = "big422.yuv";
FILE *fp_422big = fopen(big422image,"a+");
if(NULL == fp_422big)
{
printf("open file[%s] failed!\n", big422image);
return -1;
}
fwrite((void*)image_yuv422_buffer, 1, 4147200, fp_422big);
fclose(fp_422big);
}
三:YUV444(YUVYUVYUV)转NV12
void YUV444ToNV12(unsigned char *yuv, unsigned char *nv12, int width, int height)
{
int i = 0;
int j = 0;
int k = 0;
/* copy y data */
for(i = 0; i < height; i++)
{
for(j = 0; j < width; j++)
{
*(nv12 + i * width + j) = *(yuv + 3 * k);
k++;
}
}
unsigned char * ptr_u = nv12 + width * height;
unsigned char * ptr_v = ptr_u + 1;
int uv_height = height /2;
for(i = 0; i < uv_height; i++)
{
k = 0;
for(j = 0; j < width;)
{
*(ptr_u + i * width + j) = *(yuv + i * width * 3 * 2 + k * 6 + 1);
*(ptr_v + i * width + j) = *(yuv + i * width * 3 * 2 + k * 6 + 2);
j+=2;
k++;
}
}
}
四:BGR888转YUV444(YUVYUVYUV)
void BGR888ToYUV444(unsigned char *yuv, unsigned char *bgr, int pixel_num)
{
int i = 0;
for (i = 0; i < pixel_num; ++i) {
unsigned char b = bgr[i * 3];
unsigned char g = bgr[i * 3 + 1];
unsigned char r = bgr[i * 3 + 2];
// 1. Multiply transform matrix (Y′: unsigned, U/V: signed)
unsigned short y_tmp = 76 * r + 150 * g + 29 * b;
unsigned short u_tmp = -43 * r - 84 * g + 127 * b;
unsigned short v_tmp = 127 * r - 106 * g - 21 * b;
// 2. Scale down (">>8") to 8-bit values with rounding ("+128") (Y′: unsigned, U/V: signed)
y_tmp = (y_tmp + 128) >> 8;
u_tmp = (u_tmp + 128) >> 8;
v_tmp = (v_tmp + 128) >> 8;
// 3. Add an offset to the values to eliminate any negative values (all results are 8-bit unsigned)
yuv[i * 3] = (unsigned char) y_tmp;
yuv[i * 3 + 1] = (unsigned char) (u_tmp + 128);
yuv[i * 3 + 2] = (unsigned char) (v_tmp + 128);
}
}