当前位置: 首页 > news >正文

【深度学习】OpenCV 实战:从图片中精确提取扇子区域

文章目录

  • 完整代码一览
  • 导入库与辅助函数
    • 定义显示图像函数cv_show
    • 辅助轮廓排序函数 sort_contours
  • 主程序流程
    • 读取图片,缩放并逆时针旋转90度
    • Canny 边缘检测
    • 查找轮廓,筛选扇子外轮廓
    • 生成掩膜
    • 按位与操作提取扇子区域
    • 保存结果

一个完整的图像提取流程:读取图片 → 缩放 + 旋转 → Canny 边缘检测 → 查找轮廓 → 生成掩膜 → 按位与提取目标区域。

项目要求:
一张名为fan.jpg的图片,现要求使用 Python 结合 OpenCV 库编写代码实现以下功能:
(1)读取名为fan.jpg的图片,将尺寸设置为宽640,高480,然后逆时针旋转90度;
(2)使用Canny边缘检测提取(1)处理后的边缘;
(3)在提取边缘的基础上,查找轮廓并选取扇子的外轮廓,生成相应的掩模;
(4)将步骤 1 处理后的图像与步骤 3 生成的掩模执行按位与操作,提取扇子区域图像,最终将结果保存为shanzi.png文件。
样图:
fan.jpy

完整代码一览

import cv2 import numpy as np defcv_show(name,image):cv2.imshow(name,image)cv2.waitKey(0)defsort_contours(cnts,method='left-to-right'):reverse=False i=0ifmethod=='right-to-left'or method=='bottom-to-top':reverse=Trueifmethod=='top-to-bottom'or method=='bottom-to-top':i=1boundingBoxes=[cv2.boundingRect(c)forc in cnts](cnts,boundingBoxes)=zip(*sorted(zip(cnts,boundingBoxes),key=lambda b:b[1][i],reverse=reverse))returncnts,boundingBoxes #----------主程序----------#(1)读取图片,缩放并逆时针旋转90度 img=cv2.imread(r'./fan.jpg')img=cv2.resize(img,(640,480))img_1=np.rot90(img,k=1)# k=1表示逆时针旋转90度 cv2.imshow('yuan_tu',img)cv2.imshow('fan_image',img_1)cv2.waitKey(0)cv2.destroyAllWindows()#(2)Canny边缘检测 contours_img=img_1.copy()gray=cv2.cvtColor(img_1,cv2.COLOR_BGR2GRAY)blurred=cv2.GaussianBlur(gray,ksize=(5,5),sigmaX=0)cv_show('blurred',blurred)img_canny=cv2.Canny(blurred,threshold1=75,threshold2=200)cv_show('img_canny',img_canny)#(3)查找轮廓,选取扇子的外轮廓,生成掩膜 cnts=cv2.findContours(img_canny.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)[-2]cv2.drawContours(contours_img,cnts,-1,(0,0,255),3)cv_show('contours_img',contours_img)# 排序(其实这里只有一个最大的轮廓,但保留排序习惯) questionCnts=[]forc in cnts:x,y,w,h=cv2.boundingRect(c)questionCnts.append(c)questionCnts=sort_contours(questionCnts,method="top-to-bottom")[0]fan_conts=questionCnts[0]# 取第一个(最大的)轮廓 mask=np.zeros_like(gray)cv2.drawContours(mask,[fan_conts],-1,255,thickness=-1)# thickness=-1填充轮廓内部cv_show("img_mask",mask)#(4)按位与操作,提取扇子区域 img_mask_and=cv2.bitwise_and(img_1,img_1,mask=mask)cv_show('img_mask_and',img_mask_and)# 保存结果 cv2.imwrite('shanzi.png',img_mask_and)

导入库与辅助函数

定义显示图像函数cv_show

import cv2 import numpy as np defcv_show(name,image):cv2.imshow(name,image)cv2.waitKey(0)

辅助轮廓排序函数 sort_contours

defsort_contours(cnts,method='left-to-right'):reverse=False i=0ifmethod=='right-to-left'or method=='bottom-to-top':reverse=Trueifmethod=='top-to-bottom'or method=='bottom-to-top':i=1boundingBoxes=[cv2.boundingRect(c)forc in cnts](cnts,boundingBoxes)=zip(*sorted(zip(cnts,boundingBoxes),key=lambda b:b[1][i],reverse=reverse))returncnts,boundingBoxes

主程序流程

读取图片,缩放并逆时针旋转90度

img=cv2.imread(r'./fan.jpg')img=cv2.resize(img,(640,480))img_1=np.rot90(img,k=1)cv2.imshow('yuan_tu',img)cv2.imshow('fan_image',img_1)cv2.waitKey(0)cv2.destroyAllWindows()

运行结果:

Canny 边缘检测

contours_img=img_1.copy()gray=cv2.cvtColor(img_1,cv2.COLOR_BGR2GRAY)blurred=cv2.GaussianBlur(gray,ksize=(5,5),sigmaX=0)cv_show('blurred',blurred)img_canny=cv2.Canny(blurred,threshold1=75,threshold2=200)cv_show('img_canny',img_canny)

先复制旋转后的图像,用于后面绘制轮廓,再转为灰度图,用 5×5 的核进行平滑,去除噪点,避免边缘检测时出现大量假边缘。
Canny 边缘检测:阈值 75 和 200 是经验值,可根据图片对比度调整。数值越小,检测出的边缘越丰富(可能包含噪声);越大则只保留最强边缘。

运行结果:

查找轮廓,筛选扇子外轮廓

cnts=cv2.findContours(img_canny.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)[-2]cv2.drawContours(contours_img,cnts,-1,(0,0,255),3)cv_show('contours_img',contours_img)

运行结果:

这里把所有轮廓放入列表,然后用排序函数(按从上到下排序)——实际上因为只有一个大轮廓(其他小噪声轮廓面积小),排序后第一个就是面积最大的扇子轮廓。

questionCnts=[]forc in cnts:x,y,w,h=cv2.boundingRect(c)questionCnts.append(c)questionCnts=sort_contours(questionCnts,method="top-to-bottom")[0]fan_conts=questionCnts[0]

生成掩膜

mask=np.zeros_like(gray)cv2.drawContours(mask,[fan_conts],-1,255,thickness=-1)cv_show("img_mask",mask)

运行结果:

按位与操作提取扇子区域

对两张图像(这里都是 img_1)按位与,但通过 mask 参数指定只有白色区域才参与运算,黑色区域结果直接为 0。
这样,原图中只有扇子部分被保留,背景全黑,完美抠出扇子。

img_mask_and=cv2.bitwise_and(img_1,img_1,mask=mask)cv_show('img_mask_and',img_mask_and)

运行结果:

保存结果

cv2.imwrite('shanzi.png',img_mask_and)
http://www.jsqmd.com/news/1091212/

相关文章:

  • 告别快餐式传奇!冰雪传奇点卡版以经典公平机制留住玩家
  • [深圳] SHEIN 内推:算法/大模型/后端/数据/安全/测试/iOS,20-80k
  • 告别路径迷宫:一站式配置VSCode智能路径解析与跳转
  • 从零构建WordPress渗透测试靶场:实战演练与安全加固
  • LeetCode 热题 100——3.字母异位词分组
  • OmenSuperHub终极指南:免费解锁惠普游戏本的隐藏性能
  • 西安人脸识别门禁:适合老旧小区改造的需求分析与选择
  • 【单片机毕业设计】 基于 STM32 的红外感应智能定时药盒设计,基于单片机的语音播报用药提醒装置开发(012901)
  • IEEE ACCESS投稿全流程解析:从初稿到检索的实战指南
  • 【论文阅读】Stable-RAG: Mitigating Retrieval-Permutation-Induced Hallucinations in Retrieval-Augmented Gen
  • 5分钟掌握QModMaster:免费开源的ModBus调试终极解决方案
  • CentOS7 Docker 离线部署 + Registry 私有仓库完整实操
  • 微信小程序安全审计实战:使用小锦哥进行自动化漏洞检测与深度防御
  • 日本风情lr预设|日系清新旅行人像海边街拍Lightroom下载lr调色风格
  • Python+Selenium端到端自动化测试实战:从POM设计到CI/CD集成
  • BerriAI/LiteLLM 开源项目深度解析:实现多模型统一调用、负载均衡与成本管理的标准化 API 代理实战指南
  • Defender Control完整指南:如何在Windows 10/11中永久禁用Windows Defender
  • ECCV 2026 | 从静态拟合到动态分配:AMG-Fuse 用模态贡献Mask破解恶劣天气下的融合难题
  • 永不消亡的“数字幽灵”:为什么都2026年了,这个30年前的漏洞依然无处不在?
  • Netcatty 开源跨平台 SSH 运维客户端完整技术实操指南
  • 5分钟掌握MGit:Android平台最强大的Git客户端全解析
  • 优选冰雪传奇点卡版!原汁原味复古设定,打造纯净开荒体验
  • 打破苹果生态壁垒:3步让Windows电脑成为AirPlay 2投屏中心
  • W55MH32L-EVB 上手测评:硬件 TCP/IP 加持的以太网单片机,MicroPython 零门槛开发
  • 【云原生与DevOps】01-Docker从入门到实践:镜像、容器、网络三位一体
  • 我把整个代码库喂给 Claude Code,工具超 50 个就静默丢失,这个坑太阴了
  • 2.1 告别“单体应用”:为什么你的记账和炒股混在一起就是灾难
  • 大模型幻觉怎么治?引用溯源兜底实操
  • PostgreSQL 索引里到底存了什么?
  • MSP430FR5969 LaunchPad开发板:FRAM与超低功耗设计实战指南