一、实验目的

1.理解图像文件的基本组成

2.掌握结构体作为复杂数据对象的用法。进一步熟悉由问题到程序的解决方案,并掌握编程细节:如内存分配、倒序读写、字节序、文件读写过程等

二、实验要求

(1)在图像处理软件中自行生成多个BMP文件,至少含5个不同的场景画面,要求带含有班级、学号后四位和本人姓名(缩写或昵称均可)的logo。(基本要求为24bit的BMP,进阶要求为支持小于24bit的BMP。)

(2)编写将第一步所生成的多个BMP文件转化为YUV文件,要求可在命令行中设置每个画面出现的帧数。最后形成的YUV文件应至少包含200帧。重点掌握函数定义、缓冲区分配、倒序读写、结构体的操作。

(3)对整个程序进行调试,并将生成的YUV文件用播放软件观看,验证是否正确。

三、实验原理

1、典型的BMP图像文件由四部分组成:

(1)位图头文件数据结构,它包含BMP图像文件的类型、显示内容等信息;

typedef struct tagBITMAPFILEHEADER {WORD bfType; /* 说明文件的类型*/DWORD bfSize;/* 说明文件的大小,用字节为单位*/WORD bfReserved1; /* 保留,设置为0 */WORD bfReserved2; /* 保留,设置为0 */DWORD bfOffBits; /* 说明从BITMAPFILEHEADER结构开始到实际的图像数据之间的字节偏移量*/
} BITMAPFILEHEADER;

(2)位图信息数据结构,它包含有BMP图像的宽、高、压缩方法,以及定义颜色等信息;

typedef struct tagBITMAPINFOHEADER {DWORD biSize; /* 说明结构体所需字节数*/LONG biWidth; /* 以像素为单位说明图像的宽度*/LONG biHeight; /* 以像素为单位说明图像的高速*/WORD biPlanes; /* 说明位面数,必须为1 */WORD biBitCount; /* 说明位数/像素,1、2、4、8、24 */DWORD biCompression; /*说明图像是否压缩及压缩类型BI_RGB,BI_RLE8,BI_RLE4,BI_BITFIELDS */DWORD biSizeImage; /* 以字节为单位说明图像大小,必须是4的整数倍*/LONG biXPelsPerMeter; /*目标设备的水平分辨率,像素/米*/LONG biYPelsPerMeter; /*目标设备的垂直分辨率,像素/米*/DWORD biClrUsed; /* 说明图像实际用到的颜色数,如果为0,则颜色数为2的biBitCount次方*/DWORD biClrImportant; /*说明对图像显示有重要影响的颜色索引的数目,如果是0,表示都重要。*/
} BITMAPINFOHEADER;

(3)调色板,这个部分是可选的,有些位图需要调色板,有些位图,比如真彩色图(24位的BMP)就不需要调色板;

typedef struct tagRGBQUAD {BYTE rgbBlue; /*指定蓝色分量*/BYTE rgbGreen; /*指定绿色分量*/BYTE rgbRed; /*指定红色分量*/BYTE rgbReserved; /*保留,指定为0*/
} RGBQUAD;

(4)位图数据,这部分的内容根据BMP位图使用的位数不同而不同,在24位图中直接使用RGB,而其他的小于24位的使用调色板中颜色索引值。

2.字节序

不同的计算机系统采用不同的字节序存储数据,同样一个4字节的32位整数,在内存中存储的方式不同。字节序分为小尾字节序(Little Endian)和大尾字节序(Big Endian)。Intel处理器大多数使用小尾字节序,Motorola处理器大多数使用大尾(Big Endian)字节序。

小尾就是低位字节排放在内存的低端,高位字节排放在内存的高端,即所谓的“低位在前,高位在后”。大尾就是高位字节排放在内存的低端,低位字节排放在内存的高端,即所谓的“高位在前,低位在后”。TCP/IP各层协议将字节序定义为大尾,因此TCP/IP协议中使用的字节序通常称之为网络字节序。

在实现BMP文件头信息的写入和读出时,需要注意整数保存时的字节序。例如:文件大小是以Intel序保存的。在编程前先用二进制打开方式观察BMP文件各个部分的数据存储格式。

四、实验步骤

1. 程序初始化(打开两个文件、定义变量和缓冲区等)

2. 读取BMP文件,抽取或生成RGB数据写入缓冲区

3. 调用RGB2YUV的函数实现RGB到YUV数据的转换 (采用部分查找表法,提高运行效率)

4. 写YUV文件

5. 程序收尾工作(关闭文件,释放缓冲区)

代码实现:

1.main.cpp

main函数流程为实验主要步骤

//zyzcuczyz
#define _CRT_SECURE_NO_DEPRECATE
#include<iostream>
#include<Windows.h>
#include<wingdi.h>
#include"bmp2yuv.h";
#include"rgb2yuv.h";using namespace std;
int main(int argc, char* argv[]) {//变量BITMAPFILEHEADER File_header;BITMAPINFOHEADER Info_header;FILE* bmpFile = NULL;FILE* yuvFile = NULL;//const int i = atoi(argv[1]);const char* bmpName[5] = { argv[2],argv[3],argv[4],argv[5],argv[6] };//"1.bmp","2.bmp","3.bmp","4.bmp"const char* yuvName = argv[7];//"bmp.yuv"unsigned char* rgbBuf;unsigned char* yBuf;unsigned char* uBuf;unsigned char* vBuf;bool flip = TRUE;//打开文件yuvFile = fopen(yuvName, "wb");for (int i = 0; i < 5; i++) {bmpFile = fopen(bmpName[i], "rb");//文件头,信息头if (fread(&File_header, sizeof(BITMAPFILEHEADER), 1, bmpFile) != 1){printf("read file header error!\n");exit(0);}if (File_header.bfType != 0x4D42){printf("Not bmp file!\n");exit(0);}else{printf("this is a bmp file!\n");}if (fread(&Info_header, sizeof(BITMAPINFOHEADER), 1, bmpFile) != 1){printf("read info header error!\n");exit(0);}int frameWidth = Info_header.biWidth;int frameHeight = Info_header.biHeight;//分配空间rgbBuf = (unsigned char*)malloc(frameWidth * frameHeight * 3);yBuf = (unsigned char*)malloc(frameWidth * frameHeight);uBuf = (unsigned char*)malloc(frameWidth * frameHeight / 4);vBuf = (unsigned char*)malloc(frameWidth * frameHeight / 4);RGBQUAD* pRGB = (RGBQUAD*)malloc(sizeof(RGBQUAD) * (unsigned int)pow(2, Info_header.biBitCount));if (!MakePalette(bmpFile, File_header, Info_header, pRGB))printf("No palette!\n");//读rgbREADRGB(frameWidth, frameHeight, bmpFile, rgbBuf);//rgb2yuvif (RGB2YUV(frameWidth, frameHeight, rgbBuf, yBuf, uBuf, vBuf, flip)){printf("error!\n");return 0;}for (int i = 0; i < frameWidth * frameHeight; i++){if (yBuf[i] < 16) yBuf[i] = 16;if (yBuf[i] > 235) yBuf[i] = 235;}for (int i = 0; i < frameWidth * frameHeight / 4; i++){if (uBuf[i] < 16) uBuf[i] = 16;if (uBuf[i] > 240) uBuf[i] = 240;if (vBuf[i] < 16) vBuf[i] = 16;if (vBuf[i] > 240) vBuf[i] = 240;}//写入yuv文件//WriteYUV(frameWidth, frameHeight, yBuf, uBuf, vBuf, yuvFile);int n = atoi(argv[8]);for (int i = 0; i < n; i++) {fwrite(yBuf, 1, frameWidth * frameHeight, yuvFile);fwrite(uBuf, 1, (frameWidth * frameHeight) / 4, yuvFile);fwrite(vBuf, 1, (frameWidth * frameHeight) / 4, yuvFile);}free(rgbBuf);free(yBuf);free(uBuf);free(vBuf);fclose(bmpFile);}fclose(yuvFile);return 0;
}

2.rgb2yuv.h

rgb2yuv.h文件中包含:

READRGB函数,实现读取文件rgb数据的操作

//void RGB2YUV();
//void READRGB();
//void WriteYUV();void READRGB(int width, int height, FILE* bmpFile, unsigned char* rgb)
{unsigned char* bmp = (unsigned char*)malloc(sizeof(unsigned char) * width * height * 3);unsigned char* tmp_rgb = (unsigned char*)malloc(sizeof(unsigned char) * width * height * 3);fread(bmp, width * height * 3, 1, bmpFile);for (int i = 0; i < width * height * 3; i++){*(tmp_rgb + i) = *bmp;bmp++;}//倒序转正序for (int i = 0; i < height; i++){for (int j = 0; j < width * 3; j++){*(rgb + (height - 1 - i) * width * 3 + j) = *tmp_rgb;tmp_rgb++;}}
}

RGB2YUV函数,实现将rgb转为yuv的操作

//int RGB2YUV(int x_dim, int y_dim, void* bmp, void* y_out, void* u_out, void* v_out, int flip);int RGB2YUV(int x_dim, int y_dim, void* bmp, void* y_out, void* u_out, void* v_out, int flip)
{static int init_done = 0;long i, j, size;unsigned char* r, * g, * b;unsigned char* y, * u, * v;unsigned char* pu1, * pu2, * pv1, * pv2, * psu, * psv;unsigned char* y_buffer, * u_buffer, * v_buffer;unsigned char* sub_u_buf, * sub_v_buf;if (init_done == 0){InitLookupTable();init_done = 1;}// check to see if x_dim and y_dim are divisible by 2if ((x_dim % 2) || (y_dim % 2)) return 1;size = x_dim * y_dim;// allocate memoryy_buffer = (unsigned char*)y_out;sub_u_buf = (unsigned char*)u_out;sub_v_buf = (unsigned char*)v_out;u_buffer = (unsigned char*)malloc(size * sizeof(unsigned char));v_buffer = (unsigned char*)malloc(size * sizeof(unsigned char));if (!(u_buffer && v_buffer)){if (u_buffer) free(u_buffer);if (v_buffer) free(v_buffer);return 2;}b = (unsigned char*)bmp;y = y_buffer;u = u_buffer;v = v_buffer;// convert RGB to YUVif (!flip) {for (j = 0; j < y_dim; j++){y = y_buffer + (y_dim - j - 1) * x_dim;u = u_buffer + (y_dim - j - 1) * x_dim;v = v_buffer + (y_dim - j - 1) * x_dim;for (i = 0; i < x_dim; 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);b += 3;y++;u++;v++;}}}else {for (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);b += 3;y++;u++;v++;}}// subsample UVfor (j = 0; j < y_dim / 2; j++){psu = sub_u_buf + j * x_dim / 2;psv = sub_v_buf + j * x_dim / 2;pu1 = u_buffer + 2 * j * x_dim;pu2 = u_buffer + (2 * j + 1) * x_dim;pv1 = v_buffer + 2 * j * x_dim;pv2 = v_buffer + (2 * j + 1) * x_dim;for (i = 0; i < x_dim / 2; i++){*psu = (*pu1 + *(pu1 + 1) + *pu2 + *(pu2 + 1)) / 4;*psv = (*pv1 + *(pv1 + 1) + *pv2 + *(pv2 + 1)) / 4;psu++;psv++;pu1 += 2;pu2 += 2;pv1 += 2;pv2 += 2;}}free(u_buffer);free(v_buffer);return 0;
}

InitLookupTable函数为查找表函数

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;
}

3.bmp2yuv.h

bmp2yuv.h中包含调色板函数

//bool MakePalette(FILE* pFile, BITMAPFILEHEADER& file_h, BITMAPINFOHEADER& info_h, RGBQUAD* pRGB_out);bool MakePalette(FILE* pFile, BITMAPFILEHEADER& file_h, BITMAPINFOHEADER& info_h, RGBQUAD* pRGB_out)
{if ((file_h.bfOffBits - sizeof(BITMAPFILEHEADER) - info_h.biSize) == sizeof(RGBQUAD) * pow(2, info_h.biBitCount)){fseek(pFile, sizeof(BITMAPFILEHEADER) + info_h.biSize, 0);fread(pRGB_out, sizeof(RGBQUAD), (unsigned int)pow(2, info_h.biBitCount), pFile);return true;}else{return false;}
}

五、实验结果

实验使用的图片均来自网络,经处理后转换为256*256的bmp文件:

运行main函数后生成名为bmp.yuv的文件,使用YUVviewer MFC播放

参考:

【数据压缩(五)】基于C++实现BMP序列转YUV文件_zyzcuczyu的博客-CSDN博客

【数据压缩(四)】c语言实现BMP序列转YUV文件并播放相关推荐

  1. 【数据压缩(五)】基于C++实现BMP序列转YUV文件

    基于C++实现BMP序列转YUV文件 一.实验目的 二.实验要求 三.实验原理 四.实验步骤 1.`main.cpp` 2.`bmp2yuv.h` 3.`bmp2yuv.cpp` (1)引头文件以及定 ...

  2. BMP序列转YUV文件

    BMP序列转YUV文件 借鉴链接:https://blog.csdn.net/zyzcuczyu/article/details/115276854 实验原理 首先我们来了解bmp格式文件的结构 BM ...

  3. 使用go语言GUI库实现对mp3文件的播放1(简单的播放mp3文件)

    使用go语言GUI库实现对mp3文件的播放1(简单的播放mp3文件) 使用beep播放mp3文件(10num) 使用go语言GUI库fyne实现音乐播放器 要是想使用go语言实现播放mp3需要借助be ...

  4. 【数据压缩】C语言实现bmp图片序列生成yuv视频

    一.实验要求 1.解析BMP格式文件,获取图像信息 2.转化BMP图像为YUV格式的图像 3.多张BMP图像,转化为YUV视频 二.实验内容 1.获取图片 获取(540*720)的bmp图片若干: 2 ...

  5. bmp文件c语言压缩算法,BMP文件数据压缩与解压缩方法.pdf

    BMP文件数据压缩与解压缩方法 20 1 Vol. 20 No. 1 2 0 0 0 3 JOURNAL OF FU SHUN PET ROLEU M INST IT UTE Mar. 2000 : ...

  6. vs2010用c语言实现数据转换成图片,数据压缩第二次实验报告——用C语言实现bmp to yuv的图片格式转化...

    实验目标 实验主要要求将图片格式从BMP到YUV的转化,并生成含有至少五幅图片不少于200帧的图像流. 实验原理 一.BMP图像简介: 典型的BMP图像文件由四部分组成(部分摘自360百科对BMP的定 ...

  7. C语言读取BMP格式图片

    C语言读取BMP格式图片 BMP 维基百科,自由的百科全书 汉漢▼ 位图 扩展名 .bmp 开发者 Microsoft 格式 图像文件格式  本文介绍的是一种图像文件格式. 关于Unicode的第1区 ...

  8. C语言读取bmp图像并做简单显示

    C语言读取bmp图像并做简单显示) bmp文件格式 读取bmp文件信息并展示 bmp文件格式 bmp文件大体上分为四个部分: bmp文件构成 位图文件头BITMAPFILEHEADER 位图信息头BI ...

  9. 【Golang】Go 语言 XML 的序列与反序列化实践

    Go 语言 XML 的序列与反序列化实践 导读 本文使用 Go 原生支持的包,对 XML 字符串以及 .xml 文件进行序列化与反序列化实践.同时对 Go 语言下的 JSON 序列化反序列化与 XML ...

最新文章

  1. 一个不错的安全评估站点vulnerabilityassessment.co.uk
  2. php gd库画线,[PHP] GD库(十)绘制线段与圆弧 imageline、imagesetstyle 与 imagearc 函数...
  3. boost::fusion::erase_key用法的测试程序
  4. 洛谷——P1181 数列分段Section I
  5. PowerDesigner 逆向工程 从SQL文件转换成PDM 从PDM转成CDM
  6. 使用Identity Server 4建立Authorization Server (5)
  7. 小程序webview不全屏_小程序不在小(深度)
  8. java中static、final 和 static final之间的区别
  9. STM32H743-梳理ADC模数转换器在CubeMX上的配置
  10. newman执行测试_postman+newman+Jenkins之API全自动化测试(MAC)
  11. 报错日常——Tomcat45秒超时问题
  12. 8 个常用的 Python 爬虫技巧,分分钟提高效率!!
  13. RedHat Linux RHEL6配置本地YUM源
  14. 微信读书产品调研报告
  15. Matpower建模
  16. win10/win11掉驱动问题
  17. tl wn322g linux驱动下载,TP-Link TL-WN322G+网卡驱动
  18. block的名词形式_block是什么意思_block在线翻译_英语_读音_用法_例句_海词词典
  19. 蓝桥杯第十届省赛 NE555测方波
  20. 错误:VM5729:1 Blocked script execution in ‘about:blank‘

热门文章

  1. 考虑未来,我转行了软件测试,入职薪资9K
  2. 连续六年稳居中国SDN(软件)市场份额第一
  3. 基于51单片机农业土壤湿度监测及自动灌溉系统设计
  4. Open3D Delaunay三角剖分(三维)
  5. C语言:用switch,case函数,做一个自动售卖机
  6. Java设计模式--原型模式Prototype
  7. 关于ACM,关于CSU
  8. 2016年大数据核心产业规模达168亿
  9. 搭档之家:以中位数碾压腾讯平均数!网曝台积电普通员工年薪约37.4万元
  10. NUXT 踩坑 —— 封装 Axios 请求拦截