
图像处理实战从基础操作到项目应用全解析在数字时代图像处理技术已成为计算机视觉、人工智能等领域不可或缺的基础技能。无论是简单的图片尺寸调整还是复杂的特征提取与识别掌握图像处理的核心原理和实用技巧对开发者来说都至关重要。本文将围绕图像处理的四个核心项目带你从基础概念到实战应用完整掌握图像处理的关键技术栈。1. 图像处理基础概念与环境搭建1.1 图像处理的核心概念图像处理本质上是对数字图像进行各种操作以改善图像质量或提取有用信息的过程。数字图像由像素矩阵组成每个像素包含颜色信息。常见的图像格式包括JPEG、PNG、BMP等每种格式都有其特定的压缩算法和适用场景。在开始实战前需要理解几个关键概念像素图像的基本单位包含RGB红绿蓝或灰度值分辨率图像包含的像素数量直接影响图像清晰度色彩空间除了常见的RGB还有HSV、LAB等色彩表示方式图像通道彩色图像通常包含3个通道R、G、B灰度图只有1个通道1.2 开发环境准备本文使用Python作为主要编程语言配合OpenCV、PIL等图像处理库。建议使用以下环境配置# 创建虚拟环境可选 python -m venv image_env source image_env/bin/activate # Linux/Mac image_env\Scripts\activate # Windows # 安装必要库 pip install opencv-python pip install pillow pip install numpy pip install matplotlib版本要求Python 3.7OpenCV 4.5Pillow 8.0NumPy 1.19验证安装import cv2 import numpy as np from PIL import Image import matplotlib.pyplot as plt print(fOpenCV版本: {cv2.__version__}) print(fNumPy版本: {np.__version__})2. 项目一图像基础操作与预处理2.1 图像读取与显示图像处理的第一步是正确读取图像文件。OpenCV和PIL库都提供了强大的图像读取功能但需要注意色彩空间的差异。import cv2 import matplotlib.pyplot as plt # 使用OpenCV读取图像 def read_image_opencv(image_path): # 读取彩色图像 img_bgr cv2.imread(image_path) # 将BGR转换为RGBOpenCV默认使用BGR格式 img_rgb cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB) return img_rgb # 使用PIL读取图像 def read_image_pil(image_path): from PIL import Image img Image.open(image_path) return img # 显示图像对比 def display_images(original_path): # 读取图像 img_opencv read_image_opencv(original_path) img_pil read_image_pil(original_path) # 创建子图 fig, (ax1, ax2) plt.subplots(1, 2, figsize(12, 6)) # 显示OpenCV读取的图像 ax1.imshow(img_opencv) ax1.set_title(OpenCV读取 (RGB格式)) ax1.axis(off) # 显示PIL读取的图像 ax2.imshow(img_pil) ax2.set_title(PIL读取) ax2.axis(off) plt.tight_layout() plt.show() # 打印图像信息 print(f图像尺寸: {img_opencv.shape}) print(f数据类型: {img_opencv.dtype}) # 使用示例 if __name__ __main__: image_path sample.jpg # 替换为实际图像路径 display_images(image_path)2.2 图像尺寸调整与裁剪在实际应用中经常需要调整图像尺寸或进行区域裁剪。这些操作不仅影响显示效果还关系到后续处理的效率。def resize_image(image, new_size, methodopencv): 调整图像尺寸 :param image: 输入图像 :param new_size: 新尺寸 (width, height) :param method: 调整方法 (opencv 或 pil) :return: 调整后的图像 if method opencv: # 使用OpenCV调整尺寸 resized cv2.resize(image, new_size, interpolationcv2.INTER_LINEAR) else: # 使用PIL调整尺寸 from PIL import Image if isinstance(image, np.ndarray): pil_img Image.fromarray(image) else: pil_img image resized_pil pil_img.resize(new_size, Image.Resampling.LANCZOS) resized np.array(resized_pil) return resized def crop_image(image, crop_box): 裁剪图像指定区域 :param image: 输入图像 :param crop_box: 裁剪区域 (x, y, width, height) :return: 裁剪后的图像 x, y, w, h crop_box cropped image[y:yh, x:xw] return cropped # 综合示例图像预处理管道 def image_preprocessing_pipeline(image_path, target_size(224, 224)): 完整的图像预处理流程 # 1. 读取图像 img cv2.imread(image_path) img_rgb cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # 2. 调整尺寸 img_resized resize_image(img_rgb, target_size) # 3. 中心裁剪示例 h, w img_resized.shape[:2] crop_size min(h, w) // 2 crop_x (w - crop_size) // 2 crop_y (h - crop_size) // 2 img_cropped crop_image(img_resized, (crop_x, crop_y, crop_size, crop_size)) # 4. 最终调整到目标尺寸 img_final resize_image(img_cropped, target_size) return img_final # 测试预处理管道 processed_image image_preprocessing_pipeline(sample.jpg) plt.imshow(processed_image) plt.title(预处理后的图像) plt.axis(off) plt.show()2.3 色彩空间转换与直方图均衡化色彩空间转换和直方图均衡化是图像增强的常用技术能够改善图像视觉效果。def color_space_conversion(image): 色彩空间转换演示 # RGB转灰度图 gray cv2.cvtColor(image, cv2.COLOR_RGB2GRAY) # RGB转HSV hsv cv2.cvtColor(image, cv2.COLOR_RGB2HSV) # RGB转LAB lab cv2.cvtColor(image, cv2.COLOR_RGB2LAB) return gray, hsv, lab def histogram_equalization(image): 直方图均衡化增强对比度 if len(image.shape) 3: # 彩色图像 - 对每个通道分别处理 ycrcb cv2.cvtColor(image, cv2.COLOR_RGB2YCrCb) ycrcb[:,:,0] cv2.equalizeHist(ycrcb[:,:,0]) equalized cv2.cvtColor(ycrcb, cv2.COLOR_YCrCb2RGB) else: # 灰度图像 equalized cv2.equalizeHist(image) return equalized # 色彩增强综合示例 def enhance_image_quality(image_path): # 读取图像 img cv2.imread(image_path) img_rgb cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # 色彩空间转换 gray, hsv, lab color_space_conversion(img_rgb) # 直方图均衡化 equalized histogram_equalization(img_rgb) # 显示结果 fig, axes plt.subplots(2, 3, figsize(15, 10)) images [img_rgb, gray, hsv, lab, equalized, equalized] titles [原图, 灰度图, HSV空间, LAB空间, 均衡化结果, 对比] for i, (ax, img_display, title) in enumerate(zip(axes.flat, images, titles)): if i 1: # 灰度图 ax.imshow(img_display, cmapgray) elif i 2 or i 3: # HSV和LAB需要特殊处理显示 # 只显示第一个通道用于演示 ax.imshow(img_display[:,:,0], cmaphot) else: if len(img_display.shape) 3: ax.imshow(img_display) else: ax.imshow(img_display, cmapgray) ax.set_title(title) ax.axis(off) plt.tight_layout() plt.show() # 运行示例 enhance_image_quality(sample.jpg)3. 项目二图像滤波与边缘检测3.1 常用图像滤波技术图像滤波主要用于去除噪声、平滑图像或增强特征。不同的滤波器有不同的应用场景。def apply_filters(image): 应用多种滤波器 # 高斯滤波 - 去除高斯噪声 gaussian_blur cv2.GaussianBlur(image, (5, 5), 0) # 中值滤波 - 去除椒盐噪声 median_blur cv2.medianBlur(image, 5) # 双边滤波 - 保持边缘的同时去噪 bilateral_blur cv2.bilateralFilter(image, 9, 75, 75) # 均值滤波 mean_blur cv2.blur(image, (5, 5)) return gaussian_blur, median_blur, bilateral_blur, mean_blur def filter_comparison(image_path): 滤波器效果对比 img cv2.imread(image_path) img_rgb cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # 添加噪声用于演示去噪效果 noisy_img add_salt_pepper_noise(img_rgb, 0.05) # 应用各种滤波器 gaussian, median, bilateral, mean apply_filters(noisy_img) # 显示结果 fig, axes plt.subplots(2, 3, figsize(15, 10)) images [img_rgb, noisy_img, gaussian, median, bilateral, mean] titles [原图, 加噪图像, 高斯滤波, 中值滤波, 双边滤波, 均值滤波] for ax, img_display, title in zip(axes.flat, images, titles): ax.imshow(img_display) ax.set_title(title) ax.axis(off) plt.tight_layout() plt.show() def add_salt_pepper_noise(image, prob): 添加椒盐噪声 output np.copy(image) # 盐噪声 salt np.random.random(image.shape[:2]) prob/2 output[salt] 255 # 椒噪声 pepper np.random.random(image.shape[:2]) prob/2 output[pepper] 0 return output # 运行滤波器比较 filter_comparison(sample.jpg)3.2 边缘检测算法实战边缘检测是图像处理中的重要任务用于识别图像中的物体边界。def edge_detection_methods(image): 多种边缘检测方法对比 # 转换为灰度图 gray cv2.cvtColor(image, cv2.COLOR_RGB2GRAY) # Sobel算子 sobelx cv2.Sobel(gray, cv2.CV_64F, 1, 0, ksize3) sobely cv2.Sobel(gray, cv2.CV_64F, 0, 1, ksize3) sobel_combined np.sqrt(sobelx**2 sobely**2) # Laplacian算子 laplacian cv2.Laplacian(gray, cv2.CV_64F) # Canny边缘检测最常用 edges_canny cv2.Canny(gray, 100, 200) return sobel_combined, laplacian, edges_canny, gray def advanced_edge_detection(image_path): 高级边缘检测技术 img cv2.imread(image_path) img_rgb cv2.cvtColor(img, cv2.COLOR_BGR2RGB) sobel, laplacian, canny, gray edge_detection_methods(img_rgb) # 多尺度Canny检测 edges_low cv2.Canny(gray, 50, 150) edges_medium cv2.Canny(gray, 100, 200) edges_high cv2.Canny(gray, 150, 250) # 显示结果 fig, axes plt.subplots(2, 4, figsize(20, 10)) results [gray, sobel, laplacian, canny, edges_low, edges_medium, edges_high, edges_medium] titles [灰度图, Sobel边缘, Laplacian, Canny标准, Canny低阈值, Canny中阈值, Canny高阈值, 最佳效果] for ax, result, title in zip(axes.flat, results, titles): if len(result.shape) 2: ax.imshow(result, cmapgray) else: ax.imshow(result) ax.set_title(title) ax.axis(off) plt.tight_layout() plt.show() return edges_medium # 返回最佳边缘检测结果 # 运行边缘检测 best_edges advanced_edge_detection(sample.jpg)3.3 图像金字塔与多尺度处理图像金字塔用于多尺度分析在目标检测和图像融合中广泛应用。def build_image_pyramid(image, levels4): 构建高斯金字塔和拉普拉斯金字塔 # 高斯金字塔 gaussian_pyramid [image] for i in range(levels-1): image cv2.pyrDown(image) gaussian_pyramid.append(image) # 拉普拉斯金字塔 laplacian_pyramid [] for i in range(levels-1): size (gaussian_pyramid[i].shape[1], gaussian_pyramid[i].shape[0]) expanded cv2.pyrUp(gaussian_pyramid[i1], dstsizesize) laplacian cv2.subtract(gaussian_pyramid[i], expanded) laplacian_pyramid.append(laplacian) return gaussian_pyramid, laplacian_pyramid def pyramid_application(image_path): 金字塔应用示例图像融合 # 读取两张图像 img1 cv2.imread(image_path) img1 cv2.cvtColor(img1, cv2.COLOR_BGR2RGB) # 创建另一张测试图像可以是旋转或处理后的版本 img2 cv2.rotate(img1, cv2.ROTATE_90_CLOCKWISE) # 调整图像尺寸相同 img2 cv2.resize(img2, (img1.shape[1], img1.shape[0])) # 构建金字塔 levels 4 gpA, lpA build_image_pyramid(img1, levels) gpB, lpB build_image_pyramid(img2, levels) # 金字塔融合 LS [] for la, lb in zip(lpA, lpB): rows, cols, dpt la.shape ls np.hstack((la[:,:cols//2], lb[:,cols//2:])) LS.append(ls) # 重建图像 ls_ LS[0] for i in range(1, levels-1): size (LS[i].shape[1], LS[i].shape[0]) ls_ cv2.pyrUp(ls_, dstsizesize) ls_ cv2.add(ls_, LS[i]) # 显示金字塔结果 fig, axes plt.subplots(2, levels, figsize(20, 10)) for i in range(levels): axes[0, i].imshow(gpA[i]) axes[0, i].set_title(f高斯层 {i}) axes[0, i].axis(off) if i levels-1: axes[1, i].imshow(lpA[i]) axes[1, i].set_title(f拉普拉斯层 {i}) axes[1, i].axis(off) plt.tight_layout() plt.show() # 显示融合结果 plt.figure(figsize(15, 5)) plt.subplot(1, 3, 1) plt.imshow(img1) plt.title(图像A) plt.axis(off) plt.subplot(1, 3, 2) plt.imshow(img2) plt.title(图像B) plt.axis(off) plt.subplot(1, 3, 3) plt.imshow(ls_) plt.title(金字塔融合结果) plt.axis(off) plt.tight_layout() plt.show() # 运行金字塔示例 pyramid_application(sample.jpg)4. 项目三特征提取与图像匹配4.1 关键点检测与描述符提取特征提取是计算机视觉的基础用于图像匹配、目标识别等任务。def feature_detection_comparison(image_path): 多种特征检测算法对比 img cv2.imread(image_path) gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # SIFT特征检测 sift cv2.SIFT_create() kp_sift, des_sift sift.detectAndCompute(gray, None) # ORB特征检测 orb cv2.ORB_create() kp_orb, des_orb orb.detectAndCompute(gray, None) # SURF特征检测需要opencv-contrib-python try: surf cv2.xfeatures2d.SURF_create(400) kp_surf, des_surf surf.detectAndCompute(gray, None) except: kp_surf, des_surf [], None print(SURF不可用需要安装opencv-contrib-python) # 显示特征点 img_sift cv2.drawKeypoints(gray, kp_sift, None, flagscv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS) img_orb cv2.drawKeypoints(gray, kp_orb, None, flagscv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS) fig, axes plt.subplots(1, 3, figsize(15, 5)) images [gray, img_sift, img_orb] titles [原图, fSIFT特征点: {len(kp_sift)}, fORB特征点: {len(kp_orb)}] for ax, img_display, title in zip(axes, images, titles): ax.imshow(img_display, cmapgray) ax.set_title(title) ax.axis(off) plt.tight_layout() plt.show() return kp_sift, des_sift, kp_orb, des_orb # 运行特征检测 kp_sift, des_sift, kp_orb, des_orb feature_detection_comparison(sample.jpg)4.2 图像匹配与Homography变换特征匹配用于在不同图像间建立对应关系是图像拼接、目标跟踪的基础。def feature_matching(image1_path, image2_path): 特征匹配完整流程 # 读取图像 img1 cv2.imread(image1_path) img2 cv2.imread(image2_path) gray1 cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY) gray2 cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY) # 使用SIFT检测特征 sift cv2.SIFT_create() kp1, des1 sift.detectAndCompute(gray1, None) kp2, des2 sift.detectAndCompute(gray2, None) # 特征匹配 bf cv2.BFMatcher() matches bf.knnMatch(des1, des2, k2) # 应用比率测试 good_matches [] for m, n in matches: if m.distance 0.75 * n.distance: good_matches.append(m) # 绘制匹配结果 img_matches cv2.drawMatches(img1, kp1, img2, kp2, good_matches, None, flags2) plt.figure(figsize(15, 10)) plt.imshow(cv2.cvtColor(img_matches, cv2.COLOR_BGR2RGB)) plt.title(f特征匹配结果 (匹配点: {len(good_matches)})) plt.axis(off) plt.show() return good_matches, kp1, kp2 def homography_transformation(image1_path, image2_path): Homography变换与图像对齐 good_matches, kp1, kp2 feature_matching(image1_path, image2_path) if len(good_matches) 10: # 提取匹配点坐标 src_pts np.float32([kp1[m.queryIdx].pt for m in good_matches]).reshape(-1, 1, 2) dst_pts np.float32([kp2[m.trainIdx].pt for m in good_matches]).reshape(-1, 1, 2) # 计算Homography矩阵 H, mask cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0) # 应用变换 img1 cv2.imread(image1_path) img2 cv2.imread(image2_path) height, width img2.shape[:2] img1_transformed cv2.warpPerspective(img1, H, (width, height)) # 显示结果 plt.figure(figsize(15, 5)) plt.subplot(1, 3, 1) plt.imshow(cv2.cvtColor(img1, cv2.COLOR_BGR2RGB)) plt.title(图像1) plt.axis(off) plt.subplot(1, 3, 2) plt.imshow(cv2.cvtColor(img2, cv2.COLOR_BGR2RGB)) plt.title(图像2) plt.axis(off) plt.subplot(1, 3, 3) plt.imshow(cv2.cvtColor(img1_transformed, cv2.COLOR_BGR2RGB)) plt.title(变换后的图像1) plt.axis(off) plt.tight_layout() plt.show() return H, mask else: print(匹配点不足无法计算Homography) return None, None # 运行图像匹配需要两张相关图像 # H, mask homography_transformation(img1.jpg, img2.jpg)4.3 图像拼接实战基于特征匹配和Homography变换实现多图像自动拼接。def image_stitching(image_paths): 多图像自动拼接 # 读取所有图像 images [] for path in image_paths: img cv2.imread(path) images.append(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)) # 使用OpenCV的Stitcher类 stitcher cv2.Stitcher.create(cv2.Stitcher_PANORAMA) status, panorama stitcher.stitch(images) if status cv2.Stitcher_OK: plt.figure(figsize(15, 10)) plt.imshow(panorama) plt.title(拼接结果) plt.axis(off) plt.show() return panorama else: print(f拼接失败错误代码: {status}) return None # 手动实现简单拼接两图像 def manual_stitching(image1_path, image2_path): 手动实现两图像拼接 img1 cv2.imread(image1_path) img2 cv2.imread(image2_path) # 转换为RGB img1_rgb cv2.cvtColor(img1, cv2.COLOR_BGR2RGB) img2_rgb cv2.cvtColor(img2, cv2.COLOR_BGR2RGB) # 特征匹配 good_matches, kp1, kp2 feature_matching(image1_path, image2_path) if len(good_matches) 10: src_pts np.float32([kp1[m.queryIdx].pt for m in good_matches]).reshape(-1, 1, 2) dst_pts np.float32([kp2[m.trainIdx].pt for m in good_matches]).reshape(-1, 1, 2) H, mask cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0) # 计算拼接后图像尺寸 h1, w1 img1.shape[:2] h2, w2 img2.shape[:2] corners1 np.float32([[0, 0], [0, h1], [w1, h1], [w1, 0]]).reshape(-1, 1, 2) corners2 np.float32([[0, 0], [0, h2], [w2, h2], [w2, 0]]).reshape(-1, 1, 2) corners2_transformed cv2.perspectiveTransform(corners2, H) all_corners np.concatenate((corners1, corners2_transformed), axis0) # 计算拼接画布尺寸 x_min, y_min np.int32(all_corners.min(axis0).ravel() - 0.5) x_max, y_max np.int32(all_corners.max(axis0).ravel() 0.5) translation_dist [-x_min, -y_min] H_translation np.array([[1, 0, translation_dist[0]], [0, 1, translation_dist[1]], [0, 0, 1]]) # 应用变换 result cv2.warpPerspective(img1_rgb, H_translation.dot(H), (x_max - x_min, y_max - y_min)) result[translation_dist[1]:translation_dist[1] h2, translation_dist[0]:translation_dist[0] w2] img2_rgb plt.figure(figsize(15, 10)) plt.imshow(result) plt.title(手动拼接结果) plt.axis(off) plt.show() return result else: print(匹配点不足无法拼接) return None # 运行拼接示例 # panorama manual_stitching(left.jpg, right.jpg)5. 项目四图像分割与目标提取5.1 阈值分割技术阈值分割是最简单的图像分割方法适用于背景和前景对比明显的场景。def threshold_segmentation_methods(image_path): 多种阈值分割方法对比 img cv2.imread(image_path) gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 全局阈值分割 _, thresh1 cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY) _, thresh2 cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY_INV) _, thresh3 cv2.threshold(gray, 127, 255, cv2.THRESH_TRUNC) _, thresh4 cv2.threshold(gray, 127, 255, cv2.THRESH_TOZERO) # 自适应阈值分割 thresh5 cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 11, 2) thresh6 cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2) # Otsu阈值分割 _, thresh7 cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY cv2.THRESH_OTSU) # 显示结果 images [gray, thresh1, thresh2, thresh3, thresh4, thresh5, thresh6, thresh7] titles [原图, 二值化, 反二值化, 截断, 零阈值, 自适应平均, 自适应高斯, Otsu阈值] fig, axes plt.subplots(2, 4, figsize(20, 10)) for ax, img_display, title in zip(axes.flat, images, titles): ax.imshow(img_display, cmapgray) ax.set_title(title) ax.axis(off) plt.tight_layout() plt.show() return thresh7 # 返回最佳分割结果 # 运行阈值分割 best_threshold threshold_segmentation_methods(sample.jpg)5.2 基于边缘的分割结合边缘检测和形态学操作实现更精确的分割。def edge_based_segmentation(image_path): 基于边缘的分割方法 img cv2.imread(image_path) gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 边缘检测 edges cv2.Canny(gray, 100, 200) # 形态学操作闭合边缘 kernel cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5)) closed_edges cv2.morphologyEx(edges, cv2.MORPH_CLOSE, kernel) # 查找轮廓 contours, _ cv2.findContours(closed_edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 创建掩码 mask np.zeros_like(gray) cv2.drawContours(mask, contours, -1, 255, -1) # 应用掩码 segmented cv2.bitwise_and(img, img, maskmask) # 显示结果 fig, axes plt.subplots(2, 3, figsize(15, 10)) results [gray, edges, closed_edges, mask, cv2.cvtColor(segmented, cv2.COLOR_BGR2RGB), segmented] titles [原图, Canny边缘, 闭合边缘, 分割掩码, 分割结果, 最终效果] for ax, result, title in zip(axes.flat, results, titles): if len(result.shape) 2: ax.imshow(result, cmapgray) else: ax.imshow(result) ax.set_title(title) ax.axis(off) plt.tight_layout() plt.show() return segmented, contours # 运行边缘分割 segmented_img, contours edge_based_segmentation(sample.jpg)5.3 分水岭算法分割分水岭算法适用于复杂背景下的物体分割。def watershed_segmentation(image_path): 分水岭算法实现图像分割 img cv2.imread(image_path) img_rgb cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # 转换为灰度图并去噪 gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) gray cv2.medianBlur(gray, 5) # 二值化 _, 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) _, 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) # 标记连通组件 _, markers cv2.connectedComponents(sure_fg) markers markers 1 markers[unknown 255] 0 # 应用分水岭算法 markers cv2.watershed(img, markers) img[markers -1] [255, 0, 0] # 标记边界为红色 # 显示结果 fig, axes plt.subplots(2, 4, figsize(20, 10)) results [img_rgb, gray, thresh, opening, sure_bg, dist_transform, sure_fg, cv2.cvtColor(img, cv2.COLOR_BGR2RGB)] titles [原图, 灰度