优化多维NumPy矩阵的迭代

时间:2017-02-10 08:26:47

标签: python numpy steganography

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

根据python文档的append函数是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

1 个答案:

答案 0 :(得分:2)

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

相关的绩效相关概念: