【问题标题】:Changing lsb value of image rgb value giving inconsistent value更改图像 rgb 值的 lsb 值给出不一致的值
【发布时间】:2014-12-23 23:51:02
【问题描述】:

我正在尝试更改图像像素的 lsb 值,使其与字符串“abc”匹配,但将 1 或 0 添加到具有奇数值的像素返回 0。 代码如下:

public static void main(String[] args) {
    BufferedImage img = null;

    try {
        img = ImageIO.read(new File("a.jpg"));
    } catch (IOException ex) {

    }

    int pixel[] = img.getRGB(0, 0, img.getWidth(), img.getHeight(), null, 0, img.getWidth());
    String s = "abc";
    byte[] b = s.getBytes();

    String f = "";
    for (int i = 0; i < b.length; i++) {
        f += Integer.toBinaryString(b[i]);
    }

    f.trim();

    int[] newpixel = new int[pixel.length];
    for (int i = 0; i < pixel.length; i++) {
        if (i < f.length()) {
            if (pixel[i] % 2 == 0) {
                if (f.charAt(i) == '0') {
                    newpixel[i] = pixel[i];
                }
                if (f.charAt(i) == '1') {
                    newpixel[i] = pixel[i] + 1;
                }
            }
            if (pixel[i] % 2 == 1) {
                if (f.charAt(i) == '0') {
                    newpixel[i] = pixel[i] - 1;
                }
                if (f.charAt(i) == '1') {
                    newpixel[i] = pixel[i];
                }
            }
        } else {
            newpixel[i] = pixel[i];
        }
    }

    o:
    for (int i = 0; i < img.getWidth() * img.getHeight(); i++) {

        if (i < f.length()) {
            System.out.print("  " + f.charAt(i) + ":(" + pixel[i] + "," + newpixel[i] + ")");
        } else {
            break o;
        }

    }

}

输出是:

1:(-11235948,-11235947) 1:(-11893363,0) 0:(-11893617,0) 0:(-10577497,0) 0:(-11695976,-11695976) 0:(-12090996 ,-12090996) 1:(-11170168,-11170167) 1:(-10775924,-10775923) 1:(-9724765,0) 0:(-9658965,0) 0:(-9856341,0) 0:(- 11236466,-11236466) 1:(-11564174,-11564173) 0:(-11431819,0) 1:(-10380136,-10380135) 1:(-10973290,-10973289) 0:(-12093056,-1209) :(-10842985,0) 0:(-10118999,0) 1:(-11368034,-11368033) 1:(-11630686,-11630685)

【问题讨论】:

    标签: java rgb bufferedimage steganography


    【解决方案1】:

    The modulo of a negative odd number does not return 1 in java,所以你的if (pixel[i] % 2 == 1) 块不会被执行。从上面的链接中,您可以改写if ((((pixel[i] % 2) + 2) % 2) == 1) 来获得一个正数。然而,一个数字的奇偶性是排他的,所以它要么是偶数要么是奇数。建议您将代码更改为此

    if (pixel[i] % 2 == 0) {
        ...
    }
    else {
        ...
    }
    

    不过,您的代码还有另一个错误。 f += Integer.toBinaryString(b[i]); 行将字符转换为二进制字符串,但如果 ascii 字符的值小于 128,则转换将使用最小位数。例如a = '1100001',只有 7 位。您想在左侧填充 0 以获得 8 位。快速搜索产生this,上面的行应该变成

    f += String.format("%8s", Integer.toBinaryString(b[i])).replace(' ', '0');
    

    如果我可以建议对您的代码进行一些可选的改进,我会这样做

    import java.util.Arrays;
    
    public static void main(String[] args) {
        BufferedImage img = null;
    
        try {
            img = ImageIO.read(new File("a.jpg"));
        } catch (IOException ex) {
    
        }
    
        int pixel[] = img.getRGB(0, 0, img.getWidth(), img.getHeight(), null, 0, img.getWidth());
        int[] newpixel = Arrays.copyOf(pixel, pixel.length);
    
        String s = "abc";
        byte[] b = s.getBytes();
    
        int count = 0;
        for (int i = 0; i < b.length; i++) {
            byte current_byte = b[i];
            for (int j = 7; j >= 0; j--) {
                int lsb = (current_byte >> j) & 1;
                newpixel[count] = (pixel[count] & 0xfffffffe) + lsb;
                System.out.println(lsb + ":(" + pixel[count] + "," + newpixel[count] + ")");
                count++;
            }
        }
    
        // Extraction sequence
        String secret = "";
        int bit = 0;
        for (int i = 0; i < b.length; i++) {
            int ascii = 0;
            for (int j = 7; j >=0; j--) {
                ascii += (newpixel[bit] & 1) << j;
                bit++;
            }
            secret += (char)ascii;
        }
        System.out.print(secret);
    
    }
    

    注意事项:

    Arrays.copyOf() 是为了保留原始图像的副本以比较差异。通常,我会直接在现场直接编辑pixel

    您不需要将字节转换为由 1 和 0 组成的字符串,因为稍后您将需要将这些数字作为整数。以下循环使用right bitshiftbitwise and 操作从最高有效位(最左边)到最低位一一提取位。

    for (int j = 7; j >=0; j--) {
        int lsb = (b[i] >> j) & 1;
    }
    

    您可以将其归零,然后从上述循环中添加 lsb,而不是检查像素的 lsb 的值。您可以使用按位和运算来实现此目的。一个像素由四个字节组成,每个字节的最大值为 255 (0xff)。这些字节对应于 alpha 透明度、红色、绿色和蓝色通道(称为 ARGB)。你可以阅读它here

    newpixel[count] = (pixel[count] & 0xfffffffe) + lsb;
    

    提取过程与嵌入相反。但这里有个窍门。在提取整个消息之前,该程序不知道要读取多少像素。您要做的是引入一个等于8 * b.length 的长度变量。您可以分配前 16 个像素以将这个数字隐藏在 1 和 0 中,就像您的角色一样。然后提取读取前 16 个像素,计算要读取的像素数,并从第 17 个像素开始计算。

    【讨论】:

    • :但是我认为你的代码会使代码的提取有点困难。你能建议我如何将字符串提取回来吗?
    • :将 newpixel 写入 jpg 文件时,颜色模型应该是什么?我尝试了几乎所有类型的颜色模型,但提取不成功,尽管我的代码在使用像素数组时工作正常。
    • 将此文件写入 jpg 文件时的 colrmodel 应该是什么?我尝试了几乎所有类型的颜色模型,但提取并不成功,尽管我的代码在使用像素数组时工作正常。
    • 您不能对jpg图像使用此方法,因为该格式具有有损压缩。这意味着某些像素值与您在像素数组中的值不同。您只能将此方法用于无损格式,例如 bmp、png 和 gif。对于 jpg 隐写术,您需要研究 DCT(离散余弦变换)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-08-03
    • 1970-01-01
    • 2017-06-28
    • 1970-01-01
    • 2010-12-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多