超出最大允许尺寸

maximum allowed dimention exceeded

我正在尝试根据宇宙质量将圆周率和地球在海平面的引力常数转换为二进制来制作一幅画。我已经计算过并且我有正确的维度并且它应该只小于 1 兆字节的 ram 但是我 运行 进入最大允许的维度超过值错误。

代码如下:

import matplotlib.pyplot as plt
import matplotlib.cm as cm
import numpy as np

boshi = 123456789098765432135790864234579086542098765432135321 # universal mass

genesis = boshi ** 31467 # padding

artifice = np.binary_repr(genesis) # formatting

A = int(artifice) 

D = np.array(A).reshape(A, (1348, 4117))

plt.imsave('hello_world.png', D, cmap=cm.gray) # save image

我在 D = np.array... 一直 运行 错误,也许我的重塑太大但它只比 4k 大一点。看起来这对于 gpu 增强型 colab 应该没有问题。 运行 在我的家用机器上也不会出现同样的错误。这会用更多的 ram 解决吗?

我无法重现您的问题,因为 A = int(artifice) 行就像永远一样。我将其替换为 ,for 循环以单独投射每个数字。代码随后运行并生成了所需的图像。

import matplotlib.pyplot as plt
import matplotlib.cm as cm
import numpy as np

boshi = 123456789098765432135790864234579086542098765432135321
genesis = boshi ** 31467
artifice = np.binary_repr(genesis)

D = np.zeros((1348, 4117), dtype=int)
for i, val in enumerate(D):
    D[i] = int(artifice[i])

plt.imsave('hello_world.png', D, cmap=cm.gray)

让它发挥作用

问题是 artifice = np.binary_repr(genesis) 创建了一个字符串。该字符串由 1348 * 4117 = 5549716 位数字组成,全部为零和一。如果将字符串转换为 python 整数,A = int(artifice),您将 (A) 等待很长时间,并且 (B) 得到一个不可迭代的对象。您使用 np.array(A) 创建的数组将只有一个元素。

好消息是你可以完全绕过这个耗时的步骤,因为字符串 artifice 已经是一个可迭代的:

D = np.array(list(artifice), dtype=np.uint8).reshape(1348, 4117)

步骤 list(artifice) 需要几秒钟,因为它必须拆分字符串,但其他一切都应该很快。

绘图很容易 plt.imsave('hello_world.png', D, cmap=cm.gray):

色图

您可以在保存图像时轻松地将颜色图更改为 coolwarm 或您想要的任何颜色。请记住,您的图像是二进制的,因此实际上只有两个值很重要:

plt.imsave('hello_world2.png', D, cmap=cm.coolwarm)

探索

您有机会在这里为您的图像添加大量颜色。通常,PNG 是 8 位的。例如,不是将 genesis 转换为位,而是可以从中获取字节来构建图像。您还可以使用半字节(半字节)来构建具有 16 种颜色的索引图像。通过一点点填充,您甚至可以确保拥有三个数据点的倍数,并以多种方式创建全彩色 RGB 图像。我不会讨论更复杂的选项,但我想探索从字节制作简单图像。

5549716 位是 693715 = 5 * 11 * 12613 字节(有四个前导零位)。这是一个非常糟糕的分解,导致图像大小为 55x12613,所以让我们删除高半字节:虽然 693716 的分解和 693715 一样糟糕,但 693714 的分解非常糟糕很好地进入 597 * 1162.

您可以使用它自己的 to_bytes 方法将整数转换为字节数组:

from math import ceil

byte_genesis = genesis.to_bytes(ceil(genesis.bit_length() / 8), 'big')

我使用内置 ceil rather than np.ceil 的原因是它 return 是整数而不是浮点数。

转换大整数的速度非常快,因为 bytes 对象可以直接访问整数的数据:即使它进行了复制,也几乎不做任何处理。它甚至可以共享缓冲区,因为 bytesint 名义上都是不可变的。同样,您可以使用 np.frombuffer:

bytes 创建一个 numpy 数组作为对同一内存位置的视图
img = np.frombuffer(byte_genesis, dtype=np.uint8)[1:].reshape(597, 1162)

[1:] 是切掉前导半字节所必需的,因为 bytes_genesis 必须足够大才能容纳整个 genesis。您也可以在 bytes 一侧砍掉:

img = np.frombuffer(byte_genesis[1:], dtype=np.uint8).reshape(597, 1162)

结果是一样的。这是图片的样子:

plt.imsave('hello_world3.png', img, cmap=cm.viridis)

结果太大无法上传(因为它不是二进制图像),但这里是随机选择的样本:

我不确定这是否符合您的审美要求,但希望这为您提供了一个开始研究如何将非常大的数字转换为数据缓冲区的地方。

更多选项,因为这很有趣

我想看看这里使用的是半字节而不是字节,因为这样可以让每个像素有 16 种颜色,并且像素数量是原来的两倍。您可以获得一张 1162x1194 的图像,从

开始
temp = np.frombuffer(byte_genesis, dtype=np.uint8)[1:]

这是解压半字节的一种方法:

img = np.empty((1162, 1194), dtype=np.uint8)
img.ravel()[::2] = np.bitwise_and(temp >> 4, 0x0F)
img.ravel()[1::2] = np.bitwise_and(temp, 0x0F)

使用像 jet 这样的颜色图,您会得到:

plt.imsave('hello_world4.png', img, cmap=cm.jet)

另一种选择,从某种意义上说是相反的方向)是根本不使用颜色图。相反,您可以将 space 除以三,并在 RGB space 中生成您自己的颜色。幸运的是,693714 的主要因素之一是 3。因此,您可以获得 398x581 图像 (693714 == 3 * 398 * 581)。您如何解释数据比平时更取决于您。

继续之前的旁注

使用黑白二值图像,您可以控制图像的颜色、大小和方向。使用 8 位数据,您可以控制位的采样方式(8 位或更少,如 4 位示例)、解释的字节序、颜色图和图像大小。使用全色,您可以将每个三元组视为一种单独的颜色,将整个数据集视为三个连续的颜色平面,甚至可以对数组应用 Bayer filter 之类的操作。除了其他选项,如大小、排序、每个样本的位数等。

下面将暂时显示颜色三元组和三个颜色平面选项。

全彩色图像

要将每组 3 个连续字节视为 RGB 三元组,您可以这样做:

img = temp.reshape(398, 581, 3)
plt.imsave('hello_world5.png', img)

请注意,在这种情况下没有颜色图。

将数据解释为三个颜色平面需要额外的步骤,因为 plt.imsave expects the last dimension to have size 3. np.rollaxis 是一个很好的工具:

img = np.rollaxis(temp.reshape(3, 398, 581), 0, 3)
plt.imsave('hello_world6.png', img)