Рубрики
Без рубрики

Давайте спрятаем секретное сообщение на изображении с Python и OpenCV

Сегодня мы собираемся использовать библиотеку OpenCV CV2, чтобы кодировать и декодировать секретные сообщения внутри изображения … Tagged with Python, учебник, стеганография.

Сегодня мы собираемся использовать библиотеку OpenCV CV2 Чтобы кодировать и декодировать секретные сообщения в файле изображения. Я не имею в виду, что мы собираемся сделать крошечный текст и спрятать его в углу, мы собираемся копать глубже, чем это. Запустите своего любимого редактора и консоли Python, это на самом деле не займет слишком много времени.

Если вы не хотите сидеть через меня, рассказывая о том, как это работает и что такое стеганография и Куза Куза Куза Тогда просто зайдите в мой GitHub Gist здесь

Как это работает??

Я рад, что ты спросил. Во -первых, вам нужен быстрый сбоев в пикселях. Ваш экран состоит из пикселей, и, вероятно, немало из них. Мое разрешение на монитор говорит о «1920×1080», что означает, что мой экран составляет 1920 пикселей по отношению к глубине 1080 пикселей, и в целом 2073 600 пикселей. Каждый из этих пикселей способен излучать свет в цветовой диапазоне. Цвет света, который он излучает, (обычно) основан на комбинации цветов красного зеленого и синего. Интенсивность каждого цвета может быть от 0 до 255. Другими словами, RGB (255, 255, 255) белый, RGB (0, 0, 0) – черный, а RGB (113, 238, 184) – Seafoam Green.

Файлы изображений – это в основном сериализация пикселей изображения и значений RGB. Файл сообщает компьютеру, который освещает пиксели и с каким цветом. Когда мы используем CV2 функция imread и передайте ему файл изображения, этот файл изображения переводится в массив Numpy, содержащий значение RGB для каждый пиксель на изображении.

Чтобы проиллюстрировать, представьте, что у нас была крошечная 4 -пиксельная картина (2 пикселя на 2 пикселя) черно -белой шахматной доски с 4 плитки. Массив Numpy по сути будет выглядеть так:

[
  [
    [255, 255, 255], [0, 0, 0]
  ],
  [
    [0, 0, 0], [255, 255, 255]
  ]
]

Примечание: это не точная репликация, иногда есть другие данные в массиве, но этого достаточно для вы понимаете

Это ваш курс пикселя, мы немного вернемся к этому.

Что такое стеганография?

Стеганография-это практика скрытия секретных данных внутри не секретных данных. В большинстве случаев мы говорим о скрытии сообщений внутри файлов изображений, но это не обязательно должно быть файлы изображений. Допустим, я хочу поделиться с вами секретным рецептом. Я мог бы поднять свою любимую фотографию вас и меня, кодировать рецепт в картинку и опубликовать его на своей стене в Facebook или что -то в этом роде. В мир, похоже, я только что прислал вам классную картину. Но так как у вас есть декодер, вы проведете изображение через него, и теперь вы знаете, как сделать всемирно известное печенье моей бабушки.

Вы понимаете, что это сейчас сейчас? Хорошо! Давайте подумаем на практике.

Кодировать

Вот что мы собираемся сделать. Во -первых, мы собираемся взять секретное сообщение и перевести его в номера Unicode с ord () функция Мы собираемся сделать это с функцией, которая возвращает объект генератора Python:

def char_generator(message):
  for c in message:
    yield ord(c)

Если вы не уверены, что такое генератор, не волнуйтесь слишком сильно для этого урока. В основном генератор даст нам значения по одному, используя Далее (генератор)

Хорошо, это было легко. Теперь мы захотим получить наши изображения и вернуть их в виде массивов Numpy. К счастью, у нас есть OpenCV CV2 библиотека для этого. Вы можете установить его с PIP установить OpenCV-Python и PIP установить OpenCV-Contrib-Python Анкет После того, как они установлены, положите Импорт CV2 В верхней части вашего сценария. Давайте напишем функцию, которая возвращает изображение с Numpy-idate:

def get_image(image_location):
  img = cv2.imread(image_location)
  return img

Легко.

Так что теперь у меня есть большой массив значений RGB для картинки и генератор, который выплевывает числа из букв. Я хочу сделать сейчас, так это обращаться через файл изображения и изменить один из трех значений RGB с номером Unicode секретного сообщения.

Хотя есть проблема. Если я вытекаю через и последовательно изменяю каждый пиксель по порядку, я рискую изменить изображение настолько, что очевидно, что я его изменил. Так что я определенно не хочу менять один пиксель за другим.

Образец, в котором вы решили выбрать пиксели, чтобы изменить, зависит от вас, но я собираюсь использовать GCD массива изображений. Вот:

def gcd(x, y):
  while(y):
    x, y = y, x % y

  return x

Все это делает Выбирает наибольший общий знаменатель x и y. Мы собираемся отправить длину и ширину изображения в эту функцию и использовать ее, чтобы решить, какие пиксели мы собираемся манипулировать. Так что, если GCD 7, мы собираемся захватить каждый седьмой пиксель и скрыть следующую часть нашего секретного сообщения в нем.

Есть еще одна проблема, хотя. Как мы расскажем декодеру, когда закончим? Ну, вы можете сделать все, что хотите, но я собираюсь установить следующий пиксель, чтобы выбрать на 0. Поскольку символ, представляемый Unicode 0, не может быть имитирован на клавиатуре, наш декодер может предположить, что 0 означает, что сообщение закончено.

Итак, давайте напишем фактическую функцию кодирования изображения. Мы собираемся передать ему местоположение изображения и секретное сообщение. Затем мы сделаем массив Numpy этого изображения, создадим объект генератора для секретного сообщения и рассчитаем GCD изображения. Наконец, мы напишем самую уродливую вложенную петлю, чтобы фактически кодировать картинку. Наблюдать:

def encode_image(image_location, msg):
  img = get_image(image_location)
  msg_gen = char_generator(msg)
  pattern = gcd(len(img), len(img[0]))
  for i in range(len(img)):
    for j in range(len(img[0])):
      if (i+1 * j+1) % pattern == 0:
        try:
          img[i-1][j-1][0] = next(msg_gen)
        except StopIteration:
          img[i-1][j-1][0] = 0
          return img

Я знаю, ты, верно? Обратите внимание на пару вещей об этой функции: мы проверяем и видим, что продукт координат высоты и ширины делится на GCD (переменная Однако до этого мы на самом деле добавляем его в итераторы. Почему? Потому что, если мы находимся на первой итерации высоты или ширины, мы умножаем ноль. И 0 % все, что угодно равно 0, что означает, что мы будем писать только в одном столбце или строке. Это сделало бы очевидным, что картина была изменена.

В любом случае, если наш пиксель кратный GCD, мы попробуйте Чтобы получить следующий символ в генераторе секретного сообщения. Когда вы звоните Следующий На генераторе после того, как все сгенерировало, вы получите Остановка Исключение, следовательно, наш кроме блокировать. Когда мы достигли этого блока, мы знаем, что сообщение закончилось, поэтому мы установили это значение на ноль.

Эта функция не включает сохранение нового кодированного изображения на диск, поэтому давайте запустим консоль Python. Запустите консоль в каталоге с файлом скрипта Python (я позвонил в мой stego.py) и установите файл изображения, готовый к манипулированию. Мой был назван «erikandfubar.png» (моя картина профиля).

>>> import stego, cv2
>>> file_location = "ErikAndFubar.png"
>>> secret_message = "Hello from inside the picture!"
>>> encoded_image = stego.encode_image(file_location, secret_message)
>>> cv2.imwrite("EncodedImage.png", encoded_image)

Мы не говорили о cv2.imwrite Но если вы не можете сказать, это просто сохраняет файл изображения. После того, как вы сохраните его, посмотрите на картинку. Бьюсь об заклад, вы не можете сказать, что в этом есть что -то другое.

Декодировать

Теперь, когда у нас кодирована наша картинка, давайте напишем функцию декодера. Мы передаем функцию местоположение файла, сгенерируем из нее еще один массив Numpy, выясните GCD Таким образом, мы знаем, где находятся секретные биты, затем снова перетекают через картинку. Как dis:

def decode_image(img_loc):
  img = get_image(img_loc)
  pattern = gcd(len(img), len(img[0]))
  message = ''
  for i in range(len(img)):
    for j in range(len(img[0])):
      if (i-1 * j-1) % pattern == 0:
        if img[i-1][j-1][0] != 0:
          message = message + chr(img[i-1][j-1][0])
        else:
          return message

Эта цикл немного легче рассуждать, но не очень много. Мы снова перечитываем арест с изображением, останавливаясь на множестве GCD и захватываем числовое значение красного значения Pixel, если оно не равна нулю. Когда у нас есть значение, мы добавляем вывод Chr к этому, который берет номер Юникода и возвращает букву (так chr (103) дает нам 'G' ) Если значение, которое мы получили, равно нулю, мы знаем, что дошли до конца сообщения, поэтому мы возвращаем сообщение, которое мы получили.

Давайте проверим это в консоли:

>>> import stego
>>> encoded_image = "EncodedImage.png"
>>> stego.decode(image(encoded_image))
'Hello from inside the picture!'

Та-да!

Весь сценарий:

import cv2


def char_generator(message):
  for c in message:
    yield ord(c)

def get_image(image_location):
  img = cv2.imread(image_location)
  return img

def gcd(x, y):
  while(y):
    x, y = y, x % y

  return x

def encode_image(image_location, msg):
  img = get_image(image_location)
  msg_gen = char_generator(msg)
  pattern = gcd(len(img), len(img[0]))
  for i in range(len(img)):
    for j in range(len(img[0])):
      if (i+1 * j+1) % pattern == 0:
        try:
          img[i-1][j-1][0] = next(msg_gen)
        except StopIteration:
          img[i-1][j-1][0] = 0
          return img

def decode_image(img_loc):
  img = get_image(img_loc)
  pattern = gcd(len(img), len(img[0]))
  message = ''
  for i in range(len(img)):
    for j in range(len(img[0])):
      if (i-1 * j-1) % pattern == 0:
        if img[i-1][j-1][0] != 0:
          message = message + chr(img[i-1][j-1][0])
        else:
          return message

Мы научились скрывать секретные сообщения на картинках сегодня, но это все мы изучили? Когда я решил, что хочу попытаться научиться это сделать, я не знал о генераторах и не знал о хр и Ord функции. Поэтому я узнал кое -что из этого маленького побочного проекта, кроме того, что я пытался сделать. Вот почему побочные проекты важны. Если вы будете держать их веселыми и интересными, вы можете узнать то, чего даже не знали.

Кроме того, это не очень хороший энкодер. Мы всегда меняем первое значение RGB (Red Pixel), когда на самом деле мы должны его переключать. Как бы вы это изменили?

На еще более базовом уровне мы не делаем никакой проверки пользователя, например, проверить, на самом деле существует действительное местоположение изображения. Мы также не проверяем, достаточно ли наша фотография, чтобы справиться с длиной сообщения. Я оставляю эти улучшения в качестве упражнения для читателя.

Пожалуйста, не стесняйтесь сообщить мне, если у вас есть какие -либо вопросы!

Оригинал: “https://dev.to/erikwhiting88/let-s-hide-a-secret-message-in-an-image-with-python-and-opencv-1jf5”