计算机视觉——Opencv(实现抠图功能)
本文将介绍如何利用OpenCV (cv2)和NumPy对图像进行一系列操作调整图像尺寸并旋转使用 Canny 算法进行边缘检测提取最大轮廓并生成掩模利用掩模提取原图中的目标区域并保存我们将以下面这张图作为示例目标是提取图像中最大的物体区域并保存成一张新图片导入库 读取图片 预处理# 1. 导入需要的库 import cv2 import numpy as np # -------------------------- 读取并预处理图片 -------------------------- # 读取图片把路径换成你自己的图片路径 img cv2.imread(rC:\Users\LEGION\Desktop\fba8f805b62cae66c6579969abeb86d8.jpg) # 检查图片是否读取成功非常重要 if img is None: raise FileNotFoundError(图片读取失败请检查路径是否正确) # 统一调整图片大小宽640高480 img_resized cv2.resize(img, (640, 480)) # 逆时针旋转90度让扇子摆正方便检测 img_rotated cv2.rotate(img_resized, cv2.ROTATE_90_COUNTERCLOCKWISE) # 显示效果 cv2.imshow(1-原图预处理后, img_rotated) cv2.waitKey(0) cv2.destroyAllWindows()整尺寸resize()统一图片大小降低计算量保证处理稳定旋转图片rotate()ROTATE_90_COUNTERCLOCKWISE 逆时针 90 度作用让扇子摆正边缘检测更准确注意旋转方向要明确如果写成cv2.ROTATE_90_CLOCKWISE就会顺时针旋转。缩放先于旋转可以避免旋转后图像尺寸不一致导致的裁切问题。Canny 边缘检测核心步骤# -------------------------- Canny边缘检测 -------------------------- # 1. 转为灰度图边缘检测必须用灰度图 gray cv2.cvtColor(img_rotated, cv2.COLOR_BGR2GRAY) # 2. 高斯模糊去噪点边缘检测前必做 blurred cv2.GaussianBlur(gray, (5, 5), 0) # 3. Canny边缘检测 edges cv2.Canny(blurred, 50, 150) # 显示结果 cv2.imshow(2-灰度图, gray) cv2.imshow(3-模糊后, blurred) cv2.imshow(4-Canny边缘结果, edges) cv2.waitKey(0) cv2.destroyAllWindows()灰度化cvtColor彩色图有 3 个通道灰度图只有 1 个通道Canny 边缘检测只接受灰度图高斯模糊GaussianBlur(5,5)是模糊核大小必须奇数作用消除噪点防止把噪点当成边缘Canny 边缘检测50低阈值 —— 小于这个值的边缘会被抛弃150高阈值 —— 大于这个值的边缘会被保留标准比例1:2 或 1:3运行后你会看到扇子变成白色线条背景黑色这就是边缘。提示阈值可以调节低阈值太小会有噪声太大会丢失细节。查找轮廓 版本兼容处理# -------------------------- 查找轮廓兼容所有OpenCV版本 -------------------------- # 查找轮廓 contour_result cv2.findContours( edges.copy(), cv2.RETR_EXTERNAL, # 只找最外层轮廓 cv2.CHAIN_APPROX_SIMPLE ) # 版本兼容3.x 和 4.x/5.x 返回值不同 if len(contour_result) 2: contours, hierarchy contour_result else: _, contours, hierarchy contour_result # 判断是否找到轮廓 if not contours: raise ValueError(未检测到扇子轮廓请调整Canny阈值) # 选择面积最大的轮廓扇子主体 max_contour max(contours, keycv2.contourArea) print(f找到 {len(contours)} 个轮廓最大轮廓面积为{cv2.contourArea(max_contour)})findContours查找轮廓从 Canny 边缘图中提取所有闭合形状RETR_EXTERNAL只提取最外层不包含内部小孔版本兼容OpenCV 3.x 返回 3 个值OpenCV 4.x/5.x 返回 2 个值代码自动适配不会报错筛选最大轮廓扇子是图片中最大的物体用max(..., keycv2.contourArea)自动选出扇子轮廓生成掩模Mask# -------------------------- 生成掩模 -------------------------- # 创建和图片一样大的全黑图片掩模 mask np.zeros_like(img_rotated) # 在掩模上把扇子轮廓涂成白色 cv2.drawContours( mask, # 在哪个图上画 [max_contour], # 画哪个轮廓 -1, # 画所有层级 (255,255,255), # 白色 cv2.FILLED # 填充内部 ) # 显示掩模 cv2.imshow(5-掩模, mask) cv2.waitKey(0) cv2.destroyAllWindows()掩模是什么全黑图片 不要的区域白色区域 要保留的区域drawContours填充轮廓cv2.FILLED填充轮廓内部最终得到一张只有扇子是白色、其余全黑的图片这就是掩模掩模作用告诉程序 “只保留白色区域”。提取扇子 保存图片# -------------------------- 提取扇子并保存 -------------------------- # 按位与操作只保留掩模白色区域 result cv2.bitwise_and(img_rotated, mask) # 保存图片 cv2.imwrite(shanzi.png, result) # 显示最终结果 cv2.imshow(6-最终提取的扇子, result) cv2.waitKey(0) cv2.destroyAllWindows() print(✅ 处理完成扇子已保存为 shanzi.png)bitwise_and按位与只有原图和掩模同时为非 0的区域才会保留黑色区域0会被直接过滤常见问题检测不到轮廓把 Canny 阈值调低30, 100提取不完整模糊核改小(3,3)阈值调低运行结果