OpenCV实战指南:从零掌握计算机视觉核心技术与应用场景

如果你刚开始接触计算机视觉,可能会被各种专业术语搞得一头雾水:图像分割、目标检测、特征提取、边缘检测...这些概念听起来都很高大上,但实际开发中到底该怎么用?OpenCV作为计算机视觉领域的瑞士军刀,功能强大但学习曲线陡峭,很多教程要么过于理论化,要么只讲零散API,缺乏系统性的实战指导。

本文将从零开始,带你系统掌握OpenCV的核心功能模块。不同于传统的概念罗列,我们将通过真实项目场景串联各个知识点,让你不仅知道每个功能"是什么",更明白"什么时候用"和"怎么用"。读完本文,你将能够独立完成从环境搭建到实际应用的完整流程,解决图像处理中的常见问题。

1. OpenCV到底能解决什么实际问题?

OpenCV(Open Source Computer Vision Library)是一个开源的计算机视觉库,它封装了数百种图像处理和计算机视觉算法。但很多初学者容易陷入一个误区:把OpenCV当作一个简单的图像处理工具包,实际上它的价值远不止于此。

在实际项目中,OpenCV主要解决以下几类问题:

图像预处理问题:原始图像往往存在噪声、光照不均、角度倾斜等问题,直接进行分析效果很差。OpenCV提供的图像滤波、几何变换等功能可以大幅提升后续处理的准确性。

特征提取与匹配问题:无论是人脸识别、物体追踪还是图像拼接,都需要从图像中提取有区分度的特征。OpenCV提供了SIFT、ORB、HOG等多种特征提取算法,并支持特征匹配。

目标检测与识别问题:从监控视频中检测行人、从医疗影像中识别病灶、从工业图像中定位缺陷产品,这些都是目标检测的典型应用场景。

实时视频处理问题:OpenCV对视频流的支持非常完善,可以轻松处理摄像头输入、视频文件分析等实时应用。

最重要的是,OpenCV提供了统一的C++、Python、Java接口,相同的算法在不同平台上都能稳定运行,这大大降低了计算机视觉项目的开发门槛。

2. 环境搭建:避开新手最容易踩的坑

OpenCV环境搭建是很多初学者的第一道坎。不同操作系统、不同Python版本、不同OpenCV版本之间存在各种兼容性问题。下面以Python环境为例,提供最稳妥的安装方案。

2.1 选择正确的Python版本

建议使用Python 3.8-3.10版本,这些版本与当前主流的OpenCV版本兼容性最好。避免使用Python 3.11以上的最新版本,可能存在预编译包不兼容的问题。

# 检查Python版本 python --version # 应该显示 Python 3.8.x 或 Python 3.9.x 或 Python 3.10.x

2.2 使用pip安装OpenCV

推荐使用pip安装预编译版本,避免从源码编译的复杂过程:

# 安装基础版OpenCV(包含主要模块) pip install opencv-python # 如果需要扩展模块(如SIFT、SURF等专利算法) pip install opencv-contrib-python # 如果上面命令出现网络问题,可以使用国内镜像 pip install -i https://pypi.tuna.tsinghua.edu.cn/simple opencv-python

2.3 验证安装是否成功

创建简单的测试脚本验证安装:

# test_opencv.py import cv2 # 打印OpenCV版本 print("OpenCV版本:", cv2.__version__) # 测试基本功能 - 创建一个空白图像 img = cv2.imread('test.jpg') # 如果文件不存在会返回None if img is not None: print("图像加载成功,尺寸:", img.shape) else: print("创建测试图像...") img = np.zeros((300, 300, 3), dtype=np.uint8) cv2.imwrite('test.jpg', img) print("测试图像创建成功") print("OpenCV环境验证通过!")

运行测试脚本:

python test_opencv.py

2.4 常见安装问题排查

问题现象可能原因解决方案
ModuleNotFoundError: No module named 'cv2'OpenCV未正确安装重新执行pip install opencv-python
导入cv2时出现DLL加载错误VC++运行库缺失安装Microsoft Visual C++ Redistributable
部分功能无法使用安装了基础版而非contrib版安装opencv-contrib-python
安装过程超时网络连接问题使用国内镜像源或设置超时时间

3. 图像基础操作:从文件读写到像素处理

掌握图像的基本操作是使用OpenCV的前提。让我们从最基础的图像读写开始,逐步深入到像素级操作。

3.1 图像读取与显示

import cv2 import numpy as np # 读取图像 img = cv2.imread('image.jpg') # 默认以彩色模式读取 # 如果图像路径错误,img将为None if img is None: print("图像加载失败,请检查文件路径") else: # 显示图像 cv2.imshow('Original Image', img) # 等待按键,0表示无限等待 cv2.waitKey(0) # 关闭所有窗口 cv2.destroyAllWindows() # 以灰度模式读取图像 gray_img = cv2.imread('image.jpg', cv2.IMREAD_GRAYSCALE)

3.2 图像属性获取

# 获取图像的基本属性 print("图像形状(高度, 宽度, 通道数):", img.shape) print("图像数据类型:", img.dtype) print("图像总像素数:", img.size) print("图像维度:", img.ndim) # 对于灰度图像,shape只有两个值(高度, 宽度) if len(gray_img.shape) == 2: print("灰度图像形状:", gray_img.shape)

3.3 像素级操作

# 访问单个像素值(BGR格式) pixel_value = img[100, 100] # 第100行第100列的像素 print("BGR值:", pixel_value) # 修改像素值 img[100:150, 100:150] = [0, 0, 255] # 将指定区域设置为红色 # 复制图像 img_copy = img.copy() # 裁剪图像区域(ROI - Region of Interest) roi = img[50:200, 50:200] # 高度范围50-200,宽度范围50-200 # 调整图像大小 resized_img = cv2.resize(img, (400, 300)) # 宽度400,高度300 # 保存图像 cv2.imwrite('modified_image.jpg', img)

3.4 色彩空间转换

OpenCV默认使用BGR格式,但很多算法需要其他色彩空间:

# BGR转灰度 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # BGR转HSV(常用于颜色识别) hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) # BGR转RGB(用于matplotlib显示) rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # 显示不同色彩空间的图像 cv2.imshow('BGR', img) cv2.imshow('Gray', gray) cv2.imshow('HSV', hsv) cv2.waitKey(0) cv2.destroyAllWindows()

4. 图像滤波:噪声处理与图像增强

图像滤波是图像预处理的关键步骤,主要用于去除噪声、增强特征、平滑图像等。OpenCV提供了丰富的滤波函数。

4.1 均值滤波

# 均值滤波 - 简单的平滑处理 blur = cv2.blur(img, (5, 5)) # 5x5的卷积核 # 显示对比 cv2.imshow('Original', img) cv2.imshow('Blurred', blur) cv2.waitKey(0) cv2.destroyAllWindows()

4.2 高斯滤波

# 高斯滤波 - 更自然的平滑效果 gaussian_blur = cv2.GaussianBlur(img, (5, 5), 0) # 参数说明:(5,5)是卷积核大小,0是标准差(0表示自动计算)

4.3 中值滤波

# 中值滤波 - 对椒盐噪声特别有效 median_blur = cv2.medianBlur(img, 5) # 特别适合处理扫描文档中的噪声点

4.4 双边滤波

# 双边滤波 - 在平滑的同时保留边缘信息 bilateral_filter = cv2.bilateralFilter(img, 9, 75, 75) # 参数说明:9是邻域直径,75是颜色空间标准差,75是坐标空间标准差

4.5 滤波效果对比实战

import numpy as np # 创建带噪声的图像 def add_noise(image, noise_type='gaussian'): row, col, ch = image.shape if noise_type == 'gaussian': 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 = image + gauss * 255 return np.clip(noisy, 0, 255).astype(np.uint8) elif noise_type == 'salt_pepper': s_vs_p = 0.5 amount = 0.04 out = np.copy(image) # 盐噪声 num_salt = np.ceil(amount * image.size * s_vs_p) coords = [np.random.randint(0, i-1, int(num_salt)) for i in image.shape] out[coords[0], coords[1], :] = 255 # 椒噪声 num_pepper = np.ceil(amount * image.size * (1. - s_vs_p)) coords = [np.random.randint(0, i-1, int(num_pepper)) for i in image.shape] out[coords[0], coords[1], :] = 0 return out # 测试不同滤波器的去噪效果 noisy_img = add_noise(img, 'salt_pepper') # 应用不同滤波器 blurred = cv2.blur(noisy_img, (5,5)) gaussian = cv2.GaussianBlur(noisy_img, (5,5), 0) median = cv2.medianBlur(noisy_img, 5) bilateral = cv2.bilateralFilter(noisy_img, 9, 75, 75) # 显示结果对比 cv2.imshow('Noisy', noisy_img) cv2.imshow('Mean Filter', blurred) cv2.imshow('Gaussian Filter', gaussian) cv2.imshow('Median Filter', median) cv2.imshow('Bilateral Filter', bilateral) cv2.waitKey(0) cv2.destroyAllWindows()

5. 边缘检测:从Canny到实际应用

边缘检测是图像处理中的重要技术,用于识别图像中物体的轮廓。Canny边缘检测算法是其中最经典和常用的方法。

5.1 Canny边缘检测原理

Canny算法包含四个步骤:

  1. 高斯滤波去噪声
  2. 计算梯度幅值和方向
  3. 非极大值抑制
  4. 双阈值检测
# 基本的Canny边缘检测 edges = cv2.Canny(img, 100, 200) # 阈值1=100, 阈值2=200 # 显示结果 cv2.imshow('Original', img) cv2.imshow('Canny Edges', edges) cv2.waitKey(0) cv2.destroyAllWindows()

5.2 阈值选择策略

阈值选择是Canny算法的关键:

  • 低阈值:检测弱边缘,但可能包含噪声
  • 高阈值:只检测强边缘,可能丢失重要轮廓
# 自动阈值计算(基于图像中值) def auto_canny(image, sigma=0.33): # 计算图像的中值 v = np.median(image) # 根据中值设置阈值 lower = int(max(0, (1.0 - sigma) * v)) upper = int(min(255, (1.0 + sigma) * v)) edged = cv2.Canny(image, lower, upper) return edged # 使用自动阈值 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) auto_edges = auto_canny(gray) # 对比不同阈值的效果 low_edges = cv2.Canny(gray, 50, 150) high_edges = cv2.Canny(gray, 150, 250) auto_edges = auto_canny(gray) cv2.imshow('Low Threshold', low_edges) cv2.imshow('High Threshold', high_edges) cv2.imshow('Auto Threshold', auto_edges) cv2.waitKey(0) cv2.destroyAllWindows()

5.3 边缘检测实战:文档扫描仪

def document_scanner(image_path): # 读取图像 image = cv2.imread(image_path) orig = image.copy() # 转换为灰度图 gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # 高斯模糊 blurred = cv2.GaussianBlur(gray, (5, 5), 0) # 边缘检测 edged = cv2.Canny(blurred, 75, 200) # 查找轮廓 contours, _ = cv2.findContours(edged.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE) # 按面积排序,取前5个 contours = sorted(contours, key=cv2.contourArea, reverse=True)[:5] # 寻找文档轮廓 for contour in contours: # 计算轮廓周长 peri = cv2.arcLength(contour, True) # 多边形近似 approx = cv2.approxPolyDP(contour, 0.02 * peri, True) # 如果是四边形,则认为找到了文档 if len(approx) == 4: screen_cnt = approx break # 绘制轮廓 cv2.drawContours(image, [screen_cnt], -1, (0, 255, 0), 2) # 显示结果 cv2.imshow('Original', orig) cv2.imshow('Edged', edged) cv2.imshow('Document Outline', image) cv2.waitKey(0) cv2.destroyAllWindows() return screen_cnt # 使用示例 # document_contour = document_scanner('document.jpg')

6. 特征提取:SIFT、ORB与实战应用

特征提取是计算机视觉的核心技术,用于从图像中提取具有区分度的关键点和描述符。

6.1 ORB特征提取器

ORB(Oriented FAST and Rotated BRIEF)是一种快速的特征检测算法,无需专利许可,适合商业应用。

# 初始化ORB检测器 orb = cv2.ORB_create(nfeatures=1000) # 检测关键点和计算描述符 keypoints, descriptors = orb.detectAndCompute(gray, None) # 在图像上绘制关键点 img_with_keypoints = cv2.drawKeypoints(img, keypoints, None, color=(0, 255, 0), flags=0) cv2.imshow('ORB Keypoints', img_with_keypoints) cv2.waitKey(0) cv2.destroyAllWindows()

6.2 SIFT特征提取器

SIFT(Scale-Invariant Feature Transform)具有尺度不变性,但需要OpenCV contrib模块。

# 初始化SIFT检测器(需要opencv-contrib-python) sift = cv2.SIFT_create() # 检测关键点和描述符 keypoints, descriptors = sift.detectAndCompute(gray, None) # 绘制关键点 img_sift = cv2.drawKeypoints(img, keypoints, None, flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS) cv2.imshow('SIFT Keypoints', img_sift) cv2.waitKey(0) cv2.destroyAllWindows()

6.3 特征匹配实战

def feature_matching(img1, img2): # 转换为灰度图 gray1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY) gray2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY) # 初始化ORB检测器 orb = cv2.ORB_create(1000) # 检测关键点和描述符 kp1, des1 = orb.detectAndCompute(gray1, None) kp2, des2 = orb.detectAndCompute(gray2, None) # 创建BFMatcher对象 bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True) # 匹配描述符 matches = bf.match(des1, des2) # 按距离排序 matches = sorted(matches, key=lambda x: x.distance) # 绘制前50个匹配点 img_matches = cv2.drawMatches(img1, kp1, img2, kp2, matches[:50], None, flags=2) cv2.imshow('Feature Matches', img_matches) cv2.waitKey(0) cv2.destroyAllWindows() return matches # 使用示例 # img1 = cv2.imread('image1.jpg') # img2 = cv2.imread('image2.jpg') # matches = feature_matching(img1, img2)

7. 图像分割:从阈值分割到分水岭算法

图像分割是将图像划分为多个区域的过程,每个区域代表有意义的物体或区域。

7.1 阈值分割

# 全局阈值分割 ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY) # 自适应阈值分割(适用于光照不均的图像) adaptive_thresh = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2) # Otsu's二值化(自动确定最佳阈值) ret2, otsu_thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU) cv2.imshow('Global Threshold', thresh) cv2.imshow('Adaptive Threshold', adaptive_thresh) cv2.imshow("Otsu's Threshold", otsu_thresh) cv2.waitKey(0) cv2.destroyAllWindows()

7.2 分水岭算法

分水岭算法适用于相互接触物体的分割。

def watershed_segmentation(image_path): # 读取图像 img = cv2.imread(image_path) 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] # 将边界标记为红色 cv2.imshow('Watershed Segmentation', img) cv2.waitKey(0) cv2.destroyAllWindows() return markers # 使用示例 # markers = watershed_segmentation('coins.jpg')

8. 目标检测:从传统方法到深度学习

目标检测是计算机视觉中的重要任务,旨在定位和识别图像中的特定物体。

8.1 基于Haar特征的级联分类器

# 加载预训练的人脸检测器 face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml') def detect_faces(image): gray = cv2.cvtColor(image, 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(image, (x, y), (x+w, y+h), (255, 0, 0), 2) return image, faces # 使用示例 # result_img, faces = detect_faces(img) # cv2.imshow('Face Detection', result_img) # cv2.waitKey(0) # cv2.destroyAllWindows()

8.2 基于深度学习的目标检测

OpenCV支持多种深度学习模型,如YOLO、SSD等。

def load_yolo_model(): # 加载YOLO模型(需要提前下载权重文件和配置文件) net = cv2.dnn.readNet('yolov3.weights', 'yolov3.cfg') # 加载类别名称 with open('coco.names', 'r') as f: classes = [line.strip() for line in f.readlines()] return net, classes def yolo_detection(image, net, classes): height, width = image.shape[:2] # 准备输入blob blob = cv2.dnn.blobFromImage(image, 1/255.0, (416, 416), swapRB=True, crop=False) net.setInput(blob) # 前向传播 outputs = net.forward(net.getUnconnectedOutLayersNames()) # 处理检测结果 boxes = [] confidences = [] class_ids = [] for output in outputs: for detection in output: scores = detection[5:] class_id = np.argmax(scores) confidence = scores[class_id] if confidence > 0.5: # 置信度阈值 center_x = int(detection[0] * width) center_y = int(detection[1] * height) w = int(detection[2] * width) h = int(detection[3] * height) x = int(center_x - w/2) y = int(center_y - h/2) boxes.append([x, y, w, h]) confidences.append(float(confidence)) class_ids.append(class_id) # 非极大值抑制 indices = cv2.dnn.NMSBoxes(boxes, confidences, 0.5, 0.4) # 绘制检测结果 if len(indices) > 0: for i in indices.flatten(): x, y, w, h = boxes[i] label = f"{classes[class_ids[i]]}: {confidences[i]:.2f}" cv2.rectangle(image, (x, y), (x+w, y+h), (0, 255, 0), 2) cv2.putText(image, label, (x, y-10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2) return image # 使用示例(需要先下载YOLO模型文件) # net, classes = load_yolo_model() # result = yolo_detection(img, net, classes) # cv2.imshow('YOLO Detection', result) # cv2.waitKey(0) # cv2.destroyAllWindows()

9. 人脸识别:从检测到身份验证

人脸识别是OpenCV最经典的应用之一,包含人脸检测、特征提取和身份识别三个步骤。

9.1 人脸检测与关键点定位

# 使用DNN模块进行更准确的人脸检测 def load_face_detector(): # 加载预训练的人脸检测模型 model_file = "opencv_face_detector_uint8.pb" config_file = "opencv_face_detector.pbtxt" net = cv2.dnn.readNetFromTensorflow(model_file, config_file) return net def detect_faces_dnn(image, net): height, width = image.shape[:2] # 准备输入blob blob = cv2.dnn.blobFromImage(image, 1.0, (300, 300), [104, 117, 123]) net.setInput(blob) # 前向传播 detections = net.forward() # 处理检测结果 for i in range(detections.shape[2]): confidence = detections[0, 0, i, 2] if confidence > 0.7: # 置信度阈值 x1 = int(detections[0, 0, i, 3] * width) y1 = int(detections[0, 0, i, 4] * height) x2 = int(detections[0, 0, i, 5] * width) y2 = int(detections[0, 0, i, 6] * height) # 绘制矩形框 cv2.rectangle(image, (x1, y1), (x2, y2), (0, 255, 0), 2) # 添加置信度文本 label = f"Face: {confidence:.2f}" cv2.putText(image, label, (x1, y1-10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2) return image # 使用示例 # net = load_face_detector() # result = detect_faces_dnn(img, net) # cv2.imshow('Face Detection DNN', result) # cv2.waitKey(0) # cv2.destroyAllWindows()

9.2 人脸识别完整流程

import os import numpy as np class SimpleFaceRecognizer: def __init__(self): self.face_recognizer = cv2.face.LBPHFaceRecognizer_create() self.labels = {} self.current_label = 0 def prepare_training_data(self, data_folder_path): faces = [] labels = [] # 遍历每个人物文件夹 for person_name in os.listdir(data_folder_path): person_path = os.path.join(data_folder_path, person_name) if not os.path.isdir(person_path): continue # 为每个人物分配标签 if person_name not in self.labels: self.labels[self.current_label] = person_name current_label_id = self.current_label self.current_label += 1 else: current_label_id = [k for k, v in self.labels.items() if v == person_name][0] # 读取该人物的所有图像 for image_name in os.listdir(person_path): image_path = os.path.join(person_path, image_name) image = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE) # 检测人脸 faces_detected = face_cascade.detectMultiScale(image, scaleFactor=1.1, minNeighbors=5) for (x, y, w, h) in faces_detected: faces.append(image[y:y+h, x:x+w]) labels.append(current_label_id) return faces, labels def train(self, data_folder_path): faces, labels = self.prepare_training_data(data_folder_path) self.face_recognizer.train(faces, np.array(labels)) def predict(self, test_image): gray = cv2.cvtColor(test_image, cv2.COLOR_BGR2GRAY) faces = face_cascade.detectMultiScale(gray, 1.1, 5) for (x, y, w, h) in faces: face_roi = gray[y:y+h, x:x+w] label, confidence = self.face_recognizer.predict(face_roi) person_name = self.labels.get(label, "Unknown") label_text = f"{person_name} ({confidence:.2f})" cv2.rectangle(test_image, (x, y), (x+w, y+h), (0, 255, 0), 2) cv2.putText(test_image, label_text, (x, y-10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2) return test_image # 使用示例 # recognizer = SimpleFaceRecognizer() # recognizer.train('training_data/') # result = recognizer.predict(test_img) # cv2.imshow('Face Recognition', result) # cv2.waitKey(0) # cv2.destroyAllWindows()

10. 实战项目:智能图像处理系统

现在我们将前面学到的所有知识整合到一个完整的图像处理系统中。

import cv2 import numpy as np import tkinter as tk from tkinter import filedialog, messagebox from PIL import Image, ImageTk class ImageProcessor: def __init__(self): self.original_image = None self.processed_image = None def load_image(self, file_path): self.original_image = cv2.imread(file_path) if self.original_image is not None: self.processed_image = self.original_image.copy() return True return False def apply_filter(self, filter_type, **kwargs): if self.processed_image is None: return False if filter_type == 'gaussian': kernel_size = kwargs.get('kernel_size', 5) self.processed_image = cv2.GaussianBlur(self.processed_image, (kernel_size, kernel_size), 0) elif filter_type == 'median': kernel_size = kwargs.get('kernel_size', 5) self.processed_image = cv2.medianBlur(self.processed_image, kernel_size) elif filter_type == 'canny': low_threshold = kwargs.get('low_threshold', 50) high_threshold = kwargs.get('high_threshold', 150) gray = cv2.cvtColor(self.processed_image, cv2.COLOR_BGR2GRAY) edges = cv2.Canny(gray, low_threshold, high_threshold) self.processed_image = cv2.cvtColor(edges, cv2.COLOR_GRAY2BGR) elif filter_type == 'threshold': thresh_value = kwargs.get('thresh_value', 127) gray = cv2.cvtColor(self.processed_image, cv2.COLOR_BGR2GRAY) _, thresh = cv2.threshold(gray, thresh_value, 255, cv2.THRESH_BINARY) self.processed_image = cv2.cvtColor(thresh, cv2.COLOR_GRAY2BGR) return True def detect_faces(self): if self.processed_image is None: return False gray = cv2.cvtColor(self.processed_image, cv2.COLOR_BGR2GRAY) face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml') faces = face_cascade.detectMultiScale(gray, 1.1, 5) for (x, y, w, h) in faces: cv2.rectangle(self.processed_image, (x, y), (x+w, y+h), (0, 255, 0), 2) return len(faces) > 0 def reset_image(self): if self.original_image is not None: self.processed_image = self.original_image.copy() return True return False def save_image(self, file_path): if self.processed_image is not None: cv2.imwrite(file_path, self.processed_image) return True return False # 简单的GUI界面 class ImageProcessorApp: def __init__(self, root): self.root = root self.root.title("OpenCV图像处理系统") self.root.geometry("800x600") self.processor = ImageProcessor() self.setup_ui() def setup_ui(self): # 菜单栏 menubar = tk.Menu(self.root) file_menu = tk.Menu(menubar, tearoff=0) file_menu.add_command(label="打开图像", command=self.open_image) file_menu.add_command(label="保存图像", command=self.save_image) file_menu.add_separator() file_menu.add_command(label="退出", command=self.root.quit) menubar.add_cascade(label="文件", menu=file_menu) # 处理菜单 process_menu = tk.Menu(menubar, tearoff=0) process_menu.add_command(label="高斯模糊", command=lambda: self.apply_filter('gaussian')) process_menu.add_command(label="中值滤波", command=lambda: self.apply_filter('median')) process_menu.add_command(label="边缘检测", command=lambda: self.apply_filter('canny')) process_menu.add_command(label="二值化", command=lambda: self.apply_filter('threshold')) process_menu.add_command(label="人脸检测", command=self.detect_faces) process_menu.add_command(label="重置图像", command=self.reset_image) menubar.add_cascade(label="处理", menu=process_menu) self.root.config(menu=menubar) # 图像显示区域 self.image_label = tk.Label(self.root) self.image_label.pack(expand=True, fill='both') # 状态栏 self.status_var = tk.StringVar() self.status_var.set("就绪") status_bar = tk.Label(self.root, textvariable=self.status_var, relief=tk.SUNKEN, anchor=tk.W) status_bar.pack(side=tk.BOTTOM, fill=