Нет смысла обнулять все LSB всех пикселей, потому что, если ваш секрет намного меньше размера вашего изображения, вы изменили ~ 50% оставшихся пикселей без причины.
Я бы просто получил битовый поток сообщения, сгладил изображение и затем скрыл ваше сообщение в фрагменте этого массива, который соответствует сообщению. Затем измените его обратно на 2D.
string = 'Hello world'
# Getting the bits from each character with bitwise operations is better
# than using intermediate strings with `bin` or string formats
for byte in map(ord, string):
bits.extend((byte >> i) & 1 for i in range(7, -1, -1))
flat = img.flatten()
flat[:len(bits)] = (flat[:len(bits)] & 0xfe) | bits
stego = flat.reshape(img.shape)
Если изображение RGB, то порядок пикселей равен (0, 0, R), (0, 0, G), (0, 0,B), (0, 1, R) и т. Д. Если вы хотите сначала встроить свой секрет, скажем, только в синий канал, извлеките эту цветовую плоскость, вставьте столько битов, сколько она может вписать в описанный выше процесс, изатем перейдите на другой канал. Это немного более запутанно, но не очень сложно.
Если вы настаиваете на преобразовании потока битов в двумерный массив того же размера, что и ваше изображение, просто посчитайте, сколько пикселей у вашего изображения, сколько битов у вас есть, идобавьте столько единиц или 0 к вашему потоку битов. Затем используйте np.reshape()
. Опять же, если в результате получается трехмерный массив, вы должны помнить об окончательном порядке битов.
В общем, если вам не нужно внедрять свой секрет в конкретные плоскости, используйтеметод, который я предложил. Он очень короткий и понятный и не требует каких-либо посторонних вычислений или модификаций вашего изображения.