OpenCV计算机视觉实战:从图像处理到目标检测完整指南
如果你刚开始接触计算机视觉可能会被各种专业术语搞得一头雾水图像分割、目标检测、特征提取、边缘检测...这些听起来高大上的技术在实际项目中到底该怎么用更重要的是作为初学者从哪里开始才能真正掌握这些核心技能OpenCV 作为计算机视觉领域的瑞士军刀几乎涵盖了所有基础图像处理需求。但很多教程要么过于理论化要么只讲零散功能缺乏系统性的实战指导。本文将从零开始带你完整掌握 OpenCV 的核心知识体系每个知识点都配有可运行的代码示例确保你能真正理解并应用。1. 这篇文章真正要解决的问题对于计算机视觉初学者来说最大的痛点不是缺乏资料而是资料太多却不成体系。你可能会遇到以下典型问题概念混淆不清图像分割和目标检测有什么区别特征提取和边缘检测又是什么关系这些基础概念如果理解错误后续学习会事倍功半。理论与实践脱节看了很多理论文章但面对实际项目时不知道如何下手。比如知道边缘检测的原理却不知道在什么场景下该用 Canny 还是 Sobel 算法。环境配置困难OpenCV 的安装和配置经常出现各种问题特别是涉及 Python 版本、系统环境变量时新手很容易在这里放弃。代码无法运行网上找到的代码示例经常因为版本兼容性问题无法运行或者缺少关键的环境配置说明。本文将通过完整的实战案例系统性地解决这些问题。你将不仅理解每个技术点的原理更能掌握在实际项目中如何选择和组合这些技术。2. OpenCV 基础概念与核心原理2.1 OpenCV 是什么为什么选择它OpenCVOpen 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.14Python 版本推荐 Python 3.8-3.10最新版本可能存在兼容性问题OpenCV 版本OpenCV 4.5本文基于 OpenCV 4.5.43.2 安装 OpenCV方法一使用 pip 安装推荐初学者# 安装 OpenCV 基础包 pip install opencv-python # 如果需要扩展功能如 SIFT 特征提取 pip install opencv-contrib-python方法二使用 conda 安装conda install -c conda-forge opencv3.3 验证安装创建测试文件test_opencv.pyimport cv2 import numpy as np print(OpenCV版本:, cv2.__version__) print(NumPy版本:, np.__version__) # 创建一个简单的图像测试基本功能 img np.zeros((100, 100, 3), dtypenp.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), dtypenp.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, i1) # OpenCV 使用 BGRmatplotlib 使用 RGB if len(images[i].shape) 3: plt.imshow(cv2.cvtColor(images[i], cv2.COLOR_BGR2RGB)) else: plt.imshow(images[i], cmapgray) 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, ksize5) sobely cv2.Sobel(gray, cv2.CV_64F, 0, 1, ksize5) 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, i1) plt.imshow(images[i], cmapgray) 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, i1) plt.imshow(edges, cmapgray) plt.title(fCanny: {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), cmapgray) plt.title(Standard Canny) plt.axis(off) plt.subplot(1, 2, 2) plt.imshow(edges_adaptive, cmapgray) 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(nfeatures100) # 检测关键点和描述符 keypoints, descriptors orb.detectAndCompute(gray, None) # 绘制关键点 img_orb cv2.drawKeypoints(img, keypoints, None, color(0, 255, 0), flags0) 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(fORB 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, crossCheckTrue) matches bf.match(des1, des2) # 按距离排序 matches sorted(matches, keylambda x: x.distance) # 绘制匹配结果 img_matches cv2.drawMatches(img1, kp1, img2, kp2, matches[:50], None, flags2) 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, i1) 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, i1) 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, iterations2) # 确定背景区域 sure_bg cv2.dilate(opening, kernel, iterations3) # 确定前景区域 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, i1) plt.imshow(img_copy, cmapgray) plt.title(method) plt.axis(off) plt.tight_layout() plt.show() def contour_detection(): 轮廓检测 # 创建测试图像 img np.zeros((500, 500, 3), dtypenp.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(fDetected 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), (xw, yh), (255, 0, 0), 2) plt.figure(figsize(10, 8)) plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)) plt.title(fFace 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(clipLimit2.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:yh, x:xw] # 增强图像 enhanced_plate self.enhance_plate_image(plate_roi) # 绘制边界框 cv2.rectangle(result_img, (x, y), (xw, yh), (0, 255, 0), 3) cv2.putText(result_img, fPlate {i1}, (x, y-10), cv2.FONT_HERSHEY_SIMPLEX,