你有没有想过,只靠几行代码就能从一张普通照片里,精准抠出你想要的物体?今天我就带大家从零开始,用 Python 和 OpenCV 库,一步步把一张扇子图片里的扇子完美提取出来,全程无门槛,小白也能跟着做!


🎯 我们要实现什么?

先明确我们的目标,一共 4 步:

  1. 读取名为fan.jpg的图片,把它缩放到宽 640、高 480,再逆时针旋转 90 度
  2. 用 Canny 算法提取图片的边缘轮廓
  3. 找到扇子的外轮廓,生成一个 “遮罩”(掩模),只保留扇子区域
  4. 用遮罩和原图做运算,把扇子单独抠出来,保存成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就可以关闭所有窗口,结束程序

🚀 怎么运行代码?

  1. 把你的扇子图片命名为fan.jpg,和代码放在同一个文件夹里
  2. 把上面所有代码复制到一个.py文件里(比如fan_extract.py
  3. 打开终端,进入这个文件夹,输入:python fan_extract.py
  4. 按空格一步步看效果,最后在文件夹里找到shanzi.png,就是抠好的扇子啦!

💡 常见小问题解决

  1. 报错:找不到fan.jpg→ 检查图片和代码是不是在同一个文件夹,或者把cv2.imread里的路径改成绝对路径(比如C:/Users/ASUS/Desktop/fan.jpg
  2. 报错:too many values to unpack→ 就是我们代码里已经修复的 OpenCV 版本问题,直接用我给的兼容代码就好
  3. 抠出来的扇子不完整→ 可以调整 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

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐