实验目的:熟悉TGA图像文件格式,将TGA格式的图像转换成YUV文件**(4:2:0).**
简单回顾YUV文件的存储方式:
TGA文件格式简介
参考:Truevision TGA FILE FORMAT SPECIFICATION Version 2.0
https://en.wikipedia.org/wiki/Truevision_TGA
TGA格式图像文件的数据可以大致分为五大部分:
- TGA文件头(TGA File Header)
- 图像/颜色表数据(Image/Color Data Map)
- 开发者区域 (Developer Area)
其中主要涉及格式转化的为前两个部分,第三个部分完全由开发者决定,读取图像数据时可以忽略。
1.TGA文件头
- 文件头长度固定(18字节),按顺序由以下字段构成:
图像信息字段长度 ID Length 1字节 - 颜色表类型 Color Map Type 1字节:0则代表无颜色表,1代表有,2-127:reserved by Truevision, 128-255: available for developer use
- 图像类型 Image Type 1字节 各取值说明如下:
Image Type 取值 | 说明 |
---|---|
0 | 无图像数据 |
1 | 未压缩颜色表索引图象 |
2 | 未压缩RGB真彩图像 |
3 | 未压缩灰度图像 |
9 | 压缩颜色表索引图象 |
10 | 压缩RGB真彩图像 |
11 | 压缩灰度图像 |
表中所列的压缩方法皆为RLE行程编码
此外,还有:32 - 使用 huffman,delta 和 runlength 编码的颜色表图像;33 - 使用 huffman,delta 和 runlength 编码的颜色映射图像,4 趟四叉树类型处理。较为复杂,本文暂不涉及。
- 颜色表规约 Color Map Specification 共5字节,包括以下字段:(无颜色表则全为0)
字段名 | 长度(字节) | 说明 |
---|---|---|
颜色表首地址 First Entry Index | 2 | 第一个颜色表的索引 |
颜色表长度 Color Map Length | 2 | 颜色表表项数量 |
颜色表表项大小 Color Map Entry Size | 1 | 各表项占用位数,有15,16,24,32 |
- 图像规约 Image Specification 共10字节,由以下字段构成:
字段名 | 长度(字节)) | 说明 |
---|---|---|
图像x起始位置 X-origin of Image | 2 | 图像起始点水平坐标 |
图像y起始位置 Y-origin of Image | 2 | 图像左起始点垂直坐标 |
图像宽度 Image Width | 2 | 单位为像素 |
图像高度 Image Height | 2 | 同上 |
像素深度 Pixel Depth | 1 | 一个像素占用位数,一般为8.16.24.32 |
图像描述符 Image Descriptor | 1 | 规定了一些信息(包括图像起始位置),不是特别重要,略过 |
各长度大于1字节的字段,都是低位在前高为在后
为方便起见,本实验规定图像起始点为左下角,和BMP一样。
2.图像/颜色表数据
按顺序主要有三部分组成:
图像信息字段 Image ID :长度由Fileheader中的 Image ID Length 决定,储存了图像的身份信息。
颜色表数据 Color Map Data:包含了LUT数据,长度由文件头中相关字段决定。一个表项由整数倍字节进行存储。若深度为24,则BGR分别占8字节;若为32位,则BGR和属性值A各占8字节。
图像数据 Image Data:是本次实验的重中之重,顺序存储了图像中各像素的信息。RAW,unmapped图像数据的存储方式:
首先,一个像素的颜色信息所占字节数由FileHeader中的Pixel Depth决定:
Pixel Depth = 16:
此时一个像素存储2字节16位,具体构成为:arrrrrgg gggbbbbb 其中低位在前,高为在后
Pixel Depth = 15:
其余同上,一项颜色变为15bit,即:rrrrrgg gggbbbbb
具体读取算法可表示为:
rgbBuf[j] = (Buf[0] & 0x1f) << 3;//b
rgbBuf[j + 1] = (Buf[0] & 0xe0) >> 2 + (Buf[1] & 0x03) << 6;//b
rgbBuf[j + 2] = (Buf[1] & 0x7c) << 1;//r
Pixel Depth = 24 :
BGR各存储8字节,顺序为BGR
Pixel Depth = 32 :
BGR仍旧各存储8字节,此外属性值A也为8字节,即BGRA
这两种个情况的代码表示:
rgbBuf[j] = Buf[0];//b
rgbBuf[j + 1] = Buf[1];//g
rgbBuf[j + 2] = Buf[2];//r
若为Mapped 数据,则每个像素为整数个字节的索引值(如1,2个)规范中并无具体规定,本实验暂不涉及mapped image
对 gray image, image data 一个像素为为8/16字节,pixel depth = 8/16,16字节时,gray_level在低位,属性值alpha在高位。
在这个基础上,需要着重介绍的是在Image Type = 9 10 11的图像中使用的压缩算法RLE
TGA中的RLE行程编码
我们直接了解RLE编码下的图像数据存储方式:
在RLE中,图像数据以“数据包”作为单位,可以分为以下两种数据包:
- A类:包含连续的不同像素颜色值。
- B类:包含连续的相同像素颜色值。
每个数据包构成如下:
- 包头Header 1字节
- 数据 Data 可变长
其中数据包类型由包头Header的第一位决定:0表示A类,1表示B类。
若是A类,则剩下7位代表数据包内颜色项的数量size
若是B类,则包头接下来应该仅包含一个组颜色值,具体长度由Pixel Depth决定。而剩下7位代表此颜色在接下来顺序像素中的重复次数runsize。
由此可以想到数据读取大致算法:
while(...)
读取header第一位
读取header剩下7位
if header第一位 = 0
while(size)
依次读取各像素值并存储
else if header第一位 = 1
读取像素值
while(runsize)
依次存储该像素值
else
数据包有误
压缩,未压缩的颜色表内的数据存储形式也可参照上述的存储形式。
实验代码:
由于时间关系与个人能力原因,本实验暂时只涉及RLE压缩与未压缩的rgb真彩图像和和灰度图像,即Image Type = 2,3,10,11。其他暂不涉及。对RGB真彩图像有Bit Depth = 16,24,32。对灰度图像有Bit Depth = 8,16.
考虑:
- 为了代码简洁可观,有必要设定相应的结构体简化代码书写。
- 各Image Type的算法有许多相似之处,可适当的定义函数以减少代码冗余。
- 充分考虑到可能出现的错误情况。
- 输出图像与算法相关信息以便检查,修改代码。
- 本实验选择图像起始点皆为左下角,需作上下倒向处理。
实验代码如下:
header.h
#pragma once
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
#include<math.h>
#include<stdint.h>
using namespace std;
typedef struct
{
uint8_t ID_len; //图像信息字段Image ID长度(单位字节)
uint8_t colormap_type; //0:无颜色表 1:有颜色表
uint8_t image_type; //图像类型,很多,不一一介绍
uint16_t colormapPos; //第一个颜色表表项位置
uint16_t colormap_len; //颜色表表项数量
uint8_t colormap_entrysize; //颜色表表项大小,可以为15,16,24,32(bit)
uint16_t x_orig; //图像左下角水平坐标,前低后高
uint16_t y_orig; //图像左下角垂直坐标,前低后高
uint16_t width; //图像宽度,前低后高
uint16_t height; //图像高度,前低后高
uint8_t depth; //图像颜色深度 8,16,24,32(位)
uint8_t descriptor;//描述符
}FILEHEADER;
void rgb_to_yuv(unsigned char* rgbBuf, unsigned char* yBuf, unsigned char* uBuf, unsigned char* vBuf, int Width, int Height);
void readfileheader(FILEHEADER* hd, FILE* tga);
void readRGB (FILEHEADER* hd, FILE* tga, unsigned char* rgbBuf, int w, int h);
void readGray(FILEHEADER* hd, FILE* tga, unsigned char* rgbBuf, int w, int h);
rgb2yuv.cpp
#include"header.h"
void rgb_to_yuv(unsigned char* rgbBuf, unsigned char* yBuf, unsigned char* uBuf, unsigned char* vBuf, int Width, int Height)
{
int y = 0;
for (int i = 0; i < Width * Height * 3; i = i + 3)
{
yBuf[y] = 0.114 * rgbBuf[i] + 0.587 * rgbBuf[i + 1] + 0.299 * rgbBuf[i + 2];//bgr顺序
//Y范围:16-235
if (yBuf[y] > 235)
yBuf[y] = 235;
if (yBuf[y] < 16)
yBuf[y] = 16;
y++;
}
int u = 0, v = 0;
for (int i = 0; i < Width * Height * 3;)
{
uBuf[u] = 0.5 * (rgbBuf[i] + rgbBuf[i + 3] + rgbBuf[i + Width * 3] + rgbBuf[i + Width * 3 + 3]) / 4
- 0.3316 * (rgbBuf[i + 1] + rgbBuf[i + 4] + rgbBuf[i + Width * 3 + 1] + rgbBuf[i + Width * 3 + 4]) / 4
- 0.1684 * (rgbBuf[i + 2] + rgbBuf[i + 5] + rgbBuf[i + Width * 3 + 2] + rgbBuf[i + Width * 3 + 5]) / 4 + 128;
vBuf[v] = -0.083 * (rgbBuf[i] + rgbBuf[i + 3] + rgbBuf[i + Width * 3] + rgbBuf[i + Width * 3 + 3]) / 4
- 0.4187 * (rgbBuf[i + 1] + rgbBuf[i + 4] + rgbBuf[i + Width * 3 + 1] + rgbBuf[i + Width * 3 + 4]) / 4
+ 0.5 * (rgbBuf[i + 2] + rgbBuf[i + 5] + rgbBuf[i + Width * 3 + 2] + rgbBuf[i + Width * 3 + 5]) / 4 + 128;
u++;
v++;
//U,V范围:16-240
if (uBuf[u] > 240)
uBuf[u] = 240;
if (uBuf[u] < 16)
uBuf[u] = 16;
if (vBuf[v] > 240)
vBuf[v] = 240;
if (vBuf[v] < 16)
vBuf[v] = 16;
if ((i / 3) % Width == 254)
i = i + (Width + 2) * 3;
else
i = i + 6;
}
}
readfileheader.cpp
#include"header.h"
void readfileheader(FILEHEADER* hd, FILE* tga)
{
fread(&hd->ID_len, sizeof(uint8_t), 1, tga);
fread(&hd->colormap_type, sizeof(uint8_t), 1, tga);
fread(&hd->image_type, sizeof(uint8_t), 1, tga);
fread(&hd->colormapPos, sizeof(uint16_t), 1, tga);
fread(&hd->colormap_len, sizeof(uint16_t), 1, tga);
fread(&hd->colormap_entrysize, sizeof(uint8_t), 1, tga);
fread(&hd->x_orig, sizeof(uint16_t), 1, tga);
fread(&hd->y_orig, sizeof(uint16_t), 1, tga);
fread(&hd->width, sizeof(uint16_t), 1, tga);
fread(&hd->height, sizeof(uint16_t), 1, tga);
fread(&hd->depth, sizeof(uint8_t), 1, tga);
fread(&hd->descriptor, sizeof(uint8_t), 1, tga);
switch((uint8_t)hd->image_type)
{
case 0:
{
printf("No image data in the image.\n");
system("pasue");
exit(1);
}
case 1:
{
printf("Uncompressed Color_Mapped Image.\n");
break;
}
case 2:
{
printf("Uncompressed Ture_Color Image.\n");
break;
}
case 3:
{
printf("Uncompressed Grey Image.\n");
break;
}
case 9:
{
printf("Compressed Color_Mapped Image.\n");
break;
}
case 10:
{
printf("Compressed Ture_Color Image.\n");
break;
}
case 11:
{
printf("Compressed Grey Image.\n");
break;
}
default:
{
printf("TGA Image may be invalid, or unsuitable for this program.\n");
system("pasue");
exit(1);
}
}
printf("ID Length\t%d\n" ,(uint8_t)hd->ID_len); //不能用cout,"0"的问题
printf("Color Map Type\t%d\n", (uint8_t)hd->colormap_type);
printf("Image Type\t%d\n", (uint8_t)hd->image_type);
printf("Color Map Offset\t%d\n",(uint16_t)hd->colormapPos);
printf("Color Map Length\t%d\n", (uint16_t)hd->colormap_len);
printf("Color Map Entry Size\t%d\n", (uint8_t)hd->colormap_entrysize);
printf("X Original\t%d\n",(uint16_t)hd->x_orig);
printf("Y Original\t%d\n", (uint16_t)hd->y_orig);
printf("Width\t%d\n", (uint16_t)hd->width);
printf("Height\t%d\n", (uint16_t)hd->height);
printf("Bit Depth\t%d\n", (uint8_t)hd->depth);
printf("Image Descriptor\t%d\n", (uint8_t)hd->descriptor);
system("pause");
}
readRGB.cpp
#include"header.h";
void read_rgb_depth16(unsigned char* rgbBuf, unsigned char *Buf, int j)
{
rgbBuf[j] = (Buf[0] & 0x1f) << 3;//b
rgbBuf[j + 1] = (Buf[0] & 0xe0) >> 2 + (Buf[1] & 0x03) << 6;//g
rgbBuf[j + 2] = (Buf[1] & 0x7c) << 1;//r
}
void read_rgb_depth24and32(unsigned char* rgbBuf, unsigned char *Buf, int j)
{
rgbBuf[j] = Buf[0];//b
rgbBuf[j + 1] = Buf[1];//g
rgbBuf[j + 2] = Buf[2];//r
}
void extract_raw_rgb(int flag, FILE* tga, unsigned char* rgbBuf, int w, int h)//顺序bgr
{
int j = 0;
switch(flag)
{
case 16:
{
unsigned char *Buf = (unsigned char*)malloc(sizeof(unsigned char) * 2);
for (int i = 0; i < w * h; i++)
{
fread(Buf, sizeof(unsigned char), 2, tga);
read_rgb_depth16(rgbBuf, Buf, j);
j = j + 3;
}
break;
}
case 24:
{
unsigned char *Buf = (unsigned char*)malloc(sizeof(unsigned char) * 3);
for (int i = 0; i < w * h; i++)
{
fread(Buf, sizeof(unsigned char), 3, tga);
read_rgb_depth24and32(rgbBuf, Buf, j);
j = j + 3;
}
break;
}
case 32:
{
unsigned char *Buf = (unsigned char*)malloc(sizeof(unsigned char) * 4);
for (int i = 0; i < w * h; i++)
{
fread(Buf, sizeof(unsigned char), 4, tga);
read_rgb_depth24and32(rgbBuf, Buf, j);
j = j + 3;
}
break;
}
default:
{
printf("Invalid Bit Depth!");
system("pause");
exit(1);
}
}
}
void extract_RLE_rgb(int flag, FILE* tga, unsigned char* rgbBuf, int w, int h)
{
int j = 0;
int packsize,packid;
unsigned char packheader = (unsigned char)malloc(sizeof(unsigned char));
switch(flag)
{
case 16:
{
unsigned char *Buf = (unsigned char*)malloc(sizeof(unsigned char) * 2);
for (int i = 0; i < w * h;)//i标记像素点
{
fread(&packheader, 1, 1, tga);
packid = (packheader & 0x80) >> 7;
packsize = (packheader & 0x7f) + 1;
if (packid == 1)//RLE compressed data
{
if (fread(Buf, sizeof(unsigned char), 2, tga) == NULL)
break;
for (int k = 0; k < packsize; k++)
{
read_rgb_depth16(rgbBuf, Buf, j);
i++;
j = j + 3;
}
}
else if (packid == 0)//raw data
{
for (int k = 0; k < packsize; k++)
{
if (fread(Buf, sizeof(unsigned char), 2, tga) == NULL)
break;
read_rgb_depth16(rgbBuf, Buf, j);
i++;
j = j + 3;
}
}
else
{
printf("error in packet data!");
system("pause");
exit(1);
}
}
break;
}
case 24:
{
unsigned char *Buf = (unsigned char*)malloc(sizeof(unsigned char) * 3);
for (int i = 0; i < w * h; )//i标记像素点
{
fread(&packheader, 1, 1, tga);
packid = (packheader & 0x80) >> 7;
packsize = (packheader & 0x7f) + 1;
if (packid == 1)//RLE compressed data
{
if (fread(Buf, sizeof(unsigned char), 3, tga) == NULL)
break;
for (int k = 0; k < packsize; k++)
{
read_rgb_depth24and32(rgbBuf, Buf, j);
i++;
j = j + 3;
}
}
else if (packid == 0)//raw data
{
for (int k = 0; k < packsize; k++)
{
if (fread(Buf, sizeof(unsigned char), 3, tga) == NULL)
break;
read_rgb_depth24and32(rgbBuf, Buf, j);
i++;
j = j + 3;
}
}
else
{
printf("error in packet data!");
system("pause");
exit(1);
}
}
break;
}
case 32:
{
unsigned char *Buf = (unsigned char*)malloc(sizeof(unsigned char) * 4);
for (int i = 0; i < w * h; )//i标记像素点
{
fread(&packheader, 1, 1, tga);
packid = (packheader & 0x80) >> 7;
packsize = (packheader & 0x7f) + 1;
if (packid == 1)//RLE compressed data
{
if (fread(Buf, sizeof(unsigned char), 4, tga) == NULL)
break;
for (int k = 0; k < packsize; k++)
{
read_rgb_depth24and32(rgbBuf, Buf, j);
i++;
j = j + 3;
}
}
else if (packid == 0)//raw data
{
for (int k = 0; k < packsize; k++)
{
if (fread(Buf, sizeof(unsigned char), 4, tga) == NULL)
break;
read_rgb_depth24and32(rgbBuf, Buf, j);
i++;
j = j + 3;
}
}
else
{
printf("error in packet data!");
system("pause");
exit(1);
}
}
break;
}
default:
{
printf("Invalid Bit Depth!");
system("pause");
exit(1);
}
}
}
void readRGB(FILEHEADER* hd, FILE* tga, unsigned char* rgbBuf, int w, int h)
{
if ((uint8_t)hd->image_type == 2)//Uncompressed Ture_Color Image
extract_raw_rgb((uint8_t)hd->depth, tga, rgbBuf, w, h);
if ((uint8_t)hd->image_type == 10)//Compressed Ture_Color Image
extract_RLE_rgb((uint8_t)hd->depth, tga, rgbBuf, w, h);
}
readGray.cpp
#include"header.h"
void read_gray_depth8and16(unsigned char* rgbBuf, unsigned char *Buf, int j)
{
rgbBuf[j] = Buf[0];//b
rgbBuf[j + 1] = Buf[0];//g
rgbBuf[j + 2] = Buf[0];//r
}
void extract_raw_gray(int flag, FILE* tga, unsigned char* rgbBuf, int w, int h)
{
int j = 0;
switch(flag)
{
case 8:
{
unsigned char *Buf = (unsigned char*)malloc(sizeof(unsigned char));
for (int i = 0; i < w * h; i++)
{
fread(Buf, sizeof(unsigned char), 1, tga);
read_gray_depth8and16(rgbBuf, Buf, j);
j = j + 3;
}
break;
}
case 16:
{
unsigned char *Buf = (unsigned char*)malloc(sizeof(unsigned char) * 2);
for (int i = 0; i < w * h; i++)
{
fread(Buf, sizeof(unsigned char), 2, tga);
read_gray_depth8and16(rgbBuf, Buf, j);
j = j + 3;
}
break;
}
default:
{
printf("Invalid Bit Depth!");
system("pause");
exit(1);
}
}
}
void extract_RLE_gray(int flag, FILE* tga, unsigned char* rgbBuf, int w, int h)
{
int j = 0;
int packsize,packid;
unsigned char packheader = (unsigned char)malloc(sizeof(unsigned char));
switch(flag)
{
case 8:
{
unsigned char *Buf = (unsigned char*)malloc(sizeof(unsigned char));
for (int i = 0; i < w * h;)//i标记像素点
{
fread(&packheader, 1, 1, tga);
packid = (packheader & 0x80) >> 7;
packsize = (packheader & 0x7f) + 1;
if (packid == 1)//RLE compressed data
{
if (fread(Buf, sizeof(unsigned char), 1, tga) == NULL)
break;
for (int k = 0; k < packsize; k++)
{
read_gray_depth8and16(rgbBuf, Buf, j);
j = j + 3;
i++;
}
}
else if (packid == 0)//raw data
{
for (int k = 0; k < packsize; k++)
{
if (fread(Buf, sizeof(unsigned char), 1, tga) == NULL)
break;
read_gray_depth8and16(rgbBuf, Buf, j);
i++;
j = j + 3;
}
}
else
{
printf("error in packet data!");
system("pause");
exit(1);
}
}
break;
}
case 16:
{
unsigned char *Buf = (unsigned char*)malloc(sizeof(unsigned char) * 2);
for (int i = 0; i < w * h;)//i标记像素点
{
fread(&packheader, 1, 1, tga);
packid = (packheader & 0x80) >> 7;
packsize = (packheader & 0x7f) + 1;
if (packid == 1)//RLE compressed data
{
if (fread(Buf, sizeof(unsigned char), 2, tga) == NULL)
break;
for (int k = 0; k < packsize; k++)
{
read_gray_depth8and16(rgbBuf, Buf, j);
i++;
j = j + 3;
}
}
else if (packid == 0)//raw data
{
for (int k = 0; k < packsize; k++)
{
if (fread(Buf, sizeof(unsigned char), 2, tga) == NULL)
break;
read_gray_depth8and16(rgbBuf, Buf, j);
i++;
j = j + 3;
}
}
else
{
printf("error in packet data!");
system("pause");
exit(1);
}
}
break;
}
default:
{
printf("Invalid Bit Depth!");
system("pause");
exit(1);
}
}
}
void readGray(FILEHEADER* hd, FILE* tga, unsigned char* rgbBuf, int w, int h)
{
if ((uint8_t)hd->image_type == 3)//Uncompressed Ture_Color Image
extract_raw_gray((uint8_t)hd->depth, tga, rgbBuf, w, h);
if ((uint8_t)hd->image_type == 11)//Compressed Ture_Color Image
extract_RLE_gray((uint8_t)hd->depth, tga, rgbBuf, w, h);
}
main.cpp
#include"header.h"
int read_image_and_colormap(FILEHEADER* hd, FILE* tga)
{
int offset = 0;
if ((uint8_t)hd->ID_len == 0)
printf("No Image ID information.\n");
else
{
unsigned char *image_id = (unsigned char*)malloc(sizeof(unsigned char) * (uint8_t)hd->ID_len);
offset += (uint8_t)hd->ID_len;
fread(image_id, sizeof(unsigned char), (uint8_t)hd->ID_len, tga);
cout << "Image ID:\t" << image_id << "\n";
}
if ((int8_t)hd->colormap_type == 0)
printf("No PALETTE in tga image.\n");
else if ((int8_t)hd->colormap_type == 1)
{
offset += (uint16_t)hd->colormap_len * (uint8_t)hd->colormap_entrysize;
}
system("pause");
return offset;
}
int main(int argc, char *argv)
{
FILE* tga = NULL;
FILE* yuv = NULL;
FILEHEADER hd;
memset(&hd, 0, sizeof(FILEHEADER));
tga = fopen(argv[1], "rb");//argv[1]为tga文件位置
if (tga == NULL)
{
printf("errors in opening tga file.");
exit(1);
}
readfileheader(&hd, tga);//读取图像信息
//读取其他信息
const int Width = hd.width;
const int Height = hd.height;
int offset = read_image_and_colormap(&hd, tga) + 18;
fseek(tga, offset, SEEK_SET);
//读取颜色信息
unsigned char *rgbBuf = (unsigned char*)malloc(sizeof(unsigned char) * (Width * Height * 3));
switch((uint8_t)hd.image_type)
{
case 2:
case 10://真彩图
{
readRGB(&hd, tga, rgbBuf, Width, Height);//读出数据
printf("rgb\n");
break;
}
case 3:
case 11://灰度图
{
readGray(&hd, tga, rgbBuf, Width, Height);//读出数据
printf("gray\n");
break;
}
default:
{
printf("the program does not support this type of image.");
system("pause");
exit(0);
}
}
fclose(tga);
//上下倒向
unsigned char *newBuf = (unsigned char*)malloc(sizeof(unsigned char) * (Width * Height * 3));
for (int i = 0; i < Height; i++)
{
for (int j = 0; j < Width * 3; j = j + 3)
{
newBuf[i * Width * 3 + j] = rgbBuf[(Height - i - 1) * Width * 3 + j];
newBuf[i * Width * 3 + j + 1] = rgbBuf[(Height - i - 1) * Width * 3 + j + 1];
newBuf[i * Width * 3 + j + 2] = rgbBuf[(Height - i - 1) * Width * 3 + j + 2];
}
}
//转向YUV空间
unsigned char *yBuf, *uBuf, *vBuf;
yBuf = (unsigned char*)malloc(sizeof(unsigned char) * (Width * Height));
uBuf = (unsigned char*)malloc(sizeof(unsigned char) * (Width * Height / 4));
vBuf = (unsigned char*)malloc(sizeof(unsigned char) * (Width * Height / 4));
rgb_to_yuv(newBuf, yBuf, uBuf, vBuf, Width, Height);//RGBtoYUV
//输出YUV文件
yuv = fopen(argv[2], "wb");//argv[2]为输出YUV文件文件位置
if (yuv == NULL)
{
printf("errors in opening yuv file.");
system("pause");
exit(1);
}
fwrite(yBuf, sizeof(unsigned char), Width * Height, yuv);
fwrite(uBuf, sizeof(unsigned char), Width * Height / 4, yuv);
fwrite(vBuf, sizeof(unsigned char), Width * Height / 4, yuv);
fclose(yuv);
printf("convert sucessfully\n");
system("pause");
}
实验结果:
实验共测试了8种图像(256*256):
24,32色非压缩RGB真彩图像
24,32色RLE压缩RGB真彩图像
8,16级非压缩灰度图像
8,16级RLE压缩灰度图像
转换成YUV文件后用YUVviewerPlus打开后如下:
从这几张图看效果还是很不错的。
实验中碰到的问题:
- cout输出’0’时会碰到输出空字符的情况,要注意。
- 算法一定要确认无误再进行扩展,改代码是在痛苦。。
- 尤其注意对内存分配的相关应用和容易出现的问题。
- 对结构体指针等的应用应该更加熟悉,避免出现低级错误。
- 代码其实可以更加简洁,写代码前务必理清思路。
其他:
对有颜色表的图像可参考github上的大佬写的代码,本实验的测试图片也是这里找的。