As mentioned in this very answer and this more popular question & answer and also in effbot.page
When you add a PhotoImage or other Image object to a Tkinter widget,
  you must keep your own reference to the image object. If you don’t,
  the image won’t always show up.
The problem is that the Tkinter/Tk interface doesn’t handle references
  to Image objects properly; the Tk widget will hold a reference to the
  internal object, but Tkinter does not. When Python’s garbage collector
  discards the Tkinter object, Tkinter tells Tk to release the image.
  But since the image is in use by a widget, Tk doesn’t destroy it. Not
  completely. It just blanks the image, making it completely
  transparent…
The solution is to make sure to keep a reference to the Tkinter
  object,
For example the image in below code  , if at all as it isn't declared in global scope:
, if at all as it isn't declared in global scope:
import tkinter as tk
root = tk.Tk()
def show_image():
    img_label = tk.Label(root)
    image = tk.PhotoImage(file="test.png")
    img_label['image'] = image
    img_label.pack()
show_image()
root.mainloop()

whereas in the example below img_label.image is declared globally, as an attribute attached to our very img_label in this example, and  :
:
import tkinter as tk
root = tk.Tk()
def show_image():
    img_label = tk.Label(root)
    img_label.image = tk.PhotoImage(file="test.png")
    img_label['image'] = img_label.image
    img_label.pack()
show_image()
root.mainloop()

It is though still strange as img_label isn't globally declared either. A less confusing way would be adding global image as the first line to the show_image.