在计算机视觉项目中,OpenCV就像一把瑞士军刀,几乎能解决所有基础图像处理需求。我处理过大量工业检测和安防监控项目,90%的图像预处理工作都可以用OpenCV的基础操作组合实现。下面这些操作不是孤立的技巧,而是可以像乐高积木一样灵活组合的模块。
重要提示:所有代码示例基于OpenCV 4.5+版本,建议使用Python接口时保持版本一致以避免API差异
python复制import cv2
# 读取图像时的关键参数
img = cv2.imread('test.jpg', cv2.IMREAD_COLOR | cv2.IMREAD_IGNORE_ORIENTATION)
IMREAD_IGNORE_ORIENTATION:自动纠正手机拍摄图像的EXIF方向信息IMREAD_REDUCED_COLOR_2:直接读取缩小2倍的图像,节省内存python复制cv2.imwrite('output.png', img, [cv2.IMWRITE_PNG_COMPRESSION, 9])
BGR转灰度不只是cvtColor那么简单:
python复制gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 更符合人眼感知的灰度转换公式
gray_human = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY, 0.114, 0.587, 0.299)
HSV空间处理肤色检测的典型参数:
python复制hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
lower_skin = np.array([0, 48, 80], dtype=np.uint8)
upper_skin = np.array([20, 255, 255], dtype=np.uint8)
mask = cv2.inRange(hsv, lower_skin, upper_skin)
常规的直方图均衡化会放大噪声:
python复制# CLAHE是更好的选择
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
enhanced = clahe.apply(gray)
分通道处理彩色图像:
python复制lab = cv2.cvtColor(img, cv2.COLOR_BGR2LAB)
l, a, b = cv2.split(lab)
l = clahe.apply(l)
enhanced = cv2.merge((l,a,b))
result = cv2.cvtColor(enhanced, cv2.COLOR_LAB2BGR)
| 噪声类型 | 推荐滤波器 | 参数建议 |
|---|---|---|
| 高斯噪声 | GaussianBlur | kernel=5x5, σ=1.5 |
| 椒盐噪声 | medianBlur | kernel=5 |
| 细密纹理噪声 | bilateralFilter | d=9, σColor=75 |
| 运动模糊 | Wiener滤波(需自定义实现) | PSF估计是关键 |
双边滤波的实用技巧:
python复制# 人像皮肤平滑处理
blurred = cv2.bilateralFilter(img, d=9, sigmaColor=75, sigmaSpace=75)
# 边缘保持的降噪
denoised = cv2.bilateralFilter(noisy_img, d=5, sigmaColor=25, sigmaSpace=25)
python复制# 十字形结构元素比矩形更适合文字处理
kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (3,3))
# 椭圆结构元素适合细胞图像处理
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5,5))
工业零件尺寸测量预处理流程:
python复制# 1. 自适应阈值
thresh = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
cv2.THRESH_BINARY_INV, 11, 2)
# 2. 闭运算填充小孔
closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE,
cv2.getStructuringElement(cv2.MORPH_RECT, (5,5)))
# 3. 开运算去除毛刺
opened = cv2.morphologyEx(closed, cv2.MORPH_OPEN,
cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3,3)))
python复制# 自动计算高低阈值
v = np.median(gray)
sigma = 0.33
lower = int(max(0, (1.0-sigma)*v))
upper = int(min(255, (1.0+sigma)*v))
edges = cv2.Canny(gray, lower, upper, apertureSize=3, L2gradient=True)
python复制# 金字塔+边缘检测
levels = 3
gp = [gray]
for i in range(levels):
gp.append(cv2.pyrDown(gp[-1]))
edge_pyramid = []
for level in gp:
edges = cv2.Canny(level, 50, 150)
edge_pyramid.append(edges)
python复制# 工业场景优化参数
orb = cv2.ORB_create(
nfeatures=1000,
scaleFactor=1.2,
nlevels=8,
edgeThreshold=15,
firstLevel=0,
WTA_K=2,
scoreType=cv2.ORB_HARRIS_SCORE,
patchSize=31,
fastThreshold=10
)
python复制# 暴力匹配+比率测试
bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=False)
matches = bf.knnMatch(des1, des2, k=2)
good = []
for m,n in matches:
if m.distance < 0.75*n.distance:
good.append(m)
python复制# 三点法计算变换矩阵
src_pts = np.float32([[50,50], [200,50], [50,200]])
dst_pts = np.float32([[10,100], [200,50], [100,250]])
M = cv2.getAffineTransform(src_pts, dst_pts)
warped = cv2.warpAffine(img, M, (cols,rows))
python复制# 文档扫描自动校正
contours = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnt = sorted(contours, key=cv2.contourArea, reverse=True)[0]
epsilon = 0.02 * cv2.arcLength(cnt, True)
approx = cv2.approxPolyDP(cnt, epsilon, True)
if len(approx) == 4:
pts = np.float32([approx[0][0], approx[1][0],
approx[2][0], approx[3][0]])
dst = np.float32([[0,0], [w,0], [w,h], [0,h]])
M = cv2.getPerspectiveTransform(pts, dst)
warped = cv2.warpPerspective(img, M, (w,h))
python复制contours, _ = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
valid_contours = []
for cnt in contours:
area = cv2.contourArea(cnt)
if 1000 < area < 50000: # 面积筛选
x,y,w,h = cv2.boundingRect(cnt)
aspect_ratio = float(w)/h
if 0.8 < aspect_ratio < 1.2: # 宽高比筛选
hull = cv2.convexHull(cnt)
solidity = float(area)/cv2.contourArea(hull)
if solidity > 0.9: # 凸性筛选
valid_contours.append(cnt)
python复制# 最小外接圆
(x,y), radius = cv2.minEnclosingCircle(cnt)
# 方向角
_, _, angle = cv2.fitEllipse(cnt)
# 多边形逼近
epsilon = 0.01*cv2.arcLength(cnt,True)
approx = cv2.approxPolyDP(cnt,epsilon,True)
python复制template = cv2.imread('template.png',0)
w, h = template.shape[::-1]
found = None
for scale in np.linspace(0.8, 1.2, 15)[::-1]:
resized = cv2.resize(gray, None, fx=scale, fy=scale)
if resized.shape[0] < h or resized.shape[1] < w:
break
result = cv2.matchTemplate(resized, template, cv2.TM_CCOEFF_NORMED)
_, max_val, _, max_loc = cv2.minMaxLoc(result)
if found is None or max_val > found[0]:
found = (max_val, max_loc, scale)
python复制angles = np.arange(0, 360, 10)
best_val = -1
best_angle = 0
best_loc = None
for angle in angles:
rotated = rotate_bound(template, angle)
result = cv2.matchTemplate(gray, rotated, cv2.TM_CCOEFF_NORMED)
_, max_val, _, max_loc = cv2.minMaxLoc(result)
if max_val > best_val:
best_val = max_val
best_angle = angle
best_loc = max_loc
python复制# 使用UMat自动启用OpenCL加速
img_umat = cv2.UMat(img)
gray_umat = cv2.cvtColor(img_umat, cv2.COLOR_BGR2GRAY)
blurred_umat = cv2.GaussianBlur(gray_umat, (5,5), 0)
result = blurred_umat.get()
python复制from concurrent.futures import ThreadPoolExecutor
def process_image(img_path):
img = cv2.imread(img_path)
# 处理流程...
return result
with ThreadPoolExecutor(max_workers=4) as executor:
results = list(executor.map(process_image, image_paths))
python复制# 可视化中间结果
cv2.imshow('Debug', np.hstack([
cv2.resize(gray, (300,300)),
cv2.resize(thresh, (300,300)),
cv2.resize(edges, (300,300))
]))
cv2.waitKey(0)
# 绘制带编号的轮廓
for i,cnt in enumerate(contours):
cv2.drawContours(img, [cnt], -1, (0,255,0), 2)
M = cv2.moments(cnt)
cx = int(M['m10']/M['m00'])
cy = int(M['m01']/M['m00'])
cv2.putText(img, str(i), (cx,cy),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255,0,0), 2)
python复制# 使用TickMeter测量耗时
tm = cv2.TickMeter()
tm.start()
# 执行待测代码
processed = your_processing_pipeline(img)
tm.stop()
print('Execution time: {}ms'.format(tm.getTimeMilli()))