Welcome to K230 Vision Module repository
2. OpenCV API Reference
K230 OpenCV (cv2) API Reference
Based on K230 CanMV firmware, referencing original OpenCV demos and opencv_demo collection ⚠️ K230 specific limitations marked | 📎 Source code examples included
Color Space Conversion
| Function | Signature | Example Files |
|---|---|---|
cvtColor | cv2.cvtColor(src, code) | 01, 02, 13 |
COLOR_BGR2GRAY | BGR→Grayscale, most commonly used | |
COLOR_BGR2HSV | BGR→HSV, for color segmentation |
Example
xxxxxxxxxx# BGR → Grayscale (preprocessing for edge detection, thresholding, etc.)gray = cv2.cvtColor(img_np, cv2.COLOR_BGR2GRAY)
# BGR → HSV (must convert before inRange color segmentation)hsv = cv2.cvtColor(img_np, cv2.COLOR_BGR2HSV)Geometric Transformation
| Function | Signature | Example Files |
|---|---|---|
resize | cv2.resize(src, (w, h)) | 01 |
flip | cv2.flip(src, 1) 1=horizontal | 01 |
warpAffine | cv2.warpAffine(src, M, (w, h)) | 01 |
getRotationMatrix2D | cv2.getRotationMatrix2D((cx, cy), angle, scale) | 01 |
Example
xxxxxxxxxx# Horizontal flipimg_np[:,:,:] = cv2.flip(img_np, 1)
# Rotate 45 degrees + scale 0.7xM = cv2.getRotationMatrix2D((W//2, H//2), 45, 0.7)img_np[:,:,:] = cv2.warpAffine(img_np, M, (W, H))
# Downsample for speed (commonly used for heavy operations like HoughCircles/matchTemplate)small = cv2.resize(img_np, (320, 240))gray = cv2.cvtColor(small, cv2.COLOR_BGR2GRAY)Thresholding
| Function | Signature | Example Files |
|---|---|---|
threshold | cv2.threshold(src, thresh, maxval, type) | 02, 12 |
THRESH_BINARY | >thresh → maxval | |
THRESH_OTSU | Automatically calculate optimal threshold | |
adaptiveThreshold | cv2.adaptiveThreshold(src, maxVal, method, type, blockSize, C) | 12 |
Example
xxxxxxxxxx# Fixed threshold 127ret, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
# OTSU automatic threshold (works better when grayscale brightness is uneven)ret, binary = cv2.threshold(gray, 0, 255, cv2.THRESH_OTSU)
# Adaptive Gaussian threshold (scenarios with local illumination changes)binary = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2)Filtering (Blurring)
| Function | Signature | Example Files |
|---|---|---|
GaussianBlur | cv2.GaussianBlur(src, (k,k), sigma) | 05, 07, 10 |
blur | cv2.blur(src, (k,k)) | 10 |
medianBlur | cv2.medianBlur(src, k) | 10 |
bilateralFilter | cv2.bilateralFilter(src, d, sigmaColor, sigmaSpace) | 10 |
filter2D | cv2.filter2D(src, ddepth, kernel) | 10 |
Example
xxxxxxxxxx# Gaussian blur for denoising (required before Hough detection)blur = cv2.GaussianBlur(gray, (7, 7), 1.5)
# Median blur (remove salt-and-pepper noise)out = cv2.medianBlur(img_np, 7)
# Custom sharpening kernelsharpen = np.array([[-1.0,-1.0,-1.0],[-1.0,9.0,-1.0],[-1.0,-1.0,-1.0]])out = cv2.filter2D(img_np, -1, sharpen)Edge Detection
| Function | Signature | Example Files |
|---|---|---|
Canny | cv2.Canny(src, low, high) | 06, 11 |
Sobel | cv2.Sobel(src, ddepth, dx, dy) | 11 |
Laplacian | cv2.Laplacian(src, ddepth) | 11 |
Example
xxxxxxxxxx# Canny dual threshold edge detectionedges = cv2.Canny(gray, 80, 200)
# Grayscale output → displayimg_out = image.Image(W, H, image.GRAYSCALE, alloc=image.ALLOC_REF, data=edges)Display.show_image(img_out)
# Color overlay output (white edges + original image)edges = cv2.Canny(gray, 80, 200)img_np[:,:,0] = cv2.add(img_np[:,:,0], edges) # B channelimg_np[:,:,1] = cv2.add(img_np[:,:,1], edges) # G channelimg_np[:,:,2] = cv2.add(img_np[:,:,2], edges) # R channelDisplay.show_image(img)Morphology
| Function | Signature | Example Files |
|---|---|---|
getStructuringElement | cv2.getStructuringElement(shape, (k,k)) | 02 |
erode | cv2.erode(src, kernel) | 02 |
dilate | cv2.dilate(src, kernel) | 02 |
morphologyEx | cv2.morphologyEx(src, op, kernel) | 02, 07, 13 |
MORPH_OPEN | Opening (denoising) | |
MORPH_CLOSE | Closing (hole filling) |
Example
xxxxxxxxxx# Create structuring elementskr = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5)) # Rectangular kernelke = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3)) # Elliptic kernel
# Morphological operations on binary imagesret, binary = cv2.threshold(gray, 0, 255, cv2.THRESH_OTSU)closed = cv2.morphologyEx(binary, cv2.MORPH_CLOSE, kr) # Closing for hole fillingopened = cv2.morphologyEx(binary, cv2.MORPH_OPEN, ke) # Opening for denoisingContour Analysis
| Function | Signature | Example Files |
|---|---|---|
findContours | cv2.findContours(src, mode, method) | 03, 04, 07 |
contourArea | cv2.contourArea(cnt) | 03, 04, 07 |
arcLength | cv2.arcLength(cnt, closed) | 03, 04, 07 |
boundingRect | cv2.boundingRect(cnt) | 03, 07 |
approxPolyDP | cv2.approxPolyDP(cnt, epsilon, closed) | 03, 04, 07 |
| ⚠️ K230 returns (N,2) | Use pt[0] for index, not pt[0][0] | |
drawContours | cv2.drawContours(img, contours, idx, color, thickness) | 03, 04, 07 |
convexHull | cv2.convexHull(cnt) | 07 |
minEnclosingCircle | cv2.minEnclosingCircle(cnt) | 07 |
moments | cv2.moments(cnt) | 04 |
Example
xxxxxxxxxx# Complete contour pipelinecontours, _ = cv2.findContours(closed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)cnt_limit = 0for c in contours: area = cv2.contourArea(c) if area < 500: continue cnt_limit += 1 if cnt_limit > 50: break # Upper limit to prevent memory overflow
peri = cv2.arcLength(c, True) approx = cv2.approxPolyDP(c, 0.02 * peri, True) # Polygon approximation
x, y, w, h = cv2.boundingRect(c) cv2.drawContours(img_np, [approx], -1, (0, 255, 0), 2) cv2.rectangle(img_np, (x, y), (x + w, y + h), (0, 0, 255), 1) cnt_n += 1
# moments for centroid calculationm = cv2.moments(c)if m["m00"] > 0: cx = int(m["m10"] / m["m00"]) cy = int(m["m01"] / m["m00"])Feature Detection
| Function | Signature | Example Files |
|---|---|---|
HoughLines | cv2.HoughLines(edges, rho, theta, threshold) | 06 |
| ⚠️ K230 returns (N,2) | lines[i,0]=rho, lines[i,1]=theta | |
HoughLinesP | cv2.HoughLinesP(edges, rho, theta, thr, minLen, maxGap) | 06 |
HoughCircles | cv2.HoughCircles(src, method, dp, minDist, param1, param2, minR, maxR) | 05 |
| ⚠️ K230 returns (N,3) | circles[i,0]=x, [i,1]=y, [i,2]=r | |
matchTemplate | cv2.matchTemplate(src, templ, method) | 09 |
Example
xxxxxxxxxx# Hough circle detection (downsampled for speed)small = cv2.resize(img_np, (320, 240))gray = cv2.cvtColor(small, cv2.COLOR_BGR2GRAY)blur = cv2.GaussianBlur(gray, (7, 7), 1.5)circles = cv2.HoughCircles(blur, 3, dp=1, minDist=60, param1=100, param2=70, minRadius=10, maxRadius=100)if circles is not None: for i in range(circles.shape[0]): if i >= 30: break x = int(circles[i, 0]) * 2 # K230 returns (N,3), not (N,1,3) y = int(circles[i, 1]) * 2 # Coordinates ×2 back to 640x480 r = int(circles[i, 2]) * 2 cv2.circle(img_np, (x, y), 3, (0, 255, 0), -1) cv2.circle(img_np, (x, y), r, (0, 0, 255), 2)
# Template matchingrmap = cv2.matchTemplate(binary, templ, cv2.TM_CCOEFF_NORMED)minVal, maxVal, minLoc, maxLoc = cv2.minMaxLoc(rmap)if maxVal > 0.6: cv2.rectangle(img_np, (maxLoc[0], maxLoc[1]), (maxLoc[0] + TS, maxLoc[1] + TS), (0, 255, 0), 2)Color Processing
| Function | Signature | Example Files |
|---|---|---|
inRange | cv2.inRange(src, lower, upper) | 03, 13 |
Example
xxxxxxxxxx# HSV color segmentation + green overlayhsv = cv2.cvtColor(img_np, cv2.COLOR_BGR2HSV)lo = np.array([35, 60, 60]) # Green HSV lower boundhi = np.array([85, 255, 255]) # Green HSV upper boundmask = cv2.inRange(hsv, lo, hi)mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, ke) # Opening for denoisingimg_np[:,:,1] = cv2.add(img_np[:,:,1], mask) # Green channel overlayArithmetic and Bitwise Operations
| Function | Signature | Example Files |
|---|---|---|
add | cv2.add(src1, src2) | 13, 15 |
| ⚠️ Does not support scalar broadcasting | Both arrays must have the same size | |
absdiff | cv2.absdiff(src1, src2) | 15 |
addWeighted | cv2.addWeighted(src1, a, src2, b, gamma) | 15 |
bitwise_not | cv2.bitwise_not(src) | 15 |
bitwise_and | cv2.bitwise_and(src1, src2) | 15 |
bitwise_or | cv2.bitwise_or(src1, src2) | 13, 15 |
bitwise_xor | cv2.bitwise_xor(src1, src2) | 15 |
Example
xxxxxxxxxx# Frame difference (motion detection)if prev_np is not None: out = cv2.absdiff(img_np, prev_np) img_np[:,:,:] = out
# Inversion (negative effect)img_np[:,:,:] = cv2.bitwise_not(img_np)
# ⚠️ add requires same-size arrays (scalar broadcasting not supported)# Wrong: cv2.add(img_np, 50)# Correct: pre-allocate same-size arrayadd50 = np.zeros((H, W, 3), dtype=np.uint8)for c in range(W): add50[:, c, :] = 50out = cv2.add(img_np, add50_3ch)Pixel Transform
| Function | Signature | Example Files |
|---|---|---|
equalizeHist | cv2.equalizeHist(src) | 14 |
normalize | cv2.normalize(src, alpha, beta, norm_type) | 14 |
convertScaleAbs | cv2.convertScaleAbs(src, alpha, beta) | 14, 17 |
LUT | cv2.LUT(src, lut) | 14, 17 |
Example
xxxxxxxxxx# Histogram equalization (enhance contrast)out = cv2.equalizeHist(gray)
# convertScaleAbs: contrast ×1.5 brightness -30out = cv2.convertScaleAbs(gray, alpha=1.5, beta=-30)
# LUT inversion mappinglut = np.zeros((256, 1), dtype=np.uint8)for i in range(256): lut[i, 0] = 255 - iout = cv2.LUT(gray, lut)Channel Operations
| Function | Signature | Example Files |
|---|---|---|
split | cv2.split(src) | 16 |
merge | cv2.merge(channels) | 13, 15, 16 |
mean | cv2.mean(src) | 16 |
minMaxLoc | cv2.minMaxLoc(src) | 09 |
Example
xxxxxxxxxx# Split channels, display single channelb, g, r = cv2.split(img_np)img_out = image.Image(W, H, image.GRAYSCALE, alloc=image.ALLOC_REF, data=b)Display.show_image(img_out)
# Channel statisticsavg = cv2.mean(img_np) # Returns (B_mean, G_mean, R_mean)Drawing
| Function | Example Files |
|---|---|
line, rectangle, circle, ellipse | 08 |
putText, arrowedLine, drawMarker, fillPoly | 08 |
Example
xxxxxxxxxxcv2.line(img_np, (50, 80), (250, 80), (0, 255, 0), 3)cv2.rectangle(img_np, (50, 120), (200, 200), (0, 255, 255), 3)cv2.circle(img_np, (400, 160), 50, (0, 255, 0), 3)cv2.ellipse(img_np, (160, 320), (80, 40), 0, 0, 360, (0, 255, 0), 3)cv2.putText(img_np, "OpenCV K230", (220, 400), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 255), 2)cv2.drawMarker(img_np, (400, 260), (0, 255, 0), cv2.MARKER_CROSS, 20, 3)cv2.arrowedLine(img_np, (300, 80), (500, 80), (255, 0, 0), 3)
# fillPoly for triangle fillingtri = np.array([[80.0, 60.0], [160.0, 60.0], [120.0, 120.0]])cv2.fillPoly(img_np, [tri], (255, 100, 100), cv2.LINE_AA)File I/O (REPL exercises, no camera demo)
| Function | Example |
|---|---|
imread | img = cv2.imread("/sdcard/test.jpg") |
imwrite | cv2.imwrite("/sdcard/out.png", img) |
Display Method Quick Reference
# Color image (after modifying sensor native img, display)img_np[:,:,:] = cv2.flip(img_np, 1)Display.show_image(img)
# Grayscale image (cv2 output → image.Image wrapper)edges = cv2.Canny(gray, 80, 200)img_out = image.Image(W, H, image.GRAYSCALE, alloc=image.ALLOC_REF, data=edges)Display.show_image(img_out)
# ⚠️ Color images cannot use image.Image(RGB888, ALLOC_REF) to wrap cv2 output!