阅读PPM图像问题

Read PPM image issues

本文关键字:问题 图像 PPM 阅读      更新时间:2023-10-16

我一直有吨的麻烦让我的算法成功读取PPM图像…它可以完美地处理一些图像,但在处理其他图像时却失败了,导致图像呈现半灰色(RGB 205,205,205)。

我已经尝试了我能找到的一切,并研究了几个小时。我已经被困了一个星期了。

我希望你们能帮忙。

    Image* pnm_read(char* filePath)
    {
        FILE* file;
        char token[20];
        int imageWidth, imageHeight, maximumColorValue;
        Image* image;
        /* Abre arquivo PNM. */
        file = fopen(filePath, "r");
        if (file == NULL)
        {
            fprintf(stderr, "Não foi possível localizar o arquivo de imagem %s.n", filePath);
            return 0;
        }
        /* Lê Magic Number do cabecalho e vê se é P6*/
        pnm_get_token(file, token, sizeof token);
        if (strcmp(token, "P6"))
        {
            fprintf(stderr, "%s não é um arquivo PPM válido.n", filePath);
            fclose(file);
            return 0;
        }
        //Lê widht, height e valor máximo rgb
        if (sscanf(pnm_get_token(file, token, sizeof token), "%d", &imageWidth)        != 1 ||
            sscanf(pnm_get_token(file, token, sizeof token), "%d", &imageHeight)       != 1 ||
            sscanf(pnm_get_token(file, token, sizeof token), "%d", &maximumColorValue) != 1)
        {
            fprintf(stderr, "%s não é um arquivo PNM válido.n", filePath);
            fclose(file);
            return 0;
        }
        //Se não for RGB com componentes de 8 bits (0-255) dá erro
        if (maximumColorValue != 255)
        {
            fprintf(stderr, "%s does not have 8-bit components: maximumColorValue=%dn", filePath, maximumColorValue);
            fclose(file);
            return 0;
        }
        image = new Image(imageWidth, imageHeight);
        unsigned char* pixelComponents = new unsigned char[imageWidth * imageHeight * 3];
        fread(pixelComponents, sizeof(unsigned char), imageWidth * imageHeight * 3, file);
        fclose(file);
        int r, g, b, pixel;
        for(int i = 3; i <= imageWidth * imageHeight * 3; i += 3)
        {   
            r = pixelComponents[i-3] & 0xff;
            g = pixelComponents[i-2] & 0xff;
            b = pixelComponents[i-1] & 0xff;
            /*fread(&r, sizeof(char), sizeof(char), file);
            fread(&g, sizeof(char), sizeof(char), file);
            fread(&b, sizeof(char), sizeof(char), file);
            r = r & 0xff;
            g = g & 0xff;
            b = b & 0xff;*/
            pixel = (255 << 24) | (r << 16) | (g << 8) | b;             
            // Atribuindo os pixels e virando imagem de cabeca para baixo
            image->pixels[ (imageWidth * imageHeight) - (i/3) - 1] = pixel;
        }
        printf("Lido arquivo PNM (%s): %dx%d pixels.n", filePath, image->width, image->height);
        return image;
    }

我修改了你的代码,使用结构体来帮助理解和帮助调试。我还删除了难以调试的片段,如"(imageWidth * imageHeight) - (I/3) - 1",并引入了一些临时变量来辅助。

一些注意事项:你的图像像素似乎包括一个alpha通道,所以我添加了一个到RGBA像素类型。这些pragma也假定与gcc保持一致。我假设这是可以接受的,因为没有提到编译器。最后,这个例子更倾向于可读性而不是效率。有"更好"的方法来处理RGB和RGBA像素类型,但希望这能让你在正确的方向上开始。

typedef unsigned char u8;   // define a more concise data type
// Save current packing  to ensure the pixel struct is 3 bytes in size
#pragma pack(push)
// Pack on 1-byte boundaries
#pragma pack(1)

typedef struct
{
    u8 red;
    u8 green;
    u8 blue;
    u8 alpha;
} RgbaPixel;
typedef struct
{
    u8 red;
    u8 green;
    u8 blue;
} RgbPixel;
// Restore previous packing
#pragma pack(pop)
Image* pnm_read(char* filePath)
{

    FILE* file = NULL;
    char token[20] = "";
    int imageWidth = 0; 
    int imageHeight = 0;
    int maximumColorValue = 0;
    int numPixels = 0;
    int numRead = 0;
    Image* image = NULL;
    /* Abre arquivo PNM. */
    file = fopen(filePath, "r");
    if (file == NULL)
    {
        fprintf(stderr, "Não foi possível localizar o arquivo de imagem %s.n", filePath);
        return 0;
    }
    /* Lê Magic Number do cabecalho e vê se é P6*/
    pnm_get_token(file, token, sizeof token);
    if (strcmp(token, "P6"))
    {
        fprintf(stderr, "%s não é um arquivo PPM válido.n", filePath);
        fclose(file);
        return 0;
    }
    //Lê widht, height e valor máximo rgb
    if (sscanf(pnm_get_token(file, token, sizeof token), "%d", &imageWidth)        != 1 ||
        sscanf(pnm_get_token(file, token, sizeof token), "%d", &imageHeight)       != 1 ||
        sscanf(pnm_get_token(file, token, sizeof token), "%d", &maximumColorValue) != 1)
    {
        fprintf(stderr, "%s não é um arquivo PNM válido.n", filePath);
        fclose(file);
        return 0;
    }
    //Se não for RGB com componentes de 8 bits (0-255) dá erro
    if (maximumColorValue != 255)
    {
        fprintf(stderr, "%s does not have 8-bit components: maximumColorValue=%dn", filePath, maximumColorValue);
        fclose(file);
        return 0;
    }
    image = new Image(imageWidth, imageHeight);
    numPixels = imageWidth * imageHeight;
    RgbPixel* pixelComponents = new RgbPixel [numPixels];
    numRead = fread(pixelComponents, sizeof(RgbPixel), numPixels, file);
    fclose(file);
    if (numRead != numPixels)
    {
       // Problem!
       return 0;
    }
    RgbaPixel pixel = {0};
    for (int i = 0; i < numPixels; i++)
    {   
                pixel.alpha = 255;
        pixel.red = pixelComponents[i].red;
        pixel.green = pixelComponents[i].green;
        pixel.blue = pixelComponents[i].blue;
        // Atribuindo os pixels e virando imagem de cabeca para baixo
        image->pixels[i] = pixel;
    }
    printf("Lido arquivo PNM (%s): %dx%d pixels.n", filePath, image->width, image->height);
    return image;
}

正确读取文件中的数据(宽度和高度)后,可以执行如下操作(我改编了我之前写的代码):

...
for(int i=0; i < height; ++i)
{
    for(int j=0; j < width; ++j)
    {
        // Get pixel index from the PPM data
        int pixelIndex = (i*3) * width + (j*3); 
        int r = pixelComponents[pixelIndex];
        int g = pixelComponents[pixelIndex + 1];
        int b = pixelComponents[pixelIndex + 2];
        // Calc gray value from RGB
        int pixelValue = 0.2126f * r + 0.7152f * g + 0.0722f * b;             
        // Set pixel (i, j) in the output image
        image->pixel[i * width + j] = pixelValue; 
    }
}
...

我不能保证代码是正确的,但我想它可能会帮助你找到解决问题的方法。

祝你好运!