Image.fromarray() 使矩阵 mod 中的每个元素都为 256

Image.fromarray() is making every element in the matrix mod of 256

我正在编写一个脚本来使用 PIL 在 python3 中加密和解密图像。在这里,我将图像转换为一个 numpy 数组,然后将数组的每个元素乘以 10。现在我注意到 PIL fromarray() 中的默认函数正在将数组的每个元素转换为 256 的 mod 如果它大于 255,所以当我试图检索矩阵的原始值时,我没有得到原始值。例如,如果原始值是 40,那么它的 10 次是 400,所以 fromarray() 使它成为 400 mod 256,这将得到 144。现在如果我将 256 加到 144 我将得到 400,然后除以 10 将得到 40。但如果值为 54,则 10 次为 540,540 mod 256 为 28。现在要取回原始值,我需要将 256 相加两次,这将得到 540。540当我用 256 mod 时,它不是唯一会给我 28 的数字。所以我永远不知道什么时候加 256 一次,什么时候加两次或更多。有什么办法可以让它停止用 256 的 mod 替换矩阵的每个元素?

from PIL import Image
from numpy import * 
from pylab import * 

#encryption

img1 = (Image.open('image.jpeg').convert('L')) 
img1.show() #displaying the image

img = array(Image.open('image.jpeg').convert('L'))
a,b = img.shape
print(img)
print((a,b))
tup = a,b

for i in range (0, tup[0]):
   for j in range (0, tup[1]):
       img[i][j]= img[i][j]*10 #converting every element of the original array to its 10times

print(img)
imgOut = Image.fromarray(img)
imgOut.show()
imgOut.save('img.jpeg')

#decryption

img2 = (Image.open('img.jpeg'))
img2.show()

img3 = array(Image.open('img.jpeg'))
print(img3)
a1,b1 = img3.shape
print((a1,b1))
tup1 = a1,b1

for i1 in range (0, tup1[0]):
   for j1 in range (0, tup1[1]):
       img3[i1][j1]= ((img3[i1][j1])/10) #reverse of encryption
print(img3)
imgOut1 = Image.fromarray(img3)
imgOut1.show()

乘以 10 之前的原始矩阵的一部分: [41 42 45 ... 47 41 33]

[41 43 45 ... 44 38 30]

[41 42 46 ... 41 36 30]

[43 43 44 ... 56 56 55]

[45 44 45 ... 55 55 54]

[46 46 46 ... 53 54 54]

乘以 10 后的部分矩阵: [[154 164 194 ... 214 154 74]

[154 174 194 ... 184 124 44]

[154 164 204 ... 154 104 44]

[174 174 184 ... 48 48 38]

[194 184 194 ... 38 38 28]

[204 204 204 ... 18 28 28]

除以 10 后的预期矩阵的一部分: [41 42 45 ... 47 41 33]

[41 43 45 ... 44 38 30]

[41 42 46 ... 41 36 30]

[43 43 44 ... 56 56 55]

[45 44 45 ... 55 55 54]

[46 46 46 ... 53 54 54]

脚本提供的部分输出:[[41 41 45 ... 48 40 33]

[41 43 44 ... 44 37 31]

[41 41 48 ... 41 35 30]

[44 42 43 ... 30 30 29]

[44 42 45 ... 29 29 29]

[45 47 44 ... 28 28 28]]

你在这里尝试做的事情有几个问题。

PIL 图像是每通道 8 位或每通道 16 位(据我所知)。当您加载 JPEG 时,它被加载为每个通道 8 位,因此基础数据类型是一个无符号的 8 位整数,即范围 0..255。会溢出或下溢此范围换行的操作,这看起来像您看到的模数行为。

您可以使用 np.array(img).astype('float32') 将 8 位 PIL 图像转换为浮点 numpy 数组,然后通过除以 255 将其归一化为 0..1。

此时你已经有了非量化的浮点数,你可以随心所欲地随意处理。

但是,您仍然需要保存生成的图像,此时您又遇到了格式问题。我相信 TIFF 和一些 HDR 图像格式支持浮点数据,但如果您想要广泛可读的内容,您可能会选择 PNG 或 JPEG。

对于加密用例,JPEG 不是一个好的选择,因为它们本身总是有损的,而且您很可能得不到相同的数据。

PNG 可以是每个通道 8 位或 16 位,但是,您仍然会遇到必须压缩基本上无限 "dynamic range" 像素的问题(假设您将所有内容乘以一千! ) 变成 0..255 或 0..65535.

一个明显的方法是找到图像中的最大值 (np.max(...)),将所有值除以它(所以现在你回到 0..1),然后乘以图像数据格式的最大值...所以通过简单的乘法 "cipher" 正如你所描述的,你基本上会得到相同的图像。

另一种方法是将无限范围限制在允许的值,即零以下的所有内容都是零,高于它的所有内容都是 65535。虽然这是一个有损操作,但你没有恢复未剪切值的方法。

首先,PIL only supports 8-bit per channel images - although Pillow (the PIL fork) supports many more formats including higher bit-depths. The JPEG format定义为每个通道只有8位。

因此,在 PIL 中的 JPEG 上调用 Image.open() 将 return 一个 8 位数组,因此对单个像素的任何操作都将等效于支持中的 uint8_t 算术表示。由于 uint8_t 值中的最大值为 256,因此您的所有算术都必须以 256 为模。

如果您想避免这种情况,您需要将表示转换为更高的位深度,例如 16bpp 或 32bpp。您可以使用 NumPy 代码执行此操作,例如:

img16 = np.array(img, dtype=np.uint16)
# or
img32 = np.array(img, dtype=np.uint32)

这将为您提供所需的扩展精度。

但是 - 您的代码示例表明您正在尝试加密和解密图像数据。在那种情况下,你 do 想要使用模运算!你只需要对实际的加密算法做更多的研究。

none 的答案对我帮助很大,我已经解决了问题我想给出一个答案,希望有一天它能帮助别人。这里的键是 (3, 25777) 和 (16971,25777)。 工作代码如下:

from PIL import Image
import numpy as np 

#encryption
img1 = (Image.open('image.jpeg').convert('L')) 
img1.show()

img = array((Image.open('image.jpeg').convert('L'))) 
img16 = np.array(img, dtype=np.uint32)
a,b = img.shape
print('\n\nOriginal image: ')
print(img16)
print((a,b))
tup = a,b

for i in range (0, tup[0]):
    for j in range (0, tup[1]):
        x = img16[i][j] 
        x = (pow(x,3)%25777)
        img16[i][j] = x
print('\n\nEncrypted image: ')
print(img16)
imgOut = Image.fromarray(img16)
imgOut.show()

#decryption

img3_16 = img16
img3_16 = np.array(img, dtype=np.uint32)
print('\n\nEncrypted image: ')
print(img3_16)
a1,b1 = img3_16.shape
print((a1,b1))
tup1 = a1,b1

for i1 in range (0, tup1[0]):
     for j1 in range (0, tup1[1]):
         x1 = img3_16[i1][j1] 
         x1 = (pow(x,16971)%25777)  
         img3_16[i][j] = x1
print('\n\nDecrypted image: ')
print(img3_16)
imgOut1 = Image.fromarray(img3_16)y
imgOut1.show()

欢迎指出错误。谢谢。