How to display an image in Python

Learn how to display images in Python using various methods. This guide covers tips, real-world applications, and debugging common errors.

How to display an image in Python
Published on: 
Fri
Feb 20, 2026
Updated on: 
Mon
Apr 6, 2026
The Replit Team

Displaying images in Python is a key skill for developers working on data visualization, web applications, and machine learning projects. Powerful libraries provide straightforward methods to handle and show images.

In this article, we'll cover several techniques to display images. You'll find practical tips, real-world applications, and debugging advice to help you confidently handle images in your own Python projects.

Basic image display with PIL

from PIL import Image
img = Image.open('sample.jpg')
img.show()--OUTPUT--# Output: Opens the image in the default image viewer of your operating system

The Pillow library, imported as PIL, provides the core functionality here. The Image.open() function reads an image from a file path, creating an Image object in memory. This object holds the image's data and properties, making it available for processing or display.

Calling the show() method is a convenient debugging utility. It works by saving the image to a temporary file and then launching your operating system's default image viewer to display it. While not meant for GUI applications, it’s perfect for quickly checking your image during development.

Using popular libraries

Moving beyond quick previews with PIL, other libraries offer more robust options for integrating images into plots, applications, and computer vision projects.

Using matplotlib to display images

import matplotlib.pyplot as plt
import matplotlib.image as mpimg

img = mpimg.imread('sample.jpg')
plt.imshow(img)
plt.axis('off') # Hide axes
plt.show()--OUTPUT--# Output: Displays the image in a matplotlib window without axes

matplotlib treats images as data, making it ideal for data visualization and analysis. The mpimg.imread() function reads the image file into a NumPy array—a grid of numbers representing pixel values. This array is then passed to plt.imshow(), which handles the rendering.

  • Use plt.axis('off') to hide the x and y axes for a cleaner, image-only view.
  • The plt.show() command displays the final plot in a new window.

Displaying images with OpenCV

import cv2

img = cv2.imread('sample.jpg')
cv2.imshow('Image', img)
cv2.waitKey(0)
cv2.destroyAllWindows()--OUTPUT--# Output: Shows the image in an OpenCV window titled 'Image' until a key is pressed

OpenCV is the go-to library for computer vision, and it gives you direct control over how images are displayed. The cv2.imshow() function creates a new window to show the image, but it requires a couple of extra steps to work correctly.

  • The cv2.waitKey(0) function is essential. It pauses the script and waits for you to press any key. Without it, the image window would flash and disappear instantly.
  • Once a key is pressed, cv2.destroyAllWindows() closes the window, which is important for cleaning up resources in an application.

Creating a simple image viewer with tkinter

import tkinter as tk
from PIL import Image, ImageTk

root = tk.Tk()
img = ImageTk.PhotoImage(Image.open('sample.jpg'))
label = tk.Label(root, image=img)
label.pack()
root.mainloop()--OUTPUT--# Output: Displays the image in a tkinter window that remains open until closed

For building simple graphical user interfaces (GUIs), Python's built-in tkinter library is a great choice. It integrates with Pillow to display images inside a native application window. The process involves creating a main window and then preparing the image for display.

  • First, ImageTk.PhotoImage() converts the image into a special object that tkinter can handle.
  • Next, you place this object into a Label widget.
  • Finally, root.mainloop() starts the application's event loop, which keeps the window open and responsive.

Advanced image display techniques

Building on the basics of showing one image, you can now tackle more complex tasks like arranging images in a grid, making displays interactive, and applying effects.

Showing multiple images in a grid

import matplotlib.pyplot as plt

fig, axs = plt.subplots(2, 2, figsize=(10, 8))
axs[0, 0].imshow(plt.imread('image1.jpg'))
axs[0, 1].imshow(plt.imread('image2.jpg'))
axs[1, 0].imshow(plt.imread('image3.jpg'))
axs[1, 1].imshow(plt.imread('image4.jpg'))
plt.tight_layout()
plt.show()--OUTPUT--# Output: Displays four images arranged in a 2×2 grid in a single figure

You can arrange multiple images into a grid using matplotlib for easy comparison. The key is the plt.subplots() function, which creates both a figure and a grid of subplots to hold your images.

  • The function returns an array of axes objects, letting you target each subplot by its index, like axs[0, 0] for the top-left position.
  • You then call imshow() on each specific subplot axis to place an image inside it.
  • Using plt.tight_layout() automatically adjusts the spacing between plots for a clean look.

Interactive image display with ipywidgets

from ipywidgets import interact
import matplotlib.pyplot as plt
import numpy as np

def view_image(brightness=1.0):
img = plt.imread('sample.jpg')
plt.figure(figsize=(10, 6))
plt.imshow(np.clip(img * brightness, 0, 1))
plt.axis('off')

interact(view_image, brightness=(0.5, 2.0, 0.1))--OUTPUT--# Output: Shows the image with an interactive slider to adjust brightness in Jupyter notebook

For interactive data exploration in Jupyter environments, ipywidgets is a powerful tool. It connects UI controls like sliders directly to your Python functions. The interact function automatically generates a widget based on your function's arguments, making it easy to manipulate outputs in real time.

  • The interact decorator links a slider to the brightness parameter of the view_image function.
  • As you move the slider, the function reruns with the new brightness value, which multiplies the image's pixel data.
  • The np.clip function ensures the adjusted pixel values stay within the valid display range.

Applying effects before displaying images

from PIL import Image, ImageFilter, ImageOps
import matplotlib.pyplot as plt

img = Image.open('sample.jpg')
processed = ImageOps.solarize(img.filter(ImageFilter.CONTOUR))
plt.imshow(processed)
plt.show()--OUTPUT--# Output: Displays the image with contour filter and solarize effect applied

Pillow makes it simple to process images before you display them. This example chains two effects together for a stylized result. The img.filter(ImageFilter.CONTOUR) method first applies a filter that finds and enhances the edges in your image, creating an outline effect.

  • The result is then passed to ImageOps.solarize(), which inverts pixel values above a certain threshold for a dramatic look.
  • Finally, matplotlib displays the newly processed image, showing how you can combine different libraries for powerful results.

Move faster with Replit

Replit is an AI-powered development platform that comes with all Python dependencies pre-installed, so you can skip setup and start coding instantly.

Instead of piecing together techniques, you can use Agent 4 to build complete applications. It handles everything from writing code and connecting to APIs to deploying your app, all from a simple description. For example, you could build:

  • An automatic thumbnail generator that processes a folder of images and arranges them into a clean grid for a portfolio page.
  • A profile picture styler that lets users upload an image and apply various artistic filters, like contour lines or solarization effects.
  • An interactive image comparison tool that displays before-and-after versions of an edited photo with a slider to switch between them.

Simply describe your app, and Replit will write the code, test it, and fix issues automatically, all within your browser.

Common errors and challenges

When displaying images, you might run into issues like missing files, incorrect colors, or performance lags; here’s how to solve them.

Handling missing image files with PIL

If the Image.open() function can't locate an image at the specified path, your script will stop with a FileNotFoundError. To avoid a crash, you can handle this exception using a try-except block. This lets you catch the error and run alternative code, like logging a warning or showing a default image, ensuring your program continues to run smoothly.

Fixing color display issues when using OpenCV with matplotlib

You may notice that colors look wrong when you load an image with OpenCV and display it with matplotlib. This is a classic color space mismatch—OpenCV loads images in BGR (Blue-Green-Red) format, but matplotlib expects RGB (Red-Green-Blue). The result is that the red and blue color channels are swapped.

The fix is to convert the image from BGR to RGB before passing it to matplotlib.

  • After reading the image with cv2.imread(), use cv2.cvtColor(img, cv2.COLOR_BGR2RGB) to correct the color order.
  • Then, display the converted image with plt.imshow(), and the colors will appear as intended.

Handling large images in tkinter

Loading high-resolution images directly into a tkinter application can cause significant performance problems or even make the app unresponsive. The issue stems from high memory usage, as tkinter attempts to handle the entire raw image data.

To prevent this, it's best to resize the image before displaying it. After opening your image with PIL, use its resize() or thumbnail() method to create a smaller version. The thumbnail() method is particularly useful because it preserves the image's aspect ratio. Once the image is scaled down, you can then convert it to a PhotoImage object and add it to your GUI without overwhelming your system's memory.

Handling missing image files with PIL

A common tripwire is providing a wrong file path, which causes a FileNotFoundError and crashes your script. It's one thing to read about it, but seeing it happen makes the problem clear. The following code triggers this error by trying to open a nonexistent image.

from PIL import Image
img = Image.open('nonexistent_image.jpg')
img.show()

The script halts because Image.open() can't find the requested file. Instead of letting the program crash, you can catch the error. The following code shows how to build in this safety check.

from PIL import Image
import os

image_path = 'nonexistent_image.jpg'
if os.path.exists(image_path):
img = Image.open(image_path)
img.show()
else:
print(f"Error: The file '{image_path}' does not exist.")

This approach proactively avoids the error. It uses os.path.exists() to confirm the image file is present before your script attempts to open it. If the check passes, the image is displayed; otherwise, a clear error message is printed, and the program continues without crashing.

This is a crucial check whenever you're working with file paths that might be incorrect, such as those provided by users or read from external configuration files.

Fixing color display issues when using OpenCV with matplotlib

It’s one thing to read about the color-swapping issue between OpenCV and matplotlib, but seeing it makes the problem clear. The code below loads an image with cv2.imread() and displays it directly with plt.imshow(), showing the incorrect colors in action.

import cv2
import matplotlib.pyplot as plt

img = cv2.imread('sample.jpg')
plt.imshow(img)
plt.axis('off')
plt.show()

The image's red and blue channels are swapped because the code passes the BGR data from cv2.imread() directly to plt.imshow(). The following code demonstrates the simple fix needed to display the colors correctly.

import cv2
import matplotlib.pyplot as plt

img = cv2.imread('sample.jpg')
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
plt.imshow(img_rgb)
plt.axis('off')
plt.show()

The corrected code works by inserting one crucial step: converting the color space with cv2.cvtColor(img, cv2.COLOR_BGR2RGB). This function rearranges the color channels from OpenCV’s BGR default to the RGB format that matplotlib requires. This simple conversion is the key to accurate color display. You'll want to remember this fix whenever you combine different imaging libraries, as color space mismatches are a common pitfall.

Handling large images in tkinter

Loading a high-resolution image directly into a tkinter app often causes performance lags or even crashes. The application becomes unresponsive because it's trying to handle too much raw image data at once. The code below triggers this exact problem.

import tkinter as tk
from PIL import Image, ImageTk

root = tk.Tk()
original = Image.open('large_image.jpg')
img = ImageTk.PhotoImage(original)
label = tk.Label(root, image=img)
label.pack()
root.mainloop()

Here, the ImageTk.PhotoImage() function is the bottleneck. It tries to load the full, unresized image into the GUI, consuming too much memory and causing the app to freeze. See how the corrected code avoids this.

import tkinter as tk
from PIL import Image, ImageTk

root = tk.Tk()
original = Image.open('large_image.jpg')
resized = original.resize((800, 600), Image.LANCZOS)
img = ImageTk.PhotoImage(resized)
label = tk.Label(root, image=img)
label.image = img
label.pack()
root.mainloop()

The corrected code prevents the app from freezing by resizing the image before displaying it. The resize() method scales the image down to a manageable size, using Image.LANCZOS for a high-quality result. It's also crucial to keep a reference to the image object with label.image = img. This prevents Python's garbage collector from accidentally deleting it. Always resize images when building GUIs to ensure your application remains responsive, especially with user-provided files.

Real-world applications

Now that you know how to troubleshoot common issues, you can confidently apply these techniques to complex, real-world projects.

Annotating images with matplotlib

You can use matplotlib to add explanatory text, arrows, and other shapes directly onto an image, which is useful for highlighting important features in data analysis or tutorials.

import matplotlib.pyplot as plt

img = plt.imread('sample.jpg')
plt.figure(figsize=(10, 8))
plt.imshow(img)
plt.arrow(100, 100, 50, 0, color='red', width=2)
plt.text(160, 100, 'Important feature', color='red', fontsize=12)
plt.annotate('Detail', xy=(300, 200), xytext=(400, 150),
arrowprops=dict(facecolor='yellow', shrink=0.05))
plt.axis('off')
plt.show()

This code shows how you can add annotations directly onto an image using matplotlib. After displaying the image with plt.imshow(), it overlays several elements to highlight specific areas.

  • The plt.arrow() and plt.text() functions work together to draw a simple pointer and add a label at specific coordinates.
  • For more complex callouts, plt.annotate() creates a label with an arrow that points from the text's position (xytext) to a precise feature on the image (xy), giving you more control over placement.

Visualizing face detection with OpenCV

You can use OpenCV to visualize the results of computer vision tasks, such as drawing rectangles around detected faces in an image.

import cv2
import matplotlib.pyplot as plt

img = cv2.imread('people.jpg')
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')
faces = face_cascade.detectMultiScale(img_rgb, 1.3, 5)
for (x, y, w, h) in faces:
cv2.rectangle(img_rgb, (x, y), (x+w, y+h), (255, 0, 0), 2)
plt.imshow(img_rgb)
plt.axis('off')
plt.show()

This example demonstrates using OpenCV with a pre-trained model to perform face detection. After correcting the image's color space for matplotlib, the script gets to work.

  • First, cv2.CascadeClassifier loads a Haar Cascade file, which is a model trained to recognize frontal faces.
  • Next, detectMultiScale() scans the image and returns the coordinates for any faces it finds.
  • Finally, the code loops through these coordinates and uses cv2.rectangle() to draw a red box around each detected face before displaying the final annotated image.

Get started with Replit

Turn your knowledge into a tool with Replit Agent. Try prompts like: "Build a tool to detect faces in an image with OpenCV" or "Create a dashboard that displays a grid of images from a folder."

Replit Agent writes the code, tests for errors, and deploys your application from a single prompt. Start building with Replit.

Build your first app today

Describe what you want to build, and Replit Agent writes the code, handles the infrastructure, and ships it live. Go from idea to real product, all in your browser.

Build your first app today

Describe what you want to build, and Replit Agent writes the code, handles the infrastructure, and ships it live. Go from idea to real product, all in your browser.