2016-10-12 1 views
0

Обучаясь NumPy, я написал код, который делает LSB (стеганография) шифрования:Python присваивание NumPy массив Integer индексированный плоский срез

def str2bits_nparray(s): 
    return np.array(map(int, (''.join(map('{:07b}'.format, bytearray(s))))), dtype=np.bool) 

def LSB_encode(img, msg, channel): 
    msg_bits = str2bits_nparray(msg) 
    xor_mask = np.zeros_like(img, dtype=np.bool) 
    xor_mask[:, :, channel].flat[:len(msg_bits)] = np.ones_like(msg_bits, dtype=np.bool) 
    img[xor_mask] = img[xor_mask] >> 1 << 1 | msg_bits 


msg = 'A' * 1000 
img_name = 'screenshot.png' 
chnl = 2 
img = imread(img_name) 
LSB_encode(img, msg, chnl) 

код работает отлично, но когда я пытаюсь сделал chnl = [2, 1] этой линии:

xor_mask[:, :, channel].flat[:len(msg_bits)] = np.ones_like(msg_bits, dtype=np.bool) 

оленья кожа значение Присвоить xor_mask с

xor_mask[:, :,[2, 1]].flat[:len(msg_bits)]

Есть ли способ исправить это?

I судимым раствора для цикла по каналам:

for ch in channel: 
    xor_mask[:, :, ch].flat[:len(msg_bits)] = np.ones_like(msg_bits, dtype=np.bool) 

Но это делает не то, что я хочу от

xor_mask[:, :,[2, 1]].flat[:len(msg_bits)] = np.ones_like(msg_bits, dtype=np.bool)

ответ

1

IIUC, вот подход для получения линейных индексов, а затем отрезать длину до. от elems требуется устанавливать, а затем выполнить настройку -

m,n,r = xor_mask.shape # Store shape info 

# Create range arrays corresponding to those shapes 
x,y,z = np.ix_(np.arange(m),np.arange(n),channel) 

# Get the indices to be set and finaally perform the setting 
idx = (x*n*r + y*r + z).ravel()[:len(msg_bits)] 
xor_mask.ravel()[idx] = 1 

Sample пробег -

In [180]: xor_mask 
Out[180]: 
array([[[25, 84, 37, 96, 72, 84, 91], 
     [94, 56, 78, 71, 48, 65, 98]], 

     [[33, 56, 14, 92, 90, 64, 76], 
     [71, 71, 77, 31, 96, 36, 49]]]) 

In [181]: # Other inputs 
    ...: channel = np.array([2,1]) 
    ...: msg_bits = np.array([2,3,6,1,4]) 
    ...: 

In [182]: m,n,r = xor_mask.shape # Store shape info 
    ...: x,y,z = np.ix_(np.arange(m),np.arange(n),channel) 
    ...: idx = (x*n*r + y*r + z).ravel()[:len(msg_bits)] 
    ...: xor_mask.ravel()[idx] = 1 
    ...: 

In [183]: xor_mask # First 5 elems from flattend version 
        # of xor_mask[:,:,channel] set as 1 
        # as len(msg_bits) = 5. 
Out[183]: 
array([[[25, 1, 1, 96, 72, 84, 91], 
     [94, 1, 1, 71, 48, 65, 98]], 

     [[33, 56, 1, 92, 90, 64, 76], 
     [71, 71, 77, 31, 96, 36, 49]]]) 

Вместо этого, если вы пытаетесь установить для всех elems по всем измерениям в 3D входного массива вдоль первой из channel: 2, а затем вдоль второй один 1 и так далее, мы должны создать idx по-разному, например, так -

idx = (x*n*r + y*r + z).transpose(2,0,1).ravel()[:len(msg_bits)]