OpenCV实现手势音量控制
前言:Hello大家好,我是Dream。 今天来学习一下如何使用OpenCV实现手势音量控制,欢迎大家一起前来探讨学习~
一、需要的库及功能介绍
本次实验需要使用OpenCV和mediapipe库进行手势识别,并利用手势距离控制电脑音量。
导入库:
- cv2:OpenCV库,用于读取摄像头视频流和图像处理。
- mediapipe:mediapipe库,用于手部关键点检测和手势识别。
- ctypes和comtypes:用于与操作系统的音频接口进行交互。
- pycaw:pycaw库,用于控制电脑音量。
功能:
- 初始化mediapipe和音量控制模块,获取音量范围。
- 打开摄像头,读取视频流。
- 对每一帧图像进行处理:
- 转换图像为RGB格式。
- 使用mediapipe检测手部关键点。
- 如果检测到手部关键点:
- 在图像中标注手指关键点和手势连线。
- 解析手指关键点坐标。
- 根据拇指和食指指尖的坐标,计算手势距离。
- 将手势距离转换为音量大小,并控制电脑音量。
- 显示处理后的图像。
- 循环执行前述步骤,直到手动停止程序或关闭摄像头。
注意事项:
- 在运行代码之前,需要安装相关库(opencv、mediapipe、pycaw)。
- 需要连接音频设备并使其可访问。
- 检测到多个手部时,只处理第一个检测到的手部。
- 检测到手指关键点时,将索引指为0的关键点作为拇指的指尖,索引指为1的关键点作为食指的指尖。
cv2.VideoCapture()函数参数问题

这并没有错。但在树莓派上调用时需要更改参数,改为:
cap = cv2.VideoCapture(1)
调用电脑摄像头时:
电脑在用cv2.VideoCapture(0)时,程序结束后会有报错:
[ WARN:0] SourceReaderCB::~SourceReaderCB terminating async callback
需要改为:
cv2.VideoCapture(0,cv2.CAP_DSHOW)
二、导入所需要的模块
# 导入OpenCV
import cv2
# 导入mediapipe
import mediapipe as mp
# 导入电脑音量控制模块
from ctypes import cast, POINTER
from comtypes import CLSCTX_ALL
from pycaw.pycaw import AudioUtilities, IAudioEndpointVolume# 导入其他依赖包
import time
import math
import numpy as np
三、初始化 HandControlVolume 类
class HandControlVolume:def __init__(self):"""初始化 HandControlVolume 类的实例初始化 mediapipe 对象,用于手部关键点检测和手势识别。获取电脑音量接口,并获取音量范围。"""# 初始化 medialpipeself.mp_drawing = mp.solutions.drawing_utilsself.mp_drawing_styles = mp.solutions.drawing_stylesself.mp_hands = mp.solutions.hands# 获取电脑音量范围devices = AudioUtilities.GetSpeakers()interface = devices.Activate(IAudioEndpointVolume._iid_, CLSCTX_ALL, None)self.volume = cast(interface, POINTER(IAudioEndpointVolume))self.volume.SetMute(0, None)self.volume_range = self.volume.GetVolumeRange()
- 初始化 mediapipe 对象,用于手部关键点检测和手势识别。
- 获取电脑音量接口,并获取音量范围。
四、主函数
1.计算刷新率
-
初始化刷新率的计算,记录当前时间作为初始时间。
-
使用
OpenCV打开视频流,此处读取摄像头设备,默认使用设备ID为0。 -
设置视频流的分辨率为指定的
resize_w和resize_h大小,并将图像resize为该尺寸。 -
在使用hands对象之前,使用
with语句创建一个上下文环境,设置手部检测和追踪的相关参数,包括最小检测置信度、最小追踪置信度和最大手的数量。 -
进入循环,判断视频流是否打开。使用
cap.read()函数从视频流中读取一帧图像,返回的success表示是否读取成功,image则是读取到的图像。 -
对读取到的图像进行
resize,将其调整为指定的大小。如果读取失败,则打印提示信息并继续下一次循环。
# 主函数def recognize(self):# 计算刷新率fpsTime = time.time()# OpenCV读取视频流cap = cv2.VideoCapture(0)# 视频分辨率resize_w = 640resize_h = 480# 画面显示初始化参数rect_height = 0rect_percent_text = 0with self.mp_hands.Hands(min_detection_confidence=0.7,min_tracking_confidence=0.5,max_num_hands=2) as hands:while cap.isOpened():success, image = cap.read()image = cv2.resize(image, (resize_w, resize_h))if not success:print("空帧.")continue
2.提高性能
-
将图像的可写标志image.flags.writeable设置为False,以便进行内存优化。
-
将图像从BGR格式转换为RGB格式,这是因为MediaPipe模型处理的输入要求为RGB格式。
-
对图像进行水平翻转,即镜像操作,以使图像更符合常见的镜像显示。
-
使用MediaPipe模型对图像进行处理,得到结果。
-
将图像的可写标志image.flags.writeable设置为True,以重新启用对图像的写入操作。
-
将图像从RGB格式转换回BGR格式,以便后续的显示和处理。
这些优化操作旨在提高程序的性能和效率。其中,将图像的可写标志设置为False可以减少不必要的内存拷贝,转换图像的格式和镜像操作则是为了符合MediaPipe模型的输入要求和更好地进行手势识别。最后,将图像转换回BGR格式是为了与OpenCV的显示函数兼容。
# 提高性能image.flags.writeable = False# 转为RGBimage = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)# 镜像image = cv2.flip(image, 1)# mediapipe模型处理results = hands.process(image)image.flags.writeable = Trueimage = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
3.判断是否有手掌
-
判断
results.multi_hand_landmarks是否存在,即是否检测到手掌。如果存在,则继续执行下面的代码。 -
遍历
results.multi_hand_landmarks中的每个hand_landmarks,即遍历每个检测到的手掌。 -
使用
self.mp_drawing.draw_landmarks函数将检测到的手掌标注在图像上,包括手指的关键点和手指之间的连接线。
# 判断是否有手掌if results.multi_hand_landmarks:# 遍历每个手掌for hand_landmarks in results.multi_hand_landmarks:# 在画面标注手指self.mp_drawing.draw_landmarks(image,hand_landmarks,self.mp_hands.HAND_CONNECTIONS,self.mp_drawing_styles.get_default_hand_landmarks_style(),self.mp_drawing_styles.get_default_hand_connections_style())
4.解析手指,存入各个手指坐标
首先解析手指的坐标,并存入landmark_list列表中。然后,根据手指的坐标计算出大拇指和食指的指尖坐标,以及两者的中间点坐标。接下来,绘制了大拇指、食指和两者之间的连线,并使用勾股定理计算了两个指尖之间的长度。
-
创建一个空的landmark_list列表用于存储手指坐标。
-
遍历手部关键点的每个元素,将每个关键点的id、x、y和z坐标存储在一个列表中,然后将该列表添加到landmark_list中。
-
判断landmark_list是否不为空,如果不为空,继续执行下面的代码。
-
从landmark_list中获取大拇指指尖坐标的列表项,然后计算出在图像上的像素坐标。
-
从landmark_list中获取食指指尖坐标的列表项,然后计算出在图像上的像素坐标。
-
计算大拇指指尖和食指指尖的中间点坐标。
-
绘制大拇指和食指的指尖点,以及中间点。
-
绘制大拇指和食指之间的连线。
-
使用勾股定理计算大拇指指尖和食指指尖之间的长度,保存在line_len中。
# 解析手指,存入各个手指坐标landmark_list = []for landmark_id, finger_axis in enumerate(hand_landmarks.landmark):landmark_list.append([landmark_id, finger_axis.x, finger_axis.y,finger_axis.z])if landmark_list:# 获取大拇指指尖坐标thumb_finger_tip = landmark_list[4]thumb_finger_tip_x = math.ceil(thumb_finger_tip[1] * resize_w)thumb_finger_tip_y = math.ceil(thumb_finger_tip[2] * resize_h)# 获取食指指尖坐标index_finger_tip = landmark_list[8]index_finger_tip_x = math.ceil(index_finger_tip[1] * resize_w)index_finger_tip_y = math.ceil(index_finger_tip[2] * resize_h)# 中间点finger_middle_point = (thumb_finger_tip_x + index_finger_tip_x) // 2, (thumb_finger_tip_y + index_finger_tip_y) // 2# print(thumb_finger_tip_x)thumb_finger_point = (thumb_finger_tip_x, thumb_finger_tip_y)index_finger_point = (index_finger_tip_x, index_finger_tip_y)# 画指尖2点image = cv2.circle(image, thumb_finger_point, 10, (255, 0, 255), -1)image = cv2.circle(image, index_finger_point, 10, (255, 0, 255), -1)image = cv2.circle(image, finger_middle_point, 10, (255, 0, 255), -1)# 画2点连线image = cv2.line(image, thumb_finger_point, index_finger_point, (255, 0, 255), 5)# 勾股定理计算长度line_len = math.hypot((index_finger_tip_x - thumb_finger_tip_x),(index_finger_tip_y - thumb_finger_tip_y))
5.获取电脑最大最小音量
实现获取电脑的最大和最小音量,并将指尖的长度映射到音量范围和矩形显示上,然后将映射后的音量值设置为电脑的音量。具体过程如下:
-
self.volume_range[0]和self.volume_range[1]分别获取电脑的最小音量和最大音量。 -
np.interp函数将指尖的长度line_len映射到从50到300的范围,再映射到最小音量和最大音量的范围,得到音量值vol。 -
np.interp函数将指尖的长度line_len映射到从50到300的范围,再映射到从0到200的范围,得到矩形的高度rect_height。 -
np.interp函数将指尖的长度line_len映射到从50到300的范围,再映射到从0到100的范围,得到矩形百分比显示的数值rect_percent_text。 -
self.volume.SetMasterVolumeLevel方法将音量值vol设置为电脑的音量。
# 获取电脑最大最小音量min_volume = self.volume_range[0]max_volume = self.volume_range[1]# 将指尖长度映射到音量上vol = np.interp(line_len, [50, 300], [min_volume, max_volume])# 将指尖长度映射到矩形显示上rect_height = np.interp(line_len, [50, 300], [0, 200])rect_percent_text = np.interp(line_len, [50, 300], [0, 100])# 设置电脑音量self.volume.SetMasterVolumeLevel(vol, None)
6.显示矩形
cv2.putText函数来在图像上显示矩形框的百分比值;
cv2.rectangle函数来绘制矩形框并填充颜色;
cv2.putText函数来在图像上显示当前帧的刷新率FPS;
cv2.imshow函数来显示处理后的图像;
cv2.waitKey函数等待按键输入,当按下ESC键或关闭窗口时退出程序;
HandControlVolume类的recognize方法调用了手势识别的功能。
# 显示矩形cv2.putText(image, str(math.ceil(rect_percent_text)) + "%", (10, 350),cv2.FONT_HERSHEY_PLAIN, 3, (255, 0, 0), 3)image = cv2.rectangle(image, (30, 100), (70, 300), (255, 0, 0), 3)image = cv2.rectangle(image, (30, math.ceil(300 - rect_height)), (70, 300), (255, 0, 0), -1)# 显示刷新率FPScTime = time.time()fps_text = 1 / (cTime - fpsTime)fpsTime = cTimecv2.putText(image, "FPS: " + str(int(fps_text)), (10, 70),cv2.FONT_HERSHEY_PLAIN, 3, (255, 0, 0), 3)# 显示画面cv2.imshow('MediaPipe Hands', image)if cv2.waitKey(5) & 0xFF == 27 or cv2.getWindowProperty('MediaPipe Hands', cv2.WND_PROP_VISIBLE) < 1:breakcap.release()# 开始程序
control = HandControlVolume()
control.recognize()
五、实战演示



通过演示我们可以发现,食指与大拇指之间在屏幕中的的距离越远,那么我们的音量会越大,反之越小,实现了通过手势对音量的控制。
六、源码分享
import cv2
import mediapipe as mp
from ctypes import cast, POINTER
from comtypes import CLSCTX_ALL
from pycaw.pycaw import AudioUtilities, IAudioEndpointVolume
import time
import math
import numpy as npclass HandControlVolume:def __init__(self):# 初始化medialpipeself.mp_drawing = mp.solutions.drawing_utilsself.mp_drawing_styles = mp.solutions.drawing_stylesself.mp_hands = mp.solutions.hands# 获取电脑音量范围devices = AudioUtilities.GetSpeakers()interface = devices.Activate(IAudioEndpointVolume._iid_, CLSCTX_ALL, None)self.volume = cast(interface, POINTER(IAudioEndpointVolume))self.volume.SetMute(0, None)self.volume_range = self.volume.GetVolumeRange()# 主函数def recognize(self):# 计算刷新率fpsTime = time.time()# OpenCV读取视频流cap = cv2.VideoCapture(0)# 视频分辨率resize_w = 640resize_h = 480# 画面显示初始化参数rect_height = 0rect_percent_text = 0with self.mp_hands.Hands(min_detection_confidence=0.7,min_tracking_confidence=0.5,max_num_hands=2) as hands:while cap.isOpened():success, image = cap.read()image = cv2.resize(image, (resize_w, resize_h))if not success:print("空帧.")continue# 提高性能image.flags.writeable = False# 转为RGBimage = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)# 镜像image = cv2.flip(image, 1)# mediapipe模型处理results = hands.process(image)image.flags.writeable = Trueimage = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)# 判断是否有手掌if results.multi_hand_landmarks:# 遍历每个手掌for hand_landmarks in results.multi_hand_landmarks:# 在画面标注手指self.mp_drawing.draw_landmarks(image,hand_landmarks,self.mp_hands.HAND_CONNECTIONS,self.mp_drawing_styles.get_default_hand_landmarks_style(),self.mp_drawing_styles.get_default_hand_connections_style())# 解析手指,存入各个手指坐标landmark_list = []for landmark_id, finger_axis in enumerate(hand_landmarks.landmark):landmark_list.append([landmark_id, finger_axis.x, finger_axis.y,finger_axis.z])if landmark_list:# 获取大拇指指尖坐标thumb_finger_tip = landmark_list[4]thumb_finger_tip_x = math.ceil(thumb_finger_tip[1] * resize_w)thumb_finger_tip_y = math.ceil(thumb_finger_tip[2] * resize_h)# 获取食指指尖坐标index_finger_tip = landmark_list[8]index_finger_tip_x = math.ceil(index_finger_tip[1] * resize_w)index_finger_tip_y = math.ceil(index_finger_tip[2] * resize_h)# 中间点finger_middle_point = (thumb_finger_tip_x + index_finger_tip_x) // 2, (thumb_finger_tip_y + index_finger_tip_y) // 2# print(thumb_finger_tip_x)thumb_finger_point = (thumb_finger_tip_x, thumb_finger_tip_y)index_finger_point = (index_finger_tip_x, index_finger_tip_y)# 画指尖2点image = cv2.circle(image, thumb_finger_point, 10, (255, 0, 255), -1)image = cv2.circle(image, index_finger_point, 10, (255, 0, 255), -1)image = cv2.circle(image, finger_middle_point, 10, (255, 0, 255), -1)# 画2点连线image = cv2.line(image, thumb_finger_point, index_finger_point, (255, 0, 255), 5)# 勾股定理计算长度line_len = math.hypot((index_finger_tip_x - thumb_finger_tip_x),(index_finger_tip_y - thumb_finger_tip_y))# 获取电脑最大最小音量min_volume = self.volume_range[0]max_volume = self.volume_range[1]# 将指尖长度映射到音量上vol = np.interp(line_len, [50, 300], [min_volume, max_volume])# 将指尖长度映射到矩形显示上rect_height = np.interp(line_len, [50, 300], [0, 200])rect_percent_text = np.interp(line_len, [50, 300], [0, 100])# 设置电脑音量self.volume.SetMasterVolumeLevel(vol, None)# 显示矩形cv2.putText(image, str(math.ceil(rect_percent_text)) + "%", (10, 350),cv2.FONT_HERSHEY_PLAIN, 3, (255, 0, 0), 3)image = cv2.rectangle(image, (30, 100), (70, 300), (255, 0, 0), 3)image = cv2.rectangle(image, (30, math.ceil(300 - rect_height)), (70, 300), (255, 0, 0), -1)# 显示刷新率FPScTime = time.time()fps_text = 1 / (cTime - fpsTime)fpsTime = cTimecv2.putText(image, "FPS: " + str(int(fps_text)), (10, 70),cv2.FONT_HERSHEY_PLAIN, 3, (255, 0, 0), 3)# 显示画面cv2.imshow('xyp', image)if cv2.waitKey(5) & 0xFF == 27 or cv2.getWindowProperty('MediaPipe Hands', cv2.WND_PROP_VISIBLE) < 1:breakcap.release()
control = HandControlVolume()
control.recognize()
相关文章:
OpenCV实现手势音量控制
前言: Hello大家好,我是Dream。 今天来学习一下如何使用OpenCV实现手势音量控制,欢迎大家一起前来探讨学习~ 一、需要的库及功能介绍 本次实验需要使用OpenCV和mediapipe库进行手势识别,并利用手势距离控制电脑音量。 导入库&am…...
pytorch 深度学习之余弦相似度
文章目录 用处定理代码F.normalize() 和 F.norm() 的区别 用处 此方法特别重要,经常可以用来修改论文,提出创新点. 定理 余弦相似度是通过计算两个向量之间的夹角余弦值来衡量它们的相似性。给定两个非零向量 x 和 y,它们之间的余弦相似度…...
Postman的常规断言/动态参数断言/全局断言
近期在复习Postman的基础知识,在小破站上跟着百里老师系统复习了一遍,也做了一些笔记,希望可以给大家一点点启发。 断言,包括状态码断言和业务断言,状态码断言有一个,业务断言有多个。 一)常规的…...
ruoyi若依前端请求接口超时,增加响应时长
问题: 前端查询请求超时 解决: 找到request.js的timeout属性由10秒改成了20秒,因为默认是10秒,请求肯定是超出了10秒 祝您万事顺心,没事点个赞呗,关注一下也行啊,有啥要求您评论哈...
贪吃蛇小游戏
一. 准备工作 首先获取贪吃蛇小游戏所需要的头部、身体、食物以及贪吃蛇标题等图片。、 然后,创建贪吃蛇游戏的Java项目命名为snake_game,并在这个项目里创建一个文件夹命名为images,将图片素材导入文件夹。 再在src文件下创建两个包&#…...
cocos----1
1 前言 刚体(Rigidbody)是运动学(Kinematic)中的一个概念,指在运动中和受力作用后,形状和大小不变,而且内部各点的相对位置不变的物体。在 Unity3D 中,刚体组件赋予了游戏对…...
第十九章绘图
Java绘图类 Graphics 类 Grapics 类是所有图形上下文的抽象基类,它允许应用程序在组件以及闭屏图像上进行绘制。Graphics 类封装了Java 支持的基本绘图操作所需的状态信息,主要包括颜色、字体、画笔、文本、图像等。 Graphics 类提供了绘图常用的…...
rpmbuild 包名 version 操作系统信息部分来源 /etc/rpm/macros.dist
/etc/rpm/macros.dist openeuler bclinux src.rpm openssl-1.1.1f-13.oe1.src.rpm 打包名称结果 openeuler openssl-1.1.1f-13.aarch64.rpm bclinux openssl-1.1.1f-13.oe1.bclinux.aarch64.rpm 验证 修改openeuler配置文件macros.dist 重新在openeuler上执行rpmbuild…...
【Linux专题】SFTP 用户配置 ChrootDirectory
【赠送】IT技术视频教程,白拿不谢!思科、华为、红帽、数据库、云计算等等https://xmws-it.blog.csdn.net/article/details/117297837?spm1001.2014.3001.5502 红帽认证 认证课程介绍:红帽RHCE9.0学什么内容,新版有什么变化-CSDN…...
openssl+ DES开发实例(Linux)
文章目录 一、DES介绍二、DES原理三、DES C实现源码 一、DES介绍 DES(Data Encryption Standard)是一种对称密钥加密算法,最初由 IBM 设计,于1977年成为美国国家标准,用于加密非机密但敏感的政府数据。DES 使用相同的…...
结构体几种实用的用法
结构体的初始化 结构体的初始化是指在声明结构体变量时,为其成员变量赋初值。结构体的初始化可以通过以下几种方式实现: 1. 在声明结构体变量的同时进行初始化: struct Student { char name[20]; int age; float score; } student {…...
React Native 源码分析(四)—— TurboModules JSI通信机制
本文会详细分析React Native 基于JSI的通信方式,除不会涉及Hemers引擎部分,其余代码都会详细分析,但比较简单的,不会很啰嗦,可以说是网上最完整详细的分析文章,代码通过断点截图,可以更方便查看运行的过程 1、React Native 源码分析(一)—— 启动流程 2、React Nativ…...
【C#学习】ToString() 格式化数值
格式字符串采用以下形式:Axx,其中 A 为格式说明符,指定格式化类型,xx 为精度说明符,控制格式化输出的有效位数或小数位数。 格式说明符 说明 示例 输出 C 货币 2.5.ToString(“C”) ¥2.50 D 十进制数 25.…...
install YAPI MongoDB
docker 运行 mongodb sudo docker run -d \ --name mongodb \ --restart always \ --netdocker \ -p 27017:27017 \ -v ./db:/data/db \ -e MONGO_INITDB_DATABASEyapi \ -e MONGO_INITDB_ROOT_USERNAMEroot \ -e MONGO_INITDB_ROOT_PASSWORD123456 \ mongo…...
大数据Doris(二十三):取消导入与其他导入案例参考
文章目录 取消导入与其他导入案例参考 一、取消导入...
SQL-LABS
less8 and 11-- 12 发现存在注入点 接下来我们会接着用联合查询 和以往的题目不一样没显错位,也就是没有报错的内容,尝试用盲注 布尔型 length()返回长度 substr()截取字符串(语法substr&a…...
【中间件篇-Redis缓存数据库07】Redis缓存使用问题及互联网运用
Redis缓存使用问题 数据一致性 只要使用到缓存,无论是本地内存做缓存还是使用 redis 做缓存,那么就会存在数据同步的问题。 我以 Tomcat 向 MySQL 中写入和删改数据为例,来给你解释一下,数据的增删改操作具体是如何进行的。 我…...
物理引擎介绍
物理引擎介绍 文章目录 物理引擎介绍Panda3D物理引擎在节点上启用物理场对节点应用物理效果例子一 重力例子二 旋转的推力力的类型线性力旋转力注意事项线性力的一个例子旋转力的一个例子Bullet 如何演示重力虽然碰撞检测解决了防止对象在大多数应用中碰撞的问题,但某些游戏和…...
Ubuntu18.04平台下Qt开发程序打包的一些问题总结
目录 前言 一、在Ubuntu18.04开发环境下打包有两种方式 1、利用linuxdeployqt软件进行打包 2、利用编写shell脚本的方式进行打包 二、详细介绍shell脚本打包的方式 1、新建一个空的文件夹 2、准备脚本copylib.sh 3、准备脚本xxxx.sh。 4、给上述两个脚本添加可执行权限…...
定时器setTimeout()、setInterval()详解
定时器是JavaScript中常用的一种功能,它可以通过代码控制在指定的时间间隔或者时间点执行特定的代码。常见的定时器有setTimeout()和setInterval()两种。 setTimeout() setTimeout()函数可以让代码在指定的时间后执行一次,其语法如下: setT…...
KubeSphere 容器平台高可用:环境搭建与可视化操作指南
Linux_k8s篇 欢迎来到Linux的世界,看笔记好好学多敲多打,每个人都是大神! 题目:KubeSphere 容器平台高可用:环境搭建与可视化操作指南 版本号: 1.0,0 作者: 老王要学习 日期: 2025.06.05 适用环境: Ubuntu22 文档说…...
Chapter03-Authentication vulnerabilities
文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...
生成xcframework
打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式,可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...
C++初阶-list的底层
目录 1.std::list实现的所有代码 2.list的简单介绍 2.1实现list的类 2.2_list_iterator的实现 2.2.1_list_iterator实现的原因和好处 2.2.2_list_iterator实现 2.3_list_node的实现 2.3.1. 避免递归的模板依赖 2.3.2. 内存布局一致性 2.3.3. 类型安全的替代方案 2.3.…...
从WWDC看苹果产品发展的规律
WWDC 是苹果公司一年一度面向全球开发者的盛会,其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具,对过去十年 WWDC 主题演讲内容进行了系统化分析,形成了这份…...
R语言AI模型部署方案:精准离线运行详解
R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...
UDP(Echoserver)
网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法:netstat [选项] 功能:查看网络状态 常用选项: n 拒绝显示别名&#…...
2025 后端自学UNIAPP【项目实战:旅游项目】6、我的收藏页面
代码框架视图 1、先添加一个获取收藏景点的列表请求 【在文件my_api.js文件中添加】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口(适配服务端返回 Token) export const login async (code, avatar) > {const res await http…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个生活电费的缴纳和查询小程序
一、项目初始化与配置 1. 创建项目 ohpm init harmony/utility-payment-app 2. 配置权限 // module.json5 {"requestPermissions": [{"name": "ohos.permission.INTERNET"},{"name": "ohos.permission.GET_NETWORK_INFO"…...
【HTML-16】深入理解HTML中的块元素与行内元素
HTML元素根据其显示特性可以分为两大类:块元素(Block-level Elements)和行内元素(Inline Elements)。理解这两者的区别对于构建良好的网页布局至关重要。本文将全面解析这两种元素的特性、区别以及实际应用场景。 1. 块元素(Block-level Elements) 1.1 基本特性 …...
