当观察压缩数据时,我期望一个几乎均匀分布的字节流。当使用卡方检验测量分布时,我得到这样的结果,例如:用于ZIP文件和其他压缩数据,但不用于JPG文件。最后几天我花了很多时间找到原因,但我找不到任何原因。
当计算JPG的熵时,我得到高结果(例如7,95比特/字节)。我认为熵和分布之间必然存在联系:当每个字节以几乎相同的概率出现时,熵是高的。但是当使用卡方时,得到的p值约为4,5e-5 ......
我只是想了解不同的发行版如何影响测试结果...我认为我可以用两种测试来测量相同的属性,但显然我不能。
非常感谢您的任何提示! 汤姆
答案 0 :(得分:1)
忽略元信息和jpeg-header-data,jpeg的 payload 由描述huffmann-tables或编码的MCU的块组成(最小编码单元,方块大小16x16)。可能还有其他人,但这是最常见的。
这些块由0xFF 0xSS
分隔,其中0xSS
是特定的起始码。这是第一个问题:0xFF
比评论中提到的twalberg更频繁。
可能会发生0xFF
在编码的MCU中出现。要区分此普通有效负载和新块的开始,请插入0xFF 0x00
。如果未填充的有效负载的分布完全一致,0x00
将是填充数据的两倍。为了让糟糕的事情变得更糟,每个MCU都充满了二进制代码以获得字节对齐(稍微偏向更大的值),我们可能需要重新填充。
可能还有其他一些我不知道的因素。如果您需要更多信息,则必须提供jpeg文件。
表示rand_data:
dd if=/dev/urandom of=rand_data count=4096 bs=256
for 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
统一分布可能表示高entropy,但不是保证。此外,rand_data可能包含1MB的0x00
。它极不可能,但可能。
答案 1 :(得分:0)
在这里你可以找到两个文件:第一个是随机数据,用dev / unrandom(大约46MB)生成,第二个是普通的JPG文件(大约9MB)。很明显,JPG文件的符号不像dev / urandom那样平均分配。
如果我比较两个文件:
熵: JPG:7,969247 Bits / Byte RND:7,999996比特/字节
卡方检验的P值: JPG:0 RND:0,3621
熵如何导致如此高的结果?!?
答案 2 :(得分: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;
}