我正在尝试实现一种基本的速记技术,其中我用载体图像的MSB替换载体图像的LSB。 LSB可以属于任何RGB通道。
我的方法非常幼稚,因为我正在循环message_matrix并将其特定RGB通道的MSB存储在carrier_matrix的相应LSB中。由于图像大小不超过1024 * 1024,执行此操作的时间复杂度为O(n ^ 2),但由于我使用python,因此与Java相比,所花费的时间非常长。
可以以更优化的方式执行相同的操作吗?
def hide_using_bpcs(self, carrier_path, message_path, index, color_index):
carrier_matrix = self.image_to_matrix(carrier_path)
message_matrix = self.image_to_matrix(message_path) #use np.zeros
for row_index, row in enumerate(message_matrix):
for pixel_index, pixel in enumerate(row):
color = message_matrix[row_index][pixel_index][color_index]
msb = (color & 0xff) >> 7
carrier_pixel = carrier_matrix[
row_index][pixel_index][color_index]
carrier_matrix[row_index][pixel_index][
color_index] = self.set_bit(carrier_pixel, index, msb)
stegano_image = self.matrix_to_image(carrier_matrix)
return stegano_image
现在,为了显示一个特定的位平面,让我们说(红色0),我将绿色和蓝色平面的所有值设置为0,并仅保留红色的LSB(或0位)的值。图片。我已经完成了一些使用openCV完成的实现,如[b,g,r = cv2.split(img)],但这只是将图像分成3个通道。我想要的是通过保留相应位置的值来分割特定的通道,然后将红色进一步分为8个变化。
def display_bit_plane(self, path, color_index, color_bit):
matrix = self.image_to_matrix(path)
matrix = matrix.astype(int)
result_matrix = self.image_to_matrix(path)
mask = 1 << color_bit
for row_index, row in enumerate(matrix):
for pixel_index, pixel in enumerate(row):
for iterator in range(0, 3):
result_matrix[row_index][pixel_index][iterator] = 0
color = matrix[row_index][pixel_index][color_index]
result_matrix[row_index][pixel_index][color_index] = self.set_bit(0, 7, ((color & mask) != 0))
stegano_image = self.matrix_to_image(result_matrix)
return stegano_image
我正在使用NumPy数组执行所有计算。然而,以通常的方式迭代它是非常昂贵的。请在上述两个功能中进行一些优化,以便在不到1秒的时间内完成这些操作。
编辑1:
我已经优化了检索位平面的第二个功能。如果可以进一步简化,请告诉我们。 Color_index分别代表R,G,B为0,1,2,color_bit是0-7的位位置。
def display_bit_plane_optimised(self, path, color_index, color_bit):
message_matrix = self.image_to_matrix(path)
change_index = [0, 1, 2]
change_index.remove(color_index)
message_matrix[:, :, change_index] = 0
mask = 1 << color_bit
message_matrix = message_matrix & mask
message_matrix[message_matrix == 1] = 1 << 7
stegano_image = self.matrix_to_image(message_matrix)
return stegano_image
答案 0 :(得分:1)
任何适用于整个阵列的东西都可以进行矢量化。如果要仅对阵列的一部分应用操作,请将其切片。
我提供了完整的代码,因此不要对image_to_matrix()
和matrix_to_image()
方法做出假设。从那里拿走它。
我保持你的逻辑原封不动,但是如果你只打算在LSB中嵌入秘密,你可以抛弃pixel_bit
,将其值设置为零并简化任何常数结果出来的。例如,在embed()
中,您只需获得mask = 0xfe
,而任何位移0都无关紧要。
import numpy as np
from PIL import Image
class Steganography:
def embed(self, cover_file, secret_file, color_plane, pixel_bit):
cover_array = self.image_to_matrix(cover_file)
secret_array = self.image_to_matrix(secret_file)
# every bit except the one at `pixel_bit` position is 1
mask = 0xff ^ (1 << pixel_bit)
# shift the MSB of the secret to the `pixel_bit` position
secret_bits = ((secret_array[...,color_plane] >> 7) << pixel_bit)
height, width, _ = secret_array.shape
cover_plane = (cover_array[:height,:width,color_plane] & mask) + secret_bits
cover_array[:height,:width,color_plane] = cover_plane
stego_image = self.matrix_to_image(cover_array)
return stego_image
def extract(self, stego_file, color_plane, pixel_bit):
stego_array = self.image_to_matrix(stego_file)
change_index = [0, 1, 2]
change_index.remove(color_plane)
stego_array[...,change_index] = 0
stego_array = ((stego_array >> pixel_bit) & 0x01) << 7
exposed_secret = self.matrix_to_image(stego_array)
return exposed_secret
def image_to_matrix(self, file_path):
return np.array(Image.open(file_path))
def matrix_to_image(self, array):
return Image.fromarray(array)
当我运行它时,它会在一秒钟内完成。
plane = 0
bit = 1
cover_file = "cover.jpg"
secret_file = "secret.jpg"
stego_file = "stego.png"
extracted_file = "extracted.png"
S = Steganography()
S.embed(cover_file, secret_file, plane, bit).save(stego_file)
S.extract(stego_file, plane, bit).save(extracted_file)
备注强>
您的display_bit_plane_optimised()
已合理优化,但如果color_bit
除了0之外它有一个错误。该行
message_matrix = message_matrix & mask
每隔一位零,但除非color_bit
为0,否则这些值将是2的其他幂。所以当你来
message_matrix[message_matrix == 1] = 1 << 7
没有像素被修改。如果你想保持自己的方式,你必须将最后一行改为
message_matrix[message_matrix != 0] = 1 << 7
我的方法是简单地将嵌入位置于LSB位置,每隔一位将其置零,然后将其移至MSB位置而没有条件。