【问题标题】:Compare two pictures byte by byte in unix c在unix c中逐字节比较两张图片
【发布时间】:2018-10-15 02:46:31
【问题描述】:

我编写了这个方法,它比较两个文件,特别是图片,并在输出中打印差异在哪里以及差异是什么。此时的结果是每个字节都不同,但我正在比较的图像是相同的。你能帮我吗?代码如下:

void compareFiles(char* path1, char* path2){
    FILE* img1;
    FILE* img2;

    if((img1 = fopen(path1,"r")) == NULL || (img2 = fopen(path2,"r")) == NULL){
        printf("ERROR fopen()\n");
        exit(-1);
    }

    int i=0;
    char buffer1,buffer2;

    int c;
    while ((c=fgetc(img1)) != EOF){
        fread(&buffer1, 1,1, img1);
        fread(&buffer2, 1,1, img2);
        if(buffer1 != buffer2){
            printf("Byte differs\n IMG1: %s, IMG2: %s; Position %d\n",&buffer1,&buffer2,i);
            i++;
        }
    }

    fclose(img1);
    fclose(img2);
}

【问题讨论】:

  • c=fgetc(img1) 正在从第一个文件中读取一个字节,但没有人对第二个文件执行相同的操作。不知道它是如何具体图片,虽然...
  • printf 也是错误的...您的缓冲区实际上只是单个字符,将地址传递给这些 %s未定义的行为 (@987654325 @ 需要一个0-终止的字符串)
  • 最后,相同的图像并不意味着文件中的相同表示。有许多可能的文件格式允许不同的选项来存储图像。
  • 您还必须以二进制模式打开文件,"rb"
  • 嗯,如果你比较一个 128x128 纯红色正方形图像写成 JPEG,它将与一个 128x128 纯红色正方形写成 PNG、TIF 或 GIF 完全不同,所以你的方法将不能很好地用作图像比较器。更糟糕的是,如果您将保存在 PNG 文件中的 2 个纯红色矩形相互比较,它们可能仍然会有所不同,因为创建时间也保存在文件中......当然,作为学术练习,可以逐字节比较图像,但事实并非如此。

标签: c image file unix compare


【解决方案1】:

在我看来,您应该将它们转换为两个位图并进行标题和矩阵比较。您现在遇到了麻烦,因为标题和标签可能不同。你可以找到很多关于这个主题的教程,比如this one on Code Project

【讨论】:

    【解决方案2】:
    while ((c=fgetc(img1)) != EOF)
    

    这会从img1 读取第一个字节。假设不是EOF...

    fread(&buffer1, 1,1, img1);
    

    这会从img1 读取第二个字节。

    fread(&buffer2, 1,1, img2);
    

    这会从img2 读取第一个字节。

    if(buffer1 != buffer2)
    

    所以现在我们将img2 的第一个字节与img1 的第二个字节进行比较。

    如果它们恰好相等,我们将再次循环,最后将img2 的第二个字节与img1 的第四个字节进行比较。

    看起来您可能认为fgetc 进行了测试以查看是否有另一个字节可用,然后fread 读取它。但不是。 fgetc 从文件中读取一个字符,然后返回。如果你写

    c = fgetc(fp);
    

    几乎和你写的一模一样

    fread(&c, 1, 1, fp);
    

    因此,对您的程序的最小修复是摆脱

    fread(&buffer1, 1,1, img1);
    

    行,并将相等测试更改为

    if(c != buffer2)
    

    但这最终有点令人困惑——后来的读者可能会想,“为什么一个文件使用fgetc读取,而另一个文件使用fread读取?”

    如果我正在写这篇文章,我可能会使用getcimg1 读取一个字节,使用getcimg2 读取一个字节,然后比较它们。或者,我可以使用fread 将来自img1 的N 个字节读入一个字符数组,并将来自img2 的N 个字节读入第二个字符数组,然后使用memcmp 函数将它们进行比较。

    另外,正如 Paul Ogilvie 在评论中提到的,由于这些是二进制文件,当您调用 fopen 打开它们时,您应该指定 "rb" 模式。

    【讨论】:

    • 非常感谢!我明白了,您的解决方案对我不利,因为我需要查看哪个字节不同以及为什么不同,但是您的所有建议让我意识到该怎么做,谢谢大家!
    【解决方案3】:

    正如在其他 cmets 中所述,fgetc 正在从流中读取一个字符,因此在调用 fread 之前这两个流不同步。下面使用 2 次 fgetc 调用,然后使用返回值进行比较。

    void compareFiles(char* path1, char* path2){
        FILE* img1; 
        FILE* img2; 
    
        if((img1 = fopen(path1,"rb")) == NULL || (img2 = fopen(path2,"rb")) == NULL){ 
            printf("ERROR fopen()\n"); 
            exit(-1); 
        }   
    
        int i=0;
        int byte1,byte2;
    
        while (((byte1=fgetc(img1)) != EOF) && ((byte2=fgetc(img2)) != EOF)){
            if(byte1 != byte2){
                printf("Byte differs\n IMG1: %c, IMG2: %c; Position %d\n",byte1,byte2,i);  
                i++; 
            } 
        }  
    
        fclose(img1);
        fclose(img2);
    } 
    

    【讨论】:

    • 非常感谢!您的解决方案比我想出的更直接和优美:) 谢谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-23
    • 1970-01-01
    • 2019-07-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多