Core Concepts and Package Features

This page provides a detailed explanation of the core concepts and distinctive features that make cv3 a powerful and user-friendly wrapper for OpenCV.

RGB Format by Default

cv3 uses RGB format by default for images, which is more intuitive for most Python developers. This behavior can be changed globally using cv3.opt.RGB. The global RGB setting affects all modules: image/video reading/writing, drawing functions, and other operations.

import cv3

# By default, cv3 reads images in RGB mode (unlike OpenCV which uses BGR)
img = cv3.imread('image.jpg')  # Read in RGB format by default
print(cv3.opt.RGB)  # True (default)

# You can switch to BGR mode globally
cv3.opt.set_bgr()  # Sets RGB=False
print(cv3.opt.RGB)  # False
img_bgr = cv3.imread('image.jpg')  # Now reads in BGR format

# Or switch back to RGB mode
cv3.opt.set_rgb()  # Sets RGB=True
print(cv3.opt.RGB)  # True

Auto Scaling with Relative Coordinates

Many cv3 functions support relative coordinates, making it easier to work with images of different sizes. Coordinates between 0 and 1 are automatically detected as relative, but you can also explicitly set rel=True to force relative coordinate interpretation. This feature is available in both drawing and transformation functions.

Warning

It is highly recommended to explicitly set rel=True when you know your coordinates are relative. While cv3 can automatically detect relative coordinates in the range [0, 1], explicitly setting rel=True makes your code more readable and prevents potential issues with absolute coordinates that happen to be in this range.

Drawing with Relative Coordinates

import cv3

img = cv3.zeros(400, 600, 3)  # 600x400 image

# Draw a rectangle at 10% from left, 20% from top,
# with width 30% of image width and height 25% of image height
cv3.rectangle(img, 0.1, 0.2, 0.4, 0.45, rel=True)

# Draw a circle at center of image with radius 10% of image width
cv3.circle(img, 0.5, 0.5, 0.1, rel=True)

Transformations with Relative Coordinates

Coordinates between 0 and 1 are automatically detected as relative in transformation functions, but you can also explicitly set rel=True to force relative coordinate interpretation.

import cv3

img = cv3.imread('image.jpg')

# Shift image by 10% of width to the right and 5% of height down
shifted = cv3.shift(img, 0.1, 0.05, rel=True)

# Pad image with 5% of width on left/right and 3% of height on top/bottom
padded = cv3.pad(img, 0.03, 0.03, 0.05, 0.05, rel=True)

# Crop with relative coordinates
cropped = cv3.crop(img, 0.25, 0.25, 0.75, 0.75, rel=True)

Combined Scale and Rotate with cv3.transform

The cv3.transform function provides a convenient way to apply both rotation and scaling in a single operation, which is more efficient than applying them separately.

import cv3

img = cv3.imread('image.jpg')

# Rotate by 30 degrees and scale by 1.5 in one operation
transformed = cv3.transform(img, angle=30, scale=1.5)

# Compare with cv2 approach which requires more steps
# (h, w) = img.shape[:2]
# center = (w // 2, h // 2)
# M = cv2.getRotationMatrix2D(center, 30, 1.5)
# transformed = cv2.warpAffine(img, M, (w, h))

Dynamic Typing Support

cv3 functions are designed to be flexible with input types, automatically handling conversions where appropriate. This includes supporting float image formats with values in the range [0, 1] which are automatically scaled to [0, 255] and converted to uint8, as well as supporting floating-point coordinates.

Handling Float Image Formats

import cv3

# Get a float image (not uint8)
img = cv3.imread('image.jpg')
norm_img = img.astype(float) / 255 # from 0 to 1

# cv3 functions automatically handle the type conversion
cropped = cv3.crop(norm_img, 170, 20, 270, 120)
print(cropped.dtype)  # uint8

# Drawing on float images also works
img_rect = cv3.rectangle(norm_img, 170, 20, 270, 120, color=(1.0, 0.0, 0.0))

Handling Floating-Point Coordinates

cv3 functions support floating-point coordinates, which are automatically converted to integers. Coordinates between 0 and 1 are automatically detected as relative coordinates.

import cv3

img = cv3.zeros(100, 100, 3)

# Float coordinates are automatically converted to integers
cv3.rectangle(img, 10.7, 20.3, 50.9, 80.1)  # Works fine
cropped = cv3.crop(img, 25.5, 30.8, 75.2, 80.9)  # Also works fine

Unified Video Interface

The video module provides classes and functions for reading and writing video files with automatic color space conversion and enhanced error handling through the cv3.Video factory function.

Video Reading

Reading video files is straightforward with cv3. The Video class provides convenient properties for accessing video metadata.

import cv3

# Reading video with context manager
with cv3.Video('input.mp4') as reader:
    print(f"Video dimensions: {reader.width}x{reader.height}")
    print(f"Frame rate: {reader.fps}")
    print(f"Total frames: {len(reader)}")

    # Iterate through frames
    for i, frame in enumerate(reader):
        if i < 5:  # Process first 5 frames
            processed = process_frame(frame)
            # Do something with processed frame
    # width and height are available after initialization
    print(f"Video dimensions: {reader.width}x{reader.height}")
    print(f"Frame rate: {reader.fps}")

Video Writing

Writing videos is equally simple. Note that width and height are initialized after writing the first frame, and subsequent frames are checked for dimension matching.

import cv3

# Writing video with context manager
with cv3.Video('output.mp4', 'w') as writer:
    print(f"Output dimensions: {writer.width} x {writer.height}") # None x None
    # Write frames

    for frame in cv3.Video('input.mp4'):
        writer.write(frame)

    print(f"Output dimensions: {writer.width}x{writer.height}")
    print(f"Frame rate: {writer.fps}")

Using Video Streams Without Context Managers

You can also use video streams without context managers, but you’ll need to manually release resources.

import cv3

# You can also use it without context manager
reader = cv3.Video('input.mp4')
writer = cv3.Video('output.mp4', 'w')

# Don't forget to release resources manually when not using context managers
reader.close() # or reader.release()
writer.close() # or writer.release()

Video Reading Features

The cv3.VideoCapture class (accessible through cv3.Video with mode=’r’, which is the default) provides convenient features for video reading, including list comprehension for processing all frames, frame indexing, and current frame access.

import cv3

with cv3.Video('input.mp4') as cap:
    # Process all frames with list comprehension
    frames = [cv3.resize(frame, 10, 10) for frame in cap]

    # Rewind the video
    cap.rewind(0)  # or cap.seek(0)

    frame = cap.read()

    # Get current frame index (it's 1)
    current_frame = cap.now

    # Access a specific frame by index
    frame = cap[100]  # Get frame at index 100

    # Get current frame index (it's 101)
    current_frame = cap.now

    # Get total number of frames
    total_frames = len(cap)

Video Writing Features

The cv3.VideoWriter class (accessible through cv3.Video with mode=’w’) provides an enhanced interface for writing video files with customizable encoding parameters and automatic color space conversion.

Key features of Video Writing:

  • Automatic Initialization: The underlying OpenCV VideoWriter stream is initialized only when the first frame is written, allowing for dynamic determination of video dimensions.

  • Default Parameters: By default, videos are written with 30 FPS and ‘mp4v’ codec (FOURCC), but these can be customized (see cv3.opt.video())

  • Shape Validation: Ensures all frames written to the video have the same dimensions as the first frame.

  • Automatic Directory Creation: When mkdir=True is specified, parent directories are automatically created if they don’t exist.

  • Color Space Conversion: Automatically converts RGB images to BGR format for writing (if cv3.opt.RGB is True, which is the default).

import cv3

# Create a video writer with default settings (30 FPS, 'mp4v' codec)
writer = cv3.Video('output.mp4', 'w')

# Create a video writer with custom FPS
writer = cv3.Video('output.mp4', 'w', fps=60)

# Create a video writer with custom codec
writer = cv3.Video('output.mp4', 'w', fourcc='mp4v')

# Create a video writer with automatic directory creation
writer = cv3.Video('output/video/result.mp4', 'w', mkdir=True)

# Writing frames
frame = cv3.imread('image.jpg')
writer.write(frame)  # Stream is initialized here with frame dimensions

# Using context manager for automatic resource cleanup
with cv3.Video('output.mp4', 'w') as writer:
    writer.write(frame)

File Path Handling and Automatic Directory Creation

cv3 functions accept pathlib.Path objects in addition to string paths, making it easier to work with modern Python path handling. When writing files, cv3 can automatically create directories if they don’t exist using the mkdir=True parameter.

import cv3
from pathlib import Path

# Using pathlib.Path objects
image_path = Path('images') / 'photo.jpg'
img = cv3.imread(image_path)

# Save to a pathlib.Path with automatic directory creation
output_path = Path('output') / 'result.jpg'
cv3.imwrite(output_path, img, mkdir=True)  # Automatically creates directories

img = cv3.zeros(100, 100, 3)

# This will automatically create the 'output/nested' directory structure
cv3.imwrite('output/nested/result.jpg', img, mkdir=True)

# For videos too
with cv3.Video('output/video/result.mp4', 'w', mkdir=True) as writer:
    writer.write(img)

Window Interface with Context Manager

cv3 provides a clean window interface with context managers for automatic resource cleanup.

import cv3

img = cv3.zeros(200, 200, 3)
cv3.rectangle(img, 50, 50, 150, 150)

# Using context manager for automatic cleanup
with cv3.Window('Demo Window', pos=(100, 100)) as window:
    window.imshow(img)
    window.wait_key(0)  # Press any key to continue

# Multiple windows with context manager
with cv3.Windows(['Window1', 'Window2']) as windows:
    windows['Window1'].imshow(img)
    windows['Window2'].imshow(img)
    cv3.wait_key(0)  # Press any key to close all windows

# Display video from webcam
with cv3.Window('Webcam') as window:
    for frame in cv3.Video(0):
        window.imshow(frame)
        if cv3.wait_key(1) == ord('q'):
            break

Coordinate Format Flexibility

cv3 drawing and cropping functions support multiple coordinate formats, making it easier to work with different data sources.

import cv3

img = cv3.zeros(100, 100, 3)

# Default mode is 'xyxy' (x0, y0, x1, y1)
cv3.rectangle(img, 10, 10, 50, 50)

# 'xywh' mode (x, y, width, height)
cv3.rectangle(img, 60, 10, 30, 30, mode='xywh')

# 'ccwh' mode (center_x, center_y, width, height)
cv3.rectangle(img, 25, 75, 30, 30, mode='ccwh')

# Cropping with different modes
cropped1 = cv3.crop(img, 10, 10, 70, 70)  # xyxy
cropped2 = cv3.crop(img, 10, 10, 40, 40, mode='xywh')  # xywh

Drawing Functions

cv3 provides a comprehensive set of drawing functions with enhanced features compared to OpenCV. These functions support relative coordinates, flexible color handling, and various coordinate formats.

cv3 provides standard drawing functions like rectangle, circle, text, polylines, fill_poly, etc.

import cv3

# Example with poly functions
pts = [
    [30, 30],
    [160, 30],
    [45, 150]
]

canvas = cv3.zeros(200, 200, 3)
cv3.rectangle(canvas, 10, 10, 100, 100, color='blue')
cv3.circle(canvas, 150, 50, 30, color='red')
cv3.text(canvas, "Hello", 50, 150, color='green')
cv3.polylines(canvas, pts, is_closed=True, color='red', t=5)
cv3.fill_poly(canvas, pts, color='yellow')

Drawing with Relative Coordinates

Many cv3 drawing functions support relative coordinates. Coordinates between 0 and 1 are automatically detected as relative, but you can also explicitly set rel=True to force relative coordinate interpretation.

import cv3

img = cv3.zeros(400, 600, 3)  # 600x400 image

# Draw a rectangle at 10% from left, 20% from top,
# with width 30% of image width and height 25% of image height
cv3.rectangle(img, 0.1, 0.2, 0.4, 0.45, rel=True)

# Draw text at 50% from left, 80% from top
cv3.text(img, "Hello World", 0.5, 0.8, rel=True, scale=1.5)

Fill Parameter

The fill parameter allows you to create filled shapes.

import cv3

img = cv3.zeros(200, 200, 3)

# Filled rectangle
cv3.rectangle(img, 20, 20, 80, 80, fill=True, color='red')

# Filled circle
cv3.circle(img, 150, 50, 30, fill=True, color='blue')

Non-Destructive Drawing

By default, cv3 drawing functions modify images in-place, but you can use the copy=True parameter to avoid modifying the original image.

import cv3

img = cv3.zeros(100, 100, 3)

# Default behavior: modifies original image
cv3.rectangle(img, 10, 10, 50, 50)  # img is now modified

# Non-destructive drawing: creates a copy
img2 = cv3.zeros(100, 100, 3)
result = cv3.rectangle(img2, 10, 10, 50, 50, copy=True)
# img2 is unchanged, result contains the drawing

Color Handling

cv3 provides flexible color handling in drawing functions. Available named colors can be found in cv3.COLORS.

import cv3

img = cv3.zeros(100, 100, 3)

# Named colors
cv3.rectangle(img, 10, 10, 50, 50, color='red')
cv3.circle(img, 75, 25, 10, color='blue')

# RGB tuples
cv3.rectangle(img, 10, 60, 50, 90, color=(0, 255, 0))  # Green

# RGB tuples with relative values (0.0 to 1.0)
cv3.rectangle(img, 60, 60, 90, 90, color=(0.0, 1.0, 1.0))  # Cyan

# Single value for grayscale
gray_img = cv3.zeros(100, 100)
cv3.rectangle(gray_img, 10, 10, 50, 50, color=128)  # Gray

Border Colors in Transformations

cv3 also provides flexible color handling in transformations that require border values.

import cv3

img = cv3.zeros(100, 100, 3)

# Shift with border color
shifted = cv3.shift(img, 20, 10, value=(255, 0, 0))  # Red border

# Pad with border color
padded = cv3.pad(img, 10, 10, 10, 10, value='green')

Clear Error Messages

cv3 provides more informative error messages compared to raw OpenCV, making it easier to debug issues.

import cv3

# Trying to read a non-existent file
try:
    img = cv3.imread('non_existent.jpg')
except FileNotFoundError as e:
    print(f"Clear error message: {e}")

# Trying to write to an invalid path without mkdir
try:
    img = cv3.zeros(100, 100, 3)
    cv3.imwrite('path/that/does/not/exist.jpg', img)
except OSError as e:
    print(f"Clear error message: {e}")

# OSError when file exists but cannot be read
try:
    img = cv3.imread('/path/to/directory')  # Trying to read a directory
except OSError as e:
    print(f"Clear error message: {e}")

# StopIteration when video stream ends
try:
    with cv3.Video('input.mp4') as cap:
        while True:
            frame = cap.read()
except StopIteration as exc:
    print(f"Video stream ended: {exc}")

Convenient Color Space Conversions

cv3 provides intuitive functions for color space conversions with clear naming conventions.

import cv3

img = cv3.zeros(100, 100, 3)  # RGB image

# Simple conversions with clear names
gray = cv3.rgb2gray(img)
hsv = cv3.rgb2hsv(img)
bgr = cv3.rgb2bgr(img)

# Reverse conversions
rgb_from_gray = cv3.gray2rgb(gray)
rgb_from_hsv = cv3.hsv2rgb(hsv)
rgb_from_bgr = cv3.bgr2rgb(bgr)

Global Options System

cv3 provides a centralized configuration system through cv3.opt that allows you to set default values for various parameters.

import cv3

# Set global defaults for drawing functions
cv3.opt.COLOR = 'red'  # Default color for drawing
cv3.opt.THICKNESS = 2  # Default thickness
cv3.opt.FONT = cv2.FONT_HERSHEY_SIMPLEX  # Default font

# Set global defaults for video
cv3.opt.video(fps=30, fourcc='mp4v')

# Set global defaults for drawing
cv3.opt.draw(thickness=3, color='blue')

# Now all drawing functions will use these defaults
img = cv3.zeros(100, 100, 3)
cv3.rectangle(img, 10, 10, 90, 90)  # Uses red color and thickness 2

Additional Functions

cv3 provides utility functions for common operations in the create and utils modules.

Image Creation Functions

import cv3

# Create images with different properties
black_img = cv3.zeros(100, 100, 3)  # Black RGB image
white_img = cv3.white(100, 100, 3)  # White RGB image
random_img = cv3.random(100, 100, 3)  # Random noise image
filled_img = cv3.full(100, 100, 3, value=(255, 128, 0))  # Orange image

Utility Functions

import cv3

# Coordinate conversion utilities
x0, y0, x1, y1 = cv3.utils.xywh2xyxy(10, 20, 30, 40)
x_rel, y_rel = cv3.utils.abs2rel(50, 75, width=100, height=100)