【问题标题】:Optimising iteration over a multidimensional NumPy matrix优化多维 NumPy 矩阵的迭代
【发布时间】:2017-06-28 12:36:13
【问题描述】:

我想提取图像的 RGB 值的最低有效位并将这些位转换为 ascii 等效位。问题是我在python中循环numpy矩阵的方法非常慢。使用 Java 采用相同的策略时,速度大约快 100 倍。图像大小不超过 1024 * 1024,因此生成的矩阵最大为 1024 * 1024 * 3。

根据 python 文档的 append 函数的时间复杂度为 O(1),我的循环为 O(n^2),其中 n

这个操作能以更有效的方式完成吗?

def extract_info_from_lsb(self, path):
            lsb_message_result = []
            matrix = self.image_to_matrix(path)

            for row in matrix:
                lsb_message_list = []
                for pixel in row:
                    for color in pixel:
                        lsb = color & 1
                        lsb_message_list.append(lsb)

                lsb_message_result.append(lsb_message_list)

            for i, lsb_message in enumerate(lsb_message_result):
                lsb_message_result[i] = self.text_from_bits(lsb_message)

            return lsb_message_result

我采用的二进制转ascii的函数如下:

def text_from_bits(self, bits):
        chars = []
        for b in range(len(bits) / 8):
            byte = bits[b * 8:(b + 1) * 8]
            chars.append(chr(int(''.join([str(bit) for bit in byte]), 2)))
        return ''.join(chars)

图像到矩阵的转换函数是:

def image_to_matrix(self, path):
        image = Image.open(path)
        matrix = np.array(image)
        return matrix

【问题讨论】:

    标签: python numpy steganography


    【解决方案1】:

    从 ndarray 获取 LSB 的一种快速方法是将模运算向量化(即将其应用于整个数组)以让 numpy 进行循环(请参阅 cmets 进行解释):

    def extract_info_from_lsb(self, path):
        lsb_message_result = []
        matrix = self.image_to_matrix(path)
        matrix = matrix.astype(int)  # make sure the data type is integer (redundant)
        lsb_matrix = matrix % 2  # modulo two to get the LSB of each element
        lsb_message_result = lsb_matrix.ravel()  # flatten to a 1D array
        lsb_message_result = lsb_message_result.tolist()  # optional: convert to list
    

    向量化转换为 ASCII(它假设图像中的像素数是 8 的精确倍数):

    def text_from_bits(self, bits):
        bits = np.reshape(bits, (-1, 8))  # matrix with 8 elements per row (1 byte)
        bitvalues = [128, 64, 32, 16, 8, 4, 2, 1]
        bytes = np.sum(bits * bitvalues, axis=1)  # rows to bytes
        chars = [chr(b) for b it bytes]  # convert each byte to a character and put into a list
        return ''.join(chars)
    

    请注意,您将获得 0 - 255 范围内的 ASCII 值。这不是严格意义上的 ASCII,传统上它仅在 0 - 127 范围内。

    相关性能相关概念:

    【讨论】:

    • 谢谢!你的方法非常有效。你能解释为什么循环很慢吗? 10^6订单的操作不应该在1秒内处理吗?
    • Python 中的循环很慢,因为它是一种解释型语言。对于每个命令,Python 解释器都需要在后台执行许多操作。更糟糕的是,它是一种动态类型的语言。每当使用变量时,都会执行各种检查和转换。矢量化速度很快,因为实际的循环被委托给编译后的 C 代码。
    猜你喜欢
    • 2015-07-09
    • 2019-07-27
    • 1970-01-01
    • 2021-12-22
    • 2019-12-26
    • 2020-03-23
    • 1970-01-01
    • 2017-02-10
    • 2022-08-13
    相关资源
    最近更新 更多