Я читаю изображение и меняю его. Но изменения не сохраняются

1

Я пытаюсь реализовать стеганографию. Я читаю изображение "a.jpeg" и вставляю в него байт, меняя свои последовательные 7 байтов на младший значащий бит, начиная со смещения 50. Это выполняется успешно, когда я печатаю байты, измененные последними битами. Затем я сохранил его как "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

Как предложил Константин В. Салихов, я пробовал использовать другой формат файла (gif), и он сработал. Но есть ли способ, которым я могу использовать "jpeg"?

  • 4
    Может быть, это из-за сжатия JPEG с потерями?
  • 0
    я попробую другой формат и выложу результат
Показать ещё 5 комментариев
Теги:
arrays
byte
bufferedimage
steganography

2 ответа

2
Лучший ответ

Почему ваш подход не подходит

Как предположил Салинков, формат jpeg вызывает сжатие данных. Подводя итог тому, что вы сделали:

  • Вы загрузили данные изображения в массив байтов.
  • Вы изменили некоторые байты.
  • Вы загрузили массив байтов в качестве изображения.
  • Вы сохранили это изображение в формате jpeg, что вызывает рекомпрессию.

То, где ваш метод разваливается. Формат без потерь не приведет к возникновению этих проблем, поэтому работает gif. Или png, bmp и т.д....

Можете ли вы использовать свой метод для jpeg?

Weeeeell, нет, не совсем. Во-первых, нам нужно понять, какие данные хранятся в jpeg-изображении.

Короткий ответ заключается в том, что отдельные байты не соответствуют фактическим пикселям изображения.

Длинная история заключается в том, что вы разбиваете изображение в массивах 8x8 и принимаете DCT для получения частотных коэффициентов. После этапа квантования многие из них станут 0, особенно более высокие частотные коэффициенты (внизу справа от массива DCT - см. Здесь). Это шаг с потерями jpeg. Вы жертвуете более высокими частотными коэффициентами для некоторых переносимых искажений изображения (потеря информации). Теперь вы сохраняете ненулевые коэффициенты, основываясь на их местоположении в матрице, то есть (0, 0, -26), (0, 1, -3) и т.д. Это может быть дополнительно сжато Хаффманом кодирование. Кстати, изменение любого одного частотного компонента влияет на все 64 пикселя.

Итак, как обычно выполняется стандартная стеганография? Он в основном следует за процессом кодирования jpeg:

  • Разделить изображение в массивах 8x8.
  • DCT каждый массив 8x8 и квантовать коэффициенты.

Теперь мы получили квантованные коэффициенты DCT, и мы переходим от процесса jpeg-кодирования.

  • Примените некоторый стеганографический алгоритм, изменив значение квантованных коэффициентов.

  • Хаффман сжимает коэффициенты и продолжает с остальной частью процесса кодирования jpeg с этими модифицированными коэффициентами DCT.

  • 0
    Спасибо за ответ.
5

JPEG - механизм хранения с потерями. Это означает, что он НЕ требуется (или даже желательно), который представляет каждый байт точно так же, как оригинал. На деле, в этом весь смысл, он жертвует небольшими несовершенствами, чтобы добиться большой экономии пространства. Если вам нужно идеальное хранилище, вам нужно будет выбрать другой формат, такой как GIF, PNG или некоторые варианты BMP.

Как указано ниже, технически возможно создать JPEG без потерь, но это было позднее дополнение, не полностью поддерживаемое, и, в частности, Java не поддерживает его. См. Этот ответ для получения дополнительной информации.

  • 0
    На самом деле есть модификации JPEG без потерь, если OP так сильно хочет использовать JPEG. en.wikipedia.org/wiki/Lossless_JPEG
  • 0
    GIF поддерживает только режим индексирования цвета, поэтому изменение даже одного бита по существу приведет к изменению пикселя на любой случайный цвет (включая, возможно, прозрачные). Наш ОП уверенно заявил: «Эй, это сработало с GIF», но, конечно, это сопровождалось целым набором видимых собственных артефактов.
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню