小白也能学会!用 Python+OpenCV 一键提取扇子图片✨
今天我们用短短几十行代码,完成了从读取→处理→提取→保存的完整图像流程,是不是很神奇?其实 OpenCV 的功能远不止这些,你还可以试试抠出其他物体,比如杯子、花朵,原理都是一样的!
·
你有没有想过,只靠几行代码就能从一张普通照片里,精准抠出你想要的物体?今天我就带大家从零开始,用 Python 和 OpenCV 库,一步步把一张扇子图片里的扇子完美提取出来,全程无门槛,小白也能跟着做!
🎯 我们要实现什么?
先明确我们的目标,一共 4 步:
- 读取名为
fan.jpg的图片,把它缩放到宽 640、高 480,再逆时针旋转 90 度 - 用 Canny 算法提取图片的边缘轮廓
- 找到扇子的外轮廓,生成一个 “遮罩”(掩模),只保留扇子区域
- 用遮罩和原图做运算,把扇子单独抠出来,保存成
shanzi.png
最终效果就是:从一张杂乱的背景图里,只留下干净的扇子~
🛠️ 准备工作:安装必要的库
在开始写代码前,我们需要先安装 OpenCV 库,打开你的命令提示符(CMD)或终端,输入下面这行命令:
bash
运行
pip install opencv-python numpy
等待安装完成,我们就可以开始写代码啦!
📝 完整代码 + 逐行讲解
我会把完整代码贴出来,然后逐行解释每一步做了什么,保证你看得懂!
第一步:导入工具库
python
运行
import cv2
import numpy as np
cv2:就是我们的核心工具 OpenCV,负责处理图片numpy:用来创建和处理数组,配合 OpenCV 做矩阵运算
第二步:读取、缩放、旋转图片
python
运行
# 1. 读取 fan.jpg,设置尺寸 640×480,逆时针旋转90度
img = cv2.imread("fan.jpg") # 读取图片
img = cv2.resize(img, (640, 480)) # 把图片缩放到 宽640,高480
rotated = cv2.rotate(img, cv2.ROTATE_90_COUNTERCLOCKWISE) # 逆时针旋转90度
cv2.imread("fan.jpg"):读取你电脑里名为fan.jpg的图片,注意要把图片和代码放在同一个文件夹里哦!cv2.resize(img, (640, 480)):统一图片大小,方便后续处理cv2.ROTATE_90_COUNTERCLOCKWISE:这个参数就是 “逆时针旋转 90 度” 的意思,非常直观
第三步:Canny 边缘检测
python
运行
# 2. Canny边缘检测
gray = cv2.cvtColor(rotated, cv2.COLOR_BGR2GRAY) # 转灰度图
blurred = cv2.GaussianBlur(gray, (5, 5), 0) # 高斯模糊,减少噪点
edges = cv2.Canny(blurred, 50, 150) # 提取边缘
- 为什么要转灰度图?因为彩色图信息太多,边缘检测只需要亮度信息就够了
- 高斯模糊就像给图片 “磨皮”,去掉小噪点,让边缘更清晰
cv2.Canny(blurred, 50, 150):两个数字是阈值,调大就会只保留更明显的边缘,这里的数值是通用推荐值,直接用就行
第四步:提取扇子外轮廓 + 生成掩模
python
运行
# 3. 查找轮廓,选取扇子外轮廓,生成掩模
cnts = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = cnts[0] if len(cnts) == 2 else cnts[1] # 兼容不同OpenCV版本
largest_contour = max(contours, key=cv2.contourArea) # 找到面积最大的轮廓(就是扇子)
mask = np.zeros_like(gray) # 创建和灰度图一样大的黑色遮罩
cv2.drawContours(mask, [largest_contour], -1, 255, thickness=cv2.FILLED) # 把扇子轮廓涂成白色
cv2.findContours:这一步是找所有的边缘轮廓,因为 OpenCV 版本不同,返回值数量不一样,所以我们加了一行兼容代码,避免报错max(contours, key=cv2.contourArea):扇子是图片里最大的物体,所以面积最大的轮廓就是它!mask:就是我们的 “遮罩”,白色区域代表要保留的扇子,黑色区域代表要去掉的背景
第五步:抠出扇子 + 保存
python
运行
# 4. 按位与提取扇子,保存为 shanzi.png
result = cv2.bitwise_and(rotated, rotated, mask=mask) # 只保留遮罩白色部分的内容
cv2.imwrite("shanzi.png", result) # 保存最终图片
cv2.bitwise_and:这是一个 “按位与” 运算,简单说就是:遮罩是白色的地方,保留原图内容;遮罩是黑色的地方,变成黑色cv2.imwrite:把抠好的扇子图片保存为shanzi.png,直接在代码文件夹里就能找到!
(可选)按空格查看每一步效果
为了让你更直观地看到每一步的变化,我加了一个按空格依次显示图片的功能,旧图不会关闭,方便对比:
python
运行
# ===================== 按空格依次显示所有图片(不关闭上一张) =====================
_shown_images = []
def cv_show(name, img):
global _shown_images
cv2.imshow(name, img)
_shown_images.append(name)
while True:
key = cv2.waitKey(0)
if key == 32: # 按空格继续
break
elif key == 27: # 按ESC退出,关闭所有窗口
for win in _shown_images:
cv2.destroyWindow(win)
_shown_images.clear()
exit()
# 显示所有步骤
cv_show("1. 原图", img)
cv_show("2. 逆时针旋转90度", rotated)
cv_show("3. Canny边缘", edges)
cv_show("4. 掩模", mask)
cv_show("5. 最终提取扇子", result)
# 等待ESC关闭所有
while True:
if cv2.waitKey(0) == 27:
cv2.destroyAllWindows()
break
- 运行代码后,按空格就会弹出下一张图,所有旧图都会留在屏幕上
- 按ESC就可以关闭所有窗口,结束程序
🚀 怎么运行代码?
- 把你的扇子图片命名为
fan.jpg,和代码放在同一个文件夹里 - 把上面所有代码复制到一个
.py文件里(比如fan_extract.py) - 打开终端,进入这个文件夹,输入:
python fan_extract.py - 按空格一步步看效果,最后在文件夹里找到
shanzi.png,就是抠好的扇子啦!
💡 常见小问题解决
- 报错:找不到
fan.jpg→ 检查图片和代码是不是在同一个文件夹,或者把cv2.imread里的路径改成绝对路径(比如C:/Users/ASUS/Desktop/fan.jpg) - 报错:too many values to unpack→ 就是我们代码里已经修复的 OpenCV 版本问题,直接用我给的兼容代码就好
- 抠出来的扇子不完整→ 可以调整 Canny 的阈值,比如把
50, 150改成30, 100,让边缘更敏感
✨ 总结
今天我们用短短几十行代码,完成了从读取→处理→提取→保存的完整图像流程,是不是很神奇?其实 OpenCV 的功能远不止这些,你还可以试试抠出其他物体,比如杯子、花朵,原理都是一样的!
如果你觉得这篇文章对你有帮助,欢迎点赞收藏,下次我们再一起探索更多好玩的图像处理技巧~
最终完整代码(直接复制可用)
python
运行
import cv2
import numpy as np
# ===================== 功能实现 =====================
# 1. 读取 fan.jpg,设置尺寸 640×480,逆时针旋转90度
img = cv2.imread("fan.jpg")
img = cv2.resize(img, (640, 480))
rotated = cv2.rotate(img, cv2.ROTATE_90_COUNTERCLOCKWISE)
# 2. Canny边缘检测
gray = cv2.cvtColor(rotated, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
edges = cv2.Canny(blurred, 50, 150)
# 3. 查找轮廓,选取扇子外轮廓,生成掩模
cnts = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = cnts[0] if len(cnts) == 2 else cnts[1]
largest_contour = max(contours, key=cv2.contourArea)
mask = np.zeros_like(gray)
cv2.drawContours(mask, [largest_contour], -1, 255, thickness=cv2.FILLED)
# 4. 按位与提取扇子,保存为 shanzi.png
result = cv2.bitwise_and(rotated, rotated, mask=mask)
cv2.imwrite("shanzi.png", result)
# ===================== 按空格依次显示所有图片(不关闭上一张) =====================
_shown_images = []
def cv_show(name, img):
global _shown_images
cv2.imshow(name, img)
_shown_images.append(name)
while True:
key = cv2.waitKey(0)
if key == 32:
break
elif key == 27:
for win in _shown_images:
cv2.destroyWindow(win)
_shown_images.clear()
exit()
cv_show("1. 原图", img)
cv_show("2. 逆时针旋转90度", rotated)
cv_show("3. Canny边缘", edges)
cv_show("4. 掩模", mask)
cv_show("5. 最终提取扇子", result)
while True:
if cv2.waitKey(0) == 27:
cv2.destroyAllWindows()
break
更多推荐
所有评论(0)