Colour segmentation and compositing (green screens, overlays, regions of interest) are built from masks.
cv2.inRange(img, lower, upper) returns a uint8 mask that is 255 where every channel lies within the inclusive bounds and 0 elsewhere. On an HSV image this is the classic colour detector:
mask = cv2.inRange(hsv, (35, 80, 60), (85, 255, 255)) # greensFor red, whose hue wraps around 0, combine two ranges with cv2.bitwise_or.
The bitwise functions work per pixel and per bit: cv2.bitwise_and, bitwise_or, bitwise_xor, bitwise_not. Their most useful form takes a mask= argument: cv2.bitwise_and(img, img, mask=mask) keeps the image where the mask is non-zero and blacks out the rest.
To composite one image onto another, cut a hole in the background with the inverted mask, keep the foreground with the mask, and add the two. cv2.addWeighted(a, alpha, b, beta, gamma) blends instead, for semi-transparent overlays such as heatmaps.
Masks must be single-channel uint8 of the same height and width as the image. A NumPy boolean mask works for indexing (img[mask > 0] = (0, 0, 255)), but cv2 functions want the uint8 form. Convert with mask.astype(np.uint8) * 255.
Example
import cv2
import numpy as np
img = np.zeros((50, 100, 3), np.uint8)
img[:, :50] = (0, 200, 0) # green half
img[:, 50:] = (0, 0, 200) # red half
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
green = cv2.inRange(hsv, (35, 80, 60), (85, 255, 255))
print(green.dtype, green[0, 10], green[0, 90]) # uint8 255 0
red = cv2.bitwise_or(cv2.inRange(hsv, (0, 80, 60), (10, 255, 255)),
cv2.inRange(hsv, (170, 80, 60), (179, 255, 255)))
print(red[0, 90]) # 255
only_green = cv2.bitwise_and(img, img, mask=green)
print(only_green[0, 90]) # [0 0 0] blacked out
bg = np.full_like(img, 255) # white background
comp = cv2.add(cv2.bitwise_and(bg, bg, mask=cv2.bitwise_not(green)), only_green)
print(comp[0, 10], comp[0, 90]) # [ 0 200 0] [255 255 255]
overlay = cv2.addWeighted(img, 0.7, bg, 0.3, 0)
print(overlay[0, 10]) # [ 76 216 76]Remember
cv2.inRangemakes a 0/255 mask from per-channel bounds- Combine masks with bitwise_or/and/not
bitwise_and(img, img, mask=m)keeps only the masked regionaddWeightedblends two images for overlays
Watch out for
- Passing a boolean or 3-channel mask to a cv2 function that expects single-channel uint8.