[英]Python numpy array assignment to integer indexed flat slice
While learning numpy, I wrote code which doing LSB(steganography) encryption: 在学习numpy的同时,我编写了执行LSB(密码术)加密的代码:
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)
Code works fine, but when i'm trying to made chnl = [2, 1]
this line: 代码工作正常,但是当我尝试使chnl = [2, 1]
这行时:
xor_mask[:, :, channel].flat[:len(msg_bits)] = np.ones_like(msg_bits, dtype=np.bool)
doesnt assign value to xor_mask
with 不会将值分配给xor_mask
xor_mask[:, :,
[2, 1] ].flat[:len(msg_bits)]
xor_mask[:, :,
[2,1] ].flat[:len(msg_bits)]
Is there way to fix this? 有办法解决吗?
I tryed solution with for-loop over channels: 我尝试通过通道进行for循环的解决方案:
for ch in channel:
xor_mask[:, :, ch].flat[:len(msg_bits)] = np.ones_like(msg_bits, dtype=np.bool)
But this is doing not that i want from 但这不是我想要的
xor_mask[:, :,
[2, 1] ].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)
IIUC, here's an approach to get the linear indices, then slice to the length of no. IIUC,这是一种获取线性指数,然后切成no长度的方法。 of elems required to be set and then perform the setting - 需要设置的元素数量,然后执行设置-
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 run - 样品运行-
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]]])
Instead, if you were trying to set for all elems across all dimensions in 3D
input array along the first of channel
: 2
and then along the second one 1
and so on, we need to create idx
differently, like so - 相反,如果您要沿着第一个channel
2
设置3D
输入数组中所有维度的所有元素,然后沿着第二个1
依此类推,我们需要以不同的方式创建idx
,如下所示-
idx = (x*n*r + y*r + z).transpose(2,0,1).ravel()[:len(msg_bits)]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.