zoukankan      html  css  js  c++  java
  • 视频教程:YUV420和RGB相互转换C++实现(二)

       我是Gem,今天做个简单的视频,我的耳机坏了,不好意思,没有声音,请原谅~~
      
        时间很仓促,我把作业全部做完了,完整的过程我演示你看看,有什么问题请你指出来~~

        详细的代码说明和友好的界面(用MFC做),即将给出,如果你感兴趣,请时刻关注我的Blog: http://hexun.com/ctfysj

        我们开始,在C++ 里面我建立了两个工程,一个是RGB2YUV,另一个是yuv2rgb的,我们先看看RGB2YUV

        看我操作~~~


        RGB2YUV420 演示:

        用的图片是你给我的test.bmp,把test.bmp文件拷到工程目录下 E:\网站文件夹\YUV420和RGB相互转换\homework\RGB2YUV
       
        我转换成YUV420时候,存储在test.cif

        看我生成这种文件啊~~

        编译:  0 error(s), 0 warning(s)

        这种效果可以吗? 应该还行吧~~

        现在再看 RGB2YUV420 演示

        RGB2YUV420 演示:

        把上面生成的test.cif文件拷到工程目录下  E:\网站文件夹\YUV420和RGB相互转换\homework\yuv2rgb

        还原成test.bmp文件
       
        编译:0 error(s), 0 warning(s)

        还原后,差不多吧,反正我没有看出来有什么区别~~

        完整的代码 : 在 RGBYUV420代码完整版.txt 记事本里面


        慕容听雨
        个人主页:http://hexun.com/ctfysj
        QQ:308463776

    说明:下面的代码用C\C++执行都可以,用C的时候请把#include<iostream> 删除。
           代码的详细说明视频即将推出,请时刻关注我的Blog: http://hexun.com/ctfysj

    RGB to YUV420 原代码:  RGB2YUV.CPP文件

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include<iostream>

    //转换矩阵
    #define MY(a,b,c) (( a*  0.2989  + b*  0.5866  + c*  0.1145))
    #define MU(a,b,c) (( a*(-0.1688) + b*(-0.3312) + c*  0.5000 + 128))
    #define MV(a,b,c) (( a*  0.5000  + b*(-0.4184) + c*(-0.0816) + 128))
    //大小判断
    #define DY(a,b,c) (MY(a,b,c) > 255 ? 255 : (MY(a,b,c) < 0 ? 0 : MY(a,b,c)))
    #define DU(a,b,c) (MU(a,b,c) > 255 ? 255 : (MU(a,b,c) < 0 ? 0 : MU(a,b,c)))
    #define DV(a,b,c) (MV(a,b,c) > 255 ? 255 : (MV(a,b,c) < 0 ? 0 : MV(a,b,c)))
    //只处理352*288文件
    #define WIDTH 352
    #define HEIGHT 288

    //读BMP
    void ReadBmp(unsigned char *RGB,FILE *fp);

    //转换函数
    void Convert(unsigned char *RGB, unsigned char *YUV);

    //入口
    int main()
    {
        int i=1;
        char file[255];
        FILE *fp;
        FILE *fp2;
        unsigned char *YUV = NULL;
        unsigned char *RGB = NULL;
        unsigned int imgSize = WIDTH*HEIGHT;

        if((fp2 = fopen("test.cif", "wb")) == NULL)//生成文件名
        {
            return 0;
        }

        RGB = (unsigned char*)malloc(imgSize*6);
        YUV = (unsigned char*)malloc(imgSize + (imgSize>>1));
      
        for(i=1; i<2; i++)
        {
            sprintf(file, "test.bmp", i);//读取文件
            if((fp = fopen(file, "rb")) == NULL)
        continue;

            printf("打开文件%s\n", file);
            ReadBmp(RGB, fp);
            Convert(RGB, YUV);
            fwrite(YUV, 1, imgSize+(imgSize>>1), fp2);//写入文件
            fclose(fp);
        }

        fclose(fp2);
        if(RGB)
            free(RGB);

        if(YUV)
            free(YUV);

        printf("完成\n");
        system("pause");
        return 1;
    }

    //读BMP
    void ReadBmp(unsigned char *RGB,FILE *fp)
    {
        int i,j;
        unsigned char temp;

        fseek(fp,54, SEEK_SET);

        fread(RGB+WIDTH*HEIGHT*3, 1, WIDTH*HEIGHT*3, fp);//读取
        for(i=HEIGHT-1,j=0; i>=0; i--,j++)//调整顺序
        {
            memcpy(RGB+j*WIDTH*3,RGB+WIDTH*HEIGHT*3+i*WIDTH*3,WIDTH*3);
        }
       
        //顺序调整
        for(i=0; (unsigned int)i < WIDTH*HEIGHT*3; i+=3)
        {
            temp = RGB[i];
            RGB[i] = RGB[i+2];
            RGB[i+2] = temp;
        }
    }

    void Convert(unsigned char *RGB, unsigned char *YUV)
    {
        //变量声明
        unsigned int i,x,y,j;
        unsigned char *Y = NULL;
        unsigned char *U = NULL;
        unsigned char *V = NULL;
       
        Y = YUV;
        U = YUV + WIDTH*HEIGHT;
        V = U + ((WIDTH*HEIGHT)>>2);

        for(y=0; y < HEIGHT; y++)
            for(x=0; x < WIDTH; x++)
            {
                j = y*WIDTH + x;
                i = j*3;
                Y[j] = (unsigned char)(DY(RGB[i], RGB[i+1], RGB[i+2]));

                if(x%2 == 1 && y%2 == 1)
                {
                    j = (WIDTH>>1) * (y>>1) + (x>>1);
                    //上面i仍有效
                    U[j] = (unsigned char)
                           ((DU(RGB[i  ], RGB[i+1], RGB[i+2]) +
                             DU(RGB[i-3], RGB[i-2], RGB[i-1]) +
                             DU(RGB[i  -WIDTH*3], RGB[i+1-WIDTH*3], RGB[i+2-WIDTH*3]) +
                             DU(RGB[i-3-WIDTH*3], RGB[i-2-WIDTH*3], RGB[i-1-WIDTH*3]))/4);

                    V[j] = (unsigned char)
                           ((DV(RGB[i  ], RGB[i+1], RGB[i+2]) +
                             DV(RGB[i-3], RGB[i-2], RGB[i-1]) +
                             DV(RGB[i  -WIDTH*3], RGB[i+1-WIDTH*3], RGB[i+2-WIDTH*3]) +
                             DV(RGB[i-3-WIDTH*3], RGB[i-2-WIDTH*3], RGB[i-1-WIDTH*3]))/4);
                }

            }
    }

    YUV420 to RGB 原代码: yuv2rgb.cpp文件

    #include <stdio.h>
    #include <stdlib.h>
    #include <iostream>
    #define WIDTH 352
    #define HEIGHT 288
    //转换矩阵
    double YuvToRgb[3][3] = {1,       0,  1.4022,
                             1,    -0.3456, -0.7145,
                             1,   1.771,       0};

    //根据RGB三分量写BMP,不必关注
    int WriteBmp(int width, int height, unsigned char *R,unsigned char *G,unsigned char *B, char *BmpFileName);

    //转换函数
    int Convert(char *file, int width, int height, int n)
    {
        //变量声明
        int i = 0;
        int temp = 0;
        int x = 0;
        int y = 0;
        int fReadSize = 0;
        int ImgSize = width*height;
        FILE *fp = NULL;
        unsigned char* yuv = NULL;
        unsigned char* rgb = NULL;
        unsigned char* cTemp[6];
        char BmpFileName[256];

        //申请空间
        int FrameSize = ImgSize + (ImgSize >> 1);
        yuv = (unsigned char *)malloc(FrameSize);
        rgb = (unsigned char *)malloc(ImgSize*3);
        //读取指定文件中的指定帧
        if((fp = fopen(file, "rb")) == NULL)
            return 0;
        fseek(fp, FrameSize*(n-1), SEEK_CUR);
        fReadSize = fread(yuv, 1, FrameSize, fp);
        fclose(fp);
        if(fReadSize < FrameSize)
            return 0;
        //转换指定帧  如果你不是处理文件 主要看这里
        cTemp[0] = yuv;                        //y分量地址
        cTemp[1] = yuv + ImgSize;            //u分量地址
        cTemp[2] = cTemp[1] + (ImgSize>>2);    //v分量地址
        cTemp[3] = rgb;                        //r分量地址
        cTemp[4] = rgb + ImgSize;            //g分量地址
        cTemp[5] = cTemp[4] + ImgSize;        //b分量地址
        for(y=0; y < height; y++)
            for(x=0; x < width; x++)
            {
                //r分量
                temp = cTemp[0][y*width+x] + (cTemp[2][(y/2)*(width/2)+x/2]-128) * YuvToRgb[0][2];
                cTemp[3][y*width+x] = temp<0 ? 0 : (temp>255 ? 255 : temp);
                //g分量
                temp = cTemp[0][y*width+x] + (cTemp[1][(y/2)*(width/2)+x/2]-128) * YuvToRgb[1][1]
                                           + (cTemp[2][(y/2)*(width/2)+x/2]-128) * YuvToRgb[1][2];
                cTemp[4][y*width+x] = temp<0 ? 0 : (temp>255 ? 255 : temp);
                //b分量
                temp = cTemp[0][y*width+x] + (cTemp[1][(y/2)*(width/2)+x/2]-128) * YuvToRgb[2][1];
                cTemp[5][y*width+x] = temp<0 ? 0 : (temp>255 ? 255 : temp);
            }

        //写到BMP文件中
        sprintf(BmpFileName, "test.bmp", file, n);
        WriteBmp(width, height, cTemp[3], cTemp[4], cTemp[5], BmpFileName);

        free(yuv);
        free(rgb);
        return n;
    }
    //入口 没啥东西
    void main()
    {
        int i=1;
    //    for( i=0; i<260; i++)
            Convert("test.cif", WIDTH, HEIGHT, i);//调用上面的Convert,获取文件的第i帧
    }

    //写BMP  不必关注
    int WriteBmp(int width, int height, unsigned char *R,unsigned char *G,unsigned char *B, char *BmpFileName)
    {
        int x=0;
        int y=0;
        int i=0;
        int j=0;
        FILE *fp;
        unsigned char *WRGB;
        unsigned char *WRGB_Start;
        int yu = width*3%4;
        int BytePerLine = 0;

        yu = yu!=0 ? 4-yu : yu;
        BytePerLine = width*3+yu;

        if((fp = fopen(BmpFileName, "wb")) == NULL)
            return 0;
        WRGB = (unsigned char*)malloc(BytePerLine*height+54);
        memset(WRGB, 0, BytePerLine*height+54);
       
        //BMP头
        WRGB[0] = 'B';
        WRGB[1] = 'M';
        *((unsigned int*)(WRGB+2)) = BytePerLine*height+54;
        *((unsigned int*)(WRGB+10)) = 54;
        *((unsigned int*)(WRGB+14)) = 40;
        *((unsigned int*)(WRGB+18)) = width;
        *((unsigned int*)(WRGB+22)) = height;
        *((unsigned short*)(WRGB+26)) = 1;
        *((unsigned short*)(WRGB+28)) = 24;
        *((unsigned short*)(WRGB+34)) = BytePerLine*height;

        WRGB_Start = WRGB + 54;

        for(y=height-1,j=0; y >= 0; y--,j++)
        {
            for(x=0,i=0; x<width; x++)
            {
                WRGB_Start[y*BytePerLine+i++] = B[j*width+x];
                WRGB_Start[y*BytePerLine+i++] = G[j*width+x];
                WRGB_Start[y*BytePerLine+i++] = R[j*width+x];
            }
        }

        fwrite(WRGB, 1, BytePerLine*height+54, fp);
        free(WRGB);
        fclose(fp);
        return 1;
    }

    视频和代码下载地址:

         ftp://ctfysj.kongjian.in:***@ctfysj.kongjian.in/视频教学文件/homework.rar

      ***是密码,为了隐私,不能告诉别人,如你需要,请回复邮箱

    密码:

    **** 本内容跟帖回复才可浏览 *****

    文件名: homework.rar

    下载链接: http://cachefile5.fs2you.com/zh-cn/download/d643ef1aee1a19187dd0850c5259e48d/homework.rar

  • 相关阅读:
    关于安卓9patch图片的探究
    android中系统时间
    android中的对话框
    swing界面刷新问题
    android中的xml解析全解
    android中listView下拉刷新
    次小生成树(poj 1679)
    poj 2312(bfs+priority_queue)
    poj 2060(最小路径覆盖)
    poj 1734 (最小环)
  • 原文地址:https://www.cnblogs.com/Gemgin/p/3136479.html
Copyright © 2011-2022 走看看