我需要实现自己的F5算法。我已经阅读了F5文档,可以在here中找到该论文。
在本文的6.2矩阵编码一节中,公式16-18定义了变化密度D(k)
,嵌入率R(k)
和效率率W(k)
,如下所示:
D(k) = 1 / (n + 1) = 1 / 2**k
R(k) = k / n = k / (2**k - 1)
W(k) = R(k) / D(k) = k * 2**k / (2**k - 1)
其中,
n
是代码字中可修改位置的数量,k
是嵌入位数。 W(k)
表示每次更改可嵌入的平均位数。在源代码中,我们发现如下所述的位数。有人可以解释一下为什么
usable
和changed
是用这种方式计算的吗?我根本不了解逻辑。 int _changed = 0;
int _expected = 0;
int _one = 0;
int _large = 0;
int _zero = 0;
for (i = 0; i < coeffCount; i++) {
if (i % 64 == 0) {
continue;
}
if (coeff[i] == 1) {
_one++;
}
if (coeff[i] == -1) {
_one++;
}
if (coeff[i] == 0) {
_zero++;
}
}
_large = coeffCount - _zero - _one - coeffCount / 64;
_expected = _large + (int) (0.49 * _one);
for (i = 1; i < 8; i++) {
int usable, changed, n;
n = (1 << i) - 1;
usable = _expected * i / n - _expected * i / n % n;
changed = coeffCount - _zero - coeffCount / 64;
changed = changed * i / n - changed * i / n % n;
changed = n * changed / (n + 1) / i;
//
changed = _large - _large % (n + 1);
changed = (changed + _one + _one / 2 - _one / (n + 1)) / (n + 1);
usable /= 8;
if (usable == 0) {
break;
}
if (i == 1) {
System.out.print("default");
} else {
System.out.print("(1, " + n + ", " + i + ")");
}
System.out.println(" code: " + usable + " bytes (efficiency: " + usable * 8 / changed + "." + usable * 8
/ changed % 10 + " bits per change)");
}
coeff是一个保存DCT系数的数组,coeffCount是DCT系数的数量,_large是可以编码的图像的理论比特数,预期是图像的预期容量(有收缩)。了解可用变量和更改变量背后的逻辑是什么
最佳答案
本文第6.2节的最后一段说了以下内容,我引用:
我们可以为每个要嵌入的消息和每个消息找到一个最佳参数k
载体介质提供足够的容量,因此消息恰好适合
载体介质。例如,如果我们要将1000位消息嵌入到
容量为50000位的载体介质,然后进行必要的嵌入
比率是R = 1000:50000 = 2%。该值介于R(k = 8)和R(k = 9)之间
表1.我们选择k = 8,并且能够嵌入50000:255 = 196个代码字
长度为n =255。(1、255、8)代码可以嵌入196·8 = 1568位。如果
我们选择了k = 9,因此无法完全嵌入该消息。
我相信这应该很简单。如果您能理解这一点,则可以按照以下步骤操作。
另一件事是整个代码中的表达式result = var - var % n;
。这意味着您可以通过除去余数(取模运算)来使var
被n
完全整除。现在进入循环块。
n = 1 << i - 1
这是本文定义的代码字长度。
usable = _expected * i / n - _expected * i / n % n;
要理解这一行,请记住
i / n
是嵌入率R(i)。简而言之,可用位数(_expected
)乘以嵌入率(i / n
)得出我们可以编码的位数。在引号中的示例中为50000/255 * 8 = 1568位。changed = coeffCount - _zero - coeffCount / 64;
changed = changed * i / n - changed * i / n % n;
changed = n * changed / (n + 1) / i;
第一行说,我们可以通过的位数(称为总数)是系数(
coeffCount
)的数量,同时跳过了任何零和每个8x8块的DC分量(coeffCount / 64
)。每个8x8块具有64个系数,但是DC系数只有一个,因此每64个系数中还有一个DC系数可以跳过。第二行和第三行在一起。请注意,与第二行相比,您需要乘以嵌入率,然后使结果可以完全被代码字长整除。在第三行中,将您除以嵌入率,从而取消上一步,然后将其乘以变化密度
1 / (n + 1)
,以求出平均要改变的位数。之所以要经历整个过程,是因为除法和乘法的顺序很重要。举一个简单的例子,假设您有150个位和7个项目,您希望将其平均分配到尽可能多的位。您总共需要多少位?
7 * (150 / 7) = 7 * 21 = 147
注意:以下几行将覆盖当前计算的
changed
值。当我编写自己的_one
,_zero
,coeffCount
值时,前3行和后2行分别倾向于给出相似的答案。这两个版本之一可能是未删除的旧代码。无论如何,逻辑如下。changed = _large - _large % (n + 1);
changed = (changed + _one + _one / 2 - _one / (n + 1)) / (n + 1);
第一行与变化密度D(i)有关,因为您使表达式可以被
n + 1
完全整除。由于_large
的定义方式,因此与先前版本中的changed
计算方式相似。_large = coeffCount - _zero - _one - coeffCount / 64;
与此极为相似
changed = coeffCount - _zero - coeffCount / 64;
下一行对我来说有点朦胧,但这似乎可以实现。它重新引入在
_one
中减去的_large
以及其中一半。这是由于收缩,因为它复制了_expected = _large + int(0.49*_ones)
中的想法。我不太明白为什么要减去ones / (n + 1)
,但是将整个表达式乘以变化密度1 / (n + 1)
,就可以得到期望变化的位数。结论
计算期望的更改位数的两种方法并不精确,这与事先不知道要更改多少位有关。对于给定的
_zero
,_one
和coeffCount
值,它们似乎都给出相似的结果。实际上,这一切都不是必需的,因为它只是估算不同k
的效率,如引文中所述。您只需要找到最大的k
,您就可以使用尽可能多的载体介质来嵌入您的信息。这是通过只计算usable
并在没有足够的位数来嵌入消息时立即中断循环来完成的。确切的事情在源代码中做了一些进一步的处理。
关于java - F5隐写术算法中的矩阵编码实现尚不清楚,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23523224/