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

【python】OpenCV—findContours(4.6)

在这里插入图片描述

文章目录

  • 1、功能描述
  • 2、代码实现
  • 3、效果展示
  • 4、完整代码
  • 5、涉及到的库函数
    • cv2.inRange
  • 6、参考

1、功能描述

给出一张仅含有手指的图片,判断图片中有多少根手指

2、代码实现

导入库函数,图像预处理

import numpy as np
import cv2 as cv
img = cv.imread("./5.png")
mask_img = skinmask(img)
cv.imwrite("mask_img.jpg", mask_img)

其中 def skinmask 实现如下

def skinmask(img):hsvim = cv.cvtColor(img, cv.COLOR_BGR2HSV)lower = np.array([0, 48, 80], dtype = "uint8")upper = np.array([20, 255, 255], dtype = "uint8")skinRegionHSV = cv.inRange(hsvim, lower, upper)cv.imwrite("skinRegionHSV.jpg", skinRegionHSV)blurred = cv.blur(skinRegionHSV, (2,2))ret, thresh = cv.threshold(blurred,0,255,cv.THRESH_BINARY)return thresh

先转化为 HSV 彩色模式,然后 cv2.inRange 二值化处理,接着模糊,二值化

skinRegionHSV.jpg

在这里插入图片描述

mask_img.jpg
在这里插入图片描述

接下里计算轮廓和凸包

contours, hull = getcnthull(mask_img)cv.drawContours(img, [contours], -1, (255,255,0), 2)
cv.imwrite("contours.jpg", img)cv.drawContours(img, [hull], -1, (0, 255, 255), 2)
cv.imwrite("hull.jpg", img)

其中 def getcnthull 实现如下

def getcnthull(mask_img):contours, hierarchy = cv.findContours(mask_img, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)contours = max(contours, key=lambda x: cv.contourArea(x))hull = cv.convexHull(contours)return contours, hull

可以看到凸包是通过计算最大面积的轮廓计算得到的

轮廓 contours.jpg

在这里插入图片描述

凸包 hull.jpg

在这里插入图片描述

接着计算凸缺陷,也即介于凸包和轮廓间的区域

defects = getdefects(contours)

其中 def getdefects 的实现如下

def getdefects(contours):hull = cv.convexHull(contours, returnPoints=False)defects = cv.convexityDefects(contours, hull)return defects

遍历凸缺陷,计算角度,判断是否为手指夹缝,输出手指个数

if defects is not None:cnt = 0for i in range(defects.shape[0]):  # calculate the angles, e, f, d = defects[i][0]start = tuple(contours[s][0])end = tuple(contours[e][0])far = tuple(contours[f][0])a = np.sqrt((end[0] - start[0]) ** 2 + (end[1] - start[1]) ** 2)b = np.sqrt((far[0] - start[0]) ** 2 + (far[1] - start[1]) ** 2)c = np.sqrt((end[0] - far[0]) ** 2 + (end[1] - far[1]) ** 2)angle = np.arccos((b ** 2 + c ** 2 - a ** 2) / (2 * b * c))  #      cosine theoremif angle <= np.pi / 2:  # angle less than 90 degree, treat as fingerscnt += 1cv.circle(img, far, 4, [0, 0, 255], -1)if cnt > 0:cnt = cnt+1cv.putText(img, str(cnt), (0, 50), cv.FONT_HERSHEY_SIMPLEX,1, (255, 0, 0) , 2, cv.LINE_AA)
cv.imshow("img", img)
cv.imwrite(f"result_{str(cnt)}.jpg", img)
cv.waitKey()
cv.destroyAllWindows()

其中 angle 的计算原理如下

在这里插入图片描述

当然仔细看代码这图和代码中对应的字母有差异,代码中 start 到 end 是 a 对应上图的 c,代码中 start 到 far 和 end 到 far 为 b 和 c 对应上图的 a 和 b,

在这里插入图片描述

小于 90 度我们才认为是手指

3、效果展示

5 根手指

输入
在这里插入图片描述

输出

在这里插入图片描述

4 根手指

在这里插入图片描述

在这里插入图片描述

3 根手指

在这里插入图片描述
在这里插入图片描述

2 根手指

在这里插入图片描述

在这里插入图片描述

1 根手指

在这里插入图片描述
在这里插入图片描述
翻车

在这里插入图片描述

在这里插入图片描述

可以看到几个缺点

十分依赖前处理,前处理不行,轮廓不对,后续结果判断则会相应的出现问题

只有一个手指的时候,或者握拳的时候,这套流程应该是判断不出来有几根手指的

4、完整代码

import cv2
import numpy as np
import cv2 as cvdef skinmask(img):hsvim = cv.cvtColor(img, cv.COLOR_BGR2HSV)lower = np.array([0, 48, 80], dtype = "uint8")upper = np.array([20, 255, 255], dtype = "uint8")skinRegionHSV = cv.inRange(hsvim, lower, upper)cv.imwrite("skinRegionHSV.jpg", skinRegionHSV)blurred = cv.blur(skinRegionHSV, (2,2))ret, thresh = cv.threshold(blurred,0,255,cv.THRESH_BINARY)return threshdef getcnthull(mask_img):contours, hierarchy = cv.findContours(mask_img, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)contours = max(contours, key=lambda x: cv.contourArea(x))hull = cv.convexHull(contours)return contours, hulldef getdefects(contours):hull = cv.convexHull(contours, returnPoints=False)defects = cv.convexityDefects(contours, hull)return defectsimg = cv.imread("./5.png")
mask_img = skinmask(img)
cv.imwrite("mask_img.jpg", mask_img)contours, hull = getcnthull(mask_img)cv.drawContours(img, [contours], -1, (255,255,0), 2)
cv.imwrite("contours.jpg", img)cv.drawContours(img, [hull], -1, (0, 255, 255), 2)
cv.imwrite("hull.jpg", img)defects = getdefects(contours)if defects is not None:cnt = 0for i in range(defects.shape[0]):  # calculate the angles, e, f, d = defects[i][0]start = tuple(contours[s][0])end = tuple(contours[e][0])far = tuple(contours[f][0])a = np.sqrt((end[0] - start[0]) ** 2 + (end[1] - start[1]) ** 2)b = np.sqrt((far[0] - start[0]) ** 2 + (far[1] - start[1]) ** 2)c = np.sqrt((end[0] - far[0]) ** 2 + (end[1] - far[1]) ** 2)angle = np.arccos((b ** 2 + c ** 2 - a ** 2) / (2 * b * c))  #      cosine theoremif angle <= np.pi / 2:  # angle less than 90 degree, treat as fingerscnt += 1cv.circle(img, far, 4, [0, 0, 255], -1)if cnt > 0:cnt = cnt+1cv.putText(img, str(cnt), (0, 50), cv.FONT_HERSHEY_SIMPLEX,1, (255, 0, 0) , 2, cv.LINE_AA)
cv.imshow("img", img)
cv.imwrite(f"result_{str(cnt)}.jpg", img)
cv.waitKey()
cv.destroyAllWindows()

5、涉及到的库函数

关于 cv2.convexHullcv2.convexityDefects 的使用说明可以参考 【python】OpenCV—findContours(4.2)

cv2.inRange

cv2.inRange 是 OpenCV 库中的一个函数,用于检查数组元素是否位于两个指定的范围之间。这个函数通常用于图像处理和计算机视觉任务中,特别是在进行图像阈值处理、颜色空间转换后的颜色过滤等场景。

cv2.inRange(src, lowerb, upperb, dst=None)
  • src: 输入数组(通常是图像),它应该是一个单通道或多通道的数组。
  • lowerb: 范围的下限(包含),与 src 同类型、同大小的数组,或者是一个标量值。
  • upperb: 范围的上限(不包含),与 src 同类型、同大小的数组,或者是一个标量值。
  • dst: 输出数组,与 src 同大小、同类型。函数将结果存储在这里。如果为 None,则会自动创建一个与 src 同大小、同类型的数组。

工作原理

  • 对于 src 中的每个元素,cv2.inRange 会检查它是否位于 [lowerb, upperb) 范围内(注意,上限是开区间,即不包括上限值)。如果元素值在这个范围内,则对应的 dst 中的元素被设置为 255(对于 8 位图像),否则被设置为 0。这样,dst 数组最终会是一个二值图像(只有 0 和 255 的值),其中白色(255)表示满足条件的像素,黑色(0)表示不满足条件的像素。

应用场景

  • 颜色过滤:在 HSV 颜色空间中,可以通过 cv2.inRange 来提取特定颜色的物体。例如,提取图像中的红色部分。
  • 阈值处理:在灰度图像中,可以用来提取特定亮度范围内的像素。
  • 背景分割:如果背景的颜色或亮度与前景有明显的区别,可以用这个函数来分离背景和前景。

示例代码

以下是一个简单的示例,展示如何使用 cv2.inRange 来提取图像中的红色部分:

import cv2
import numpy as np# 读取图像
image = cv2.imread('example.jpg')# 转换到 HSV 颜色空间
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)# 定义红色的 HSV 范围
lower_red = np.array([0, 120, 70])
upper_red = np.array([10, 255, 255])
mask1 = cv2.inRange(hsv, lower_red, upper_red)lower_red = np.array([170, 120, 70])
upper_red = np.array([180, 255, 255])
mask2 = cv2.inRange(hsv, lower_red, upper_red)# 合并两个掩码
mask = mask1 | mask2# 使用掩码提取红色部分
result = cv2.bitwise_and(image, image, mask=mask)# 显示结果
cv2.imshow('Original Image', image)
cv2.imshow('Red Extracted', result)
cv2.waitKey(0)
cv2.destroyAllWindows()

这个示例首先读取一张图像,然后将其转换到 HSV 颜色空间。接着,定义了两个红色的 HSV 范围(因为红色在 HSV 空间中跨越了两个范围),并使用 cv2.inRange 生成两个掩码。之后,合并这两个掩码,并使用掩码提取图像中的红色部分。最后,显示原始图像和提取的红色部分。

6、参考

  • 凸缺陷 convexityDefects
  • 基于OpenCV的手掌检测和手指计数
  • https://github.com/madhav240/hand-detection-and-finger-counting/blob/master/finger_counting_video.py

相关文章:

【python】OpenCV—findContours(4.6)

文章目录 1、功能描述2、代码实现3、效果展示4、完整代码5、涉及到的库函数cv2.inRange 6、参考 1、功能描述 给出一张仅含有手指的图片&#xff0c;判断图片中有多少根手指 2、代码实现 导入库函数&#xff0c;图像预处理 import numpy as np import cv2 as cv img cv.im…...

【C++】——多态

一.多态的概念 1.多态 多态(polymorphism)的概念&#xff1a;通俗的来说&#xff0c;就是多种形态。多态分为静态多态(编译时多态)和动态多态(运行时多态)&#xff0c;而我们讲的多态大部分都是动态多态。 静态多态主要就是我们前面了解过的函数模板和函数重载&#xff0c;它…...

Web前端开发--HTML语言

文章目录 前言1.介绍2.组成3.基本框架4.常见标签4.1双标签4.1.1.标题标签4.2.2段落标签4.1.3文本格式化标签4.1.4超链接标签4.1.5视频标签4.1.6 音频标签 4.2单标签4.2.1换行标签和水平线标签4.2.2 图像标签 5.表单控件结语 前言 生活中处处都有网站&#xff0c;无论你是学习爬…...

AI驱动的网络空间智能对抗;无人集群系统,多体协同算法创新和故障智能预警

目录 AI驱动的网络空间智能对抗 认知与认知域安全 认知攻击-杀伤链 PPDR主动安全框架 短视频内容分析 不良视频鉴别:人工+智能 舆情监测 非介入式监测 大模型对新闻内容审查与播报 无人集群系统,多体协同算法创新和故障智能预警 一、无人集群系统概述 二、多体协…...

推荐一款SSD硬盘优化器:Auslogics SSD Optimizer Pro

SSD Optimizer Pro 是一款专为优化固态硬盘 (SSD) 性能而设计的专业工具&#xff0c;旨在最大化 SSD 的效率&#xff0c;延长硬盘使用寿命。凭借简便的操作界面和强大的优化功能&#xff0c;SSD Optimizer Pro 可以让用户充分利用 SSD 的优势&#xff0c;从而获得更高的系统性能…...

k8s-service、endpoints、pod之间是怎么进行网络互通的

k8s-service、endpoints、pod之间是怎么进行网络互通的 1、service2、endpoints3、service、endpoints、pod通信图4、不通服务pod内部间访问 1、service 在K8S中&#xff0c;Service是一种抽象&#xff0c;定义了一组Pod的逻辑集合和访问这些Pod的策略。首先&#xff0c;我们需…...

Go语言开发商城管理后台-GoFly框架商城插件已发布 需要Go开发商城的朋友可以来看看哦!

温馨提示&#xff1a;我们分享的文章是给需要的人&#xff0c;不需要的人请绕过&#xff0c;文明浏览&#xff0c;误恶语伤人&#xff01; 前言 虽然现在做商城的需求不多&#xff0c;但有很多项目中带有商城功能&#xff0c;如社区医院系统有上服务套餐、理疗产品需求、宠物…...

【51单片机】UART串口通信原理 + 使用

学习使用的开发板&#xff1a;STC89C52RC/LE52RC 编程软件&#xff1a;Keil5 烧录软件&#xff1a;stc-isp 开发板实图&#xff1a; 文章目录 串口硬件电路UART串口相关寄存器 编码单片机通过串口发送数据电脑通过串口发送数据控制LED灯 串口 串口是一种应用十分广泛的通讯接…...

高性能分布式缓存Redis-高可用部署

一、主从架构搭建 为什么要进行主从架构搭建&#xff0c;一台redis不行吗&#xff1f; ①、持久化后的数据只在一台机器上&#xff0c;因此当硬件发生故障时&#xff0c;比如主板或CPU坏了&#xff0c;这时候无法重启服务器&#xff0c;有什么办法可以保证服务器发生故障时数…...

如何使用XSL-FO生成PDF格式的电子发票的技术博文示例

目录 使用 XSL-FO 生成电子发票 PDF&#xff1a;从布局设计到优化为什么选择 XSL-FO&#xff1f;1. 初始设置2. 标题区块3. 买卖方信息4. 商品明细表格5. 合计信息6. 优化代码结构与布局7. 生成 PDF 文件8. 示例总结 使用 XSL-FO 生成电子发票 PDF&#xff1a;从布局设计到优化…...

TDengine 签约山东港,赋能港口数字化转型

随着全球港口物流数字化进程的加速&#xff0c;港口运营面临日益复杂的数据管理挑战&#xff0c;从能源管理、设备监控到运营安全保障&#xff0c;各类数据需要及时存储并高效分析。山东港在信息化建设过程中&#xff0c;数字化综合管理平台的性能和查询功能一度受到瓶颈制约。…...

基于YOLO11/v10/v8/v5深度学习的煤矿传送带异物检测系统设计与实现【python源码+Pyqt5界面+数据集+训练代码】

《------往期经典推荐------》 一、AI应用软件开发实战专栏【链接】 项目名称项目名称1.【人脸识别与管理系统开发】2.【车牌识别与自动收费管理系统开发】3.【手势识别系统开发】4.【人脸面部活体检测系统开发】5.【图片风格快速迁移软件开发】6.【人脸表表情识别系统】7.【…...

mysql-workbench 导入csv格式数据报错:Unhandled exception: Could not determine delimiter

xlsx文件中第二行某个单元格有换行符&#xff0c;csv文件中用双引号包起来了&#xff0c;但是python 在采样的时候&#xff0c;只读了前两行&#xff0c;readline可不认识csv的规则。csv文件可以识别双引号包起来的换行符是单元格内部的换行&#xff0c;python的readline识别不…...

使用Python简单实现客户端界面

服务端实现 import threading import timeimport wx from socket import socket, AF_INET, SOCK_STREAMclass LServer(wx.Frame):def __init__(self):wx.Frame.__init__(self, None, id1002, titleL服务器端界面, poswx.DefaultPosition, size(400, 450))# 窗口中添加面板pl …...

15分钟学 Go 第 43 天:前端与Go的结合

第43天&#xff1a;前端与Go的结合 目标&#xff1a;了解Go如何与前端交互&#xff0c;前端使用Vue.js 在现代Web开发中&#xff0c;Go语言常用于后端开发&#xff0c;而Vue.js是一个流行的前端框架&#xff0c;用于构建用户界面。结合二者&#xff0c;可以构建高效、可维护的…...

解决SRS推送webrtc流卡顿问题

目录 1.问题描述2.原因分析3.ffmpeg去掉B帧的方法3.1 命令行推流3.2 ffmpeg源码推流 1.问题描述 使用ffmpeg通过rtmp协议推流给SRS&#xff0c;然后浏览器通过webrtc拉取播放流&#xff0c;经多次测试发现webrtc播放流总是卡顿&#xff0c;而拉取rtmp流是正常的。 2.原因分析…...

GDPU Andriod移动应用 Broadcast Receiver

聆听广播&#xff0c;跟着节拍吧。 计时器 新建一个名为PhoneStateMonitor的工程&#xff1b; 实现一个应用运行时长的计时器&#xff0c;并在界面上刷新计数器&#xff0c;要求包括&#xff1a; &#xff08;1&#xff09;在Layout中包含两个TextView控件&#xff0c;横向分…...

CSP/信奥赛C++刷题训练:经典例题 - 栈(1):洛谷P3056 :[USACO12NOV] Clumsy Cows S

CSP/信奥赛C刷题训练&#xff1a;经典例题 - 栈&#xff08;1&#xff09;&#xff1a;洛谷P3056 &#xff1a;[USACO12NOV] Clumsy Cows S 题目描述 Bessie the cow is trying to type a balanced string of parentheses into her new laptop, but she is sufficiently clums…...

WiFi一直获取不到IP地址是怎么回事?

在当今这个信息化时代&#xff0c;WiFi已成为我们日常生活中不可或缺的一部分。无论是家庭、办公室还是公共场所&#xff0c;WiFi都为我们提供了便捷的无线互联网接入。然而&#xff0c;有时我们可能会遇到WiFi连接后无法获取IP地址的问题&#xff0c;这不仅影响了我们的网络使…...

蓝牙BLE开发——iOS 每次写入数据超过200字节报错?

iOS 写入数据超过200字节报错 文章目录 iOS 写入数据超过200字节报错官方建议&#xff1a;报错问题解决 writeblecharacteristicvalue 官方建议&#xff1a; 并行调用多次会存在写失败的可能性。APP不会对写入数据包大小做限制&#xff0c;但系统与蓝牙设备会限制蓝牙4.0单次…...

用Python和OpenCV手把手教你搞定自动驾驶图像坐标系转换(附NuScenes数据集实战代码)

用Python和OpenCV手把手教你搞定自动驾驶图像坐标系转换&#xff08;附NuScenes数据集实战代码&#xff09; 自动驾驶技术的核心在于让车辆"看懂"周围环境&#xff0c;而坐标系转换正是连接物理世界与数字世界的桥梁。想象一下&#xff0c;当一辆自动驾驶汽车行驶在…...

Unity游戏接入TapTap登录,从后台配置到打包上线的完整避坑指南

Unity游戏接入TapTap登录的全流程避坑指南&#xff1a;从配置到上线的实战经验 在独立游戏开发领域&#xff0c;TapTap平台凭借其庞大的用户基础和便捷的登录系统&#xff0c;已成为许多开发者的首选接入方案。然而&#xff0c;从后台配置到最终打包上线的完整流程中&#xff0…...

通达信数据解析终极指南:mootdx让金融数据获取变得如此简单

通达信数据解析终极指南&#xff1a;mootdx让金融数据获取变得如此简单 【免费下载链接】mootdx 通达信数据读取的一个简便使用封装 项目地址: https://gitcode.com/GitHub_Trending/mo/mootdx 在金融数据分析和量化交易的世界里&#xff0c;获取准确、完整的市场数据是…...

怎么找到一个行业的源头工厂、绕开中间商?一套五步识别流程

你下了单&#xff0c;货到了&#xff0c;质量也还行。但心里一直有个疙瘩&#xff1a;这家供应商到底是自己在生产&#xff0c;还是从别处转手赚了你一道差价&#xff1f; 这个问题对采购方和跨境卖家不是洁癖&#xff0c;是真金白银。同一款产品&#xff0c;源头工厂和中间商的…...

构建轻量级应用沙盒:Microverse原理与实践指南

1. 项目概述&#xff1a;一个轻量级、可移植的“微宇宙”开发沙盒最近在折腾一些边缘计算和嵌入式AI应用的原型验证&#xff0c;经常遇到一个头疼的问题&#xff1a;开发环境和部署环境不一致。在本地笔记本上跑得好好的Python脚本&#xff0c;放到树莓派或者Jetson Nano上&…...

基于CircuitPython与NeoPixel打造可编程LED亚克力灯牌:从硬件选型到代码实现

1. 项目概述&#xff1a;打造你的专属可编程光之铭牌在创客和电子爱好者的世界里&#xff0c;总有一些项目能完美地融合软件编程的灵活性与硬件制作的实体成就感。今天要分享的&#xff0c;就是这样一个让我爱不释手的小玩意儿&#xff1a;一个基于CircuitPython和NeoPixel的可…...

云原生安全工具:保护云原生环境

云原生安全工具&#xff1a;保护云原生环境 一、云原生安全工具概述 1.1 云原生安全工具的定义 云原生安全工具是指专为云原生环境设计的安全工具和解决方案。它们用于保护容器、Kubernetes集群、微服务和Serverless应用的安全。 1.2 云原生安全工具的价值 安全防护&#xff1a…...

EL电致发光线与3D打印技术打造可穿戴发光骨架服

1. 项目概述&#xff1a;当发光骨架“活”过来每年万圣节&#xff0c;看着满大街的“幽灵”和“僵尸”&#xff0c;我总想搞点不一样的。直到去年&#xff0c;我决定不再满足于商店里千篇一律的服装&#xff0c;而是想自己动手&#xff0c;做一件真正能“发光”的、有科技感的骨…...

VR头显立体视觉姿态估计技术解析

1. 自我中心姿态估计的技术挑战与创新思路在虚拟现实和增强现实应用中&#xff0c;准确估计用户在三维空间中的身体姿态是实现自然交互的基础。传统基于外部摄像头的动作捕捉系统虽然精度较高&#xff0c;但存在设备复杂、使用场景受限等问题。相比之下&#xff0c;基于头戴设备…...

VTube Studio API完全指南:5个核心场景教你打造个性化虚拟主播互动

VTube Studio API完全指南&#xff1a;5个核心场景教你打造个性化虚拟主播互动 【免费下载链接】VTubeStudio VTube Studio API Development Page 项目地址: https://gitcode.com/gh_mirrors/vt/VTubeStudio 想要为你的虚拟主播形象添加更多互动功能&#xff0c;却不知道…...