Pre-built Python bindings for OpenCV, the comprehensive open-source computer vision and image processing library with 2500+ algorithms
OpenCV's 2D Features Framework provides comprehensive tools for detecting, describing, and matching distinctive features in images. These features are essential for tasks like object recognition, image stitching, 3D reconstruction, and visual tracking.
Patent-free since 2020, SIFT is one of the most robust feature detection algorithms, invariant to scale, rotation, and illumination changes.
cv2.SIFT_create(
nfeatures=0, # Number of best features to retain (0 = all)
nOctaveLayers=3, # Number of layers in each octave
contrastThreshold=0.04, # Contrast threshold for filtering weak features
edgeThreshold=10, # Edge threshold for filtering edge responses
sigma=1.6 # Gaussian sigma for the first octave
) -> cv2.SIFTReturns: SIFT detector/descriptor object
Common usage:
sift = cv2.SIFT_create()
keypoints, descriptors = sift.detectAndCompute(image, None)A fast, efficient alternative to SIFT and SURF, ORB is rotation invariant and resistant to noise.
cv2.ORB_create(
nfeatures=500, # Maximum number of features to retain
scaleFactor=1.2, # Pyramid decimation ratio
nlevels=8, # Number of pyramid levels
edgeThreshold=31, # Size of border where features are not detected
firstLevel=0, # Level of pyramid to put source image
WTA_K=2, # Number of points for BRIEF descriptor (2, 3, 4)
scoreType=cv2.ORB_HARRIS_SCORE, # HARRIS_SCORE or FAST_SCORE
patchSize=31, # Size of patch used by oriented BRIEF
fastThreshold=20 # FAST threshold
) -> cv2.ORBReturns: ORB detector/descriptor object
Score types:
cv2.ORB_HARRIS_SCORE - Harris corner measure for ranking featurescv2.ORB_FAST_SCORE - FAST score for ranking featuresA fast variant of KAZE that uses binary descriptors, providing good performance with lower computational cost.
cv2.AKAZE_create(
descriptor_type=cv2.AKAZE_DESCRIPTOR_MLDB, # Descriptor type
descriptor_size=0, # Size of descriptor (0 = full size)
descriptor_channels=3, # Number of channels in descriptor
threshold=0.001, # Detector response threshold
nOctaves=4, # Number of octaves
nOctaveLayers=4, # Number of sublevels per octave
diffusivity=cv2.KAZE_DIFF_PM_G2 # Diffusivity type
) -> cv2.AKAZEReturns: AKAZE detector/descriptor object
Descriptor types:
cv2.AKAZE_DESCRIPTOR_KAZE - Upright KAZE descriptorcv2.AKAZE_DESCRIPTOR_KAZE_UPRIGHT - Upright KAZE descriptorcv2.AKAZE_DESCRIPTOR_MLDB - Modified Local Difference Binary descriptorcv2.AKAZE_DESCRIPTOR_MLDB_UPRIGHT - Upright MLDB descriptorDiffusivity types:
cv2.KAZE_DIFF_PM_G1 - Perona-Malik diffusivitycv2.KAZE_DIFF_PM_G2 - Perona-Malik diffusivity (default)cv2.KAZE_DIFF_WEICKERT - Weickert diffusivitycv2.KAZE_DIFF_CHARBONNIER - Charbonnier diffusivityA binary descriptor algorithm that is fast and provides good performance for real-time applications.
cv2.BRISK_create(
thresh=30, # AGAST detection threshold score
octaves=3, # Detection octaves (0 = single scale)
patternScale=1.0 # Scale of sampling pattern
) -> cv2.BRISKReturns: BRISK detector/descriptor object
A multiscale feature detection and description algorithm using nonlinear diffusion filtering.
cv2.KAZE_create(
extended=False, # Use extended 128-element descriptor
upright=False, # Use upright (non-rotation invariant) descriptor
threshold=0.001, # Detector response threshold
nOctaves=4, # Number of octaves
nOctaveLayers=4, # Number of sublevels per octave
diffusivity=cv2.KAZE_DIFF_PM_G2 # Diffusivity type
) -> cv2.KAZEReturns: KAZE detector/descriptor object
Detects blobs (regions of connected pixels) in images based on various properties like size, color, shape, and convexity.
cv2.SimpleBlobDetector_create(
parameters=None # SimpleBlobDetector_Params object
) -> cv2.SimpleBlobDetectorReturns: SimpleBlobDetector object
Parameters class:
params = cv2.SimpleBlobDetector_Params()
# Threshold parameters
params.minThreshold = 50
params.maxThreshold = 220
params.thresholdStep = 10
# Filter by area
params.filterByArea = True
params.minArea = 100
params.maxArea = 5000
# Filter by circularity
params.filterByCircularity = True
params.minCircularity = 0.1
# Filter by convexity
params.filterByConvexity = True
params.minConvexity = 0.87
# Filter by inertia
params.filterByInertia = True
params.minInertiaRatio = 0.01
# Filter by color
params.filterByColor = True
params.blobColor = 255 # 0 for dark blobs, 255 for light blobs
detector = cv2.SimpleBlobDetector_create(params)Detects stable regions in images across different threshold levels, useful for text detection and wide baseline matching.
cv2.MSER_create(
delta=5, # Delta for MSER test
min_area=60, # Minimum area of region
max_area=14400, # Maximum area of region
max_variation=0.25, # Maximum variation in region stability
min_diversity=0.2, # Minimum diversity
max_evolution=200, # Maximum evolution steps
area_threshold=1.01, # Area threshold for filtering
min_margin=0.003, # Minimum margin
edge_blur_size=5 # Edge blur size
) -> cv2.MSERReturns: MSER detector object
Note: MSER.detect() returns regions as contours, not KeyPoint objects.
A high-speed corner detection algorithm, often used as the first stage in feature detection pipelines.
cv2.FastFeatureDetector_create(
threshold=10, # Threshold on difference between intensity
nonmaxSuppression=True, # Apply non-maximum suppression
type=cv2.FAST_FEATURE_DETECTOR_TYPE_9_16 # FAST detector type
) -> cv2.FastFeatureDetectorReturns: FAST detector object
Detector types:
cv2.FAST_FEATURE_DETECTOR_TYPE_5_8 - 8 pixels on circle of radius 1cv2.FAST_FEATURE_DETECTOR_TYPE_7_12 - 12 pixels on circle of radius 2cv2.FAST_FEATURE_DETECTOR_TYPE_9_16 - 16 pixels on circle of radius 3An improved version of FAST with better performance and adaptivity.
cv2.AgastFeatureDetector_create(
threshold=10, # Threshold on difference between intensity
nonmaxSuppression=True, # Apply non-maximum suppression
type=cv2.AGAST_FEATURE_DETECTOR_OAST_9_16 # AGAST detector type
) -> cv2.AgastFeatureDetectorReturns: AGAST detector object
Detector types:
cv2.AGAST_FEATURE_DETECTOR_AGAST_5_8 - AGAST-5_8 decision treecv2.AGAST_FEATURE_DETECTOR_AGAST_7_12d - AGAST-7_12d decision treecv2.AGAST_FEATURE_DETECTOR_AGAST_7_12s - AGAST-7_12s decision treecv2.AGAST_FEATURE_DETECTOR_OAST_9_16 - OAST-9_16 decision treeShi-Tomasi corner detector, which finds the most prominent corners in an image.
cv2.GFTTDetector_create(
maxCorners=1000, # Maximum number of corners to return
qualityLevel=0.01, # Minimal accepted quality of corners
minDistance=1, # Minimum distance between corners
blockSize=3, # Size of averaging block
useHarrisDetector=False, # Use Harris detector (vs. Shi-Tomasi)
k=0.04 # Free parameter of Harris detector
) -> cv2.GFTTDetectorReturns: GFTT detector object
All feature detectors inherit from the Feature2D base class and share these common methods:
detector.detect(
image, # Input image (grayscale)
mask=None # Optional mask specifying detection region
) -> keypointsReturns: List of KeyPoint objects
detector.compute(
image, # Input image (grayscale)
keypoints # List of KeyPoint objects to compute descriptors for
) -> keypoints, descriptorsReturns:
keypoints - Input keypoints (may be modified)descriptors - Computed descriptors as numpy array (N × descriptor_size)detector.detectAndCompute(
image, # Input image (grayscale)
mask=None # Optional mask specifying detection region
) -> keypoints, descriptorsReturns:
keypoints - List of detected KeyPoint objectsdescriptors - Computed descriptors as numpy array (N × descriptor_size)Note: detectAndCompute() is more efficient than calling detect() and compute() separately.
detector.empty() -> boolReturns: True if the detector object is empty
detector.getDefaultName() -> strReturns: Algorithm name as string
Matches descriptors by comparing each descriptor in the first set against all descriptors in the second set using a specified distance metric.
cv2.BFMatcher_create(
normType=cv2.NORM_L2, # Distance norm type
crossCheck=False # Enable cross-check for more robust matching
) -> cv2.BFMatcher
# Alternative constructor
cv2.BFMatcher(
normType=cv2.NORM_L2,
crossCheck=False
) -> cv2.BFMatcherReturns: BFMatcher object
Norm types:
cv2.NORM_L1 - L1 norm (Manhattan distance)cv2.NORM_L2 - L2 norm (Euclidean distance) - for SIFT, SURFcv2.NORM_HAMMING - Hamming distance - for ORB, BRISK, BRIEFcv2.NORM_HAMMING2 - Hamming distance with 2 bits per dimensioncv2.NORM_INF - Infinity normCross-check: When enabled, only returns matches (i,j) where descriptor i in set A is the best match for descriptor j in set B, and vice versa.
Fast Library for Approximate Nearest Neighbors (FLANN) based matcher, faster than brute-force for large datasets.
cv2.FlannBasedMatcher_create() -> cv2.FlannBasedMatcher
# Constructor with index parameters
cv2.FlannBasedMatcher(
indexParams=None, # Index parameters dictionary
searchParams=None # Search parameters dictionary
) -> cv2.FlannBasedMatcherReturns: FlannBasedMatcher object
Index parameters examples:
# For SIFT/SURF descriptors (float)
index_params = dict(algorithm=1, trees=5) # FLANN_INDEX_KDTREE
# For ORB descriptors (binary)
index_params = dict(
algorithm=6, # FLANN_INDEX_LSH
table_number=6,
key_size=12,
multi_probe_level=1
)Search parameters:
search_params = dict(checks=50) # Number of times trees should be recursively traversedFLANN algorithm constants:
FLANN_INDEX_LINEAR = 0 - Linear brute-force searchFLANN_INDEX_KDTREE = 1 - Randomized kd-tree (for float descriptors)FLANN_INDEX_KMEANS = 2 - Hierarchical k-means treeFLANN_INDEX_COMPOSITE = 3 - Combination of trees and kmeansFLANN_INDEX_KDTREE_SINGLE = 4 - Single kd-treeFLANN_INDEX_HIERARCHICAL = 5 - Hierarchical clusteringFLANN_INDEX_LSH = 6 - Locality-sensitive hashing (for binary descriptors)Both BFMatcher and FlannBasedMatcher inherit from DescriptorMatcher and share these methods:
matcher.match(
queryDescriptors, # Query descriptors (N1 × descriptor_size)
trainDescriptors, # Train descriptors (N2 × descriptor_size)
mask=None # Optional mask for valid matches
) -> matchesReturns: List of DMatch objects (best match for each query descriptor)
matcher.knnMatch(
queryDescriptors, # Query descriptors
trainDescriptors, # Train descriptors
k, # Number of best matches to return per descriptor
mask=None, # Optional mask
compactResult=False # Remove empty matches from result
) -> matchesReturns: List of lists of DMatch objects (k best matches per query descriptor)
Common usage with ratio test:
matches = matcher.knnMatch(desc1, desc2, k=2)
# Apply Lowe's ratio test
good_matches = []
for m, n in matches:
if m.distance < 0.75 * n.distance:
good_matches.append(m)matcher.radiusMatch(
queryDescriptors, # Query descriptors
trainDescriptors, # Train descriptors
maxDistance, # Maximum allowed distance
mask=None, # Optional mask
compactResult=False # Remove empty matches from result
) -> matchesReturns: List of lists of DMatch objects (all matches within maxDistance)
matcher.add(
descriptors # List of descriptor arrays to add to training set
) -> NoneAdds descriptors to the training set for multi-image matching.
matcher.train() -> NoneTrains the matcher (required for some FLANN-based matchers).
matcher.clear() -> NoneClears the training descriptor set.
matcher.empty() -> boolReturns: True if the matcher has no training data
Draws keypoints on an image, optionally showing their size, orientation, and other properties.
cv2.drawKeypoints(
image, # Source image
keypoints, # List of KeyPoint objects to draw
outImage, # Output image (can be the same as input)
color=(0, 255, 0), # Keypoint color (B, G, R)
flags=cv2.DRAW_MATCHES_FLAGS_DEFAULT # Drawing flags
) -> outImageReturns: Output image with keypoints drawn
Drawing flags:
cv2.DRAW_MATCHES_FLAGS_DEFAULT - Simple circles at keypoint locationscv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS - Draw circles with size and orientationcv2.DRAW_MATCHES_FLAGS_NOT_DRAW_SINGLE_POINTS - Don't draw single pointscv2.DRAW_MATCHES_FLAGS_DRAW_OVER_OUTIMG - Draw on existing output imageUsage:
# Simple drawing
img_keypoints = cv2.drawKeypoints(img, keypoints, None, color=(0, 255, 0))
# Rich keypoints showing size and orientation
img_keypoints = cv2.drawKeypoints(
img, keypoints, None,
color=(0, 255, 0),
flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS
)Draws matches between keypoints from two images side by side.
cv2.drawMatches(
img1, # First source image
keypoints1, # Keypoints from first image
img2, # Second source image
keypoints2, # Keypoints from second image
matches1to2, # List of DMatch objects
outImg, # Output image (None = create new)
matchColor=(0, 255, 0), # Color for matches (B, G, R)
singlePointColor=(255, 0, 0), # Color for single points
matchesMask=None, # Mask determining which matches to draw
flags=cv2.DRAW_MATCHES_FLAGS_DEFAULT # Drawing flags
) -> outImgReturns: Output image showing both images with matches drawn between them
Parameters:
matchesMask - List of bytes (0/1) same length as matches, 1 = draw matchmatchColor - Color for match lines, or tuple for random colors per matchsinglePointColor - Color for keypoints without matchesUsage:
# Draw all matches
img_matches = cv2.drawMatches(
img1, kp1, img2, kp2, matches,
None, flags=cv2.DRAW_MATCHES_FLAGS_NOT_DRAW_SINGLE_POINTS
)
# Draw only good matches with mask
mask = [[1] if m.distance < 50 else [0] for m in matches]
img_matches = cv2.drawMatches(
img1, kp1, img2, kp2, matches, None,
matchesMask=mask, flags=cv2.DRAW_MATCHES_FLAGS_NOT_DRAW_SINGLE_POINTS
)Draws k best matches for each keypoint from two images.
cv2.drawMatchesKnn(
img1, # First source image
keypoints1, # Keypoints from first image
img2, # Second source image
keypoints2, # Keypoints from second image
matches1to2, # List of lists of DMatch objects (from knnMatch)
outImg, # Output image (None = create new)
matchColor=(0, 255, 0), # Color for matches
singlePointColor=(255, 0, 0), # Color for single points
matchesMask=None, # Mask for matches (list of lists)
flags=cv2.DRAW_MATCHES_FLAGS_DEFAULT # Drawing flags
) -> outImgReturns: Output image showing both images with k best matches per keypoint
Usage with ratio test:
# Get k=2 best matches
matches = matcher.knnMatch(desc1, desc2, k=2)
# Apply ratio test and create mask
mask = []
for m, n in matches:
if m.distance < 0.75 * n.distance:
mask.append([1, 0]) # Draw first match only
else:
mask.append([0, 0]) # Don't draw
img_matches = cv2.drawMatchesKnn(
img1, kp1, img2, kp2, matches, None,
matchesMask=mask
)Represents a detected feature point with its properties.
cv2.KeyPoint(
x, # X coordinate
y, # Y coordinate
size, # Diameter of meaningful keypoint neighborhood
angle=-1, # Orientation in degrees [0, 360)
response=0, # Response strength
octave=0, # Pyramid octave where keypoint was detected
class_id=-1 # Object class (for categorized keypoints)
) -> cv2.KeyPointAttributes:
pt - (x, y) tuple of keypoint coordinatessize - Diameter of the meaningful keypoint neighborhoodangle - Computed orientation of the keypoint (-1 if not applicable)response - Response strength (used for keypoint ranking)octave - Pyramid octave in which keypoint was detectedclass_id - Object ID for categorizing keypointsMethods:
# Convert keypoints to numpy array of (x, y) coordinates
points = cv2.KeyPoint_convert(keypoints)
# Convert numpy array to keypoints
keypoints = cv2.KeyPoint_convert(points, size=20)
# Get overlap between two keypoints
overlap = cv2.KeyPoint_overlap(kp1, kp2) # Returns 0-1Represents a match between two feature descriptors.
cv2.DMatch(
queryIdx, # Query descriptor index
trainIdx, # Train descriptor index
distance # Distance between descriptors (lower is better)
) -> cv2.DMatch
# Constructor with image index (for multi-image matching)
cv2.DMatch(
queryIdx,
trainIdx,
imgIdx, # Train image index
distance
) -> cv2.DMatchAttributes:
queryIdx - Index of descriptor in query settrainIdx - Index of descriptor in train setimgIdx - Index of train image (for multi-image matching)distance - Distance between descriptors (lower = better match)Usage:
# Sort matches by distance (best matches first)
matches = sorted(matches, key=lambda x: x.distance)
# Get top N matches
good_matches = matches[:50]
# Extract matched keypoint coordinates
src_pts = np.float32([kp1[m.queryIdx].pt for m in matches])
dst_pts = np.float32([kp2[m.trainIdx].pt for m in matches])import cv2
import numpy as np
# Read images
img1 = cv2.imread('image1.jpg', cv2.IMREAD_GRAYSCALE)
img2 = cv2.imread('image2.jpg', cv2.IMREAD_GRAYSCALE)
# Create detector
detector = cv2.SIFT_create()
# Detect and compute
kp1, desc1 = detector.detectAndCompute(img1, None)
kp2, desc2 = detector.detectAndCompute(img2, None)
# Create matcher
matcher = cv2.BFMatcher(cv2.NORM_L2, crossCheck=False)
# Match descriptors
matches = matcher.knnMatch(desc1, desc2, k=2)
# Apply ratio test
good_matches = []
for m, n in matches:
if m.distance < 0.75 * n.distance:
good_matches.append(m)
# Draw matches
img_matches = cv2.drawMatches(
img1, kp1, img2, kp2, good_matches, None,
flags=cv2.DRAW_MATCHES_FLAGS_NOT_DRAW_SINGLE_POINTS
)
cv2.imshow('Matches', img_matches)
cv2.waitKey(0)# Extract matched point coordinates
if len(good_matches) >= 4:
src_pts = np.float32([kp1[m.queryIdx].pt for m in good_matches]).reshape(-1, 1, 2)
dst_pts = np.float32([kp2[m.trainIdx].pt for m in good_matches]).reshape(-1, 1, 2)
# Find homography
H, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0)
# Use homography to transform image
h, w = img1.shape
img1_warped = cv2.warpPerspective(img1, H, (w, h))# Create mask (detect features only in specific region)
mask = np.zeros(img.shape[:2], dtype=np.uint8)
mask[100:400, 200:600] = 255 # ROI
# Detect keypoints in masked region
keypoints = detector.detect(img, mask=mask)
keypoints, descriptors = detector.compute(img, keypoints)Install with Tessl CLI
npx tessl i tessl/pypi-opencv-python