1.了解TGA文件里数据的储存方式
2.代码实现
#include "stdafx.h"
using namespace std;
#include <iostream>
#include <cstdio>
#include <fstream>
#include <windows.h>
#include <malloc.h>
#include <stdlib.h>
typedef struct _TgaHeader
{
BYTE IDLength; /* 00h Size of Image ID field */
BYTE ColorMapType; /* 01h Color map type */
BYTE ImageType; /* 02h Image type code */
}TGAHEAD;
typedef struct _TgaHeaderCMap
{
WORD CMapStart; /* 03h Color map origin */
WORD CMapLength; /* 05h Color map length */
BYTE CMapDepth; /* 07h Depth of color map entries */
}TGAHEADCMAP;
typedef struct _TgaHeaderImage
{
WORD XOffset; /* 08h X origin of image */
WORD YOffset; /* 0Ah Y origin of image */
WORD Width; /* 0Ch Width of image */
WORD Height; /* 0Eh Height of image */
BYTE PixelDepth; /* 10h Image pixel size */
BYTE ImageDescriptor; /* 11h Image descriptor byte */
}TGAHEADIMG;
int main()
{
FILE *TgaFile = NULL,*YuvFile = NULL,*RgbFile = NULL;
if((TgaFile=fopen("D:\\大三下\\数据压缩\\cx24.tga","rb")) == NULL)
{
printf("tga file open failed!");
exit(0);
}
if ((YuvFile=fopen("D:\\大三下\\数据压缩\\cx24.yuv","wb"))== NULL)
{
printf("yuv file open failed!");
exit(0);
}
TGAHEAD tga_header;
TGAHEADCMAP tga_header_cmap;
TGAHEADIMG tga_header_img;
fread(&tga_header,3,1,TgaFile);
fread(&tga_header_cmap,5,1,TgaFile);
fread(&tga_header_img,10,1,TgaFile);
unsigned char* ImageData = NULL;
unsigned char* b = NULL;
unsigned char* g = NULL;
unsigned char* r = NULL;
unsigned char* R = NULL;
unsigned char* G = NULL;
unsigned char* B = NULL;
unsigned char* Y = NULL;
unsigned char* U = NULL;
unsigned char* V = NULL;
unsigned char* u = NULL;
unsigned char* v = NULL;
unsigned char* RGB = NULL;
unsigned char* YUV = NULL;
if (tga_header.ColorMapType == 0)//不带颜色表
{
if (tga_header.ImageType == 0)
exit(0);
else if (tga_header.ImageType == 2)//未压缩的真彩色图像
{
int depth = tga_header_img.PixelDepth;
int width = tga_header_img.Width;
int height = tga_header_img.Height;
int size = width * height * depth / 8;//整个图像块的大小
cout << "该文件是未压缩的真彩色图像" << endl;
cout << "图像分辨率为" << width << "×" << height << endl;
cout << "像素深度为" << depth << "bit" << endl;
ImageData = new unsigned char[size];
fread(ImageData,1,size,TgaFile);
b = (unsigned char *)malloc(sizeof(char)*(width * height));
g = (unsigned char *)malloc(sizeof(char)*(width * height));
r = (unsigned char *)malloc(sizeof(char)*(width * height));
R = (unsigned char *)malloc(sizeof(char)*(width * height));
G = (unsigned char *)malloc(sizeof(char)*(width * height));
B = (unsigned char *)malloc(sizeof(char)*(width * height));
Y = (unsigned char *)malloc(sizeof(char)*(width * height));
U = (unsigned char *)malloc(sizeof(char)*(width * height));
V = (unsigned char *)malloc(sizeof(char)*(width * height));
u = (unsigned char *)malloc(sizeof(char)*(width * height/4));
v = (unsigned char *)malloc(sizeof(char)*(width * height/4));
RGB = new unsigned char[width * height * 3];
//16位
if (tga_header_img.PixelDepth == 16)
{
for (int j=0 ,i = 0; i < width * height; i++)
{
{
b[i] = (ImageData[j] & 0x1F) << 3;
g[i] = ((ImageData[j + 1] & 0x03) << 6) + ((ImageData[j] & 0xE0) >> 2);
r[i] = ((ImageData[j + 1] & 0x7C)) << 1;
j = j + 2;
}
}
}
//24位
if (tga_header_img.PixelDepth == 24)
{
for (int j=0 ,i = 0; i < width * height; i++)
{
b[i] = ImageData[j];
g[i] = ImageData[j + 1];
r[i] = ImageData[j + 2];
j = j + 3;
}
}
//32位
if (tga_header_img.PixelDepth == 32)
{
for (int j=0 ,i = 0; i < width * height; i++)
{
b[i] = ImageData[j];
g[i] = ImageData[j + 1];
r[i] = ImageData[j + 2];
j = j + 4;
}
}
for (int k=0,i = height-1; i >= 0; i--)
{
for (int j = 0; j < width; j++)
{
RGB[k] = b[j + i * width];
RGB[k+1] = g[j + i * width];
RGB[k+2] = r[j + i * width];
k = k + 3;
}
}
for(int i=0,j=0;i<width*height*3;i=i+3,j++)
{
R[j]=RGB[i+2];
G[j]=RGB[i+1];
B[j]=RGB[i];
}
//计算YUV分量
for(int i=0,j=0;i<width*height;i++,j++)
{
Y[j]=0.2990*R[i]+0.5870*G[i]+0.1140*B[i];
U[j]=-0.1684*R[i]-0.3316*G[i]+0.5*B[i]+128;
V[j]=0.5*R[i]-0.4187*G[i]-0.0813*B[i]+128;
}
//对UV下采样
for(int k=0, i=0;i<height;i=i+2)
{
for(int j=0;j<width;j=j+2)
{
u[k]=(U[width*i+j]+U[width*i+j+1]+U[(i+1)*width+j]+U[(i+1)*width+j+1])/4;
v[k]=(V[width*i+j]+V[width*i+j+1]+V[(i+1)*width+j]+V[(i+1)*width+j+1])/4;
k++;
}
}
//YUV量化后码电平分配
for(int k=0;k<width*height;k++)
{
if(Y[k]>235)
Y[k]=235;
if(Y[k]<16)
Y[k]=16;
}
for(int k=0;k<width*height/4;k++)
{
if(u[k]>240)
u[k]=240;
if(u[k]<16)
u[k]=16;
if(v[k]>240)
v[k]=240;
if(v[k]<16)
v[k]=16;
}
fwrite(Y,1,width*height,YuvFile);
fwrite(u,1,width*height/4,YuvFile);
fwrite(v,1,width*height/4,YuvFile);
}
}
else
exit(0);
if(ImageData);
free(ImageData);
if(b);
free(b);
if(g);
free(g);
if(r);
free(r);
if(Y);
free(Y);
if(U);
free(U);
if(V);
free(V);
if(u);
free(u);
if(v);
free(v);
if(RGB);
free(RGB);
fclose(TgaFile);
fclose(YuvFile);
return 0;
}
3.结果
原图:
无压缩真彩色16bit | 运行截图 |
---|---|
![]() | ![]() |
无压缩真彩色24bit | 运行截图 |
![]() | ![]() |
![]() | ![]() |
4.实验心得
通过这次实验我对有文件头的图像文件有了进一步的了解,尤其是对TGA文件,对结构体的定义和使用有了浅显的了解,但是对于如何调用函数还是有点问题,所以我把代码都写在一个main里了,这部分代码只能处理无压缩真彩色图像,对于有压缩图像和有颜色表的图像还不太会处理,今后对C++语言和多媒体文件还需多加学习。