【问题标题】:Open a 'PNG' file, then numpy, then base64, but image not shown?打开一个“PNG”文件,然后是 numpy,然后是 base64,但没有显示图像?
【发布时间】:2020-03-13 04:49:56
【问题描述】:

尝试进行一些图像处理,加载图像以显示在 Graph 上,但没有显示任何内容。 Win10 / Python 3.7.6 / PySimpleGUI 4.16.0 / Numpy 1.18.1

我通过 PIL.Image 加载图像,将其转换为 numpy 数组,然后转换为 base64,Graph 中的 DrawImage,但什么也不显示。我已经为此工作了好几次,一切正常。检查了几个小时,但没有任何帮助。有人可以帮我找出我错过或错误的地方吗?

我找到的东西,

  1. 我打开了,im.show() 正常
  2. im.shape 是正确的,例如 (200, 150, 3) 表示 150(宽)x 200(高)x RGB 图像。
  3. im_np 显示不同的数据,看起来还可以。
  4. im_64 显示字节串
  5. draw 是 None,它应该是一个 id。
  6. 为 DrawingImage 设置文件名选项,就可以了

我这里需要使用numpy进行一些图像处理,所以需要转换。

import base64
import numpy as np
import PySimpleGUI as sg
from PIL import Image

filename = 'D:/Disk.png'
im = Image.open(filename)
width, height = im.size
im_np = np.array(im)    # It is necesary for future process
im_64 = base64.b64encode(im_np)

def Graph(key):
    return sg.Graph(im.size, graph_bottom_left=(0, 0),
                    graph_top_right=(width, height), key=key)

layout = [[Graph('GRAPH')]]
window = sg.Window('Graph', layout=layout, finalize=True)

draw = window.FindElement('GRAPH').DrawImage(
    data=im_64, location=(width/2, height/2))           # It failed
    # filename=filename, location=(width/2, height/2))  # It working well

while True:

    event, values = window.read()

    if event == None:
        break

window.close()

【问题讨论】:

  • 大概你需要在操作后保存图像,然后再将其传递给DrawImage。我建议将其保存到io.BytesIO 缓冲区。快速查看文档显示DrawImage 接受bytes 作为data 参数。所以使用BytesIO.getvalue() 方法。无需 base64 编码。
  • im_np = np.asarray(im); buffer = BytesIO(); np.save(buffer, im_np) 并在DrawImage 中设置data=buffer,仍然无法正常工作。发帖前我已经试过了。
  • 当您执行np.save(buffer, im_np) 时,它不会以.png 图像格式保存它。您需要使用PIL才能正确保存。
  • im.save(buffer, format='PNG') 仍然无法正常工作

标签: python image numpy pysimplegui


【解决方案1】:

您需要传递 PNG “作为二进制”编码的 base64,而不是编码为 base64 的 numpy 数组。

PySimpleGUI documentation不是很清楚,但是当data作为base64传递时,数据不是base64的原始数据,而是base64的图像文件内容。

  • 将PNG文件读取为二进制文件:

    with open(filename, 'rb') as binary_file:
        #Read image file as binary data
        data = binary_file.read()
    
  • 将二进制表示编码为base64:

    im_64 = base64.b64encode(data)
    
  • im_64 传递为data

    draw = window.FindElement('GRAPH').DrawImage(
        data=im_64, location=(width/2, height/2))          # Works
    

这是一个代码示例:

import base64
import numpy as np
import PySimpleGUI as sg
from PIL import Image

#filename = 'D:/Disk.png'
filename = 'chelsea.png'

with open(filename, 'rb') as binary_file:
    #Read image file as binary data
    data = binary_file.read()

im = Image.open(filename)
width, height = im.size
im_np = np.array(im)    # It is necesary for future process
#im_64 = base64.b64encode(im_np)

# Encode the PNG binary representation 
im_64 = base64.b64encode(data)

def Graph(key):
    return sg.Graph(im.size, graph_bottom_left=(0, 0),
                    graph_top_right=(width, height), key=key)

layout = [[Graph('GRAPH')]]
window = sg.Window('Graph', layout=layout, finalize=True)

draw = window.FindElement('GRAPH').DrawImage(
    data=im_64, location=(width/2, height/2))          # Works
    #filename=filename, location=(width/2, height/2))  # It working well

while True:

    event, values = window.read()

    if event == None:
        break

window.close()

如果你想显示im_np,你可以使用下面post的解决方案。

  • im_np作为PNG图像写入字符串:

    im_pil = Image.fromarray(im_np)
    
    with io.BytesIO() as output:
        im_pil.save(output, format="PNG")
        data = output.getvalue()
    
    im_64 = base64.b64encode(data)
    

结果:

【讨论】:

  • 将图像数组转换为base64的主要原因是为了显示经过numpy处理的图像。第一个解决方案不是必需的,因为我可以直接在 DrawImage 中使用文件名选项。第二个解决方案是我需要的,但动画转换可能需要一些时间。无论如何它正在工作,谢谢您的回复。
  • 您实际上不需要将数据转换为base64,以下代码也可以:draw = window.FindElement('GRAPH').DrawImage(data=data, location=(width/2, height/2))
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-28
  • 1970-01-01
相关资源
最近更新 更多