如何使用 LSB 替换将一幅图像隐藏到另一幅图像中?

How to hide one image into another one using LSB substitutuion?

我正在尝试实现一种基本的速记技术,其中我用消息图像的 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 个通道。我想要的是通过保留相应位置的值将一个特定的通道拆分为 Red 进一步分成 8 个 Variations。

    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

适用于整个数组的任何内容都可以矢量化。如果只想对数组的一部分应用操作,请将其切片。

我提供了完整的代码,因此不会对 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 位置,没有条件。