数据压缩实验二 图像文件的读写和转换(bmp转yuv)
来源:互联网 发布:win10 windows安全性 编辑:程序博客网 时间:2024/05/17 02:15
一、实验原理
图像存储时一般由两部分组成:图像说明部分和图 像数据部分
图像说明部分:图像的格式、深度、高度、宽度、调色板、 压缩方法等
图像数据部分:描述图像每个像素的数据
1.BMP图像文件格式
位图文件(Bitmap-File,BMP)格式是Windows采 用的图像文件存储格式,在Windows环境下运行的 所有图像处理软件都支持这种格式。BMP位图文件 默认的文件扩展名是bmp或者dib。
BMP文件大体上分为四个部分:
对于一种文件的格式,C语言中往往以结构体的方式描述,因此注意工程中的结构体是十分重要的。
(1)位图头文件数据结构
typedef struct tagBITMAPFILEHEADER { WORD bfType; /* 说明文件的类型 */ DWORD bfSize; /* 说明文件的大小,用字节为单位 注意字节序*/ WORD bfReserved1; /* 保留,设置为0 */ WORD bfReserved2; /* 保留,设置为0 */ DWORD bfOffBits; /* 说明从BITMAPFILEHEADER结构开始到实际的图像数据之间的字节偏移量 */ } BITMAPFILEHEADER;
(2)位图信息数据结构
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)调色板
调色板实际上是一个数组,它所包含的元素与位图 所具有的颜色数相同,决定于biClrUsed和biBitCount字 段。数组中每个元素的类型是一个RGBQUAD结构。真 彩色无调色板部分。
typedef struct tagRGBQUAD{ BYTE rgbBlue; /*指定蓝色分量*/ BYTE rgbGreen; /*指定绿色分量*/ BYTE rgbRed; /*指定红色分量*/ BYTE rgbReserved; /*保留,指定为0*/} RGBQUAD;
(4)图像数据字节阵列:即位图数据
紧跟在调色板之后的是图像数据字节阵列。对于用到调 色板的位图,图象数据就是该象素颜色在调色板中的索引值 (逻辑色)。对于真彩色图,图象数据就是实际的R、G、B 值。
2.需要注意的地方
(1)DWORD 对齐
图像的每一扫描行由表示图像像素的连续的字节组成,每一行的字节数取决于图像的颜色数目和用像素表示的图像宽
度。规定每一扫描行的字节数必需是4的整倍数,也就是DWORD对齐的。写入位图文件数据时,如果图像每行像素字节总数[宽 X biBiCount % 8 != 0 ],系统会自动在每行最后填充若干0值使满足整数字节,接着,如果[每行像素字节数 % 4 != 0 ],系统会自动在每行最后填充若干字节0值使满足DWORD对齐。所以我们对位图加载处理时要注意判断每行数据是否有0值填充,若有0值填充则从位图中读取数据的过程中要注意指针偏移量和即时跳转。
(2)自下而上扫描
扫描行是由底向上存储的,这就是说,阵列中的第一个字节表示位图左下角的像素,而最后一个字节表示位图右上角的像素。(只针对于倒向DIB,如果是正向DIB,则扫描行是由顶向下存储)
(3)字节序
计算机系统存储数据采用的字节序有两种:小尾字节序(Little Endian)和大尾字节序(Big Endian)。以Intel处理器为代表大多数采用小端字节序,”低位在前高位在后“既地址低位存储值的低位,地址高位存储值的高位;以Motorola处理器为代表大多数使用大端字节序,”高位在前低位在后“即地址低位存储值的高位,地址高位存储值的低位。BMP文件中仅除了文件头中文件类型WORD bfType为大端字节序,剩余结构体内的定义均是小端字节序。
(4)掩码组
调色板信息中指示了RGB比特位的掩码组信息。因为图像深度可选为1、4、8、16、24、32bit,所以不同深度的RGB比特位自然不同。
以bmp位图中使用16bit为例,位运算的图示:
若读入的BMP位图的biBiCount为8bit或更小,类似的需要位的移位、与操作。
再以2bit图像举例,其数据块中的第一个字节,对应着第一个像素的索引值为:b’xx zz zz zz,其中只有头两位包含该像素的索引信息,而后六位为其他像素的索引信息。这时候需要与b’11 00 00 00=0xC0相与,再进行6位右移,得到b’00 00 00 xx=index,这便是其对应的索引值,代入pRGB[index]获得其对应的RGB分量值。
当处理像素是第二个像素是,其对应的索引值应为该字节中的第五第六位,即b’zz xx zz zz,这时候掩码值也相应跟着位移,遂引入turn–掩码位移变量,turn可用作循环判断用,当turn为零时——说明该字节中所有像素信息已读取完,可以结束循环,进行下一个字节的读取。
同时,应注意到右移的位数也发生了变换,引入shiftcnt变量,用于不同像素点需位移的长度。每进行一次像素数据读取后,shiftcnt++,因为下一个像素(不是该字节最后一个像素时)需要位移的位数减少了shift*biBitCount个。
二、实验流程
(1)初始化:打开文件,定义变量建立缓冲区
(2)解析BMP文件,抽取或生成RGB数据写入缓冲区
(3)调用RGB2YUV函数进行数据转换
(4)写入YUV文件,关闭文件,释放缓冲区
三、实验具体算法代码
1.BMP2YUV.h
#ifndef BMP2YUV_H_#define BMP2YUV_H_//define mask structtypedef struct bit32Mask{ unsigned int rgbRed; unsigned int rgbGreen; unsigned int rgbBlue; unsigned int reserved;}Mas32;typedef struct bit16Mask{ unsigned int rgbRed; unsigned int rgbGreen; unsigned int rgbBlue;}Mas16;int BMP2RGB32bit(int bitcount, int x_dim, int y_dim, void *bmpbuf, void *rgbbuf, void *mask);int BMP2RGB24bit(int bitcount, int x_dim, int y_dim, void *bmpbuf, void *rgbbuf);int BMP2RGB16bit(int bitcount, int x_dim, int y_dim, void *bmpbuf, void *rgbbuf,void *mask);int BMP2RGBNOT24bit(int bitcount, int x_dim, int y_dim, void *bmpbuf, void *rgbbuf, void *pRGB);int RGB2YUV(int x_dim, int y_dim, void *bmp, void *y_out, void *u_out, void *v_out, int flip);void InitLookupTable();void adjust(unsigned char *b, unsigned char *g, unsigned char *r, unsigned char *y, unsigned char *u, unsigned char *v);#endif
2.main.c
#include <stdio.h>#include <stdlib.h>#include <windows.h> #include <math.h> #include "bmp2yuv.h"#define u_int8_t unsigned __int8#define u_int unsigned __int32#define u_int32_t unsigned __int32int main(int argc,char **argv){ int count; BITMAPFILEHEADER File_header; BITMAPINFOHEADER Info_header; RGBQUAD *pRGB = NULL; FILE* bmp = NULL; FILE* yuvFile = NULL; Mas16 *mask16 = NULL; Mas32 *mask32 = NULL; u_int8_t* yBuf = NULL; u_int8_t* uBuf = NULL; u_int8_t* vBuf = NULL; u_int8_t* rgbBuf = NULL; u_int8_t* bmpBuf = NULL; u_int8_t* mask = NULL; u_int frameWidth; /* --width=<uint> */ u_int frameHeight; u_int bitcount; u_int py; u_int m; u_int8_t i; int sum = 0; char bmpf[][50] = { "park.bmp", "tree.bmp", "girlstwo.bmp", "02.bmp", "bea.bmp", "street.bmp" }; char yuvname[50] = "CometoYUV.yuv"; FILE *yuv=NULL; int framenumber; /* build the RAW file */ fopen_s(&yuv, yuvname, "wb+"); if (yuv == NULL) { printf("Fail to Build yuv file\n"); exit(0); } else { printf("The output rgb file is %s\n", yuvname); printf("\n"); printf("-------------------------------------------------------------------------\n"); } for (i = 0; i<6; i++) { count = 0; framenumber = atoi(argv[i + 1]); //open the bmp file fopen_s(&bmp, bmpf[i], "rb"); if (!bmp) { printf("cannot find the specific file %s:\n", bmpf[i]); exit(0); } else { printf("The input bmp file: %s\n", bmpf[i]); } if (!framenumber) { printf("\n写入帧数:0\n"); continue; } else { if (fread(&File_header, sizeof(BITMAPFILEHEADER), 1, bmp) != 1) { printf("read file header error!"); exit(0); } if (File_header.bfType != 0x4D42) { printf("Not bmp file!"); exit(0); } //printf("this is a 0x%04X:\n", File_header.bfType); if (fread(&Info_header, sizeof(BITMAPINFOHEADER), 1, bmp) != 1) { printf("read info header error!"); exit(0); } // end read header frameWidth = Info_header.biWidth; /* --width=<uint> */ frameHeight = Info_header.biHeight; py = File_header.bfOffBits; bitcount = Info_header.biBitCount; /* get an output buffer for a frame */ if ((frameWidth*bitcount % 8 == 0) && (frameWidth*bitcount / 8 % 4 == 0))//DWORD 对齐 { yBuf = (u_int8_t*)malloc(frameWidth * frameHeight); uBuf = (u_int8_t*)malloc((frameWidth * frameHeight) / 4); vBuf = (u_int8_t*)malloc((frameWidth * frameHeight) / 4); /* get an input buffer for a frame */ bmpBuf = (u_int8_t*)malloc(frameWidth * frameHeight * bitcount / 8); /* get an output buffer for a frame */ rgbBuf = (u_int8_t*)malloc(frameWidth * frameHeight * 3); if (rgbBuf == NULL || yBuf == NULL || uBuf == NULL || vBuf == NULL || bmpBuf == NULL) { printf("no enought memory\n"); exit(1); } ////////////////////////////////BMP 2 RGB while (framenumber) { fseek(bmp, py, SEEK_SET); if (!fread(bmpBuf, 1, frameWidth * frameHeight * bitcount / 8, bmp)) { printf("the image has problems!"); return 0; } if (bitcount == 32) { if (Info_header.biCompression==0) { if (BMP2RGB32bit(bitcount, frameWidth, frameHeight, bmpBuf, rgbBuf,0)) { printf("32bit BMP2RGB program runs error!"); return 0; } } else if (Info_header.biCompression == 3) { //取掩码组 m = 4*4; mask32 = (Mas32*)malloc(sizeof(Mas32)); fseek(bmp, sizeof(BITMAPFILEHEADER) + Info_header.biSize - m, SEEK_SET); fread(mask32, sizeof(Mas32),1, bmp); if (BMP2RGB32bit(bitcount, frameWidth, frameHeight, bmpBuf, rgbBuf, mask32)) { printf("32bit BMP2RGB program runs error!"); return 0; } } } else if (bitcount == 24) {//真彩位图 if (BMP2RGB24bit(bitcount, frameWidth, frameHeight, bmpBuf, rgbBuf)) { printf("24bit BMP2RGB program runs error!"); return 0; } } else if (bitcount == 16) { //16bit BMP RGB比特位根据biCompression确定 if (Info_header.biCompression == 0)//555 { if (BMP2RGB16bit(bitcount, frameWidth, frameHeight, bmpBuf, rgbBuf, 0)) { printf("16bit BMP2RGB program runs error!"); return 0; } } else if (Info_header.biCompression == 3) { //取掩码组 m = 4 * 3; mask16 = (Mas16*)malloc(sizeof(Mas16)); fseek(bmp, py-m, SEEK_SET); fread(mask16, 1, m, bmp); if (BMP2RGB16bit(bitcount, frameWidth, frameHeight, bmpBuf, rgbBuf, mask16)) { printf("16bit BMP2RGB program runs error!"); return 0; } } } else { if ((py - sizeof(BITMAPFILEHEADER) - Info_header.biSize) == sizeof(RGBQUAD)*pow(2, (double)bitcount)) {//1、2、4、8 bit 有调色板部分 m = (unsigned int)pow(2, (double)bitcount); pRGB = (RGBQUAD *)malloc(sizeof(RGBQUAD)*m); fseek(bmp, sizeof(BITMAPFILEHEADER) + Info_header.biSize, SEEK_SET); fread(pRGB, sizeof(RGBQUAD), m, bmp); if (BMP2RGBNOT24bit(bitcount, frameWidth, frameHeight, bmpBuf, rgbBuf, pRGB)) { printf("BMP 2 RGB program runs error!"); return 0; } } } /////////////////////////////RGB2YUV if (RGB2YUV(frameWidth, frameHeight, rgbBuf, yBuf, uBuf, vBuf, 0/*flip=0*/))//bmp图像格式从最后一行起逐行扫描 { printf("RGB2YUV program runs error!"); return 0; } fwrite(yBuf, 1, frameWidth * frameHeight, yuv); fwrite(uBuf, 1, (frameWidth * frameHeight) / 4, yuv); fwrite(vBuf, 1, (frameWidth * frameHeight) / 4, yuv); printf("\r...%d", ++count); framenumber--; } printf("\n写入帧数:%u %ux%u(%d bit)\n", count, frameWidth, frameHeight, bitcount); sum += count; printf("\n"); printf("\n"); } } } printf("%d帧YUV写入成功!\n",sum); /* cleanup */ fclose(bmp); fclose(yuv); //free the memory if (yBuf) { free(yBuf); } if (uBuf) { free(uBuf); } if (vBuf) { free(vBuf); } if (rgbBuf) { free(rgbBuf); } if (bmpBuf) { free(bmpBuf); } if (pRGB) { free(pRGB); } if (mask16) { free(mask16); } if (mask32) { free(mask32); } return 0;}
3.BMP2RGB.c
#include "stdlib.h"#include "bmp2yuv.h"#include <windows.h> #include <math.h> int BMP2RGB32bit(int bitcount, int x_dim, int y_dim, void *bmpbuf, void *rgbbuf, void *mask){ long i; unsigned char *bmp, *rgb; Mas32 *mas; long size = x_dim*y_dim; bmp = (unsigned char *)bmpbuf; rgb = (unsigned char *)rgbbuf; mas = (Mas32 *)mask; if (mask == NULL) { for (i = 0; i < size; i++) { *(rgb + 0) = *(bmp + 0); *(rgb + 1) = *(bmp + 1); *(rgb + 2) = *(bmp + 2); rgb += 3; bmp += 4; } return 0; } else {//根据掩码确定RGB比特位 int Gkey, Bkey, Rkey; if (mas->rgbGreen == 0) Gkey= 0; else if (mas->rgbGreen == 0xFF000000) Gkey = 3; else if (mas->rgbGreen == 0xFF0000) Gkey = 2; else if (mas->rgbGreen == 0xFF00) Gkey = 1; else return 1; if (mas->rgbBlue == 0) Bkey = 0; else if (mas->rgbBlue == 0xFF000000) Bkey = 3; else if (mas->rgbBlue == 0xFF0000) Bkey = 2; else if (mas->rgbBlue == 0xFF00) Bkey = 1; else return 1; if (mas->rgbRed == 0) Rkey = 0; else if (mas->rgbRed == 0xFF000000) Rkey = 3; else if (mas->rgbRed == 0xFF0000) Rkey = 2; else if (mas->rgbRed == 0xFF00) Rkey = 1; else return 1; for (i = 0; i < size; i++) { *(rgb + 0) = *(bmp + Bkey); *(rgb + 1) = *(bmp + Gkey); *(rgb + 2) = *(bmp + Rkey); rgb += 3; bmp += 4; } return 0; }}int BMP2RGB24bit(int bitcount, int x_dim, int y_dim, void *bmpbuf, void *rgbbuf){ long i; unsigned char *rgb;// , *raw; unsigned char *bmp; long size = x_dim*y_dim; rgb = (unsigned char *)rgbbuf; bmp = (unsigned char *)bmpbuf; for (i = 0; i < size*3; i++) { *(rgb + i) = *(bmp + i); } return 0;}int BMP2RGB16bit(int bitcount, int x_dim, int y_dim, void *bmpbuf, void *rgbbuf, void *mask){ long loop; unsigned char *Data, *rgbDataOut; long size = x_dim*y_dim*bitcount / 8; Data = (unsigned char*)bmpbuf; rgbDataOut = (unsigned char*)rgbbuf; Mas16 *mas; mas = (Mas16 *)mask; if (mask == NULL) { for (loop = 0; loop < size; loop += 2) { *rgbDataOut = (*(Data + loop) & 0x1F) << 3; *(rgbDataOut + 1) = ((*(Data + loop) & 0xE0) >> 2) + ((*(Data + loop + 1) & 0x03) << 6); *(rgbDataOut + 2) = (*(Data + loop + 1) & 0x7C) << 1; rgbDataOut += 3; } } else//555 OR 565决定于rgbGreen的比特位 { if (mas->rgbGreen == 0x07E0) { for (loop = 0; loop < size; loop += 2) { *rgbDataOut = (*(Data + loop) & 0x1F) << 3; *(rgbDataOut + 1) = ((*(Data + loop) & 0xE0) >> 3) + ((*(Data + loop + 1) & 0x07) << 5); *(rgbDataOut + 2) = (*(Data + loop + 1) & 0xF8); rgbDataOut += 3; } } else { for (loop = 0; loop < size; loop += 2) { *rgbDataOut = (*(Data + loop) & 0x1F) << 3; *(rgbDataOut + 1) = ((*(Data + loop) & 0xE0) >> 2) + ((*(Data + loop + 1) & 0x03) << 6); *(rgbDataOut + 2) = (*(Data + loop + 1) & 0x7C) << 1; rgbDataOut += 3; } } } return 0;}int BMP2RGBNOT24bit(int bitcount, int x_dim, int y_dim, void *bmpbuf, void *rgbbuf, void *ppRGB)//1\4\8 bit BMP{ unsigned char *rgb; unsigned char *bmp; unsigned char index; bmp = (unsigned char *)bmpbuf; rgb = (unsigned char *)rgbbuf; int shiftCnt; unsigned char mask; long loop = 0; unsigned char *Data, *rgbDataOut; RGBQUAD* p; long size = x_dim*y_dim*bitcount/8; Data = (unsigned char*)bmpbuf; rgbDataOut = (unsigned char*)rgbbuf; p = (RGBQUAD*)ppRGB; for (loop = 0; loop<size; loop++) { shiftCnt = 1; mask = (unsigned char)pow(2, (double)bitcount) - 1; mask = mask << (8-bitcount); while (mask) { //索引号的确定 index = (mask == 0xFF) ? *(Data + loop) : (*(Data + loop) & mask) >> (8 - shiftCnt * bitcount); *rgbDataOut = (p + index)->rgbBlue; *(rgbDataOut + 1) = (p + index)->rgbGreen; *(rgbDataOut + 2) = (p + index)->rgbRed; if (bitcount == 8) mask = 0; else mask >>= bitcount; rgbDataOut += 3; shiftCnt++; } } return 0;}
4.RGB2YUV.c
#include "stdlib.h"#include "bmp2yuv.h"static float RGBYUV02990[256], RGBYUV05870[256], RGBYUV01140[256];static float RGBYUV01684[256], RGBYUV03316[256];static float RGBYUV04187[256], RGBYUV00813[256];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 2 if ((x_dim % 2) || (y_dim % 2)) return 1; size = x_dim * y_dim; // allocate memory y_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 YUV if (!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; adjust(b, g, r, y, u, v); b += 3; y ++; u ++; v ++; } } } else { for (i = 0; i < size; i++) { g = b + 1; r = b + 2; adjust(b, g, r, y, u,v); b += 3; y ++; u ++; v ++; } } // subsample UV for (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;}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;}void adjust(unsigned char *b, unsigned char *g, unsigned char *r, unsigned char *y, unsigned char *u, unsigned char *v){ float temp = 0; temp = (float)(RGBYUV02990[*r] + RGBYUV05870[*g] + RGBYUV01140[*b]); temp = temp>235 ? 235 : temp; temp = temp<16 ? 16 : temp; *y = (unsigned char)temp; temp = (float)(-RGBYUV01684[*r] - RGBYUV03316[*g] + (*b) / 2 + 128); temp = temp>240 ? 240 : temp; temp = temp<16 ? 16 : temp; *u = (unsigned char)temp; temp = (float)((*r) / 2 - RGBYUV04187[*g] - RGBYUV00813[*b] + 128); temp = temp>240 ? 240 : temp; temp = temp<16 ? 16 : temp; *v = (unsigned char)temp;}
四、实验结果
由命令行设置每幅图片播放帧数:4幅图片,每幅转成50帧yuv序列
执行结果如图所示:
不同比特位的bmp位图的对比:
五、实验总结
本次实验中应重点掌握的是文件格式的概念、字节序、缓冲区分配、结构体操作、倒序读写文件、函数定义等操作
- 数据压缩实验二 图像文件的读写和转换(bmp转yuv)
- 实验二 图像文件的读写和转换(BMP转YUV)
- 实验二 图像文件的读写和转换(BMP转YUV)
- 数据压缩原理 实验二 图像文件的读写和转换
- 数据压缩 实验二 图像文件的读写和转换
- 实验二 图像文件的读写和转换(AVI转YUV)
- 数据压缩原理与应用 实验二 图像文件的读写和转换(BMPtoYUV)
- 数据压缩实验二:BMP转YUV
- 【实验二】图像文件的读写和转换
- 数据压缩原理与应用 图像文件的读写和转换(BMP2YUV)实验报告
- 数据压缩实验二:bmp转yuv格式实验报告
- 数据压缩实验二:bmp转yuv格式实验报告
- 数据压缩实验二bmp to yuv
- 数据压缩实验报告2-bmp转yuv
- 数据压缩第一次实验报告(rgb与yuv的转换)
- BMP图像文件的读写
- 数据压缩原理与应用 BMP转YUV
- 数据压缩第二次实验报告——用C语言实现bmp to yuv的图片格式转化
- 关于jar生成exe时出现背景图片无法显示的问题
- MySQL 主从复制与读写分离概念及架构分析
- 微信小程序之自定义模态弹窗(带动画)实例 —— 微信小程序实战系列(8)
- 使用crontab,让linux定时执行shell脚本
- Linux内核/Unix环境
- 数据压缩实验二 图像文件的读写和转换(bmp转yuv)
- 使用Struts2自带的验证出现的页面错误问题:No result defined for action action.UserAction and result
- content-type
- 滥用C++容器的教训:vector和set的查找效率问题
- 查看定时任务的执行情况
- 创建java类中类出现is not an enclosing class
- Java多态机制
- 笔记:FFMPEG 中的几个不同的 time_base
- logback滚动输出压缩格式的文件