zoukankan      html  css  js  c++  java
  • yuv420p转jpg linux(纯C语言实现)

    author : quinncy(博客园)

    最近在做一个关于图像采集的项目,需要将yuv420p的图像转换成jpg格式进行传输

    在网上看到了很多方法,如利用libjpeg,ffmpeg等

    偶然在论坛上看到了有人的博客里面写了利用纯C语言完成图像转换,

    如果移植到arm板上就不需要安装各种库支持,因此打算试试

    操作平台:ubuntu16.04

    这是从论坛上下载的源代码

    链接:https://pan.baidu.com/s/17loJTI4uLmRDeR4sLYm6_A 密码:3f0v

    由于我在项目中采集到的图片是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<size){
     9         if(i%2 != 0){
    10             in_Y[y_n]= rData[i];
    11             y_n++;        
    12         }
    13         else if(i == u){
    14             in_U[u_n]= rData[i];
    15             u += 4;    
    16             u_n++;    
    17         }
    18         else if(i == v){
    19             in_V[v_n] = rData[i];
    20             v += 4;
    21             v_n++;
    22         }
    23         i++;
    24     }

    不难看出,图像文件中的存储格式为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<nStride*height){
    3             pUVBuf[i] = pTmpUVBuf[i/2];
    4             i++;
    5     }

    这是论坛源代码里面的处理函数

    由于UYUV格式里面的数据是两个像素点共用一组uv数据,因此上面的处理应该很容易理解

    而我所用的是yuv420p,需要四个像素点共用,因此修改函数为如下:

     1     int i,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 int main()
     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
    ",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图像,链接如下:

    https://github.com/quinncy/yuv420p_jpg_linux_C/tree/master 

    现在已经通过libjpeg实现arm板上面的yuv420p到jpg的图像转换,后面会写相关的博客~~

  • 相关阅读:
    Asp.Net中Word,Excel等office com组件操作权限的问题 ————转自rainpig2008
    正则表达式摘录
    html5 Canvas画图2:画线条
    彻底理解函数声明与函数表达式优先级问题
    javascript定义变量和优先级的问题
    html5 Canvas画图4:填充和渐变
    讨论下canvas画椭圆的方法
    html5 Canvas画图3:1像素线条模糊问题
    [推荐]实在受不了canvas的语法了!我要让他支持链式语法!
    html5 Canvas画图5:画曲线之arc
  • 原文地址:https://www.cnblogs.com/zhq-blog/p/8832157.html
Copyright © 2011-2022 走看看