优化多维 NumPy 矩阵的迭代

Optimising iteration over a multidimensional NumPy matrix

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

根据 python 文档,追加函数的时间复杂度为 O(1),而我的循环为 O(n^2),其中 n <= 1024。我理解 python使用解释器,而 Java 使用 JIT 编译器进行编译,因此速度要快得多。不过这里时差太大了

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

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

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

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 范围内。

相关性能相关概念: