基于 LSB-DCT 的图像隐写术

Sam*_*eem 2 compression jpeg steganography image dct

我正在研究基于 LSB-DCT 的图像隐写术,其中我必须将 LSB 应用于图像的 DCT 系数以将数据嵌入到 JPEG。我对这一切都不熟悉。所以搜索并阅读了一些研究论文,他们都缺乏很多关于 DCT.i 之后过程的信息也在 stackoverflow 上阅读了许多问题和答案,并且变得更加困惑。

以下是问题:

1-研究论文和网络上的问题,他们都使用来自图像的 8x8 块大小进行 DCT ..如果图像的分辨率没有完全分成 8x8 块,如 724 x 520,我应该怎么做。520
/ 8 = 65 但是724 / 8 = 90.5

2-如果我有很多块和一些要隐藏的信息,我们认为它们可以放入 5 个块中..我是否仍然需要对剩余块和 idct 进行 dct。

3-我需要在 dct 之后应用量化然后应用 lsb 还是我可以直接应用 lsb ?

4 篇研究论文没有提到不涉及值为 0 和 1 以及第一个值的量化 dct 系数。现在我应该使用它们还是不使用它们?那么为何不??我知道它是 0,因为它是高频分量,并且在 JPEG 中被删除以进行压缩......而且我没有进行任何压缩......所以我可以使用它并仍然生成相同的 JPEG 文件吗???

5-in 量化我们将 DCT 系数与量化矩阵相除并四舍五入。相反,我必须将量化矩阵与 DCT 系数相乘......不能撤消四舍五入???

对于 DCT 和 IDCT 的评论:

来自不同的研究论文: 在此处输入图片说明

Ret*_*i43 5

JPEG 隐写术

如果要将图像保存为 jpeg,则必须遵循 jpeg 编码过程。不幸的是,我读过的大多数论文都说不公正。整个过程是以下(维基总结一的182页的书规格):

  1. RGB 到 YCbCr 转换(可选),
  2. 色度通道的子采样(可选),
  3. 8x8 块分割,
  4. 像素值重定位,
  5. 离散余弦变换,
  6. 基于压缩比/质量的量化,
  7. 以锯齿形模式对系数进行排序,以及
  8. 熵编码;最常涉及霍夫曼编码和游程编码 (RLE)。

实际上涉及更多细节,例如标题、部分标记、如何存储 DC 和 AC 系数的细节等。然后,有些方面标准只是松散地定义,它们的实现可能因编解码器而异,例如、子采样算法、量化表和熵编码。也就是说,大多数软件都遵循通用的 JFIF 标准,并且可以被各种软件读取。如果您希望 jpeg 文件也这样做,请准备好为编码器编写数百(到大约一千)行代码。你最好借用一个已经在互联网上发布的编码器,而不是自己编写。您可以首先查看用 C 编写的libjpeg,它是许多其他 jpeg 编解码器的基础,它的C# 实现,甚至是受它启发的Java版本。

在一些伪代码中,编码/解码过程可以描述如下。

function saveToJpeg(pixels, fileout) {
    // pixels is a 2D or 3D array containing your raw pixel values
    // blocks is a list of 2D arrays of size 8x8 each, containing pixel values
    blocks = splitBlocks(pixels);
    // a list similar to blocks, but for the DCT coefficients
    coeffs = dct(blocks);
    saveCoefficients(coeffs, fileout);
}

function loadJpeg(filein) {
    coeffs = readCoefficients(filein);
    blocks = idct(coeffs);
    pixels = combineBlocks(blocks);
    return pixels;
}
Run Code Online (Sandbox Code Playgroud)

对于隐写术,您可以对其进行如下修改。

function embedSecretToJpeg(pixels, secret, fileout) {
    blocks = splitBlocks(pixels);
    coeffs = dct(blocks);
    modified_coeffs = embedSecret(coeffs, secret);
    saveCoefficients(modified_coeffs, fileout);
}

function extractSecretFromJpeg(filein) {
    coeffs = readCoefficients(filein);
    secret = extractSecret(coeffs);
    return secret;
}
Run Code Online (Sandbox Code Playgroud)

如果您的封面图像已经是 jpeg 格式,则无需使用解码器将其加载到像素,然后将其传递给编码器以嵌入您的消息。你可以这样做。

function embedSecretToJpeg(pixels, secret, filein, fileout) {
    coeffs = readCoefficients(filein);
    modified_coeffs = embedSecret(coeffs, secret);
    saveCoefficients(modified_coeffs, fileout);
}
Run Code Online (Sandbox Code Playgroud)

就您的问题而言,编码器/解码器应处理 1、2、3 和 5,除非您自己编写。

问题 1:通常,您希望用必要数量的行/列填充图像,以便宽度和高度都可以被 8 整除。在内部,编码器将跟踪填充的行/列,以便解码器重建后丢弃它们。这些虚拟行/列的像素值的选择取决于您,但建议您不要使用恒定值,因为它会导致振铃伪影,这与方波的傅立叶变换是正弦函数。

问题 2:虽然您只会修改几个块,但编码过程要求您将它们全部转换,以便将它们存储到文件中。

问题 3:您必须量化浮点 DCT 系数,因为这是无损存储到文件的内容。在量化步骤之后,您可以根据自己的喜好修改它们。

问题 4:没有人阻止您修改任何系数,但您必须记住每个系数都会影响块中的所有 64 个像素。DC 系数和低频 AC系数引入了最大的失真,因此您可能希望远离它们。更具体地说,由于 DC 系数的存储方式,修改一个会将失真传播到所有后续块。

由于大多数高频系数为 0,因此可以使用 RLE 有效地压缩它们。修改 0 系数可能会将其翻转为 1(如果您正在进行基本的 LSB 替换),这会破坏这种有效的压缩。

最后,一些算法将它们的秘密存储在任何非零系数中,并且会跳过任何 0。但是,如果您尝试修改 1,它可能会翻转为 0,并且在提取过程中您会盲目地跳过阅读它。因此,此类算法不会接近任何值为 1 或 0 的系数。

问题 5:在解码时,您只需将系数与相应的量化表值相乘。例如,DC 系数为 309.443,量化为您提供round(309.443 / 16) = 19. 舍入位是这里的有损部分,它不允许您重建 309.433。所以反过来很简单19 * 16 = 304

DCT 在隐写术中的其他用途

频率变换(例如 DCT 和 DWT)可用于隐写术以将秘密嵌入频域中,但不一定将隐写图像存储为 jpeg。这个过程是像素 -> DCT -> 系数 -> 修改系数 -> IDCT -> 像素,这就是你发送给接收器的内容。因此,格式的选择在这里很重要。如果您决定将像素保存为 jpeg,您在 DCT 系数中的秘密可能会被jpeg 编码的另一层量化所干扰