zoukankan      html  css  js  c++  java
  • 音视频入门-08-RGB&YUV

    * 音视频入门文章目录 *

    YUV & RGB 相互转换公式

    YCbCr 的 Y 与 YUV 中的 Y 含义一致,Cb 和 Cr 与 UV 同样都指色彩,Cb 指蓝色色度,Cr 指红色色度,在应用上很广泛,JPEG、MPEG、DVD、摄影机、数字电视等皆采此一格式。
    因此一般俗称的 YUV 大多是指 YCbCr 。

    • RGB to YUV(YCbCr)

    RGB 范围 [0,255],Y 范围 [16,235] ,UV 范围 [16,239]。如果计算结果超过了取值范围要进行截取。

    Y = 0.257*R + 0.504*G + 0.098*B + 16;
    U = -0.148*R - 0.291*G + 0.439*B + 128;
    V = 0.439*R - 0.368*G - 0.071*B + 128;
    
    • YUV(YCbCr)to RGB

    RGB 范围 [0,255],Y 范围 [16,235] ,UV 范围 [16,239]。如果计算结果超过了取值范围要进行截取。

    R = 1.164*(Y - 16) + 1.596*(V - 128);
    G = 1.164*(Y - 16) - 0.813*(V - 128) - 0.391*(U - 128);
    B = 1.164*(Y - 16) + 2.018*(U - 128);
    

    FFmpeg 工具的辅助

    FFmpeg 将 之前生成的彩虹图 BMP 转成 YUV 格式的文件、RGB 格式的文件

    ffmpeg -i rainbow.bmp -video_size 700x700 -pix_fmt yuv444p rainbow-yuv444p.yuv
    
    ffmpeg -i rainbow.bmp -video_size 700x700 -pix_fmt rgb24 rainbow-rgb24.rgb
    

    FFplay 查看生成的 YUV 格式的文件、RGB 格式的文件

    ffplay -f rawvideo -pix_fmt yuv444p -video_size 700x700 rainbow-yuv444p.yuv
    
    ffplay -f rawvideo -pix_fmt rgb24 -video_size 700x700 rainbow-rgb24.rgb
    

    ffmpeg-bmp-to-yuv444p-rgb24.jpg

    用代码实现 RGB & YUV 转换

    RGB -> YUV

    将 FFmpeg 生成的 RGB24 格式转换成 YUV444P 格式。
    [rainbow-rgb24.rgb] -> [rainbow-rgb24-to-yuv444p.yuv]

    #include <stdio.h>
    #include <string.h>
    #include <math.h>
    
    // 彩虹的七种颜色
    u_int32_t rainbowColors[] = {
            0XFF0000, // 红
            0XFFA500, // 橙
            0XFFFF00, // 黄
            0X00FF00, // 绿
            0X007FFF, // 青
            0X0000FF, // 蓝
            0X8B00FF  // 紫
    };
    
    u_int8_t bound(u_int8_t start, int value, u_int8_t end) {
        if(value <= start) {
            return start;
        }
        if(value >= end) {
            return end;
        }
        return value;
    }
    
    void rgbToYuv(u_int8_t R, u_int8_t G, u_int8_t B, u_int8_t *Y, u_int8_t *U, u_int8_t *V) {
        int y_val = (int)round(0.257*R + 0.504*G + 0.098*B + 16);
        int u_val = (int)round(-0.148*R - 0.291*G + 0.439*B + 128);
        int v_val = (int)round(0.439*R - 0.368*G - 0.071*B + 128);
        *Y = bound(16, y_val, 235);
        *U = bound(16, u_val, 239);
        *V = bound(16, v_val, 239);
    }
    
    
    void rgb24ToYuv444p(const u_int8_t *rgb24Data, u_int8_t *yuv444pData, int width, int height) {
    
        int8_t yuv_y[width*height];
        int8_t yuv_u[width*height];
        int8_t yuv_v[width*height];
    
        for (int i = 0; i < width; ++i) {
            for (int j = 0; j < height; ++j) {
                u_int8_t Y, U, V;
                u_int8_t R, G, B;
    
                int currentRGBIndex = 3*(i*height+j);
                R = rgb24Data[currentRGBIndex];
                G = rgb24Data[currentRGBIndex+1];
                B = rgb24Data[currentRGBIndex+2];
    
                rgbToYuv(R, G, B, &Y, &U, &V);
    
                int currentYUVIndex = i*height+j;
                yuv_y[currentYUVIndex] = Y;
                yuv_u[currentYUVIndex] = U;
                yuv_v[currentYUVIndex] = V;
            }
        }
        
        memcpy(yuv444pData, yuv_y, sizeof(yuv_y));
        memcpy(yuv444pData + sizeof(yuv_y), yuv_u, sizeof(yuv_u));
        memcpy(yuv444pData + sizeof(yuv_y) + sizeof(yuv_u), yuv_v, sizeof(yuv_v));
        
    }
    
    int main() {
        int width = 700, height = 700;
        u_int8_t yuv444pData[width*height*3];
        u_int8_t rgb24Data[width*height*3];
        
        FILE *rgb24File = fopen("/Users/staff/Desktop/rainbow-rgb24.rgb", "rb");
        fread(rgb24Data, sizeof(rgb24Data), 1, rgb24File);
        
        rgb24ToYuv444p(rgb24Data, yuv444pData, width, height);
    
        FILE *yuv444pFile = fopen("/Users/ff/Desktop/rainbow-rgb24-to-yuv444p.yuv", "wb");
        fwrite(yuv444pData, sizeof(yuv444pData), 1, yuv444pFile);
        
        fclose(rgb24File);
        fclose(yuv444pFile);
        return 0;
    }
    
    ffplay -f rawvideo -pix_fmt rgb24 -video_size 700x700 rainbow-rgb24.rgb
    
    ffplay -f rawvideo -pix_fmt yuv444p -video_size 700x700 rainbow-rgb24-to-yuv444p.yuv
    

    rgb24-to-yuv444p.jpg

    YUV -> RGB

    将 FFmpeg 生成的 YUV444P 格式转换成 RGB24 格式。
    [rainbow-yuv444p.yuv] -> [rainbow-yuv444p-to-rgb24.rgb]

    #include <stdio.h>
    #include <math.h>
    
    
    u_int8_t bound(u_int8_t start, int value, u_int8_t end) {
        if(value <= start) {
            return start;
        }
        if(value >= end) {
            return end;
        }
        return value;
    }
    
    
    void yuv444pToRGB(u_int8_t *yuv444pData,u_int8_t *rgb24Data, int width, int height) {
        u_int8_t *srcY = yuv444pData, *srcU = srcY + width * height, *srcV = srcU + width * height;
    
        for(int i = 0 ; i < height ; i ++) {
            for (int j = 0; j < width; j++) {
                int currentYUVIndex = i * height + j;
                u_int8_t Y = srcY[currentYUVIndex], U = srcU[currentYUVIndex], V = srcV[currentYUVIndex];
    
                int r_val = (int)round(1.164*(Y-16)+1.596*(V-128));
                int g_val = (int)round(1.164*(Y-16)-0.813*(V-128)-0.391*(U-128));
                int b_val = (int)round(1.164*(Y-16)+2.018*(U-128));
    
                int currentRGBIndex = 3*(i * width + j);
                rgb24Data[currentRGBIndex] = bound(0, r_val, 255);
                rgb24Data[currentRGBIndex+1] = bound(0, g_val, 255);
                rgb24Data[currentRGBIndex+2] = bound(0, b_val, 255);
            }
        }
    }
    
    int main() {
        int width = 700, height = 700;
        u_int8_t yuv444pData[width*height*3];
        u_int8_t rgb24Data[width*height*3];
    
        FILE *yuv444pFile = fopen("/Users/staff/Desktop/rainbow-yuv444p.yuv", "rb");
        fread(yuv444pData, sizeof(yuv444pData), 1, yuv444pFile);
    
         yuv444pToRGB(yuv444pData, rgb24Data, width, height);
    
        FILE *rgb24File = fopen("/Users/staff/Desktop/rainbow-yuv444p-to-rgb24.rgb", "wb");
        fwrite(rgb24Data, sizeof(rgb24Data), 1, rgb24File);
    
        fclose(yuv444pFile);
        fclose(rgb24File);
        return 0;
    }
    
    ffplay -f rawvideo -pix_fmt yuv444p -video_size 700x700 rainbow-yuv444p.yuv
    
    ffplay -f rawvideo -pix_fmt rgb24 -video_size 700x700 rainbow-yuv444p-to-rgb24.rgb
    

    yuv444p-to-rgb24.jpg

    使用色彩丰富的图片验证

    准备一张手机拍摄的 Disney.png

    ffmpeg -i Disney.png -video_size 700x700 -pix_fmt yuv444p Disney-yuv444p.yuv
    ffmpeg -i Disney.png -video_size 700x700 -pix_fmt rgb24 Disney-rgb24.rgb
    
    ffplay -f rawvideo -pix_fmt yuv444p -video_size 700x700 Disney-yuv444p.yuv
    ffplay -f rawvideo -pix_fmt rgb24 -video_size 700x700 Disney-rgb24.rgb
    

    Disney-demo.jpg

    使用上面的代码进行转换后得到 Disney-rgb24-to-yuv444p.yuv Disney-yuv444p-to-rgb24.rgb

    Disney-demo-result.jpg

    Congratulations!


    代码:
    08-rgb-to-yuv

    参考资料:

    YUV 格式与 RGB 格式的相互转换公式及C++ 代码

    Color Conversion

    videolan-YUV

    博客目录-技术-视频处理

    YUV格式学习:YUV420P、YV12、NV12、NV21格式转换成RGB24

    图像RGB2YUV与YUV2RGB格式互转介绍

    YUV转RGB的优化算法

    YUV 格式与 RGB 格式的相互转换公式及C++ 代码

    YUV420与YUV444互转,YUV420与YUV444读取和保存,YUV的显示和播放功能

    YCbCr与YUV的区别

    维基百科-YUV

    维基百科-YCbCr

    内容有误?联系作者:

    联系作者


  • 相关阅读:
    nginx 详解
    阿里云 消息队列mq
    手机浏览器Yandex安装插件说明
    windows下JAVA环境变量配置
    共享文件夹免密登入
    自动添加静态路由
    加入WSUS补丁服务器并下载补丁
    加入时间同步服务器(NTP)
    更改rdp端口
    关闭及开启445等危险端口
  • 原文地址:https://www.cnblogs.com/binglingziyu/p/audio-video-basic-08-rgb-and-yuv.html
Copyright © 2011-2022 走看看