NV12
一个6*4的nv12格式的图片的三个分量YUV的内存形式:

虽然nv12的像素大小是width*height,但是必须为nv12图片分配width*height*3/2的内存空间,因为Y分量所占的内存为width*height,而U,V分量各占width*height/4,见上图即一目了然。
nv12分量YUV分量内存操作:可以用双重for循环遍历nv12各个分量的内存分布,从而实现给nv12图片赋予不同的颜色。
由内存YUV分量内存分布图可以知道:
0 ~ width*height 为Y分量存储的内存范围。
width*height ~ width*height*3/2 为UV交叉存储的内存范围。
操作Y分量:buf[j * width + k]
操作U分量 : buf[j / 2 * width + k - k % 2 + width * height]
操作V分量 : buf[j / 2 * width + k - k % 2 + width * height + 1]
在nv12格式的图片上画一个锁定某个目标的矩形方框图
#include <stdio.h>
#include <stdlib.h>
int nv12_border(char *pic, int pic_w, int pic_h, int rect_x, int rect_y, int rect_w, int rect_h, int R, int G, int B);
int main()
{
const int pic_w = 1920;
const int pic_h = 1080;
char *inputPathname = "/home/flypei/work/nv12-marked-rect/data/videotestsrc_1920x1080.nv12";
char *outputPathname = "./outputFile.nv12";
FILE *fin = fopen(inputPathname , "rb+");
FILE *fout = fopen(outputPathname, "wb+");
unsigned char *buf = (unsigned char *)malloc(pic_w * pic_h * 3 / 2);
fread(buf, 1, pic_w * pic_h * 3 / 2, fin);
nv12_border(buf, pic_w, pic_h, 500, 500, 300, 400, 0, 0, 255);
fwrite(buf, 1, pic_w * pic_h * 3 / 2, fout);
free(buf);
fclose(fin);
fclose(fout);
return 0;
}
int nv12_border(char *pic, int pic_w, int pic_h, int rect_x, int rect_y, int rect_w, int rect_h, int R, int G, int B)
{
const int border = 5;
int Y, U, V;
Y = 0.299 * R + 0.587 * G + 0.114 * B;
U = -0.1687 * R + 0.3313 * G + 0.5 * B + 128;
V = 0.5 * R - 0.4187 * G - 0.0813 * B + 128;
int j, k;
for(j = rect_y; j < rect_y + rect_h; j++){
for(k = rect_x; k < rect_x + rect_w; k++){
if (k < (rect_x + border) || k > (rect_x + rect_w - border) ||\
j < (rect_y + border) || j > (rect_y + rect_h - border)){
int y_index = j * pic_w + k;
int u_index = (y_index / 2 - pic_w / 2 * ((j + 1) / 2)) * 2 + pic_w * pic_h;
int v_index = u_index + 1;
pic[y_index] = Y ;
pic[u_index] = U ;
pic[v_index] = V ;
}
}
}
return 0;
}
原nv12图片(用yuvplayer查看):
加上方框的nv12图片(用yuvplayer查看):

demo优化版
#include <stdio.h>
#include <stdlib.h>
#define uchar unsigned char
typedef struct rectangle{
int x;
int y;
int w;
int h;
uchar thin;
uchar YUV[3];
}RECT;
void RgbToYuv(uchar RGB[], uchar YUV[]);
void FindAxis(RECT rect[], int n, int rect_all_axis[]);
void DrawWidthLine(uchar* pic, int pic_w, int pic_h, RECT rect[], int n, int axis[]);
void DrawHeightLine(uchar* pic, int pic_w, int pic_h, RECT rect[], int n, int axis[]);
void DrawPoint(uchar* pic, int pic_w, int pic_h, int point_axis[], int count, uchar YUV[]);
void NV12MarkRect(uchar* pic, int pic_w, int pic_h, RECT rect[], int n, int point_axis[], int count);
int main()
{
/*****************************************************/
/**** ****/
/**** Configure Parameter ****/
/**** ****/
/*****************************************************/
const int pict_w = 1920;
const int pict_h = 1080;
int picSize = pict_w * pict_h * 1.5;
uchar* picBuf = (unsigned char *)malloc(picSize);
uchar RGBblue[3] = {255, 0, 0};
uchar YUVblue[3];
RgbToYuv(RGBblue, YUVblue);
int n = 2;
uchar t = 1;
RECT Rect[] = {
{
.x = 0,
.y = 0,
.w = 96,
.h = 96,
.thin = t,
.YUV[0] = YUVblue[0],
.YUV[1] = YUVblue[1],
.YUV[2] = YUVblue[2] },
{
.x = 144,
.y = 144,
.w = 128,
.h = 128,
.thin = t,
.YUV[0] = YUVblue[0],
.YUV[1] = YUVblue[1],
.YUV[2] = YUVblue[2] }
};
int c = 30;
int point[] = { 12,233, 132,15, 142,22, 312,34, 112,45, 212,58, 127,62, 132,72, 212,84, 129,91,
112,66, 187,38, 155,13, 145,56, 134,23, 165,56, 176,67, 189,87, 174,52, 121,99,
212,66, 287,38, 255,13, 245,56, 234,23, 265,56, 276,67, 289,87, 274,52, 221,99 };
char input[255] = "videotestsrc_1920x1080.nv12";
char output[255] = "outputFile.nv12";
/******************************************************/
FILE *fin = fopen(input, "rb");
FILE *fout = fopen(output, "wb+");
fread(picBuf, 1, picSize, fin);
NV12MarkRect(picBuf, pict_w, pict_h, Rect, n, point, c);
fwrite(picBuf, 1, picSize, fout);
free(picBuf);
fclose(fin);
fclose(fout);
return 0;
}
void RgbToYuv(uchar RGB[3], uchar YUV[3])
{
YUV[0] = 0.299 * RGB[0] + 0.587 * RGB[1] + 0.114 * RGB[2];
YUV[1] = -0.1687 * RGB[0] + 0.3313 * RGB[1] + 0.5 * RGB[2] + 128;
YUV[2] = 0.5 * RGB[0] - 0.4187 * RGB[1] - 0.0813 * RGB[2] + 128;
}
void FindAxis(RECT rect[], int n, int axis[])
{
axis[0] = axis[2] = axis[4] = rect[n].x;
axis[6] = rect[n].x + rect[n].w - rect[n].thin;
axis[1] = rect[n].y;
axis[3] = rect[n].y + rect[n].h - rect[n].thin;
axis[5] = axis[7] = rect[n].y + rect[n].thin;
}
void DrawWidthLine(uchar* pic, int pic_w, int pic_h, RECT rect[], int n, int axis[])
{
int i, j, k;
int y_index, u_index, v_index;
for (i = 0; i < 4; i += 2){
for (j = axis[i+1]+rect[n].thin-1; j >= axis[i+1]; j--){
for (k = axis[i]+rect[n].w-1; k >= axis[i]; k--){
y_index = j * pic_w + k;
u_index = ((j >> 1) + pic_h) * pic_w + k - (k & 1);
v_index = u_index + 1;
pic[y_index] = rect[n].YUV[0];
pic[u_index] = rect[n].YUV[1];
pic[v_index] = rect[n].YUV[2];
}
}
}
}
void DrawHeightLine(uchar* pic, int pic_w, int pic_h, RECT rect[], int n, int axis[])
{
int i, j, k;
int y_index, u_index, v_index;
for (i = 4; i < 8; i += 2){
for (k = axis[i]+rect[n].thin-1; k >= axis[i]; k--){
for (j = axis[i+1]+rect[n].h-(2*rect[n].thin)-1; j >= axis[i+1]; j--){
y_index = j * pic_w + k;
u_index = ((j >> 1) + pic_h) * pic_w + k - (k & 1);
v_index = u_index + 1;
pic[y_index] = rect[n].YUV[0];
pic[u_index] = rect[n].YUV[1];
pic[v_index] = rect[n].YUV[2];
}
}
}
}
void DrawPoint(uchar* pic, int pic_w, int pic_h, int point_axis[], int count, uchar YUV[])
{
int a, y_point, u_point, v_point;
for (a = (count-1)*2; a >= 0; a -= 2){
y_point = point_axis[a+1] * pic_w + point_axis[a];
u_point = ((point_axis[a+1] >> 1) + pic_h) * pic_w + point_axis[a] - (point_axis[a] & 1);
v_point = u_point + 1;
pic[y_point] = YUV[0];
pic[u_point] = YUV[1];
pic[v_point] = YUV[2];
}
}
void NV12MarkRect(uchar* pic, int pic_w, int pic_h, RECT rect[], int num, int point_axis[], int count)
{
int i;
int axis[8];
for (i = num-1; i >= 0; i--){
FindAxis(rect, i, axis);
DrawWidthLine(pic, pic_w, pic_h, rect, i, axis);
DrawHeightLine(pic, pic_w, pic_h, rect, i, axis);
}
DrawPoint(pic, pic_w, pic_h, point_axis, count, rect[0].YUV);
}
|