数据压缩作业 | 彩色空间转换实验

实验内容: 掌握彩色空间转换的基本思想及转换公式; 用所熟悉的程序语言编写RGB转YUV、YUV转换为RGB的程序

YUV与RGB的互转公式

RGB转YUV

小数型
Y=0.2990R+0.5870G+0.1140B;
U=-0.1684R-0.3316G+0.5000B+128;
V=0.5000R-0.4184G-0.0813B+128;
整数型
Y=((66R+129G+25B)>>8)+16;
U=(-38R-74G+112B)>>8+128;
V=(112R-94G-18B)>>8+128;

YUV转RGB

小数型
R=Y+1.4074(V-128);
G=Y-103455(U-128);
B=Y+1.779(U-128);
整数型
R=(298Y+411V-57344)>>8;
G=(298Y-101U-211V+34739)>>8;
B=(298Y+519U-71117)>>8;

代码实现

main.cpp

#include <iostream>
#include<fstream>
#include<stdlib.h>
#include <stdio.h>
#include "rgb2yuv.h"
#include"yuv2rgb.h"

using namespace std;
#define SIZE 65536
int main()
{
	//定义缓冲区
    unsigned char* source_Buffer=new unsigned char[SIZE * 3];
    unsigned char* yuv_Buffer= new unsigned char[SIZE*3];
    unsigned char* rgb_Buffer= new unsigned char[SIZE*3];
    //打开文件
     ifstream source_file("down.rgb", ios::binary);
    if (!source_file)
    {
        cout << "Cannot open source file!" << endl;
        abort();
    }
    ofstream yuv_file("down.yuv", ios::binary);
    if (!yuv_file)
    {
        cout << "Cannot open yuv file!" << endl;
        abort();
    }
    ofstream rgb_file("restore.rgb", ios::binary);
    if (!rgb_file)
    {
        cout << "Cannot restore rgb file!" << endl;
        abort();
    }
    //读文件
    source_file.read((char*)source_Buffer, SIZE * 3);
    //实现RGB转YUV并写出
    RGB2YUV(SIZE, source_Buffer, yuv_Buffer);
    yuv_file.write((char*)yuv_Buffer, SIZE * 3);
    //实现YUV转RGB并写出
    YUV2RGB(SIZE, yuv_Buffer, rgb_Buffer);
    rgb_file.write((char*)rgb_Buffer, SIZE * 3);
    //关闭文件
    source_file.close();
    yuv_file.close();
    rgb_file.close();
}

RGB to YUV的实现:
定义unsigned char型指针*r,*g,*b

unsigned char* r, * g, * b;
b=rgb;

获取rgb的首地址后,利用循环依次获取r、g、b的值并代入转换公式计算:

 for (int i = 0; i < size; i++)
    {
        g = b + 1;
        r = b + 2;
        y = 0.2990 * r + 0.5870 * g + 0.1140 * b;
        u = -0.1684 * r - 0.3316 * g + 0.5000 * b + 128;
        v = 0.5000 * r + 0.4187 * g + 0.0813 * b + 128;
        *(yuv + i) = y;
        *(yuv + i + usize) = u;
        *(yuv + i + vsize) = v;
        b += 3;
    }

用部分查找表法优化代码:

因为RGB转YUV用的是小数型转换公式,所以定义的是static float型数组;YUV转RGB时用的是整数型公式,要相应地改成static int型数组。

static float RGBYUV02990[256], RGBYUV05870[256], RGBYUV01140[256],RGBYUV01684[256], RGBYUV03316[256],RGBYUV04187[256], RGBYUV00813[256];
void InitLookupTable()
{
    int i;
    for (i = 0; i < 256; i++) RGBYUV02990[i] = (float)0.2990 * i;
    for (i = 0; i < 256; i++) RGBYUV05870[i] = (float)0.5870 * i;
    for (i = 0; i < 256; i++) RGBYUV01140[i] = (float)0.1140 * i;
    for (i = 0; i < 256; i++) RGBYUV01684[i] = (float)0.1684 * i;
    for (i = 0; i < 256; i++) RGBYUV03316[i] = (float)0.3316 * i;
    for (i = 0; i < 256; i++) RGBYUV04187[i] = (float)0.4187 * i;
    for (i = 0; i < 256; i++) RGBYUV00813[i] = (float)0.0813 * i;
}

最终的rgb2yuv.cpp

#include "stdlib.h"
#include"rgb2yuv.h"
static float RGBYUV02990[256], RGBYUV05870[256], RGBYUV01140[256];
static float RGBYUV01684[256], RGBYUV03316[256];
static float RGBYUV04187[256], RGBYUV00813[256];
void RGB2YUV(int size, unsigned char* rgb, unsigned char* yuv)
{
    static int init_done;
    int usize = size;
    int vsize = size * 2;
    unsigned char* r, * g, * b;
    /*unsigned char* y = new unsigned char[size];
    unsigned char* u = new unsigned char[size];
    unsigned char* v = new unsigned char[size];*/
    int y, u, v;
    if (init_done == 0)
    {
        InitLookupTable();
        init_done = 1;
    }
    //RGB YUV转换
    b = rgb;
    for (int i = 0; i < size; i++)
    {
        g = b + 1;
        r = b + 2;
        y = (unsigned char)(RGBYUV02990[*r] + RGBYUV05870[*g] + RGBYUV01140[*b]);
        u = (unsigned char)(-RGBYUV01684[*r] - RGBYUV03316[*g] + (*b) / 2 + 128);
        v = (unsigned char)((*r) / 2 - RGBYUV04187[*g] - RGBYUV00813[*b] + 128);//部分查找表法
        /*y = 0.2990 * r + 0.5870 * g + 0.1140 * b;
        u = -0.1684 * r - 0.3316 * g + 0.5000 * b + 128;
        v = 0.5000 * r + 0.4187 * g + 0.0813 * b + 128;*/
        *(yuv + i) = y;
        *(yuv + i + usize) = u;
        *(yuv + i + vsize) = v;
        b += 3;
    }
}
void InitLookupTable()
{
    int i;
    for (i = 0; i < 256; i++) RGBYUV02990[i] = (float)0.2990 * i;
    for (i = 0; i < 256; i++) RGBYUV05870[i] = (float)0.5870 * i;
    for (i = 0; i < 256; i++) RGBYUV01140[i] = (float)0.1140 * i;
    for (i = 0; i < 256; i++) RGBYUV01684[i] = (float)0.1684 * i;
    for (i = 0; i < 256; i++) RGBYUV03316[i] = (float)0.3316 * i;
    for (i = 0; i < 256; i++) RGBYUV04187[i] = (float)0.4187 * i;
    for (i = 0; i < 256; i++) RGBYUV00813[i] = (float)0.0813 * i;
}

头文件rgb2yuv.h中对函数的声明:

void RGB2YUV(int size, unsigned char* rgb, unsigned char* yuv);
void InitLookupTable();

YUV to RGB的实现

思路与RGB2YUV一样,但需要对溢出部分进行修正

if (r > 255){ r = 255;}
else if (r < 0){r = 0;}
if (g > 255){ g = 255;}
else if (g < 0){g = 0;}
if (b > 255){ b = 255;}
else if (b < 0){b = 0;}

最终yuv2rgb.cpp

#include "stdlib.h"
#include"yuv2rgb.h"
static int YUVRGB298[256], YUVRGB411[256], YUVRGB101[256],YUVRGB519[256],YUVRGB211[256];
void YUV2RGB(int size, unsigned char* yuv, unsigned char* rgb)
{
    static int init_done;
    int usize = size;
    int vsize = size * 2;
    unsigned char* y, * u, * v;
    /*unsigned char* r = new unsigned char[size];
    unsigned char* g = new unsigned char[size];
    unsigned char* b = new unsigned char[size];*/
    int r, g, b;
    //int y, u, v;
    if (init_done == 0)
    {
        LookupTable();
        init_done = 1;
    }
    y = yuv;
    for (int i = 0; i < usize; i++)
    {
        u = y + usize;
        v = y + vsize;
        r = (YUVRGB298[*y] + YUVRGB411[*v] - 57344) >> 8;
        if (r > 2){ r = 255;}
        else if (r < 0){r = 0;}
        g = (YUVRGB298[*y] - YUVRGB101[*u] - YUVRGB211[*v] + 34739) >> 8;
        if (g > 255){g = 255;}
        else if (g < 0){g = 0;}
        b = (YUVRGB298[*y] + YUVRGB519[*u] - 71117) >> 8;
        if (b > 255){b = 255;}
        else if (b < 0){b = 0;}
        /*r[i] = *y + (float)1.4075 * (*v - 128);
        g[i] = *y - (float)0.3455 * (*u - 128) - (float)0.7169 * (*v - 128);
        b[i] = *y + (float)1.779 - (*u - 128);*/
        *(rgb + i) = b;
        *(rgb + i + 1) = g;
        *(rgb + i + 2) = r;
        y ++;
    }
}
void LookupTable()
{
    int i;
    for (i = 0; i < 256; i++) YUVRGB298[i] = 298 * i;
    for (i = 0; i < 256; i++) YUVRGB411[i] = 411 * i;
    for (i = 0; i < 256; i++) YUVRGB101[i] = 101 * i;
    for (i = 0; i < 256; i++) YUVRGB519[i] = 519 * i;
    for (i = 0; i < 256; i++) YUVRGB211[i] = 211 * i;
}

头文件yuv2rgb.h中对函数的声明:

void YUV2RGB(int size, unsigned char* rgb, unsigned char* yuv);
void LookupTable();

实验结果

从左向右一次为原图down.rgb、RGB转YUV的down.yuv、YUV转RGB的restore.rgb
在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值