RGB<---->YUV转换

       与我们熟知的RGB类似,YUV也是一种颜色编码方法,主要用于电视系统以及模拟视频领域,它将亮度信息(Y)与色彩信息(UV)分离,没有UV信息一样可以显示完整的图像,只不过是黑白的,这样的设计很好地解决了彩色电视机与黑白电视的兼容问题。

      并且,YUV不像RGB那样要求三个独立的视频信号同时传输,所以用YUV方式传送占用极少的频宽

1、RGB---->YUV转换

// BmptoYuv420.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

// 说明:下面的代码用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*/320
#define HEIGHT /*288*/240

//读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);
            }

        }
}

说明:生成一个YUV格式的文件,此处取名为:test.cif

 

2、YUV---->RGB转换(把test.cif转换成bmp图片)

// YuvtoRgb.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

// 
// int main(int argc, char* argv[])
// {
// 	return 0;
// }

#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#define WIDTH /*352*/320
#define HEIGHT /*288*/240
//转换矩阵
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;
}


 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用libjpeg-turbo库将YUV图像转换为JPEG图像,可以按照以下步骤进行: 1. 准备好YUV图像数据,包括图像宽度、高度、采样格式、YUV数据缓冲区等。 2. 定义一个jpeg_compress_struct结构体,用于设置JPEG图像的压缩参数。 ```c jpeg_compress_struct cinfo; ``` 3. 初始化jpeg_compress_struct结构体,并设置压缩参数。其中,input_components表示输入图像的每个像素包含的颜色分量数,通常为3(表示RGB颜色空间),quality表示压缩质量,取值范围为0-100。 ```c jpeg_create_compress(&cinfo); cinfo.image_width = width; cinfo.image_height = height; cinfo.input_components = 3; cinfo.in_color_space = JCS_YCbCr; jpeg_set_defaults(&cinfo); jpeg_set_quality(&cinfo, quality, TRUE); ``` 4. 定义一个jpeg_error_mgr结构体,用于处理JPEG图像压缩过程中的错误信息。 ```c jpeg_error_mgr jerr; cinfo.err = jpeg_std_error(&jerr); ``` 5. 调用jpeg_stdio_dest函数设置JPEG图像输出文件。 ```c FILE *outfile = fopen(output_filename, "wb"); jpeg_stdio_dest(&cinfo, outfile); ``` 6. 调用jpeg_start_compress函数,开始压缩JPEG图像。 ```c jpeg_start_compress(&cinfo, TRUE); ``` 7. 循环读取YUV图像数据,并使用jpeg_write_scanlines函数将每行数据转换为JPEG格式写入输出文件中。 ```c JSAMPROW row_pointer[1]; int row_stride = width * 3; while (cinfo.next_scanline < cinfo.image_height) { row_pointer[0] = &yuv_data[cinfo.next_scanline * row_stride]; jpeg_write_scanlines(&cinfo, row_pointer, 1); } ``` 8. 调用jpeg_finish_compress函数和jpeg_destroy_compress函数结束压缩JPEG图像过程。 ```c jpeg_finish_compress(&cinfo); fclose(outfile); jpeg_destroy_compress(&cinfo); ``` 完整代码示例: ```c #include <stdio.h> #include <jpeglib.h> int yuv_to_jpeg(const char *output_filename, unsigned char *yuv_data, int width, int height, int quality) { jpeg_compress_struct cinfo; jpeg_error_mgr jerr; FILE *outfile; JSAMPROW row_pointer[1]; int row_stride; cinfo.err = jpeg_std_error(&jerr); jpeg_create_compress(&cinfo); outfile = fopen(output_filename, "wb"); if (outfile == NULL) { return -1; } jpeg_stdio_dest(&cinfo, outfile); cinfo.image_width = width; cinfo.image_height = height; cinfo.input_components = 3; cinfo.in_color_space = JCS_YCbCr; jpeg_set_defaults(&cinfo); jpeg_set_quality(&cinfo, quality, TRUE); jpeg_start_compress(&cinfo, TRUE); row_stride = width * 3; while (cinfo.next_scanline < cinfo.image_height) { row_pointer[0] = &yuv_data[cinfo.next_scanline * row_stride]; jpeg_write_scanlines(&cinfo, row_pointer, 1); } jpeg_finish_compress(&cinfo); fclose(outfile); jpeg_destroy_compress(&cinfo); return 0; } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值