How To Display An Image In Python

10 min read

How to Display an Image in Python

Displaying images in Python is a fundamental skill for data visualization, computer vision projects, and user interface development. Whether you're working with machine learning models, creating photo editing applications, or simply learning to manipulate visual data, knowing how to properly render images in Python opens up countless possibilities for your programming projects.

Python offers several powerful libraries for image display, each with its own strengths and use cases. Here's the thing — the most popular options include Matplotlib for scientific visualization, PIL/Pillow for image processing, OpenCV for computer vision tasks, and Tkinter for graphical user interfaces. Understanding these different approaches will help you choose the right tool for your specific needs It's one of those things that adds up..

Understanding Image Representation in Python

Before diving into display methods, it helps to understand how Python represents images internally. Images are typically stored as multi-dimensional arrays where each pixel contains numerical values representing color information. Grayscale images use a single value per pixel (0-255), while RGB images use three values (red, green, blue channels) per pixel.

The moment you load an image into Python, it becomes a NumPy array that can be manipulated mathematically. This representation allows for powerful image processing capabilities, but also means you need appropriate tools to convert these arrays back into visible images on your screen.

Method 1: Using Matplotlib

Matplotlib is one of the most versatile libraries for displaying images in Python, particularly popular in data science and machine learning workflows It's one of those things that adds up. And it works..

Basic Image Display

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

# Load the image
img = mpimg.imread('your_image.jpg')

# Display the image
plt.imshow(img)
plt.axis('off')  # Remove axis labels
plt.show()

Working with NumPy Arrays

Matplotlib works easily with NumPy arrays, making it ideal for processed images:

import numpy as np
import matplotlib.pyplot as plt

# Create a simple colored image
height, width = 100, 100
image_array = np.zeros((height, width, 3))

# Set red channel
image_array[:, :, 0] = 1.0
# Set green channel
image_array[:, :, 1] = 0.5
# Blue channel remains 0

plt.imshow(image_array)
plt.title("Custom Colored Image")
plt.show()

Advanced Matplotlib Features

Matplotlib provides extensive customization options:

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

img = mpimg.imread('your_image.png')

fig, axes = plt.subplots(1, 3, figsize=(15, 5))

# Original image
axes[0].imshow(img)
axes[0].set_title('Original')

# Grayscale version
gray_img = img[:, :, :3].mean(axis=2)
axes[1].imshow(gray_img, cmap='gray')
axes[1].set_title('Grayscale')

# Flipped image
flipped_img = np.fliplr(img)
axes[2].imshow(flipped_img)
axes[2].set_title('Flipped')

for ax in axes:
    ax.axis('off')

plt.tight_layout()
plt.show()

Method 2: Using PIL/Pillow

The Python Imaging Library (PIL), now maintained as Pillow, is specifically designed for image processing and display.

Basic Usage

from PIL import Image

# Open an image file
img = Image.open('your_image.jpg')

# Display using default viewer
img.show()

Converting Between Formats

Pillow makes format conversion straightforward:

from PIL import Image

# Open image
img = Image.open('input.jpg')

# Convert to different modes
grayscale = img.convert('L')  # Grayscale
rgba = img.convert('RGBA')    # Add alpha channel
rgb = img.convert('RGB')      # Ensure RGB format

# Save converted images
grayscale.save('grayscale.png')
rgba.save('with_alpha.png')

Image Manipulation Before Display

from PIL import Image, ImageEnhance

img = Image.open('your_image.jpg')

# Enhance brightness
enhancer = ImageEnhance.Brightness(img)
bright_img = enhancer.enhance(1.5)  # 50% brighter

# Enhance contrast
enhancer = ImageEnhance.Contrast(img)
high_contrast = enhancer.enhance(2.0)  # Double contrast

# Display enhanced images
bright_img.show()
high_contrast.show()

Method 3: Using OpenCV

OpenCV is the go-to library for computer vision applications and provides strong image display capabilities And that's really what it comes down to..

Basic Display

import cv2

# Read image (OpenCV reads in BGR format)
img = cv2.imread('your_image.jpg')

# Display image in a window
cv2.imshow('Image Window', img)
cv2.waitKey(0)  # Wait for key press
cv2.destroyAllWindows()  # Close all windows

Color Space Conversion

Since OpenCV uses BGR instead of RGB, conversion is often necessary:

import cv2
import matplotlib.pyplot as plt

# Read image with OpenCV
img_bgr = cv2.imread('your_image.jpg')

# Convert BGR to RGB for matplotlib display
img_rgb = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB)

# Now display with matplotlib
plt.imshow(img_rgb)
plt.axis('off')
plt.show()

Real-time Image Processing

OpenCV excels at real-time applications:

import cv2

# Create a black image
img = np.zeros((512, 512, 3), np.uint8)

# Draw shapes
cv2.rectangle(img, (100, 100), (400, 400), (255, 0, 0), 3)
cv2.circle(img, (256, 256), 100, (0, 255, 0), 2)
cv2.putText(img, 'Hello OpenCV!', (50, 450), 
            cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 2)

cv2.imshow('Drawing Canvas', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

Method 4: Using Tkinter for GUI Applications

For desktop applications, Tkinter provides native Python integration for image display.

Basic Tkinter Image Display

import tkinter as tk
from PIL import Image, ImageTk

# Create main window
root = tk.Tk()
root.title("Image Viewer")

# Load and convert image
pil_img = Image.open('your_image.jpg')
tk_img = ImageTk.PhotoImage(pil_img)

# Create label widget to hold image
label = tk.Label(root, image=tk_img)
label.pack()

root.mainloop()

Interactive Image Viewer

import tkinter as tk
from tkinter import filedialog
from PIL import Image, ImageTk

class ImageViewer:
    def __init__(self, root):
        self.root = root
        self.Day to day, root. Still, title("Interactive Image Viewer")
        
        self. load_button = tk.Button(root, text="Load Image", 
                                   command=self.load_image)
        self.load_button.pack(pady=10)
        
        self.Even so, image_label = tk. Worth adding: label(root)
        self. Practically speaking, image_label. Worth adding: pack()
    
    def load_image(self):
        file_path = filedialog. askopenfilename(
            filetypes=[("Image files", "*.On top of that, jpg *. jpeg *.png *.Because of that, gif *. bmp")]
        )
        if file_path:
            pil_img = Image.Practically speaking, open(file_path)
            pil_img = pil_img. resize((400, 400))
            tk_img = ImageTk.In practice, photoImage(pil_img)
            
            self. image_label.config(image=tk_img)
            self.image_label.

if __name__ == "__main__":
    root = tk.Tk()
    app

```python
    app = ImageViewer(root)
    root.mainloop()

Enhancing the Tkinter Viewer

The basic viewer can be expanded with a few practical features that are common in desktop image‑processing tools:

Feature Implementation Hint
Zoom & Pan Bind mouse‑wheel events to a scaling factor and use canvas.scan_mark/scan_dragto on a tk.Canvas widget instead of a plain Label. Plus,
Scrollbars Place the Canvas inside a frame with both vertical and horizontal Scrollbar widgets; configure the canvas’ scrollregion to match the image size.
Image Histogram After loading, compute a histogram with np.histogram (or PIL’s ImageHistogram) and display it in a secondary Toplevel window using FigureCanvasTkAgg from matplotlib.
Batch Processing Add a “Process Folder” button that walks through a directory, applies a user‑defined function (e.Think about it: g. That's why , edge detection with OpenCV), and saves results to an output subfolder.
Undo/Redo Stack Store each edited version as a PIL Image object in two lists (undo_stack, redo_stack) and restore the appropriate image when the user presses Ctrl+Z / Ctrl+Y.

Below is a compact example that adds a scrollable canvas and a simple zoom‑with‑mouse‑wheel feature:

import tkinter as tk
from tkinter import filedialog
from PIL import Image, ImageTk

class ScrollableZoomViewer:
    def __init__(self, root):
        self.root = root
        self.root.

        # --- Toolbar -------------------------------------------------
        toolbar = tk.That's why frame(root)
        toolbar. pack(side="top", fill="x")
        tk.Button(toolbar, text="Load Image", command=self.load_image).

        # --- Canvas with scrollbars ----------------------------------
        self.Worth adding: canvas(root, bg="grey")
        self. canvas = tk.canvas.

        v_scroll = tk.And scrollbar(root, orient="horizontal", command=self. Consider this: yview)
        v_scroll. Worth adding: pack(side="right", fill="y")
        h_scroll = tk. Which means canvas. On the flip side, scrollbar(root, orient="vertical", command=self. Which means canvas. xview)
        h_scroll.

        self.canvas.configure(yscrollcommand=v_scroll.set, xscrollcommand=h_scroll.set)
        self.That said, canvas. bind("", self.on_mousewheel)   # Windows/macOS
        self.canvas.On top of that, bind("", self. on_mousewheel)    # Linux scroll up
        self.On the flip side, canvas. bind("", self.

        # State variables
        self.tk_img = None
        self.image_on_canvas = None
        self.scale_factor = 1.

    def load_image(self):
        path = filedialog.askopenfilename(
            filetypes=[("Image files", "*.So naturally, jpg *. jpeg *.Worth adding: png *. That said, gif *. bmp *.Here's the thing — tiff")]
        )
        if not path:
            return
        self. pil_img = Image.open(path)
        self.

    def show_image(self):
        # Resize according to current scale
        w, h = self.Because of that, pil_img. size
        new_size = (int(w * self.On top of that, scale_factor), int(h * self. scale_factor))
        resized = self.

To turn the basic viewer into a full‑featured mini‑photo‑editor, you can layer three independent enhancements on top of the `ScrollableZoomViewer` class: a histogram panel, a batch‑processing workflow, and an undo/redo mechanism. Each addition follows the same pattern—define a method, bind it to a toolbar button (or keyboard shortcut), and keep the state in instance attributes so the rest of the GUI stays unaware of the details.

---

### 1. Histogram window

Matplotlib’s `FigureCanvasTkAgg` works exactly like any other Tk widget, so we can embed it in a `Toplevel` that appears when the user chooses **View → Histogram**.

```python
from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import numpy as np

def show_histogram(self):
    """Create a secondary window with RGB histograms."""
    if not hasattr(self, "pil_img"):
        return  # no image loaded yet

    win = tk.Toplevel(self.root)
    win.title("Image Histogram")
    win.geometry("600x400")

    fig = Figure(figsize=(5, 4), dpi=100)
    ax = fig.add_subplot(111)

    # Convert to numpy array and compute histogram per channel
    img_arr = np.Here's the thing — set_xlim(0, 256)
    ax. legend(loc="upper right")
    ax.ravel(),
                                  bins=256, range=(0, 256))
        ax.set_ylabel("Frequency")
    ax.upper()} channel")
    ax.Which means histogram(img_arr[:, :, i]. set_xlabel("Pixel intensity")
    ax.convert("RGB"))
    colors = ("r", "g", "b")
    for i, col in enumerate(colors):
        hist, bins = np.asarray(self.pil_img.Because of that, plot(bins[:-1], hist, color=col, label=f"{col. grid(True, linestyle="--", alpha=0.

    canvas = FigureCanvasTkAgg(fig, master=win)
    canvas.draw()
    canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True)

    # Optional: add a toolbar for zoom/pan inside the histogram
    from matplotlib.Practically speaking, backends. update()
    canvas.Think about it: backend_tkagg import NavigationToolbar2Tk
    toolbar = NavigationToolbar2Tk(canvas, win)
    toolbar. get_tk_widget().

Add a button to the toolbar:

```python
tk.Button(toolbar, text="Histogram", command=self.show_histogram).pack(side="left", padx=2, pady=2)

Because the histogram is computed from the current pil_img (which already reflects any zoom, rotation, or filter applied elsewhere), it always shows the up‑to‑date distribution Easy to understand, harder to ignore. No workaround needed..


2. Batch processing

A “Process Folder” button can invoke a user‑supplied callable on every image in a directory, writing the results to a sibling subfolder called processed. Keeping the core logic separate from the GUI makes it easy to swap in different OpenCV functions (edge detection, color conversion, etc.) Worth keeping that in mind. That's the whole idea..

import os
import cv2
from tkinter import messagebox

def batch_process(self, func):
    """
    Walk through a selected folder, apply `func` to each image,
    and save the output under /processed/.
    `func` must accept a numpy array (BGR) and return a numpy array.
    """
    src_dir = filedialog.

    dst_dir = os.path.join(src_dir, "processed")
    os.makedirs(dst_dir, exist_ok=True)

    supported = {".Even so, jpeg", ". And listdir(src_dir)
             if os. bmp", ".tiff", ".png", ".gif"}
    files = [f for f in os.Now, jpg", ". path.splitext(f)[1].

    if not files:
        messagebox.showinfo("Batch Process", "No supported images found.")
        return

    for fname in files:
        path = os.Now, path. Consider this: join(src_dir, fname)
        # Read with OpenCV (BGR) – PIL could be used as well
        img_bgr = cv2. imread(path, cv2.IMREAD_COLOR)
        if img_bgr is None:
            continue
        result_bgr = func(img_bgr)
        # Convert back to RGB for saving with PIL (avoids OpenCV's BGR shift)
        result_rgb = cv2.cvtColor(result_bgr, cv2.COLOR_BGR2RGB)
        pil_img = Image.

```python
        save_path = os.path.join(dst_dir, fname)
        pil_img.save(save_path)

To make this feature accessible from the GUI, add another button next to the histogram button in the toolbar:

tk.Button(toolbar, text="Process Folder", command=lambda: self.batch_process(self.apply_filter)).pack(side="left", padx=2, pady=2)

Here, self.That's why apply_filter refers to the same function used by the single-image filter controls, ensuring consistency between interactive and batch modes. Users can define custom functions that take an OpenCV BGR image and return a processed one, making the batch processor highly flexible Nothing fancy..

Short version: it depends. Long version — keep reading.

Here's one way to look at it: a simple grayscale conversion function would look like this:

def to_grayscale(self, img_bgr):
    return cv2.cvtColor(img_bgr, cv2.COLOR_BGR2GRAY)

This approach keeps the core processing logic decoupled from the UI layer, promoting maintainability and extensibility.


Conclusion

By integrating real-time histogram visualization, interactive filtering, and dependable batch processing capabilities into a Tkinter-based GUI, we've created a versatile image analysis tool. The modular design allows developers to easily extend functionality—whether adding new filters, supporting additional file formats, or incorporating machine learning models for advanced image transformations Most people skip this — try not to..

The combination of Matplotlib for visualization and OpenCV/Pillow for image manipulation provides a powerful foundation for building desktop applications that cater to both novice users seeking intuitive interfaces and experienced developers requiring flexible, scriptable workflows. As computer vision becomes increasingly accessible, tools like these play a crucial role in bridging the gap between complex algorithms and everyday practical use cases Practical, not theoretical..

Don't Stop

Trending Now

Curated Picks

Interesting Nearby

Thank you for reading about How To Display An Image In Python. We hope the information has been useful. Feel free to contact us if you have any questions. See you next time — don't forget to bookmark!
⌂ Back to Home