pythonnumpyoptimizationscipysteganography

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, which 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

Solution

  • 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