JPEG文件中字节的分布

4
观察压缩数据时,我期望获得几乎均匀分布的字节流。当使用卡方检验来衡量分布时,我会得到这样的结果,例如对于ZIP文件和其他压缩数据,但不适用于JPG文件。最近几天我一直在找出原因,但是我找不到任何原因。
当计算JPG的熵时,我得到了一个高结果(例如7.95比特/字节)。我认为熵和分布之间一定有联系:当每个字节出现的概率几乎相同时,熵就很高。但是当使用卡方检验时,我得到的p值大约为4.5e-5...
我只是想了解不同分布如何影响测试结果...我以为我可以用两种测试方法测量相同的属性,但显然我不能。
非常感谢任何提示! 汤姆

你是只测量了正文还是包括未压缩的头部? - usr
我试图排除元信息...因此我跳过了前后的4096字节(每个1个簇)。 - tommynogger
JPEG和许多其他格式在整个文件中都有节标题和其他元数据,而不仅仅是在开头和/或结尾。如果您真的想跳过所有元数据,您需要解析标题以找出其他部分的位置,以便您也可以跳过它们... - twalberg
我已经查看了一些文件,但没有找到类似元数据的东西,所有内容看起来都很统一。 - tommynogger
你用卡方检验测试了什么?是 256 字节值的频率吗? - usr
我观察到字节,即你有256个不同的值。 - tommynogger
3个回答

1

JPEG文件的分布

在忽略元信息和jpeg头数据的情况下,jpeg文件的有效载荷由描述huffman表或编码的MCU(最小编码单元,大小为16x16的正方形块)的块组成。可能还有其他类型的块,但这些是最常见的。

这些块由0xFF 0xSS分隔,其中0xSS是特定的起始码。这里有第一个问题:0xFFtwalberg在评论中提到的更加频繁。

在编码的MCU中可能会出现0xFF,为了区分这个正常负载和一个新块的开始,插入了0xFF 0x00。如果未填充负载的分布完全均匀,那么0x00将在填充数据中出现两次。更糟糕的是,每个MCU都会被填满二进制1以获得字节对齐(稍微偏向较大值),我们可能需要再次填充。

还可能有其他因素我不知道。如果您需要更多信息,您必须提供JPEG文件。

关于您的基本假设:

对于rand_data:

 dd if=/dev/urandom of=rand_data count=4096 bs=256

对于 rand_pseudo(Python):

s = "".join(chr(i) for i in range(256))
with file("rand_pseudo", "wb") as f:
    for i in range(4096):
        f.write(s)

它们的字节值应该是一致的,不是吗?;)

$ ll rand_*
-rw-r--r-- 1 apuch apuch 1048576 2012-12-04 20:11 rand_data
-rw-r--r-- 1 apuch apuch 1048967 2012-12-04 20:13 rand_data.tar.gz
-rw-r--r-- 1 apuch apuch 1048576 2012-12-04 20:14 rand_pseudo
-rw-r--r-- 1 apuch apuch    4538 2012-12-04 20:15 rand_pseudo.tar.gz

均匀分布可能表明高,但这并不是保证。此外,rand_data可能由1MB的0x00组成。虽然极不可能,但仍有可能。


非常感谢!显然我需要更深入地了解JPG文件格式。无论如何,我仍然困惑为什么熵很高,但卡方计算的P值非常低(比ZIP/DOC/PDF低得多)... - tommynogger

0

这是我的Java代码

         public static double getShannonEntropy_Image(BufferedImage actualImage){
         List<String> values= new ArrayList<String>();
           int n = 0;
           Map<Integer, Integer> occ = new HashMap<>();
           for(int i=0;i<actualImage.getHeight();i++){
             for(int j=0;j<actualImage.getWidth();j++){
               int pixel = actualImage.getRGB(j, i);
               int alpha = (pixel >> 24) & 0xff;
               int red = (pixel >> 16) & 0xff;
               int green = (pixel >> 8) & 0xff;
               int blue = (pixel) & 0xff;
//0.2989 * R + 0.5870 * G + 0.1140 * B greyscale conversion
//System.out.println("i="+i+" j="+j+" argb: " + alpha + ", " + red + ", " + green + ", " + blue);
                int d= (int)Math.round(0.2989 * red + 0.5870 * green + 0.1140 * blue);
               if(!values.contains(String.valueOf(d)))
                   values.add(String.valueOf(d));
               if (occ.containsKey(d)) {
                   occ.put(d, occ.get(d) + 1);
              } else {
                  occ.put(d, 1);
              }
              ++n;
       }
    }
    double e = 0.0;
    for (Map.Entry<Integer, Integer> entry : occ.entrySet()) {
         int cx = entry.getKey();
         double p = (double) entry.getValue() / n;
         e += p * log2(p);
    }
 return -e;
  }

0
在这里,您可以找到两个文件:第一个是随机数据,使用dev/unrandom(大约46MB)生成的;第二个是普通JPG文件(大约9MB)。很明显,JPG文件的符号分布不如dev/urandom均匀。
如果我比较这两个文件:
熵: JPG:7.969247比特/字节 RND:7.999996比特/字节
卡方检验的P-值: JPG:0 RND:0.3621
熵怎么可能导致如此高的结果?!

Random Data (dev/urandom JPG


我想推送那篇帖子,因为我还没有找到答案...顺便祝大家新年快乐 :) - tommynogger

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接