我想学习如何将各种格式的图像读入字节数组。这对我来说是一项相当艰巨的任务,所以我从最简单的格式开始。PPM P6 没有问题,但是当我决定处理 TGA 图像时,我遇到了一些我无法找到解释的事情。例如,我不明白使用这种格式的压缩算法是如何工作的。
你可以在网上找到一个TGA 2的规范,据我了解,TGA 2格式并没有改变常规TGA的基本原理,只是在文件末尾添加了一些数据,所以压缩算法并且排序图像像素颜色序列不应该改变。可以在此处阅读规范:https ://www.dca.fee.unicamp.br/~martino/disciplinas/ea978/tgaffs.pdf或此处: http://tfc.duke.free.fr/coding/tga_specs。 pdf
该文档指出,如果文件的第三个字节指示该格式可以使用游程编码 (RLE) 算法(假设第三个字节是 TGA 压缩图像中的 9、10 或 11 [第 6 页])。
我对 RLE 在理论上的工作原理知之甚少。例如,字符序列AAABBBBBC压缩后应该变成3A5B1C或A3B5C1。因此,算法必须固定重复字符的数量。我希望在 TGA 文件中看到类似的内容。
为了获取和比较压缩和未压缩的 TGA 图像,我使用了 Paint dot NET 图形编辑器。保存 TGA 文件时,编辑器允许您在特殊窗口中启用或禁用压缩,如下图所示:
我保存的压缩和未压缩的图像是 50*50px 并且是 RGB(11,12,13) 颜色的实心正方形。图像中的所有像素都必须是这种颜色。
使用 slassstd::ifstream
及其方法get()
,我能够将图像的 TGA 字符输出到控制台。根据规范,文件的前 18 个字节总是被关于图像的各种信息占用。如果文件不包含颜色图和名为 Image ID 的字段,则图片像素的颜色序列在第 18 个字节之后立即开始。
这是我得到的:
未压缩的TGA 图像:
1) 0
2) 0
3) 2 // <- третий байт не равен 9, 10 или 11, поэтому изображение является несжатым
4) 0
5) 0
6) 0
7) 0
8) 0
9) 0
10) 0
11) 0
12) 0
13) 50
14) 0
15) 50
16) 0
17) 24
18) 0
19) 13 // <- первый символ, описывающий цвет пикселя
20) 12
21) 11
22) 13
23) 12
24) 11
25) 13
26) 12
27) 11
28) 13
29) 12
30) 11
31) 13
32) 12
33) 11
... // и так далее
压缩的 TGA 图像:
1) 0
2) 0
3) 10 // <- третий байт равен 10, поэтому изображение является сжатым
4) 0
5) 0
6) 0
7) 0
8) 0
9) 0
10) 0
11) 0
12) 0
13) 50
14) 0
15) 50
16) 0
17) 24
18) 0
19) 177 // <- первый символ, описывающий цвет пикселя
20) 13
21) 12
22) 11
23) 177
24) 13
25) 12
26) 11
27) 177
28) 13
29) 12
30) 11
31) 177
32) 13
33) 12
34) 11
... // и так далее
在未压缩的图像中,蓝色、绿色和红色 (BGR) 值位于字符 18 之后。由于图片中的所有像素都有这个颜色,所以三个值13 12 11的序列重复了很多次。压缩后的图像多次重复四个值的序列177 13 12 11。我不明白那是什么意思。结果与我之前的预期和描述不同。
我真的很想了解这个压缩算法的逻辑,但目前我找不到这方面的信息。阅读规范和搜索互联网还没有帮助我找到这个问题的答案。请告诉我在哪里可以读到它?也许有一些文章或书籍?
我还没有弄清楚如何附加我的代码在此处处理的 TGA 格式图像,但在我看来这不是必需的。
#include <iostream>
#include <fstream>
#include <string>
void ReadImage_TGA(const char* file_path_c_str);
int main()
{
ReadImage_TGA(".../image.tga");
return 0;
}
void ReadImage_TGA(const char* file_path_c_str)
{
std::string file_path = file_path_c_str;
std::ifstream file_stream;
file_stream.open(file_path, std::ios_base::binary);
if (file_stream.is_open() == false)
{
perror(("Error while opening file " + file_path).c_str());
return;
}
char current_char;
int count = 1;
while ((bool)file_stream.get(current_char) == true)
{
std::cout << count << ") " << (int)current_char << std::endl;
count++;
}
if (file_stream.eof())
{
std::cout << "End of file reached." << std::endl;
}
else if (file_stream.fail())
{
std::cout << "Type error." << std::endl;
}
else
{
std::cout << "Unknown error" << std::endl;
}
file_stream.close();
}
图像从底部开始逐行编码。数据分批存储。第一个字节是标题。如果其中第 7 位为 0,则数据包包含未压缩的 N 个像素的颜色,如果为 1,则数据包包含重复 N 次的像素颜色。数 N 在其余 7 位 + 1 中取整数。
因此,报头 177 (10110001) 表示存在像素颜色重复 50 (00110001 + 1) 次的数据包。原来是原始图像的一行。理论上,这个序列应该重复 50 次。
http://www.paulbourke.net/dataformats/tga/