OpenCV计算机视觉实战:从图像处理到目标检测完整指南
如果你刚开始接触计算机视觉,可能会被各种专业术语搞得一头雾水:图像分割、目标检测、特征提取、边缘检测...这些听起来高大上的技术,在实际项目中到底该怎么用?更重要的是,作为初学者,从哪里开始才能真正掌握这些核心技能?
OpenCV 作为计算机视觉领域的"瑞士军刀",几乎涵盖了所有基础图像处理需求。但很多教程要么过于理论化,要么只讲零散功能,缺乏系统性的实战指导。本文将从零开始,带你完整掌握 OpenCV 的核心知识体系,每个知识点都配有可运行的代码示例,确保你能真正理解并应用。
1. 这篇文章真正要解决的问题
对于计算机视觉初学者来说,最大的痛点不是缺乏资料,而是资料太多却不成体系。你可能会遇到以下典型问题:
概念混淆不清:图像分割和目标检测有什么区别?特征提取和边缘检测又是什么关系?这些基础概念如果理解错误,后续学习会事倍功半。
理论与实践脱节:看了很多理论文章,但面对实际项目时不知道如何下手。比如知道边缘检测的原理,却不知道在什么场景下该用 Canny 还是 Sobel 算法。
环境配置困难:OpenCV 的安装和配置经常出现各种问题,特别是涉及 Python 版本、系统环境变量时,新手很容易在这里放弃。
代码无法运行:网上找到的代码示例经常因为版本兼容性问题无法运行,或者缺少关键的环境配置说明。
本文将通过完整的实战案例,系统性地解决这些问题。你将不仅理解每个技术点的原理,更能掌握在实际项目中如何选择和组合这些技术。
2. OpenCV 基础概念与核心原理
2.1 OpenCV 是什么?为什么选择它?
OpenCV(Open Source Computer Vision Library)是一个开源的计算机视觉库,自 1999 年由 Intel 发起以来,已经成为计算机视觉领域的事实标准。它的核心优势在于:
- 跨平台性:支持 Windows、Linux、macOS、Android、iOS
- 多语言支持:C++、Python、Java 等多种编程接口
- 丰富的算法:包含 2500 多个优化算法,涵盖从基础图像处理到高级机器学习
- 商业友好:基于 BSD 许可证,可免费用于商业项目
2.2 核心概念解析
图像分割vs目标检测:
- 图像分割:将图像分成多个区域或对象,通常输出的是像素级的分类结果(每个像素属于哪个类别)
- 目标检测:在图像中定位特定对象的位置,通常用边界框表示,同时识别对象的类别
特征提取vs边缘检测:
- 特征提取:从图像中提取有意义的信息点,如角点、纹理等,用于后续的图像匹配或识别
- 边缘检测:识别图像中亮度明显变化的区域,通常是物体边界的位置
图像滤波:通过卷积操作对图像进行平滑、锐化等处理,去除噪声或增强特征
人脸识别:基于特征提取和机器学习技术,识别和验证图像中的人脸身份
3. 环境准备与前置条件
3.1 系统要求与版本选择
操作系统:Windows 10/11、Ubuntu 18.04+、macOS 10.14+Python 版本:推荐 Python 3.8-3.10(最新版本可能存在兼容性问题)OpenCV 版本:OpenCV 4.5+(本文基于 OpenCV 4.5.4)
3.2 安装 OpenCV
方法一:使用 pip 安装(推荐初学者)
# 安装 OpenCV 基础包 pip install opencv-python # 如果需要扩展功能(如 SIFT 特征提取) pip install opencv-contrib-python方法二:使用 conda 安装
conda install -c conda-forge opencv3.3 验证安装
创建测试文件test_opencv.py:
import cv2 import numpy as np print("OpenCV版本:", cv2.__version__) print("NumPy版本:", np.__version__) # 创建一个简单的图像测试基本功能 img = np.zeros((100, 100, 3), dtype=np.uint8) cv2.rectangle(img, (20, 20), (80, 80), (0, 255, 0), 2) cv2.imshow('Test Image', img) cv2.waitKey(0) cv2.destroyAllWindows()运行后如果能看到一个绿色矩形框,说明安装成功。
4. 图像处理基础:读取、显示和保存
4.1 基本图像操作
import cv2 import numpy as np # 读取图像 def basic_image_operations(): # 读取图像(第二个参数:1-彩色,0-灰度,-1-包含alpha通道) img_color = cv2.imread('image.jpg', 1) # 彩色图像 img_gray = cv2.imread('image.jpg', 0) # 灰度图像 # 显示图像 cv2.imshow('Color Image', img_color) cv2.imshow('Gray Image', img_gray) # 等待按键(0表示无限等待) cv2.waitKey(0) cv2.destroyAllWindows() # 保存图像 cv2.imwrite('gray_image.jpg', img_gray) # 获取图像信息 print("图像形状:", img_color.shape) # (高度, 宽度, 通道数) print("图像大小:", img_color.size) # 总像素数 print("数据类型:", img_color.dtype) # 数据类型 # 如果没有图像文件,可以创建一个测试图像 def create_test_image(): # 创建512x512的彩色图像 img = np.zeros((512, 512, 3), dtype=np.uint8) # 绘制图形 cv2.line(img, (0, 0), (511, 511), (255, 0, 0), 5) # 蓝色对角线 cv2.rectangle(img, (100, 100), (400, 400), (0, 255, 0), 3) # 绿色矩形 cv2.circle(img, (256, 256), 100, (0, 0, 255), -1) # 红色实心圆 # 添加文字 font = cv2.FONT_HERSHEY_SIMPLEX cv2.putText(img, 'OpenCV Demo', (100, 50), font, 1, (255, 255, 255), 2) cv2.imshow('Test Image', img) cv2.waitKey(0) cv2.destroyAllWindows() return img if __name__ == "__main__": # 如果没有图像文件,先创建测试图像 test_img = create_test_image() cv2.imwrite('test_image.jpg', test_img) # 测试基本操作 basic_image_operations()5. 图像滤波:噪声处理与图像增强
5.1 常见的图像滤波技术
图像滤波是图像处理的基础,主要用于去噪、平滑、锐化等操作。
import cv2 import numpy as np from matplotlib import pyplot as plt def image_filtering_demo(): # 创建带噪声的图像 img = cv2.imread('test_image.jpg') # 添加高斯噪声 row, col, ch = img.shape mean = 0 var = 0.1 sigma = var**0.5 gauss = np.random.normal(mean, sigma, (row, col, ch)) gauss = gauss.reshape(row, col, ch) noisy_img = img + gauss * 50 noisy_img = np.clip(noisy_img, 0, 255).astype(np.uint8) # 各种滤波方法 # 1. 均值滤波 blur = cv2.blur(noisy_img, (5, 5)) # 2. 高斯滤波 gaussian_blur = cv2.GaussianBlur(noisy_img, (5, 5), 0) # 3. 中值滤波(对椒盐噪声特别有效) median_blur = cv2.medianBlur(noisy_img, 5) # 4. 双边滤波(保边去噪) bilateral_blur = cv2.bilateralFilter(noisy_img, 9, 75, 75) # 显示结果 titles = ['Original', 'Noisy', 'Mean Filter', 'Gaussian Filter', 'Median Filter', 'Bilateral Filter'] images = [img, noisy_img, blur, gaussian_blur, median_blur, bilateral_blur] plt.figure(figsize=(15, 10)) for i in range(6): plt.subplot(2, 3, i+1) # OpenCV 使用 BGR,matplotlib 使用 RGB if len(images[i].shape) == 3: plt.imshow(cv2.cvtColor(images[i], cv2.COLOR_BGR2RGB)) else: plt.imshow(images[i], cmap='gray') plt.title(titles[i]) plt.axis('off') plt.tight_layout() plt.show() def sharpening_demo(): """图像锐化示例""" img = cv2.imread('test_image.jpg') # 创建锐化核 kernel = np.array([[-1, -1, -1], [-1, 9, -1], [-1, -1, -1]]) sharpened = cv2.filter2D(img, -1, kernel) # 对比显示 plt.figure(figsize=(10, 5)) plt.subplot(1, 2, 1) plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)) plt.title('Original') plt.axis('off') plt.subplot(1, 2, 2) plt.imshow(cv2.cvtColor(sharpened, cv2.COLOR_BGR2RGB)) plt.title('Sharpened') plt.axis('off') plt.tight_layout() plt.show() if __name__ == "__main__": image_filtering_demo() sharpening_demo()5.2 滤波技术选择指南
不同的滤波方法适用于不同场景:
- 均值滤波:简单快速,但边缘保持较差
- 高斯滤波:最常用的平滑滤波,对高斯噪声效果好
- 中值滤波:对椒盐噪声特别有效,能较好保持边缘
- 双边滤波:保边去噪,计算量较大但效果最好
6. 边缘检测:识别图像中的边界信息
6.1 边缘检测算法对比
边缘检测是图像处理中的重要步骤,用于识别图像中亮度明显变化的区域。
import cv2 import numpy as np import matplotlib.pyplot as plt def edge_detection_comparison(): # 读取图像并转为灰度图 img = cv2.imread('test_image.jpg') gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 1. Sobel 算子 sobelx = cv2.Sobel(gray, cv2.CV_64F, 1, 0, ksize=5) sobely = cv2.Sobel(gray, cv2.CV_64F, 0, 1, ksize=5) sobel_combined = np.sqrt(sobelx**2 + sobely**2) # 2. Laplacian 算子 laplacian = cv2.Laplacian(gray, cv2.CV_64F) # 3. Canny 边缘检测(最常用) edges_canny = cv2.Canny(gray, 100, 200) # 显示结果 plt.figure(figsize=(15, 10)) images = [gray, sobelx, sobely, sobel_combined, laplacian, edges_canny] titles = ['Original Gray', 'Sobel X', 'Sobel Y', 'Sobel Combined', 'Laplacian', 'Canny Edge Detection'] for i in range(6): plt.subplot(2, 3, i+1) plt.imshow(images[i], cmap='gray') plt.title(titles[i]) plt.axis('off') plt.tight_layout() plt.show() def canny_edge_detection_demo(): """Canny 边缘检测参数调优""" img = cv2.imread('test_image.jpg') gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 不同的阈值参数 thresholds = [ (50, 100), # 低阈值,检测更多边缘 (100, 200), # 中等阈值 (150, 250) # 高阈值,只检测强边缘 ] plt.figure(figsize=(15, 5)) for i, (low_threshold, high_threshold) in enumerate(thresholds): edges = cv2.Canny(gray, low_threshold, high_threshold) plt.subplot(1, 3, i+1) plt.imshow(edges, cmap='gray') plt.title(f'Canny: {low_threshold}-{high_threshold}') plt.axis('off') plt.tight_layout() plt.show() def advanced_edge_detection(): """高级边缘检测技术""" img = cv2.imread('test_image.jpg') gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 先进行高斯模糊去除噪声 blurred = cv2.GaussianBlur(gray, (5, 5), 0) # 自适应阈值 Canny v = np.median(blurred) lower = int(max(0, (1.0 - 0.33) * v)) upper = int(min(255, (1.0 + 0.33) * v)) edges_adaptive = cv2.Canny(blurred, lower, upper) plt.figure(figsize=(10, 5)) plt.subplot(1, 2, 1) plt.imshow(cv2.Canny(gray, 100, 200), cmap='gray') plt.title('Standard Canny') plt.axis('off') plt.subplot(1, 2, 2) plt.imshow(edges_adaptive, cmap='gray') plt.title('Adaptive Canny') plt.axis('off') plt.tight_layout() plt.show() if __name__ == "__main__": edge_detection_comparison() canny_edge_detection_demo() advanced_edge_detection()6.2 边缘检测算法选择建议
- Sobel:计算简单,适合实时应用,但对噪声敏感
- Laplacian:对边缘方向不敏感,但噪声放大明显
- Canny:效果最好,包含噪声抑制、梯度计算、非极大值抑制和滞后阈值四个步骤
7. 特征提取:从图像中提取关键信息
7.1 角点检测
角点是图像中重要的特征点,常用于图像匹配和三维重建。
import cv2 import numpy as np import matplotlib.pyplot as plt def feature_detection_demo(): img = cv2.imread('test_image.jpg') gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 1. Harris 角点检测 gray_float = np.float32(gray) harris_corners = cv2.cornerHarris(gray_float, 2, 3, 0.04) # 膨胀角点标记 harris_corners = cv2.dilate(harris_corners, None) # 标记角点 img_harris = img.copy() img_harris[harris_corners > 0.01 * harris_corners.max()] = [0, 0, 255] # 2. Shi-Tomasi 角点检测(改进的Harris) corners = cv2.goodFeaturesToTrack(gray, 100, 0.01, 10) corners = np.int0(corners) img_shi = img.copy() for i in corners: x, y = i.ravel() cv2.circle(img_shi, (x, y), 3, (0, 255, 0), -1) # 显示结果 plt.figure(figsize=(15, 5)) plt.subplot(1, 3, 1) plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)) plt.title('Original Image') plt.axis('off') plt.subplot(1, 3, 2) plt.imshow(cv2.cvtColor(img_harris, cv2.COLOR_BGR2RGB)) plt.title('Harris Corner Detection') plt.axis('off') plt.subplot(1, 3, 3) plt.imshow(cv2.cvtColor(img_shi, cv2.COLOR_BGR2RGB)) plt.title('Shi-Tomasi Corner Detection') plt.axis('off') plt.tight_layout() plt.show() def orb_feature_detection(): """ORB 特征检测(专利免费)""" img = cv2.imread('test_image.jpg') gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 创建 ORB 检测器 orb = cv2.ORB_create(nfeatures=100) # 检测关键点和描述符 keypoints, descriptors = orb.detectAndCompute(gray, None) # 绘制关键点 img_orb = cv2.drawKeypoints(img, keypoints, None, color=(0, 255, 0), flags=0) plt.figure(figsize=(10, 5)) plt.subplot(1, 2, 1) plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)) plt.title('Original Image') plt.axis('off') plt.subplot(1, 2, 2) plt.imshow(cv2.cvtColor(img_orb, cv2.COLOR_BGR2RGB)) plt.title(f'ORB Features: {len(keypoints)} points') plt.axis('off') plt.tight_layout() plt.show() return keypoints, descriptors def feature_matching_demo(): """特征匹配示例""" # 创建两个略有差异的图像 img1 = cv2.imread('test_image.jpg') # 对原图像进行变换创建第二个图像 h, w = img1.shape[:2] M = np.float32([[1, 0, 50], [0, 1, 30]]) # 平移变换 img2 = cv2.warpAffine(img1, M, (w, h)) # 旋转15度 M_rotation = cv2.getRotationMatrix2D((w/2, h/2), 15, 1) img2 = cv2.warpAffine(img2, M_rotation, (w, h)) # 检测特征点 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) # 绘制匹配结果 img_matches = cv2.drawMatches(img1, kp1, img2, kp2, matches[:50], None, flags=2) plt.figure(figsize=(15, 8)) plt.imshow(cv2.cvtColor(img_matches, cv2.COLOR_BGR2RGB)) plt.title('Feature Matching Results') plt.axis('off') plt.show() if __name__ == "__main__": feature_detection_demo() keypoints, descriptors = orb_feature_detection() feature_matching_demo()8. 图像分割:将图像分成有意义的区域
8.1 阈值分割
import cv2 import numpy as np import matplotlib.pyplot as plt def threshold_segmentation(): """阈值分割示例""" img = cv2.imread('test_image.jpg') gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 各种阈值方法 ret, thresh1 = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY) ret, thresh2 = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY_INV) ret, thresh3 = cv2.threshold(gray, 127, 255, cv2.THRESH_TRUNC) ret, thresh4 = cv2.threshold(gray, 127, 255, cv2.THRESH_TOZERO) ret, thresh5 = cv2.threshold(gray, 127, 255, cv2.THRESH_TOZERO_INV) titles = ['Original', 'BINARY', 'BINARY_INV', 'TRUNC', 'TOZERO', 'TOZERO_INV'] images = [gray, thresh1, thresh2, thresh3, thresh4, thresh5] plt.figure(figsize=(15, 8)) for i in range(6): plt.subplot(2, 3, i+1) plt.imshow(images[i], 'gray') plt.title(titles[i]) plt.axis('off') plt.tight_layout() plt.show() def adaptive_threshold(): """自适应阈值分割""" img = cv2.imread('test_image.jpg') gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 全局阈值 ret, th1 = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY) # 自适应阈值 th2 = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 11, 2) th3 = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2) titles = ['Original', 'Global Thresholding', 'Adaptive Mean Thresholding', 'Adaptive Gaussian Thresholding'] images = [gray, th1, th2, th3] plt.figure(figsize=(12, 8)) for i in range(4): plt.subplot(2, 2, i+1) plt.imshow(images[i], 'gray') plt.title(titles[i]) plt.axis('off') plt.tight_layout() plt.show() def watershed_segmentation(): """分水岭算法分割""" # 读取图像 img = cv2.imread('test_image.jpg') gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 二值化 ret, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU) # 噪声去除 kernel = np.ones((3, 3), np.uint8) opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=2) # 确定背景区域 sure_bg = cv2.dilate(opening, kernel, iterations=3) # 确定前景区域 dist_transform = cv2.distanceTransform(opening, cv2.DIST_L2, 5) ret, sure_fg = cv2.threshold(dist_transform, 0.7 * dist_transform.max(), 255, 0) # 找到未知区域 sure_fg = np.uint8(sure_fg) unknown = cv2.subtract(sure_bg, sure_fg) # 标记标签 ret, markers = cv2.connectedComponents(sure_fg) markers = markers + 1 markers[unknown == 255] = 0 # 应用分水岭算法 markers = cv2.watershed(img, markers) img[markers == -1] = [255, 0, 0] plt.figure(figsize=(12, 6)) plt.subplot(1, 2, 1) plt.imshow(cv2.cvtColor(cv2.imread('test_image.jpg'), cv2.COLOR_BGR2RGB)) plt.title('Original Image') plt.axis('off') plt.subplot(1, 2, 2) plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)) plt.title('Watershed Segmentation') plt.axis('off') plt.tight_layout() plt.show() if __name__ == "__main__": threshold_segmentation() adaptive_threshold() watershed_segmentation()9. 目标检测:定位和识别图像中的对象
9.1 基于传统方法的目标检测
import cv2 import numpy as np import matplotlib.pyplot as plt def template_matching(): """模板匹配目标检测""" # 读取原图像和模板 img = cv2.imread('test_image.jpg') img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 创建模板(从原图中截取一部分) template = img_gray[100:200, 100:200] # 截取一个区域作为模板 w, h = template.shape[::-1] # 多种模板匹配方法 methods = ['cv2.TM_CCOEFF', 'cv2.TM_CCOEFF_NORMED', 'cv2.TM_CCORR', 'cv2.TM_CCORR_NORMED', 'cv2.TM_SQDIFF', 'cv2.TM_SQDIFF_NORMED'] plt.figure(figsize=(15, 10)) for i, method in enumerate(methods): img_copy = img_gray.copy() method = eval(method) # 应用模板匹配 res = cv2.matchTemplate(img_gray, template, method) min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res) # 根据方法选择最佳匹配位置 if method in [cv2.TM_SQDIFF, cv2.TM_SQDIFF_NORMED]: top_left = min_loc else: top_left = max_loc bottom_right = (top_left[0] + w, top_left[1] + h) # 绘制矩形框 cv2.rectangle(img_copy, top_left, bottom_right, 255, 2) plt.subplot(2, 3, i+1) plt.imshow(img_copy, cmap='gray') plt.title(method) plt.axis('off') plt.tight_layout() plt.show() def contour_detection(): """轮廓检测""" # 创建测试图像 img = np.zeros((500, 500, 3), dtype=np.uint8) # 绘制几个形状 cv2.rectangle(img, (50, 50), (150, 150), (255, 0, 0), -1) cv2.circle(img, (300, 100), 50, (0, 255, 0), -1) cv2.ellipse(img, (400, 400), (100, 50), 0, 0, 360, (0, 0, 255), -1) # 转为灰度并二值化 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) ret, thresh = cv2.threshold(gray, 127, 255, 0) # 查找轮廓 contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) # 绘制轮廓 contour_img = img.copy() cv2.drawContours(contour_img, contours, -1, (255, 255, 255), 3) # 计算轮廓特征 for i, contour in enumerate(contours): # 面积 area = cv2.contourArea(contour) # 周长 perimeter = cv2.arcLength(contour, True) # 边界矩形 x, y, w, h = cv2.boundingRect(contour) print(f"轮廓 {i}: 面积={area:.2f}, 周长={perimeter:.2f}, 边界矩形=({x},{y},{w},{h})") plt.figure(figsize=(12, 6)) plt.subplot(1, 2, 1) plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)) plt.title('Original Shapes') plt.axis('off') plt.subplot(1, 2, 2) plt.imshow(cv2.cvtColor(contour_img, cv2.COLOR_BGR2RGB)) plt.title(f'Detected Contours: {len(contours)}') plt.axis('off') plt.tight_layout() plt.show() def haar_cascade_face_detection(): """基于 Haar cascade 的人脸检测""" # 加载预训练的人脸检测器 face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml') # 读取图像 img = cv2.imread('test_image.jpg') gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 检测人脸 faces = face_cascade.detectMultiScale(gray, 1.1, 4) # 绘制检测框 for (x, y, w, h) in faces: cv2.rectangle(img, (x, y), (x+w, y+h), (255, 0, 0), 2) plt.figure(figsize=(10, 8)) plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)) plt.title(f'Face Detection: {len(faces)} faces found') plt.axis('off') plt.show() if __name__ == "__main__": template_matching() contour_detection() haar_cascade_face_detection()10. 完整实战项目:车牌检测系统
10.1 项目概述
我们将综合运用前面学到的知识,构建一个完整的车牌检测系统。这个项目涵盖了图像预处理、边缘检测、轮廓分析、字符识别等多个环节。
import cv2 import numpy as np import matplotlib.pyplot as plt class LicensePlateDetector: def __init__(self): self.plate_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_russian_plate_number.xml') def preprocess_image(self, img): """图像预处理""" # 转为灰度图 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 高斯模糊去噪 blurred = cv2.GaussianBlur(gray, (5, 5), 0) return blurred def detect_plate_region(self, img): """检测车牌区域""" gray = self.preprocess_image(img) # 方法1: 使用边缘检测 edges = cv2.Canny(gray, 50, 150) # 闭操作连接边缘 kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5)) closed = cv2.morphologyEx(edges, cv2.MORPH_CLOSE, kernel) # 查找轮廓 contours, _ = cv2.findContours(closed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 筛选可能是车牌的轮廓 plate_contours = [] for contour in contours: # 计算轮廓的边界矩形 x, y, w, h = cv2.boundingRect(contour) # 根据长宽比筛选(车牌通常有特定的长宽比) aspect_ratio = w / h if 2.0 < aspect_ratio < 5.0 and w > 100 and h > 30: plate_contours.append(contour) return plate_contours def enhance_plate_image(self, plate_roi): """增强车牌图像质量""" # 转为灰度 gray = cv2.cvtColor(plate_roi, cv2.COLOR_BGR2GRAY) # 对比度增强 clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8)) enhanced = clahe.apply(gray) # 二值化 _, binary = cv2.threshold(enhanced, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU) return binary def detect_plates(self, img_path): """主检测函数""" # 读取图像 img = cv2.imread(img_path) if img is None: print("无法读取图像") return None # 检测车牌区域 plate_contours = self.detect_plate_region(img) # 绘制检测结果 result_img = img.copy() plates = [] for i, contour in enumerate(plate_contours): x, y, w, h = cv2.boundingRect(contour) # 提取车牌区域 plate_roi = img[y:y+h, x:x+w] # 增强图像 enhanced_plate = self.enhance_plate_image(plate_roi) # 绘制边界框 cv2.rectangle(result_img, (x, y), (x+w, y+h), (0, 255, 0), 3) cv2.putText(result_img, f'Plate {i+1}', (x, y-10), cv2.FONT_HERSHEY_SIMPLEX,