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()
欢迎指出错误。谢谢。
我正在编写一个脚本来使用 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()
欢迎指出错误。谢谢。