CV

示例代码

按场景分类的可运行示例,覆盖 C++ / Python / JavaScript。完整示例库见官方 GitHub samples 目录 ↗

基础操作

读取并显示图像(Python)

imread / imshow / waitKey 最小示例

Python
import cv2

img = cv2.imread("cat.jpg")          # BGR 顺序
if img is None:
    raise FileNotFoundError("无法读取图像")

cv2.imshow("image", img)
cv2.waitKey(0)                        # 等待按键
cv2.destroyAllWindows()

创建矩阵与访问像素(C++)

Mat 构造、at<> 访问、类型查看

C++
#include <opencv2/core.hpp>
#include <iostream>
using namespace cv;

int main() {
    Mat img(Size(640, 480), CV_8UC3, Scalar(0, 255, 0)); // 绿色图
    std::cout << "type=" << img.type()
              << " channels=" << img.channels() << "\n";

    Vec3b& px = img.at<Vec3b>(10, 10); // BGR
    px[0] = 255;                       // 蓝色分量
    return 0;
}

视频捕获与边缘检测(C++)

官方 Introduction 示例:摄像头 → 灰度 → 高斯模糊 → Canny

C++
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
using namespace cv;

int main(int, char**) {
    VideoCapture cap(0);
    if (!cap.isOpened()) return -1;

    Mat frame, edges;
    namedWindow("edges", WINDOW_AUTOSIZE);
    for (;;) {
        cap >> frame;   // frame 自动分配
        cvtColor(frame, edges, COLOR_BGR2GRAY);
        GaussianBlur(edges, edges, Size(7, 7), 1.5, 1.5);
        Canny(edges, edges, 0, 30, 3);   // edges 自动分配
        imshow("edges", edges);
        if (waitKey(30) >= 0) break;
    }
    return 0;
}

图像处理

自适应阈值二值化

光照不均场景下优于固定阈值

Python
import cv2

gray = cv2.cvtColor(cv2.imread("doc.jpg"), cv2.COLOR_BGR2GRAY)

# 固定阈值
_, th1 = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)

# 自适应阈值
th2 = cv2.adaptiveThreshold(
    gray, 255,
    cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
    cv2.THRESH_BINARY, 11, 2,
)
cv2.imwrite("binary.png", th2)

轮廓检测与外接矩形

findContours + boundingRect

Python
import cv2
import numpy as np

img = cv2.imread("shapes.png")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
_, bw = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)

contours, _ = cv2.findContours(bw, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for c in contours:
    if cv2.contourArea(c) < 100:
        continue
    x, y, w, h = cv2.boundingRect(c)
    cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)

cv2.imwrite("detected.png", img)

仿射与透视变换

getAffineTransform / warpPerspective

Python
import cv2
import numpy as np

img = cv2.imread("board.jpg")
h, w = img.shape[:2]

# 仿射:3 点对应
src = np.float32([[0, 0], [w, 0], [0, h]])
dst = np.float32([[50, 50], [w - 50, 20], [20, h - 50]])
M = cv2.getAffineTransform(src, dst)
affine = cv2.warpAffine(img, M, (w, h))

# 透视:4 点对应(如文档矫正)
pts_src = np.float32([[0, 0], [w, 0], [w, h], [0, h]])
pts_dst = np.float32([[0, 0], [w, 0], [w, h], [0, h]])
H = cv2.getPerspectiveTransform(pts_src, pts_dst)
persp = cv2.warpPerspective(img, H, (w, h))

特征与匹配

ORB 特征检测与匹配

免专利的快速特征;比 SIFT 快且开源友好

Python
import cv2

img1 = cv2.imread("box.png", cv2.IMREAD_GRAYSCALE)
img2 = cv2.imread("box_in_scene.png", cv2.IMREAD_GRAYSCALE)

orb = cv2.ORB_create(nfeatures=1000)
kp1, des1 = orb.detectAndCompute(img1, None)
kp2, des2 = orb.detectAndCompute(img2, None)

bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
matches = sorted(bf.match(des1, des2), key=lambda m: m.distance)

out = cv2.drawMatches(img1, kp1, img2, kp2, matches[:20], None,
                      flags=cv2.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS)
cv2.imwrite("matches.png", out)

单应性估计(RANSAC)

findHomography 用于拼接与增强现实

Python
import cv2
import numpy as np

# pts1 / pts2 为对应点 Nx2
H, mask = cv2.findHomography(pts1, pts2, cv2.RANSAC, 5.0)
inliers = mask.ravel().sum()
print(f"inliers: {inliers}/{len(pts1)}")

# 将图1投影到图2坐标系
warp = cv2.warpPerspective(img1, H, (img2.shape[1], img2.shape[0]))

视频分析

背景减除(MOG2)

静态摄像头前景/背景分割

Python
import cv2

cap = cv2.VideoCapture("traffic.mp4")
backSub = cv2.createBackgroundSubtractorMOG2(
    history=500, varThreshold=50, detectShadows=True
)

while True:
    ok, frame = cap.read()
    if not ok:
        break
    fg = backSub.apply(frame)
    cv2.imshow("fg", fg)
    if cv2.waitKey(30) & 0xFF == 27:
        break

cap.release()
cv2.destroyAllWindows()

Meanshift 目标跟踪

基于直方图反投影的区域跟踪

Python
import cv2

cap = cv2.VideoCapture(0)
ok, frame = cap.read()
x, y, w, h = 100, 100, 200, 200  # 初始 ROI
track_window = (x, y, w, h)

roi = frame[y:y+h, x:x+w]
hsv = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV)
mask = cv2.inRange(hsv, (0, 60, 32), (180, 255, 255))
roi_hist = cv2.calcHist([hsv], [0], mask, [180], [0, 180])
cv2.normalize(roi_hist, roi_hist, 0, 255, cv2.NORM_MINMAX)

term_crit = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 1)
while True:
    ok, frame = cap.read()
    if not ok:
        break
    hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
    dst = cv2.calcBackProject([hsv], [0], roi_hist, [0, 180], 1)
    ret, track_window = cv2.meanShift(dst, track_window, term_crit)
    x, y, w, h = track_window
    cv2.rectangle(frame, (x, y), (x+w, y+h), 255, 2)
    cv2.imshow("track", frame)
    if cv2.waitKey(30) & 0xFF == 27:
        break

目标检测(DNN)

ONNX 模型加载与前向

5.0 ENGINE_AUTO 优先新引擎

Python
import cv2

net = cv2.dnn.readNet("yolov8n.onnx")
img = cv2.imread("street.jpg")
blob = cv2.dnn.blobFromImage(img, 1/255.0, (640, 640), swapRB=True)
net.setInput(blob)
outs = net.forward(net.getUnconnectedOutLayersNames())
print([o.shape for o in outs])

Haar 人脸检测(传统方法)

objdetect 经典 API,无需深度模型

Python
import cv2

face_cascade = cv2.CascadeClassifier(
    cv2.data.haarcascades + "haarcascade_frontalface_default.xml"
)
img = cv2.imread("people.jpg")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

faces = face_cascade.detectMultiScale(gray, scaleFactor=1.1,
                                       minNeighbors=5, minSize=(30, 30))
for (x, y, w, h) in faces:
    cv2.rectangle(img, (x, y), (x+w, y+h), (0, 255, 0), 2)

cv2.imwrite("faces.png", img)

浏览器(OpenCV.js)

页面中加载 OpenCV.js 并模糊图像

WASM 运行时,onRuntimeInitialized 回调

JavaScript
<script async src="opencv.js" onload="onOpenCvReady();"></script>
<script>
function onOpenCvReady() {
  console.log('OpenCV.js is ready:', cv.getBuildInformation());
}

function blurCanvas() {
  let src = cv.imread('canvasInput');
  let dst = new cv.Mat();
  cv.GaussianBlur(src, dst, new cv.Size(15, 15), 0, 0, cv.BORDER_DEFAULT);
  cv.imshow('canvasOutput', dst);
  src.delete();
  dst.delete();
}
</script>