一、实验目的
1.学会从计算和程序的角度分析问题
通过完成本实验,理解计算思维,即从问题出发,通过逐步分析和分解,把原问题转化 为可用程序方式解决的问题。在此过程中设计出一个解决方案。
2.进一步理解彩色空间的概念并掌握不同彩色空间转换的基本方程。
3.通过逐步设计程序,掌握编程细节:如查找表的设计,内存分配,对 U 和 V 信号进 行下采样,文件读写过程等。掌握程序调试的基本方法。
二、知识基础
1、亮度方程
{ Y = 0.2990 R + 0.5870 G + 0.1140 B R − Y = 0.7010 R − 0.5870 G − 0.1140 B B − Y = − 0.2990 R − 0.5870 G + 0.8860 B \begin{cases} Y=0.2990R+0.5870G+0.1140B\\ R-Y=0.7010R-0.5870G-0.1140B\\ B-Y=-0.2990R-0.5870G+0.8860B\\ \end{cases} ⎩⎪⎨⎪⎧Y=0.2990R+0.5870G+0.1140BR−Y=0.7010R−0.5870G−0.1140BB−Y=−0.2990R−0.5870G+0.8860B
2、模拟分量
{ P b = 0.564 ( B − Y ) = − 0.1684 R − 0.3316 G + 0.5000 B P r = 0.713 ( R − Y ) = 0.5000 R − 0.4187 G − 0.0813 B \begin{cases} P_b=0.564(B-Y)=-0.1684R-0.3316G+0.5000B\\ P_r=0.713(R-Y)=0.5000R-0.4187G-0.0813B\\ \end{cases} {Pb=0.564(B−Y)=−0.1684R−0.3316G+0.5000BPr=0.713(R−Y)=0.5000R−0.4187G−0.0813B
3、电平分配
亮度信号
- Y动态范围为16-235
色度信号
- Cr、Cb动态范围为16-240
三、实验记录
1、RGB2YUV
自己按照自己理解写的很垃圾的版本,没有用到老师讲的一些知识点(想试来着但是一直出bug),将会在YUV2RGB中继续尝试。
#include<iostream>
#include<math.h>
using namespace std;
int main()
{
unsigned char* RGB = new unsigned char[256*256*3]; //存储图像所有值
unsigned char* R = new unsigned char[256*256];
unsigned char* G = new unsigned char[256*256];
unsigned char* B = new unsigned char[256*256];
unsigned char* Y = new unsigned char[256*256];
unsigned char* U = new unsigned char[256*256];
unsigned char* V = new unsigned char[256*256];
//读取RGB文件内容
FILE* fp1=fopen("/Users/hugo/Desktop/数据压缩/第二周/down.rgb","rb");
if(fp1 == NULL)
cout<<"错误读取"<<endl;
fread(RGB,sizeof(unsigned char),256*256*3,fp1);
fclose(fp1);
//创建yuv文件
FILE* data=fopen("/Users/hugo/Desktop/数据压缩/第二周/RGB2YUV.yuv","w");
//RGB2YUV
for (int i = 0, j = 0; i < 256*256*3; i += 3, j++)
{
B[j] = RGB[i];
G[j] = RGB[1 + i];
R[j] = RGB[2 + i];
Y[j] = ((66 * R[j] + 129 * G[j] + 25 * B[j]) >> 8) + 16;
U[j] = ((-38 * R[j] - 74 * G[j] + 112 * B[j])>> 8) + 128;
V[j] = ((112 * R[j] - 94 * G[j] - 18 * B[j]) >> 8) + 128;
}
//写入文件
fwrite(Y,sizeof(unsigned char),256*256,data);
fwrite(U,sizeof(unsigned char),256*256,data);
fwrite(V,sizeof(unsigned char),256*256,data);
//关闭文件
fclose(data);
return 0;
}
实验结果
2、YUV2RGB
# include<iostream>
# include <fstream>
using namespace std;
static int RGB298[256];
static int RGB411[256];
static int RGB101[256];
static int RGB211[256];
static int RGB519[256];
//查找表
void initLookupTable()
{
int i;
for (i = 0; i < 256; i++) RGB298[i] = 298 * i;
for (i = 0; i < 256; i++) RGB411[i] = 411 * i;
for (i = 0; i < 256; i++) RGB101[i] = 101 * i;
for (i = 0; i < 256; i++) RGB211[i] = 211 * i;
for (i = 0; i < 256; i++) RGB519[i] = 519 * i;
}
void yuv2rgb(unsigned char* YUV_Buffer, unsigned char* RGB_Buffer_out, int size,int width) {
initLookupTable();
int uoffset = size;
int voffset = 1.25 * size;
unsigned char* U_dataExpand = new unsigned char[size];
unsigned char* V_dataExpand = new unsigned char[size];
for (int i = 0; i < size/4; i++) {
unsigned char temp = *(YUV_Buffer + i + uoffset);
int offset = 2*(i%(width/2))+i/(width/2)*2*width;
*(U_dataExpand + offset)= temp;
*(U_dataExpand + offset+1) = temp;
*(U_dataExpand + offset+width) = temp;
*(U_dataExpand + offset + 1+width) = temp;
temp= *(YUV_Buffer + i + voffset);
*(V_dataExpand + offset) = temp;
*(V_dataExpand + offset + 1) = temp;
*(V_dataExpand + offset + width) = temp;
*(V_dataExpand + offset + 1 + width) = temp;
}
for (int i = 0, j = 0; i < size; i++, j += 3) {
unsigned char Y = *(YUV_Buffer + i);
unsigned char U = *(U_dataExpand + i);
unsigned char V = *(V_dataExpand + i);
int B = (RGB298[Y] + RGB519[U] - 71200) >> 8;
if (B > 255) B = 255;
if(B < 0) B = 0;
int G = (RGB298[Y] - RGB101[U] - RGB211[V] + 35168) >> 8;
if (G > 255) G = 255;
if (G < 0) G = 0;
int R = (RGB298[Y] + RGB411[V] - 57376) >> 8;
if (R > 255) R = 255;
if (R < 0) R = 0;
*(RGB_Buffer_out + j) = (unsigned char)(B);
*(RGB_Buffer_out + 1 + j) = (unsigned char)(G);
*(RGB_Buffer_out + 2 + j) = (unsigned char)(R);
}
}
int main()
{
FILE* originYUV=fopen("/Users/hugo/Desktop/数据压缩/第二周/down.yuv","rb");
FILE* RGB_out=fopen("/Users/hugo/Desktop/数据压缩/第二周/YUV2RGB.rgb","w");
if (!originYUV || !RGB_out) {
cout << "错误读取" << endl;
return 0;
}
int size = 256*256;
unsigned char* YUV_Buffer = new unsigned char[size * 1.5];
unsigned char* RGB_Buffer_out = new unsigned char[size * 3];
fread((char*)YUV_Buffer,sizeof(unsigned char),size * 1.5,originYUV);
yuv2rgb(YUV_Buffer,RGB_Buffer_out,size,256);
fwrite((char*)RGB_Buffer_out,sizeof(unsigned char),size * 3,RGB_out);
delete[] YUV_Buffer;
delete[] RGB_Buffer_out;
fclose(originYUV);
fclose(RGB_out);
return 0;
}
实验结果
由于实在没找到mac平台的看rgb文件的软件,所以找同学帮忙打开
四、反思总结
- 整体来说自己的编程能力还是较差,且还没弄清楚mac平台的vscode全部功能所以本来想用老师说的命令行参数argc和argv来着还没琢磨出来。
- 在编程过程中对于U、V格式的扩展和下采样处理方式还是没有太清楚,借鉴学习了Endless Ferry同学文章。