Вопрос по rgb, steganography, java, bufferedimage – Изменение значения lsb значения rgb изображения, приводящего к несогласованному значению

0

Я пытаюсь изменить значение 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, -12093056) 0: (- 10842985,0) 0: (- 10118999,0) 1: (- 11368034, -11368033) 1: (- 11630686, -11630685)

Ваш Ответ

1   ответ
1

Модуль отрицательного нечетного числа не возвращает 1 в 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 бит. Вы хотите заполнить нулями слева, чтобы получить 8 бит. Быстрый поиск даетэтот и приведенная выше строка должна измениться на

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, поскольку позже вам понадобятся эти числа как целые числа. Следующий цикл извлекает биты один за другим из старшего значащего бита (крайнего левого) в младший, используяправильное смещение ипоразрядно и операции.

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

Вместо того, чтобы проверять значение lsb пикселя, вы можете обнулить его, а затем добавить lsb из вышеуказанного цикла. Вы можете использовать побитовые и операции для достижения этой цели. Пиксель состоит из четырех байтов, с максимальным значением 255 (0xff) для каждого. Байты соответствуют альфа-прозрачности, красный, зеленый и синий каналы (известный как ARGB). Вы можете прочитать об этомВот.

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

Процесс извлечения противоположен встраиванию. Но здесь кроется подвох. Программа не знает, сколько пикселей нужно прочитать, прежде чем извлекать все сообщение. Что вы хотите сделать, это ввести переменную длины, которая равна8 * b.length, Вы можете выделить первые 16 пикселей, чтобы скрыть это число в 1 и 0, как ваши персонажи. Затем извлечение считывает эти первые 16 пикселей, вычисляет, сколько пикселей нужно прочитать, и делает это, начиная с 17-го пикселя.

: При записи newpixel в файл jpg какой должна быть цветовая модель? Я попробовал почти все типы цветовых моделей, но извлечение не удалось, хотя мой код работает правильно при работе с массивами пикселей. Ankit Anand
Вы не можете использовать этот метод для изображений JPG, потому что формат имеет сжатие с потерями. Это означает, что некоторые значения пикселей изменяются по сравнению с теми, которые у вас были в ваших массивах пикселей. Вы можете использовать этот метод только с форматами без потерь, например, bmp, png и gif. Для стеганографии JPG вы хотите посмотреть в DCT (дискретное косинусное преобразование). Reti43
Я обновил ответ с помощью фрагмента извлечения. Reti43
Но я думаю, что ваш код сделает извлечение кода немного сложным. Можете ли вы предложить мне, как извлечь строку обратно. Ankit Anand
какой должна быть colrmodel при записи этого файла в файл jpg? Я испробовал почти все типы цветовых моделей, но извлечение не удалось, хотя мой код работает правильно при работе с массивами пикселей. Ankit Anand

Похожие вопросы