Юра Махоткин Юра Махоткин - 1 month ago 16
Python Question

Remake for-loop to numpy broadcast

I'm trying to code LSB steganography method via numpy arrays. I got code which makes the bool index mask, wich will give those bits of red channel, which need to xor with 1.

import numpy as np
from scipy.misc import imread
import matplotlib.pyplot as plt

message = 'Hello, World!'
message_bits = np.array(map(bool, map(int, (''.join(map('{:b}'.format, bytearray(message)))))), dtype=np.bool)
img = imread('screenshot.png')
xor_mask = np.zeros_like(img, dtype=np.bool)
ind = 0
for j, line in enumerate(xor_mask):
for i, column in enumerate(line):
if ind < len(message_bits):
xor_mask[j, i, 0] = message_bits[ind]
ind += 1
else:
break
else:
continue
break
img[xor_mask] ^= 1


Is there more compact way to construct the xor_mask? Maybe through numpy broadcast

UPD:
Reduced my for-loop to this:

for j, line in enumerate(xor_mask):
if ind < len(message_bits):
xor_mask[j, :, 0] = message_bits[ind]
ind += len(xor_mask[j])
else:
break

Answer

If you pad message_bits to have as many elements as pixels in xor_mask then it gets simple:

xor_mask = np.zeros_like(img, dtype=np.bool)
xor_mask[:, :, 0] = np.reshape(message_bits, xor_mask.shape[:2])

Another way, without padding:

xor_mask[:, :, 0].flat[:len(message_bits)] = message_bits
Comments