python - 如何将8bit(0-255)数据表保存为图像文件,然后从图像中检索数据?

标签 python image python-imaging-library image-compression webp

我正在测试如何将 8 位(0-255)数据表保存为图像格式以存储原始数据文件并加载图像以检索相同的数据。
下面的代码显示了我当前正在尝试的内容。具有 32x32 数据表 (random_data)。
我想将此数据以灰度形式绘制为 32x32 像素图像,然后打开/检索它以查看哪种图像格式最能保留该数据。如果可以做到这一点,我想将其缩放到更大尺寸的数据/图像。

以下是我面临的一些挑战:

  • 问题1:
    Plt.figureplt.savefig 没有直接选项来绘制 32x32 数据表并将其保存为 32x32 像素图像,我添加并手动调整了 dpi 设置和 Figsize 选项和参数以获得 32x32 像素。但是,当我打开保存的图像文件然后将其转换为数组时,它不会给出与输入相同的值。 (见下文)

  • 问题2:
    是否可以将图形保存为 PNG 和 JPEG 之外的其他较新的图像格式? (例如 AVIF、WebP、HEIF、JPEG XL、JPEG XS 等)?

  • 问题3:
    如果问题 2 无法实现,那么保存和保留相同数据值的最佳图像格式是什么?

import matplotlib.pyplot as plt
from PIL import Image
import numpy as np
from numpy import asarray
import sys
import numpy

numpy.set_printoptions(threshold=sys.maxsize)

# Randomly generated data table in 0-255
random_data=([179,22,29,72,118,117,88,182,155,114,95,62,75,67,30,252], 
[161,88,76,74,70,99,136,246,178,113,233,125,177,135,94,72], 
[46,123,106,28,192,240,85,164,75,183,160,126,157,140,182,98], 
[6,147,229,193,224,103,31,133,19,176,194,171,223,123,173,204], 
[228,25,207,39,93,119,34,157,150,186,161,242,2,89,187,226], 
[109,198,151,25,122,136,48,250,245,102,205,180,74,229,243,27], 
[135,116,223,40,233,243,95,126,54,153,246,57,120,162,8,143], 
[78,249,58,237,80,237,99,92,67,157,64,200,0,249,31,33], 
[154,111,170,120,143,81,97,237,249,85,154,135,41,163,147,8], 
[137,195,189,167,196,240,185,117,199,179,57,170,87,253,89,152], 
[183,250,88,189,143,232,4,213,110,254,246,240,100,103,99,229], 
[155,205,45,236,60,87,121,216,99,3,243,61,107,104,180,58], 
[240,52,238,143,99,51,230,139,49,3,175,70,160,226,85,108], 
[98,131,157,38,120,4,9,87,122,179,118,41,79,120,119,246], 
[120,131,21,48,225,191,149,144,133,46,56,170,225,207,45,139], 
[118,59,128,238,228,110,70,247,132,225,223,77,53,161,115,197]) 

# Trying to plot the data in 32x32 pixel image then saving it
plt.figure(figsize=(.32, .32), dpi=100, frameon=False)
plt.imshow(random_data, interpolation='none', vmin=0, vmax=255, cmap='gray') 
plt.axis('off')
plt.savefig('test.png',  dpi=133, bbox_inches='tight', pad_inches=0)

# Calling saved image then converting it to array to compare it against the original input data
test_output=Image.open('test.png') 
test_output_gray=test_output.convert('L') 
test_output_gray=asarray(test_output_gray) 
print(test_output_gray.shape) 

print(test_output_gray)

输出如下:

[[179 179  22  22  29  29  72  72 118 118 117 117  88  88 182 182 155 155 
  155 113 113  95  95  62  62  75  75  67  67  30  30 252] 
 [161 161  88  88  76  76  73  73  70  70  99  99 136 136 246 246 178 178 
  178 113 113 233 233 125 125 177 177 135 135  94  94  72] 
 [161 161  88  88  76  76  73  73  70  70  99  99 136 136 246 246 178 178 
  178 113 113 233 233 125 125 177 177 135 135  94  94  72] 
 [ 46  46 123 123 105 105  28  28 192 192 240 240  85  85 163 163  75  75 
   75 183 183 160 160 126 126 157 157 140 140 182 182  97] 
 [ 46  46 123 123 105 105  28  28 192 192 240 240  85  85 163 163  75  75 
   75 183 183 160 160 126 126 157 157 140 140 182 182  97] 
 [  6   6 147 147 229 229 193 193 224 224 103 103  31  31 133 133  19  19 
   19 176 176 194 194 171 171 223 223 123 123 173 173 204] 
 [  6   6 147 147 229 229 193 193 224 224 103 103  31  31 133 133  19  19 
   19 176 176 194 194 171 171 223 223 123 123 173 173 204] 
 [227 227  25  25 207 207  39  39  93  93 119 119  34  34 157 157 150 150 
  150 186 186 161 161 242 242   2   2  89  89 187 187 226] 
 [227 227  25  25 207 207  39  39  93  93 119 119  34  34 157 157 150 150 
  150 186 186 161 161 242 242   2   2  89  89 187 187 226] 
 [109 109 198 198 151 151  25  25 121 121 136 136  48  48 250 250 245 245 
  245 102 102 205 205 179 179  73  73 229 229 243 243  27] 
 [109 109 198 198 151 151  25  25 121 121 136 136  48  48 250 250 245 245 
  245 102 102 205 205 179 179  73  73 229 229 243 243  27] 
 [135 135 116 116 223 223  40  40 233 233 243 243  95  95 126 126  54  54 
   54 153 153 246 246  56  56 120 120 162 162   8   8 143] 
 [135 135 116 116 223 223  40  40 233 233 243 243  95  95 126 126  54  54 
   54 153 153 246 246  56  56 120 120 162 162   8   8 143] 
 [ 78  78 249 249  58  58 237 237  80  80 237 237  99  99  92  92  67  67 
   67 157 157  64  64 200 200   0   0 249 249  31  31  32] 
 [ 78  78 249 249  58  58 237 237  80  80 237 237  99  99  92  92  67  67 
   67 157 157  64  64 200 200   0   0 249 249  31  31  32] 
 [154 154 111 111 170 170 120 120 143 143  81  81  97  97 237 237 249 249 
  249  85  85 154 154 135 135  40  40 163 163 147 147   8] 
 [154 154 111 111 170 170 120 120 143 143  81  81  97  97 237 237 249 249 
  249  85  85 154 154 135 135  40  40 163 163 147 147   8] 
 [154 154 111 111 170 170 120 120 143 143  81  81  97  97 237 237 249 249 
  249  85  85 154 154 135 135  40  40 163 163 147 147   8] 
 [137 137 195 195 189 189 167 167 195 195 240 240 185 185 117 117 199 199 
  199 179 179  56  56 170 170  87  87 253 253  89  89 152] 
 [137 137 195 195 189 189 167 167 195 195 240 240 185 185 117 117 199 199 
  199 179 179  56  56 170 170  87  87 253 253  89  89 152] 
 [183 183 250 250  88  88 189 189 143 143 232 232   4   4 213 213 110 110 
  110 254 254 246 246 240 240 100 100 103 103  99  99 229] 
 [183 183 250 250  88  88 189 189 143 143 232 232   4   4 213 213 110 110 
  110 254 254 246 246 240 240 100 100 103 103  99  99 229] 
 [155 155 205 205  44  44 236 236  60  60  87  87 121 121 216 216  99  99 
   99   3   3 243 243  60  60 107 107 104 104 179 179  58] 
 [155 155 205 205  44  44 236 236  60  60  87  87 121 121 216 216  99  99 
   99   3   3 243 243  60  60 107 107 104 104 179 179  58] 
 [240 240  52  52 238 238 143 143  99  99  51  51 230 230 139 139  48  48 
   48   3   3 175 175  70  70 160 160 226 226  85  85 108] 
 [240 240  52  52 238 238 143 143  99  99  51  51 230 230 139 139  48  48 
   48   3   3 175 175  70  70 160 160 226 226  85  85 108] 
 [ 97  97 131 131 157 157  38  38 120 120   4   4   9   9  87  87 121 121 
  121 179 179 118 118  40  40  79  79 120 120 119 119 246] 
 [ 97  97 131 131 157 157  38  38 120 120   4   4   9   9  87  87 121 121 
  121 179 179 118 118  40  40  79  79 120 120 119 119 246] 
 [120 120 131 131  21  21  48  48 225 225 191 191 149 149 144 144 133 133 
  133  46  46  56  56 170 170 225 225 207 207  44  44 139] 
 [120 120 131 131  21  21  48  48 225 225 191 191 149 149 144 144 133 133 
  133  46  46  56  56 170 170 225 225 207 207  44  44 139] 
 [118 118  59  59 128 128 238 238 227 227 110 110  70  70 247 247 131 131 
  131 225 225 223 223  77  77  52  52 161 161 115 115 197] 
 [118 118  59  59 128 128 238 238 227 227 110 110  70  70 247 247 131 131 
  131 225 225 223 223  77  77  52  52 161 161 115 115 197]]

谢谢。

最佳答案

我们必须保存图像,而不是保存图形。

由于图形经过调整显示,通常与原始图像有所不同。
在您的示例中,原始图像尺寸为 16x16,图形尺寸为 32x32,因此图像和图形必须不同。

注意:我们可能会显示调整大小的图像,而不调整源图像的大小(保持原始图像不变)。


使用 Pillow 将图像保存为 PNG 的示例:

  • 将 random_data 从列表转换为 uint8 类型的 NumPy 数组。

  • 将 NumPy 数组转换为 Image 对象,并保存图像。

     random_data_arr = np.array(random_data, np.uint8)  # Convert random_data to NumPy array of type 'uint8'
     pil_image = Image.fromarray(random_data_arr)  # Convert the NumPy array to PIL image
     pil_image.save('test.png')  # Save the image in PNG format
    

加载 PNG 图像并与 random_data_arr 进行比较的示例:

  • 使用Image.open('test.png')打开图像。

  • 将图像对象转换为 NumPy 数组。

  • 使用 np.array_equal 方法比较数组

     test_output = Image.open('test.png')
     test_output_gray = np.array(test_output)
     are_equal = np.array_equal(random_data_arr, test_output_gray)  # True if random_data_arr and test_output_gray are equal
     print('are_equal = ' + str(are_equal))  # are_equal = True
    

问题2

安装合适的 Python 包后可以使用更新的图像格式。

可能存在限制 - 例如,WebP packge 不支持灰度图像,因此我们必须在保存之前将图像转换为 RGB,并在加载后转换回灰度图像。

使用 WebP 格式的示例:
安装WebP Python bindings包:pip install webp

使用WebP图像格式保存、加载和比较的示例:

webp.save_image(pil_image.convert('RGB'), 'test.webp', lossless=True)

webp_output = webp.load_image('test.webp')  # Load test.webp to PIL image
webp_output_gray = np.array(webp_output.convert('L'))  # Convert to grayscale and to NumPy array

are_webp_equal = np.array_equal(random_data_arr, webp_output_gray)  # True if random_data_arr and webp_output_gray are equal
print('are_webp_equal = ' + str(are_webp_equal))  # are_webp_equal = True

问题3

最佳图像格式(就文件大小而言)是特定于域的 - 最佳格式取决于图像的内容。
使用有损图像压缩时,所选格式更相关。
当您的问题中使用无损图像压缩时,在大多数情况下,输出文件不会小很多(在大多数情况下不少于 PNG 文件的一半)。
注意:随机数据根本没有被很好地压缩。


完整代码示例:

#import matplotlib.pyplot as plt
from PIL import Image
import numpy as np
import webp

#np.set_printoptions(threshold=sys.maxsize)

# Randomly generated data table in 0-255
random_data = ([179,22,29,72,118,117,88,182,155,114,95,62,75,67,30,252], 
[161,88,76,74,70,99,136,246,178,113,233,125,177,135,94,72], 
[46,123,106,28,192,240,85,164,75,183,160,126,157,140,182,98], 
[6,147,229,193,224,103,31,133,19,176,194,171,223,123,173,204], 
[228,25,207,39,93,119,34,157,150,186,161,242,2,89,187,226], 
[109,198,151,25,122,136,48,250,245,102,205,180,74,229,243,27], 
[135,116,223,40,233,243,95,126,54,153,246,57,120,162,8,143], 
[78,249,58,237,80,237,99,92,67,157,64,200,0,249,31,33], 
[154,111,170,120,143,81,97,237,249,85,154,135,41,163,147,8], 
[137,195,189,167,196,240,185,117,199,179,57,170,87,253,89,152], 
[183,250,88,189,143,232,4,213,110,254,246,240,100,103,99,229], 
[155,205,45,236,60,87,121,216,99,3,243,61,107,104,180,58], 
[240,52,238,143,99,51,230,139,49,3,175,70,160,226,85,108], 
[98,131,157,38,120,4,9,87,122,179,118,41,79,120,119,246],
[120,131,21,48,225,191,149,144,133,46,56,170,225,207,45,139], 
[118,59,128,238,228,110,70,247,132,225,223,77,53,161,115,197]) 

# Trying to plot the data in 32x32 pixel image then saving it
#plt.figure(figsize=(.32, .32), dpi=100, frameon=False)
#plt.imshow(random_data, interpolation='none', vmin=0, vmax=255, cmap='gray') 
#plt.axis('off')
#plt.savefig('test.png', dpi=133, bbox_inches='tight', pad_inches=0)

random_data_arr = np.array(random_data, np.uint8)  # Convert random_data to NumPy array of type 'uint8'
pil_image = Image.fromarray(random_data_arr)  # Convert the NumPy array to PIL image
pil_image.save('test.png')  # Save the image in PNG format

# Loading saved image then converting it to array to compare it against the original input data
test_output = Image.open('test.png')
#test_output_gray = test_output.convert('L')
test_output_gray = np.array(test_output)
print('shape = ' + str(test_output_gray.shape))

are_equal = np.array_equal(random_data_arr, test_output_gray)  # True if random_data_arr and test_output_gray are equal
print('are_equal = ' + str(are_equal))

################################################################################
# Save image in WebP format.
# WebP does not support Grayscale - convert to RGB before saving
webp.save_image(pil_image.convert('RGB'), 'test.webp', lossless=True)

webp_output = webp.load_image('test.webp')  # Load test.webp to PIL image
webp_output_gray = np.array(webp_output.convert('L'))  # Convert to grayscale and to NumPy array

are_webp_equal = np.array_equal(random_data_arr, webp_output_gray)  # True if random_data_arr and webp_output_gray are equal
print('are_webp_equal = ' + str(are_webp_equal))
################################################################################

关于python - 如何将8bit(0-255)数据表保存为图像文件,然后从图像中检索数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75162623/

相关文章:

python - 数据帧上的条件迭代

python - array.array 与 numpy.array

Java ImageIcon/Icon 和 JLabel 不工作

python - Pillow 模块 - 裁剪和保存时色调发生变化(无转换)

python - pyautogui,屏幕截图功能无法识别已安装的 Pillow 模块

python - 将图像中的红线转换为 numpy 列表

python - Python 的 raw_input() 容易受到缓冲区溢出的影响吗?

python - 如何从剪贴板获取带有格式的内容

database - 存储多个图像并将其显示在大文本中

python - 使用 PIL 在 python 中旋转并将扩展参数设置为 true 时指定图像填充颜色