gpt4 book ai didi

c - 将tga文件转换为黑白时出现问题

转载 作者:行者123 更新时间:2023-11-30 19:21:21 29 4
gpt4 key购买 nike

我一直试图使该程序将彩色的tga图像转换为黑白。但是我不知道如何去做。我对C还是很陌生,还没有掌握语法,甚至无法正确使用ubuntu。

我认为我的问题是tga文件标头无法读取。因为在tga文件上尝试该程序时得到的结果是没有高度的无法打开的图片。 “高度= 0”。

是否有一些不错的链接供您阅读C?

#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct pixel {
uint8_t r, g, b, a;
};

static uint8_t *load_image(char *filename, int *sizex, int *sizey)
{
uint8_t *image;
char buf[512];
char *bufptr;
int ret;

FILE *fp = fopen(filename, "r");
bufptr = fgets(buf, 512, fp);
ret = fscanf(fp, "%d %d\n", sizex, sizey);
bufptr = fgets(buf, 512, fp);

image = malloc(*sizex * *sizey * 4);

int i;
uint8_t *ptr = image;
for (i=0; i<*sizex * *sizey; ++i) {
ret = fread(ptr, 1, 3, fp);
ptr += 4;
}

fclose(fp);
return image;
}

static int save_image(const char *filename, uint8_t *image, int sizex, int sizey)
{
FILE *fp = fopen(filename, "w");
fprintf(fp, "P6\n%d %d\n255\n", sizex, sizey);

int i;
uint8_t *ptr = image;
for (i=0; i<sizex * sizey; ++i) {
fwrite(ptr, 1, 3, fp);
ptr += 4;
}
fclose(fp);

return 1;
}

void convert_grayscale(uint8_t *input, uint8_t *output, int sizex, int sizey)
{
// Y = 0.299 * R + 0.587 * G + 0.114 * B

int i;

for (i = 0; i < sizex * sizey; ++i)
{
struct pixel *pin = (struct pixel*) &input[i*4];
struct pixel *pout = (struct pixel*) &output[i*4];

float luma = 0.299 * pin->r + 0.587 * pin->g + 0.114 * pin->b;

if (luma > 255)
luma = 255;

uint8_t intluma = (int) luma;

pout->r = intluma;
pout->g = intluma;
pout->b = intluma;
pout->a = 255;
}

}

int main()
{
uint8_t *inputimg, *outputimg;
int sizex, sizey;

inputimg = load_image("image.tga", &sizex, &sizey);

outputimg = malloc(sizex * sizey * 4);

convert_grayscale(inputimg, outputimg, sizex, sizey);

save_image("output.tga", outputimg, sizex, sizey);
}

最佳答案

(个人说明:阅读Why Stackoverflow sucks后会有更长的答案。对拥有主持人特权的每个人都应该阅读此书。)

问题是您的load_image代码似乎旨在读取PPM(基于ASCII)图像:


  每个PPM映像均包含以下内容:
  1.用于标识文件类型的“幻数”。 ppm图像的幻数是两个字符“ P6”。
  2.空格(空白,TAB,CR,LF)。
  3.宽度,格式为十进制的ASCII字符。
  4.空格。
  5.再次使用ASCII十进制的高度。
  6.空格。
  7.最大颜色值(Maxval),再次为ASCII十进制。必须小于65536并且大于零。
  8.单个空格字符(通常是换行符)。
  9.高度行的栅格[...]


-您的第一个fgets读取,然后丢弃“幻数”行,然后读取宽度和高度,然后丢弃“ maxval”行。

如果没有一个重要的问题,它应该适用于PPM图像(并且您可以重命名此例程load_ppm_image):在处理完所有ASCII内容之后,您切换到fread,因此这里是警告#1。

在打开文件之前,请确定是要只读取ASCII文本,还是可能需要读取二进制数据。

问题在于,“文本模式”“ w”在读写时会将某些字符转换成其他字符。这是所有常见C库中的内置行为。它试图修复上一代程序员留下的行尾字符混乱。现在,以文本模式读取文本文件变得更加简单,但是无法读取二进制数据。您无法确定文件中到底有什么。

让我们继续警告#2:并非所有文件格式都相同。

上面的例程(大多数情况下)适用于PPM图像,但由于其标头的组织方式不同,因此在TGA上将失败。 here(对Google结果的随机选择)描述了TGA标头。

规范描述了字节,因此首先要做的是将fopen行更改为

FILE *fp = fopen(filename, "rb");


顺便说一句,一个好的做法是测试它是否成功:

if (fp == NULL)
{
printf ("Opening the file '%s' failed\n", filename);
return NULL;
}


然后,您可以使用 fgetcfread读取一个或多个字节。警告#3:小心使用 fread

fread按照它们存储到文件中的顺序读取多个字节,因此您可能会认为它可以读取诸如 widthheight之类的项(每个均为2字节整数值) “读取”操作。但是 fread不知道系统中字节的顺序(文件本身也不知道),因此它可能读为“ lo-hi”(如我所指出的规范),而在计算机中则为整数中的字节数是“ hi-lo”。澄清一下:文件中是否包含此内容

80 00


然后您用 fread (&width,1,2, fp)读取然后存储,这2个字节将以相同的顺序存储到计算机内存中。字节按Big-Endian顺序排列; “大”字节在末尾。但是,如果您的计算机恰好是Little-Endian订购系统,则不会获得 0x0080 = 128值,而是 0x8000 = 32768

避免这种情况的方法是一次读取一个字节:

width = fgetc(fp) + (fgetc(fp)<<8);


将始终以正确的顺序读取数据:先低然后高。仅存储总和(按系统顺序存储,但现在不相关了!)。

有了以上内容,我认为我已经没有警告了。使用TGA规范作为指南,您现在可以打开文件,一次读取一个字节的标题,直到获得所有需要的信息,然后继续将原始图像数据 fread存入内存。您可以安全地使用 fread一次读取三个图像字节,因为它们将以与读取时相同的顺序出现在内存中(它们不是整数或更大的整数,因此“内存顺序”不是问题)。

确保您阅读正确的信息的一种好方法是:


一次读取一个字节,以防止字节顺序问题。
在代码中添加注释,详细说明它是什么
打印出值
请检查规格是否允许该值。


要开始使用,请在 fopen行之后(并进行必要的检查是否可行):

int idLength = fgetc(fp); /* length of id string after header */
printf ("id length: %u bytes\n", idLength);
int colorMapType = fgetc(fp); /* 0 = RGB */
printf ("color map type: %u\n", colorMapType);
if (colorMapType != 0)
{
printf ("unexpected color map type!\n");
return NULL;
}
int imageType = fgetc(fp); /* 0 = None, 1 = Indexed, 2 = RGB, 3 = Greyscale */


.. 等等。读取整个标头后,您不会感到意外,您就可以准备就绪,以读取实际的图像数据。那里不需要任何更改,您现有的代码应该可以正常工作。



编辑后:我看到我用过

int colorMapType = fgetc(fp);


“颜色图类型”实际上是一个字节,而不是整数。那是允许皮带和吊带的方法。如果在读取标题时遇到文件末尾,则 fgetc返回的代码为 EOFEOF不能存储到 char中,因为它是整数值: 0xFFFFFFFF(更准确地说是 (int)-1)。如果将其存储在 char中,则无法将其与完全正确的值 0x000000FF(值255)区分开。

束腰带挂起的方法是检查每个字节:

if (colorMapType == EOF)
{
printf ("encountered unexpected end of file!\n");
return NULL;
}


如果您正在使用已知文件,并且知道它是有效的TGA(可以使用位图编辑器进行查看和编辑),则可能会大材小用,但是如果您打算处理不知道它们是否有效的文件,您可能需要这个。

关于c - 将tga文件转换为黑白时出现问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20175511/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com