A opinionated tool for coercing data into something displayable
Project description
img-show
img-show is a thin, opinionated wrapper around OpenCV for displaying images. It accepts NumPy arrays, PyTorch tensors, and PIL images; auto-coerces shapes, dtypes, and channel orders; resizes windows to fit the screen; alpha-composites RGBA over a checkerboard; and renders inline as PNG when running inside a Jupyter notebook.
Installation
img-show depends only on NumPy at install time. OpenCV is selected through one of four mutually-exclusive extras so you can match it to your environment (desktop, server, or contrib build):
pip install img-show[opencv] # standard build with GUI
pip install img-show[opencv-contrib] # standard + contrib modules
pip install img-show[opencv-headless] # no GUI (servers, CI, Jupyter-only)
pip install img-show[opencv-contrib-headless] # headless + contrib modules
Pick exactly one. The extras are mutually exclusive at the resolver level (uv enforces this via a conflicts entry); installing two OpenCV variants side-by-side results in a broken cv2 import.
If you already manage cv2 yourself (for example with a system package or a custom wheel), install the bare package:
pip install img-show
img-show will detect the existing cv2 import at runtime.
Requirements
- Python >= 3.10
- NumPy >= 1.24.4
- OpenCV >= 4.5.4.60 (provided by one of the extras above)
- Tkinter (used only to query screen size; if unavailable a 1920x1080 fallback is used)
Optional dependencies
- PIL / Pillow — enables passing
PIL.Image.Imageobjects directly; not required for NumPy or PyTorch inputs. - PyTorch — enables passing
torch.Tensorobjects directly. - IPython — required only when running inside a Jupyter notebook; used for inline PNG rendering.
Quick start
import numpy as np
from img_show import show_img
img = np.random.rand(256, 256, 3)
show_img(img)
Capability detection
At import time img-show probes the runtime environment and exposes two read-only flags:
from img_show import HAS_CV2, IS_HEADLESS
HAS_CV2 # bool — True when cv2 is importable
IS_HEADLESS # bool | None — True for headless cv2 builds,
# False for GUI builds,
# None when cv2 is missing or the provider
# cannot be identified
Headless detection uses importlib.metadata.packages_distributions() to look up which PyPI distribution provides the cv2 import name. The check is fast and runs once at import.
Use these flags to branch your own code if you want to avoid RuntimeError from the display functions:
from img_show import HAS_CV2, IS_HEADLESS, show_img
if HAS_CV2 and IS_HEADLESS is False:
show_img(my_image)
else:
# fall back to saving or logging the array
...
Function requirements
Each public function has a different capability surface. The table below describes what must be available for each function to succeed:
| Function | cv2 required | GUI build required | Display required | Works in Jupyter |
|---|---|---|---|---|
coerce_img |
no | no | no | yes |
show_img |
yes | yes (outside Jupyter only) | yes (outside Jupyter only) | yes (renders inline as PNG) |
show_imgs |
yes | yes (outside Jupyter only) | yes (outside Jupyter only) | yes (renders inline as PNG) |
close_all |
yes | no | no | yes (no-op if no windows) |
When a requirement is unmet, the function raises RuntimeError at call time with a message that tells the user which extra to install. coerce_img is the only function that always works, because it is pure NumPy.
Jupyter inline rendering
When img-show detects a ZMQInteractiveShell (the standard Jupyter kernel), show_img and show_imgs encode each image to PNG with cv2.imencode and emit it through IPython.display.Image, captioned by the window name. The GUI and display requirements are skipped on this path, so a headless OpenCV build inside Jupyter is fully supported.
# In a Jupyter cell
from img_show import show_img
show_img(my_image, window_name='Step 3 output')
Usage
Multiple input types
import numpy as np
import torch
from PIL import Image
from img_show import show_img
show_img(np.random.rand(256, 256, 3)) # NumPy array
show_img(torch.randn(3, 256, 256)) # PyTorch tensor (channels-first)
show_img(Image.open('photo.png')) # PIL image
PIL images use RGB channel order; img-show reorders them to BGR for correct OpenCV display. NumPy and PyTorch inputs are assumed to be BGR already (or single-channel) and pass through unchanged.
Shape coercion
Singleton dimensions are squeezed automatically, and channels-first layouts are transposed to channels-last:
show_img(np.random.rand(1, 256, 256, 3)) # leading singleton stripped
show_img(np.random.rand(1, 1, 3, 256, 256)) # channels-first detected and fixed
show_img(np.random.rand(256, 256, 1)) # grayscale with trailing singleton
Dtype normalization
The table below describes the dtype that coerce_img returns. The display path (show_img / show_imgs) then converts every result to uint8 before handing it to OpenCV — uint16 is scaled by 1/257, floats in [0, 1] are scaled by 255, and anything else is clipped into [0, 255].
| Input dtype | coerce_img output |
|---|---|
uint8 |
passed through unchanged |
uint16 |
passed through unchanged (display path will rescale to uint8) |
bool |
scaled to 0/255 uint8 |
| other integer | scaled to the 0-1 range as float64 |
| float | scaled to 0-1 if out of range or near-constant |
Alpha compositing
Four-channel images (RGBA from PIL, or BGRA arrays) are composited over a gray checkerboard at display time. The original four-channel array is preserved by coerce_img; compositing happens only in the display pipeline.
Window sizing
If the image is taller than the screen (minus a 250-pixel toolbar margin) or wider than the screen, a resizable window is created and sized to fit while preserving aspect ratio. Otherwise an auto-sizing window is created.
Multiple images
from img_show import show_imgs
show_imgs(
[img1, img2, img3],
window_names=['Original', 'Filtered', 'Diff'],
)
When window_names is omitted the names default to Image 1, Image 2, ... A collision with an already-tracked window appends (2), (3), ...
Keeping windows open
Pass destroy_window=False (or destroy_windows=False) to leave windows open after show_img/show_imgs returns. The names are tracked internally; call close_all to dismiss them later:
from img_show import show_img, close_all
show_img(img1, window_name='Step 1', destroy_window=False)
show_img(img2, window_name='Step 2', destroy_window=False)
# ... later
close_all()
close_all silently ignores windows that have already been closed by other means (for example by clicking the X button).
API reference
show_img(img, window_name=' ', wait_delay=0, do_wait=True, destroy_window=True)
Display a single image. Coerces and prepares the input, then either opens an OpenCV window or renders inline in Jupyter.
| Parameter | Type | Default | Description |
|---|---|---|---|
img |
Any | NumPy array, PyTorch tensor, or PIL image. | |
window_name |
str | ' ' |
Window title (also used as the caption in Jupyter). |
wait_delay |
int | 0 |
Milliseconds to wait for a keypress when do_wait=True. 0 waits indefinitely. |
do_wait |
bool | True |
When True, block on cv2.waitKey. When False, paint the window briefly and return. |
destroy_window |
bool | True |
When True, close the window after waiting. When False, leave it open and track it for close_all. |
Raises RuntimeError when OpenCV is missing, when a headless build is installed and the call is made outside Jupyter, or when no display environment is available outside Jupyter.
show_imgs(imgs, window_names=None, wait_delay=0, do_wait=True, destroy_windows=True)
Display multiple images. Each image opens its own window (or renders inline in Jupyter).
| Parameter | Type | Default | Description |
|---|---|---|---|
imgs |
Iterable[Any] | Collection of images. | |
window_names |
Iterable[str] | None | None |
Names matching imgs. When None, auto-generated as Image 1, Image 2, ... |
wait_delay |
int | 0 |
Same as show_img. |
do_wait |
bool | True |
Same as show_img. |
destroy_windows |
bool | True |
Same as show_img's destroy_window. |
Raises ValueError when len(window_names) != len(imgs). Same RuntimeError cases as show_img.
coerce_img(img) -> numpy.ndarray
Convert a NumPy array, PyTorch tensor, or PIL image into a displayable NumPy array. Returns a uint8, uint16, or normalized floating-point array depending on the input. Four-channel inputs remain four-channel; alpha compositing is applied only by the display path.
This function has no runtime requirements beyond NumPy and always works.
close_all() -> None
Close every window opened by show_img or show_imgs with destroy_window=False and clear the tracking set. Already-closed windows are ignored silently.
Raises RuntimeError when OpenCV is missing.
Module attributes
HAS_CV2: bool— True whencv2is importable.IS_HEADLESS: bool | None— True for a headless cv2 build, False for a GUI build, None when cv2 is missing or the provider cannot be identified.open_window_names: set[str]— Names of currently tracked windows. Modified byshow_img,show_imgs, andclose_all.
License
img-show is licensed under the MIT License.
Author
Ben Elfner
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file img_show-1.0.0.tar.gz.
File metadata
- Download URL: img_show-1.0.0.tar.gz
- Upload date:
- Size: 119.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1d2b46bfb38c66f1c4d6beb84bcfe68fc6846ff27d603ffb4324057472b5e534
|
|
| MD5 |
6e65f623102995ec227a2c99bcb2deb1
|
|
| BLAKE2b-256 |
fb40defa881acc77f65fb9e4f6d4c80ac9ef5906ed0ff1ead6de082ed0013d0f
|
File details
Details for the file img_show-1.0.0-py3-none-any.whl.
File metadata
- Download URL: img_show-1.0.0-py3-none-any.whl
- Upload date:
- Size: 13.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3286f40d053f122e187b57d47f75bafaec3ea8ff52436c369af72cae534d5aa7
|
|
| MD5 |
bbb778bc26bc65f286b3ed45d4f19de2
|
|
| BLAKE2b-256 |
eb2621f6484c3499bd5441c477952c72092d8fcf0e54d57d8812c5adc4f7f055
|