计算机视觉(opencv)练习——抠图(图像裁剪与轮廓提取)
用 OpenCV 实现图像裁剪与轮廓提取 —— 以风扇图像为例
本文将介绍如何利用 OpenCV (cv2) 和 NumPy 对图像进行一系列操作:
调整图像尺寸并旋转
使用 Canny 算法进行边缘检测
提取最大轮廓并生成掩模
利用掩模提取原图中的目标区域并保存
我们将以一张名为 fan.jpg 的图片作为示例,目标是提取图像中最大的物体区域,并保存成一张新图片 shanzi.png。
原图:
运行结果:
1. 导入必要的库
import cv2
import numpy as np
cv2:OpenCV 的 Python 接口,提供各种图像处理函数。
numpy:用于创建掩模、矩阵运算等。
2. 读取、缩放和旋转图像
fan = cv2.imread('fan.jpg') # 读取原图
fan = cv2.resize(fan, dsize=(640, 480)) # 调整图片尺寸
fan = cv2.rotate(fan, cv2.ROTATE_90_COUNTERCLOCKWISE) # 逆时针旋转90度
解析:
cv2.imread()
读取图像,返回一个三维数组(高度、宽度、通道)。cv2.resize()
将图像缩放到 640×480,保证后续处理尺寸统一。cv2.rotate()
按指定模式旋转图像。这里使用cv2.ROTATE_90_COUNTERCLOCKWISE
实现逆时针 90° 旋转。
⚠️ 注意:
旋转方向要明确,如果写成
cv2.ROTATE_90_CLOCKWISE
就会顺时针旋转。缩放先于旋转,可以避免旋转后图像尺寸不一致导致的裁切问题。
3. 转为灰度并进行 Canny 边缘检测
fan_gray = cv2.cvtColor(fan, cv2.COLOR_BGR2GRAY) # 转换为灰度图
cv2.imshow('fan_b', fan_gray)
cv2.waitKey(0)zl_canny = cv2.Canny(fan_gray, threshold1=100, threshold2=150) # Canny边缘检测
cv2.imshow('zl_canny', zl_canny)
cv2.waitKey(0)
解析:
cv2.cvtColor()
将彩色图转为灰度图,减少通道数,提高边缘检测效率。cv2.Canny()
用双阈值算法检测边缘:threshold1=100
:低阈值,用于弱边缘判定。threshold2=150
:高阈值,强边缘必须大于此值。
cv2.imshow()
显示图像,cv2.waitKey(0)
等待用户按键。
📌 提示:
阈值可以调节,低阈值太小会有噪声,太大会丢失细节。
如果图像噪声大,建议先用
cv2.GaussianBlur()
进行平滑。
4. 查找轮廓并生成掩模
_, contours, hierarchy = cv2.findContours(zl_canny, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)image_copy = fan.copy()
image_copy = cv2.drawContours(image=image_copy, contours=contours, contourIdx=-1, color=(0, 255, 0), thickness=3)
cv2.imshow('contours_show', image_copy)
cv2.waitKey(0)cnt = sorted(contours, key=cv2.contourArea, reverse=True)[0] # 选取最大面积的轮廓
mask = np.zeros(fan_gray.shape, dtype="uint8") # 创建一个黑色掩模
cv2.drawContours(mask, contours=[cnt], contourIdx=-1, color=255, thickness=-1)
cv2.imshow('mask', mask)
cv2.waitKey(0)
解析:
cv2.findContours()
找出所有轮廓:cv2.RETR_EXTERNAL
:只检测最外层轮廓,忽略嵌套。cv2.CHAIN_APPROX_SIMPLE
:压缩冗余点,只保留拐点,提高效率。
cv2.drawContours()
用绿色画出所有轮廓,方便观察。sorted(..., key=cv2.contourArea, reverse=True)[0]
找到面积最大的轮廓。np.zeros()
创建一张全黑的图(掩模)。再用
cv2.drawContours()
填充该轮廓(thickness = -1 表示填充)。
📌 小技巧:
如果想查看每个轮廓的面积,可以
for cnt in contours: print(cv2.contourArea(cnt))
。在某些 OpenCV 版本中,
cv2.findContours()
只返回两个值,可以写成contours, hierarchy = cv2.findContours(...)
。
5. 利用掩模提取目标区域并保存
thresh_mask_and = cv2.bitwise_and(fan, fan, mask=mask)
cv2.imshow('thresh_mask_and', thresh_mask_and)
cv2.waitKey(0)
cv2.imwrite('shanzi.png', thresh_mask_and)
解析:
cv2.bitwise_and()
按位与操作,将掩模中值为 255 的部分保留下来,其余变黑。结果就是原图中最大轮廓对应的区域。
cv2.imwrite()
保存图片。
💡 建议:
保存路径可以改成绝对路径,比如
cv2.imwrite(r'C:\output\shanzi.png', thresh_mask_and)
,避免找不到文件。如果后续还需要透明背景,可以将黑色部分处理成透明通道。
6. 运行效果
整个流程执行后,你将看到:
缩放+旋转后的图像
灰度图
Canny 边缘图
绘制轮廓的彩色图
填充的掩模
最终裁剪出的目标区域,并保存为
shanzi.png
这样我们就实现了一个完整的 目标提取与裁剪 工作流。
总结
本文展示了一个典型的图像处理任务:
图像预处理:缩放、旋转、灰度化
边缘检测:Canny 算法
轮廓提取:寻找最大面积目标
掩模应用:提取目标并保存
这种方法不仅适用于风扇图片,也可以应用于其他物体提取,如分割零件、裁剪证件照、检测物品轮廓等。