【问题标题】:I am reading an image and changing it. But the changes are not being saved我正在阅读图像并对其进行更改。但是没有保存更改
【发布时间】:2014-10-23 02:57:31
【问题描述】:

我正在尝试实施隐写术。 我正在读取图像“a.jpeg”并通过在从偏移量 50 开始的最低有效位更改其连续 7 个字节来在其中插入一个字节。 这是成功完成的,因为当我打印字节时,最后一位会相应地更改。 然后我将它保存为“ao.jpeg”。但是当我从 50 读取字节值时,它们与我保存的一次不同。 这是我的代码

public static void main(String[] args) throws IOException {
        BufferedImage inputImage = ImageIO.read(new File("a.jpeg"));
        int offset=50;
        byte data = 7;
        byte[] image = get_byte_data(inputImage);//function converts bufferedimage to byte array
        //add data at end of each byte starting from offset
        System.out.println("bytes altered are :");
        for(int bit=7; bit>=0; --bit, ++offset)//for each bit of data
            {
            int b = (data >>> bit) & 1;
            image[offset] = (byte)((image[offset] & 0xFE) | b );
            String s1 = String.format("%8s", Integer.toBinaryString(image[offset] & 0xFF)).replace(' ', '0');
            System.out.println(s1);
            }
        //write changed image to ao.jpeg
        BufferedImage outputImage = ImageIO.read(new ByteArrayInputStream(image)); 
        File outputfile = new File("ao.jpeg");
        ImageIO.write(outputImage,"jpeg",outputfile);
        //read data from ao.jpeg
        System.out.println("bytes from encoded image are :");
        byte result=0;
        offset=50;
        BufferedImage oImage = ImageIO.read(new File("aoc.jpeg"));
        byte[] image1 = get_byte_data(oImage);//function converts bufferedimage to byte array
            for(int i=0; i<8; i++, ++offset)
             {
             result = (byte)((result << 1) | (image1[offset] & 1));
             String s1 = String.format("%8s", Integer.toBinaryString(image1[offset] & 0xFF)).replace(' ', '0');
             System.out.println(s1);
             }
            System.out.println("recovered data is :");
            System.out.print(result);
        }

输出样本: 插入的数据是 7。如果您注意到每个字节的最低有效位,它正在形成 7。 但是当我再次阅读时,它是随机字节。

bytes altered are :
00010100
00011100
00011010
00011110
00011110
00011101
00011011
00011101
bytes from encoded image are :
00011110
00011101
00011010
00011100
00011100
00100000
00100100
00101110
recovered data is :
64

正如 Konstantin V. Salikhov 所建议的那样,我尝试了不同的文件格式 (gif) 并且成功了。 但是有什么办法可以使用“jpeg”吗?

【问题讨论】:

  • 可能是因为 JPEG 有损压缩?
  • 我会尝试其他格式并发布结果
  • 你有什么建议吗??
  • 更改更重要的位。 JPEG 的基本原则是完全保留最低位信息,这就是它“压缩”得如此出色的原因。
  • 出于同样的原因,更改更重要的位将不起作用。 Jpeg 压缩有效地改变了一个像素的值,有时是 1。那么如果你有 00011111 并且它被更改为 00100000 怎么办?您丢失了在第 5 个 LSB 中编码的信息。

标签: java arrays byte bufferedimage steganography


【解决方案1】:

JPEG 是一种有损存储机制。这意味着不需要(甚至不希望)将每个字节完全表示为原始字节。事实上,这就是重点,为了节省大量空间,它牺牲了小瑕疵。如果您需要字节完美的存储,您将不得不选择另一种格式,例如 GIF、PNG 或某些风格的 BMP。

如下所述,从技术上讲,创建无损 JPEG 是可行的,但它是后期添加的,不完全支持,尤其是 Java 本身并不支持它。请参阅this answer 了解更多信息。

【讨论】:

  • 实际上如果 OP 想要如此努力地使用 JPEG,则可以对 JPEG 进行无损修改。 en.wikipedia.org/wiki/Lossless_JPEG
  • GIF 仅支持颜色索引模式,因此即使更改单个位也会将像素更改为任何随机颜色(可能包括透明颜色)。我们的 OP 自信地说“嘿,它与 gif 一起工作”,但肯定伴随着一整套自己的可见人工制品。
  • 感谢回复。我不想使用 jpeg,我只是想知道是否可能。当我使用 gif 时,图像没有明显改变(也许这是因为我改变了仅几个字节)。
【解决方案2】:

为什么你的方法失败了

正如 Salinkov 所建议的,jpeg 格式会导致数据压缩。总结一下你做了什么:

  • 您将图像数据加载到字节数组中。
  • 您修改了一些字节。
  • 您将字节数组加载为图像。
  • 您将此图像保存为 jpeg 格式,这会导致重新压缩。

这就是你的方法失败的地方。无损格式不会产生这些问题,这就是 gif 有效的原因。或者png、bmp等……

你能用你的方法制作jpeg吗?

Weeeeell,不,不是真的。首先,我们需要了解一张 jpeg 图片包含什么样的数据。

简短的回答是单个字节与图像中的实际像素不对应。

长话短说,您将图像拆分为 8x8 数组并采用 DCT 来获得频率系数。在量化步骤之后,它们中的许多将变为 0,尤其是较高频率的系数(DCT 阵列的右下角 - see here)。这是jpeg的有损步骤。你牺牲了更高的频率系数以获得一些可容忍的图像失真(信息丢失)。现在,您保存的是非零系数,基于它们在矩阵中的位置,即 (0, 0, -26)、(0, 1, -3) 等。这可以通过 Huffman 编码进一步压缩。顺便说一句,改变任何一个频率分量都会影响所有 64 个像素。

那么jpeg隐写术一般是怎么做的呢?大多遵循jpeg编码流程:

  • 在 8x8 阵列中分割图像。
  • 对每个 8x8 数组进行 DCT 并量化系数。

现在我们已经获得了量化的 DCT 系数,我们可以从 jpeg 编码过程中休息一下。

  • 通过更改量化系数的值来应用一些隐写算法。

  • Huffman 压缩系数并使用这些修改后的 DCT 系数继续进行 jpeg 编码过程的其余部分。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-09-04
    • 2021-04-25
    • 1970-01-01
    • 1970-01-01
    • 2020-05-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多