Python+OpenCV实战:5个图像处理小项目带你轻松入门计算机视觉
·
Python+OpenCV实战:5个图像处理小项目带你轻松入门计算机视觉
计算机视觉正以前所未有的速度渗透到我们生活的方方面面——从手机相册的智能分类到自动驾驶的环境感知,从工业质检的精准识别到医疗影像的辅助诊断。对于初学者而言,掌握这项技术的捷径不是死记硬背理论公式,而是通过动手实践来理解核心概念。本文将带你用Python和OpenCV完成五个循序渐进的实战项目,每个项目都聚焦解决一个具体的视觉问题。
1. 环境配置与基础图像操作
在开始项目前,需要搭建开发环境。推荐使用Anaconda创建独立的Python环境,避免库版本冲突:
conda create -n cv_env python=3.8
conda activate cv_env
pip install opencv-python numpy matplotlib
验证安装是否成功:
import cv2
print(cv2.__version__) # 应输出4.x版本
图像基础操作三板斧:
- 读取图像:
img = cv2.imread('image.jpg') - 显示图像:
cv2.imshow('Window', img) - 保存图像:
cv2.imwrite('output.jpg', img)
注意:OpenCV默认使用BGR色彩空间而非RGB,使用matplotlib显示时需先转换:
rgb_img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
图像本质上是多维数组,通过NumPy可以高效操作:
# 获取像素值
pixel = img[100, 200] # (B,G,R)值
# 区域裁剪
roi = img[50:150, 100:300]
# 颜色通道分离
b, g, r = cv2.split(img)
2. 项目一:智能照片滤镜生成器
这个项目将实现包括复古、素描、卡通等多种风格的实时滤镜效果。核心原理是通过卷积核实现图像滤波:
def apply_filter(img, filter_type):
if filter_type == "blur":
return cv2.GaussianBlur(img, (15,15), 0)
elif filter_type == "sketch":
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
inv_gray = 255 - gray
blur = cv2.GaussianBlur(inv_gray, (21,21), 0)
return cv2.divide(gray, 255-blur, scale=256)
elif filter_type == "cartoon":
# 边缘保留滤波
smooth = cv2.bilateralFilter(img, 9, 75, 75)
# 边缘增强
edges = cv2.Canny(img, 100, 200)
edges = cv2.cvtColor(edges, cv2.COLOR_GRAY2BGR)
return cv2.bitwise_and(smooth, edges)
效果对比表:
| 滤镜类型 | 核心方法 | 适用场景 |
|---|---|---|
| 高斯模糊 | GaussianBlur | 背景虚化 |
| 铅笔画 | 反色+高斯模糊 | 艺术效果 |
| 卡通化 | 双边滤波+Canny边缘 | 人像处理 |
实时摄像头滤镜实现:
cap = cv2.VideoCapture(0)
while True:
ret, frame = cap.read()
filtered = apply_filter(frame, "cartoon")
cv2.imshow('Live Filter', filtered)
if cv2.waitKey(1) == ord('q'):
break
cap.release()
3. 项目二:人脸检测与特征标记
OpenCV内置的Haar级联分类器能快速实现人脸检测。首先下载预训练模型:
face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')
eye_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_eye.xml')
检测与标记代码:
def detect_faces(img):
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(gray, 1.3, 5)
for (x,y,w,h) in faces:
cv2.rectangle(img, (x,y), (x+w,y+h), (255,0,0), 2)
roi_gray = gray[y:y+h, x:x+w]
roi_color = img[y:y+h, x:x+w]
eyes = eye_cascade.detectMultiScale(roi_gray)
for (ex,ey,ew,eh) in eyes:
cv2.rectangle(roi_color, (ex,ey), (ex+ew,ey+eh), (0,255,0), 2)
return img
性能优化技巧:
- 缩小检测图像尺寸可提速但会降低精度
scaleFactor参数控制图像金字塔缩放比例(建议1.01-1.5)minNeighbors参数决定检测框合并阈值(越高误检越少)
更精准的DNN人脸检测:
net = cv2.dnn.readNetFromCaffe("deploy.prototxt", "res10_300x300_ssd_iter_140000.caffemodel")
blob = cv2.dnn.blobFromImage(cv2.resize(img, (300,300)), 1.0, (300,300), (104.0,177.0,123.0))
net.setInput(blob)
detections = net.forward()
4. 项目三:文档扫描与矫正
这个项目将通过图像处理实现手机拍摄文档的自动矫正,流程包括:
- 边缘检测
- 轮廓查找
- 透视变换
def scan_document(img):
# 预处理
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (5,5), 0)
edged = cv2.Canny(blur, 75, 200)
# 查找轮廓
contours, _ = cv2.findContours(edged.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
contours = sorted(contours, key=cv2.contourArea, reverse=True)[:5]
# 寻找矩形轮廓
for c in contours:
peri = cv2.arcLength(c, True)
approx = cv2.approxPolyDP(c, 0.02*peri, True)
if len(approx) == 4:
doc_cnt = approx
break
# 透视变换
warped = four_point_transform(img, doc_cnt.reshape(4,2))
return warped
def four_point_transform(img, pts):
rect = order_points(pts)
(tl, tr, br, bl) = rect
widthA = np.sqrt(((br[0]-bl[0])**2) + ((br[1]-bl[1])**2))
widthB = np.sqrt(((tr[0]-tl[0])**2) + ((tr[1]-tl[1])**2))
maxWidth = max(int(widthA), int(widthB))
heightA = np.sqrt(((tr[0]-br[0])**2) + ((tr[1]-br[1])**2))
heightB = np.sqrt(((tl[0]-bl[0])**2) + ((tl[1]-bl[1])**2))
maxHeight = max(int(heightA), int(heightB))
dst = np.array([
[0,0],
[maxWidth-1,0],
[maxWidth-1,maxHeight-1],
[0,maxHeight-1]], dtype="float32")
M = cv2.getPerspectiveTransform(rect, dst)
warped = cv2.warpPerspective(img, M, (maxWidth, maxHeight))
return warped
常见问题解决方案:
- 光线不均:使用自适应阈值代替Canny
- 复杂背景:先进行颜色分割或形态学操作
- 曲面文档:需要更复杂的网格变换算法
5. 项目四:实时运动检测系统
基于背景减除实现运动物体检测:
fgbg = cv2.createBackgroundSubtractorMOG2(history=500, varThreshold=16, detectShadows=False)
while True:
ret, frame = cap.read()
fgmask = fgbg.apply(frame)
# 后处理
kernel = np.ones((5,5), np.uint8)
fgmask = cv2.morphologyEx(fgmask, cv2.MORPH_OPEN, kernel)
# 查找轮廓
contours, _ = cv2.findContours(fgmask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for c in contours:
if cv2.contourArea(c) < 500:
continue
(x,y,w,h) = cv2.boundingRect(c)
cv2.rectangle(frame, (x,y), (x+w,y+h), (0,255,0), 2)
cv2.imshow('Motion Detection', frame)
if cv2.waitKey(1) == ord('q'):
break
背景建模算法对比:
| 算法类型 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| MOG | 计算量小 | 对光照敏感 | 静态背景 |
| MOG2 | 自适应背景 | 阴影检测不准 | 动态背景 |
| GMG | 初始化快 | 需要学习帧 | 固定摄像头 |
6. 项目五:全景图像拼接
实现多张重叠照片的自动拼接:
def stitch_images(images):
stitcher = cv2.Stitcher_create()
status, panorama = stitcher.stitch(images)
if status == cv2.Stitcher_OK:
# 裁剪黑色边界
panorama = cv2.copyMakeBorder(panorama, 10,10,10,10, cv2.BORDER_CONSTANT, (0,0,0))
gray = cv2.cvtColor(panorama, cv2.COLOR_BGR2GRAY)
_, thresh = cv2.threshold(gray, 1, 255, cv2.THRESH_BINARY)
contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
x,y,w,h = cv2.boundingRect(contours[0])
panorama = panorama[y:y+h, x:x+w]
return panorama
else:
print("拼接失败 (错误码: %d)" % status)
return None
拍摄技巧:
- 保持30%-40%的图像重叠区域
- 使用固定曝光和白平衡
- 沿同一水平线平移相机
- 避免近景物体移动
对于更精细的控制,可以手动实现特征点匹配:
def manual_stitch(img1, img2):
# 特征检测
orb = cv2.ORB_create()
kp1, des1 = orb.detectAndCompute(img1, None)
kp2, des2 = orb.detectAndCompute(img2, None)
# 特征匹配
bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
matches = bf.match(des1, des2)
matches = sorted(matches, key=lambda x:x.distance)
# 计算单应性矩阵
src_pts = np.float32([kp1[m.queryIdx].pt for m in matches]).reshape(-1,1,2)
dst_pts = np.float32([kp2[m.trainIdx].pt for m in matches]).reshape(-1,1,2)
H, _ = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0)
# 透视变换
h1,w1 = img1.shape[:2]
h2,w2 = img2.shape[:2]
result = cv2.warpPerspective(img1, H, (w1+w2, h1))
result[0:h2, 0:w2] = img2
return result
更多推荐
所有评论(0)