author : quinncy(博客园)
最近在做一个关于图像采集的项目,需要将yuv420p的图像转换成jpg格式进行传输
在网上看到了很多方法,如利用libjpeg,ffmpeg等
偶然在论坛上看到了有人的博客里面写了利用纯C语言完成图像转换,
如果移植到arm板上就不需要安装各种库支持,因此打算试试
操作平台:ubuntu16.04
这是从论坛上下载的源代码
由于我在项目中采集到的图片是yuv420p格式的,因此需要对代码进行修改
先说test.c
里面有一个get_Y_U_V()函数
实现的功能是将图像文件的在一个数组里面的yuv数据分别读取到in_y,in_u,in_v里面
核心部分是下列代码:
1 int i = 0;2 int y_n =0;3 int u_n =0;4 int v_n =0;5 int u = 0;6 int v = 2;7
8 while(i
不难看出,图像文件中的存储格式为UYUV格式的!
但是由于我在项目中生成的是YUV420p格式的图像,因此需要修改这部分的代码
yuv420p文件存储格式如下:
因此,我更改了get_Y_U_V函数的核心代码部分如下:
1 while(i < 1280*720)2 {3 in_Y[y_n] =rData[i];4 i++;5 y_n++;6 }7 while(i < 1280*720*5/4)8 {9 in_U[u_n] =rData[i];10 i++;11 u_n++;12 }13 while(i < 1280*720*3/2)14 {15 in_V[v_n] =rData[i];16 i++;17 v_n++;18
19 }
这样就可以分别把yuv的数据存放到in_Y,in_U,in_V里面了。
然后再说YUV2Jpg函数里面
1 unsigned char*pYBuf;2 unsigned char*pUBuf;3 unsigned char*pVBuf;4 int nYLen = nStride *height;5
6 pYBuf = (unsigned char*)malloc(nYLen);7 pUBuf = (unsigned char*)malloc(nYLen);8 pVBuf = (unsigned char*)malloc(nYLen);
定义了三个指针分别指向了nYLen大小的空间
可以得到需要将每个像素点的yuv数据分别存放在pYBuf,pUBuf,pVBuf中
比如第一个像素点的yuv数据,应该是放在pYBuf[0],pUBuf[0],pVBuf[0],依次类推
因为yuv420p的数据格式中,y的数据刚好等于图像大小,最容易处理
而u,v数据是4个像素点共用一组数据,因此需要对应拓展存储到数组的相应位置
拓展的函数在processUV()
1 int i=0;2 while(i
这是论坛源代码里面的处理函数
由于UYUV格式里面的数据是两个像素点共用一组uv数据,因此上面的处理应该很容易理解
而我所用的是yuv420p,需要四个像素点共用,因此修改函数为如下:
1 inti,j;2 int count = 0;3 for(i = 0; i < height; i+=2)4 {5 for(j = 0; j < nStride; j+=2)6 {7 pUVBuf[i * width + j] =pTmpUVBuf[count];8 pUVBuf[i * width + j + 1] =pTmpUVBuf[count];9 pUVBuf[i * width + j + width] =pTmpUVBuf[count];10 pUVBuf[i * width + j + width + 1] =pTmpUVBuf[count];11 count++;12 }13 }
这样处理之后,就可以将uv数据分别与像素点对应起来!
下面将main函数贴出来:
1 intmain()2 {3 unsigned char* in_Y = (unsigned char*)malloc(1280*720);//4 unsigned char* in_U = (unsigned char*)malloc(1280* 720/4);//5 unsigned char* in_V = (unsigned char*)malloc(1280* 720 / 4);//6 unsigned char* pData = (unsigned char*)malloc(1280 * 720);//7 unsigned char* rData = (unsigned char*)malloc(1280*720*3/2);8
9 unsigned long dwSize = 0;10 FILE *rfp = fopen("./00001.yuv","rb");11 if(NULL ==rfp)12 fprintf(stderr,"fopen fp error:%s\n",strerror(errno));13 fread(rData,1280*720*3/2,1,rfp);14 get_Y_U_V(rData,in_Y,in_U,in_V,1280,720);15
16
17 YUV2Jpg(in_Y,in_U,in_V,1280,720,100,1280,pData,&dwSize);18 FILE *fp = fopen("2.jpg","wb");19 fwrite(pData,dwSize,1,fp);20 fclose(fp);21
22 free(rData);23 free(in_Y);24 free(in_U);25 free(in_V);26 free(pData);27
28 return 0;29 }
修改00001.yuv部分为你的yuv图像路径与文件名
再将图像的大小改为你的图像数据(我用的是1280x720的)
应该就可以生成2.jpg格式的图像了
注:
这个在linux(ubuntu16.04)上面使用gcc编译后已经验证成功,可以将00001.yuv格式图像转换为2.jpg
但是使用arm-linux-gcc编译后,在arm板上执行不了,会出现内存不够的现象
尝试使用malloc后,内存问题解决,但是又发现执行时间太长(大概1个半小时左右),
打算用在arm板上的慎用!!!
完整代码已经上传到github上面,里面包含测试文件00001.yuv文件,以及生成的2.jpg图像,链接如下:
现在已经通过libjpeg实现arm板上面的yuv420p到jpg的图像转换,后面会写相关的博客~~