OpenCV实现手势音量控制

前言: Hello大家好,我是Dream。 今天来学习一下如何使用OpenCV实现手势音量控制,欢迎大家一起前来探讨学习~

一、需要的库及功能介绍

本次实验需要使用OpenCV和mediapipe库进行手势识别,并利用手势距离控制电脑音量。

导入库:

  • cv2:OpenCV库,用于读取摄像头视频流和图像处理。
  • mediapipe:mediapipe库,用于手部关键点检测和手势识别。
  • ctypes和comtypes:用于与操作系统的音频接口进行交互。
  • pycaw:pycaw库,用于控制电脑音量。

功能:

  1. 初始化mediapipe和音量控制模块,获取音量范围。
  2. 打开摄像头,读取视频流。
  3. 对每一帧图像进行处理:
    • 转换图像为RGB格式。
    • 使用mediapipe检测手部关键点。
    • 如果检测到手部关键点:
      • 在图像中标注手指关键点和手势连线。
      • 解析手指关键点坐标。
      • 根据拇指和食指指尖的坐标,计算手势距离。
      • 将手势距离转换为音量大小,并控制电脑音量。
    • 显示处理后的图像。
  4. 循环执行前述步骤,直到手动停止程序或关闭摄像头。

注意事项:

  • 在运行代码之前,需要安装相关库(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 对象,用于手部关键点检测和手势识别。
        获取电脑音量接口,并获取音量范围。
        """
        # 初始化 medialpipe
        self.mp_drawing = mp.solutions.drawing_utils
        self.mp_drawing_styles = mp.solutions.drawing_styles
        self.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.计算刷新率

  1. 初始化刷新率的计算,记录当前时间作为初始时间。

  2. 使用OpenCV打开视频流,此处读取摄像头设备,默认使用设备ID为0。

  3. 设置视频流的分辨率为指定的resize_w和resize_h大小,并将图像resize为该尺寸。

  4. 在使用hands对象之前,使用with语句创建一个上下文环境,设置手部检测和追踪的相关参数,包括最小检测置信度、最小追踪置信度和最大手的数量。

  5. 进入循环,判断视频流是否打开。使用cap.read()函数从视频流中读取一帧图像,返回的success表示是否读取成功,image则是读取到的图像。

  6. 对读取到的图像进行resize,将其调整为指定的大小。如果读取失败,则打印提示信息并继续下一次循环。

# 主函数
    def recognize(self):
        # 计算刷新率
        fpsTime = time.time()

        # OpenCV读取视频流
        cap = cv2.VideoCapture(0)
        # 视频分辨率
        resize_w = 640
        resize_h = 480

        # 画面显示初始化参数
        rect_height = 0
        rect_percent_text = 0

        with 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.提高性能

  1. 将图像的可写标志image.flags.writeable设置为False,以便进行内存优化。

  2. 将图像从BGR格式转换为RGB格式,这是因为MediaPipe模型处理的输入要求为RGB格式。

  3. 对图像进行水平翻转,即镜像操作,以使图像更符合常见的镜像显示。

  4. 使用MediaPipe模型对图像进行处理,得到结果。

  5. 将图像的可写标志image.flags.writeable设置为True,以重新启用对图像的写入操作。

  6. 将图像从RGB格式转换回BGR格式,以便后续的显示和处理。

这些优化操作旨在提高程序的性能和效率。其中,将图像的可写标志设置为False可以减少不必要的内存拷贝,转换图像的格式和镜像操作则是为了符合MediaPipe模型的输入要求和更好地进行手势识别。最后,将图像转换回BGR格式是为了与OpenCV的显示函数兼容。

                # 提高性能
                image.flags.writeable = False
                # 转为RGB
                image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
                # 镜像
                image = cv2.flip(image, 1)
                # mediapipe模型处理
                results = hands.process(image)

                image.flags.writeable = True
                image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)

3.判断是否有手掌

  1. 判断results.multi_hand_landmarks是否存在,即是否检测到手掌。如果存在,则继续执行下面的代码。

  2. 遍历results.multi_hand_landmarks中的每个hand_landmarks,即遍历每个检测到的手掌。

  3. 使用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列表中。然后,根据手指的坐标计算出大拇指和食指的指尖坐标,以及两者的中间点坐标。接下来,绘制了大拇指、食指和两者之间的连线,并使用勾股定理计算了两个指尖之间的长度。

  1. 创建一个空的landmark_list列表用于存储手指坐标。

  2. 遍历手部关键点的每个元素,将每个关键点的id、x、y和z坐标存储在一个列表中,然后将该列表添加到landmark_list中。

  3. 判断landmark_list是否不为空,如果不为空,继续执行下面的代码。

  4. 从landmark_list中获取大拇指指尖坐标的列表项,然后计算出在图像上的像素坐标。

  5. 从landmark_list中获取食指指尖坐标的列表项,然后计算出在图像上的像素坐标。

  6. 计算大拇指指尖和食指指尖的中间点坐标。

  7. 绘制大拇指和食指的指尖点,以及中间点。

  8. 绘制大拇指和食指之间的连线。

  9. 使用勾股定理计算大拇指指尖和食指指尖之间的长度,保存在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.获取电脑最大最小音量

实现获取电脑的最大和最小音量,并将指尖的长度映射到音量范围和矩形显示上,然后将映射后的音量值设置为电脑的音量。具体过程如下:

  1. self.volume_range[0]和self.volume_range[1]分别获取电脑的最小音量和最大音量。

  2. np.interp函数将指尖的长度line_len映射到从50到300的范围,再映射到最小音量和最大音量的范围,得到音量值vol。

  3. np.interp函数将指尖的长度line_len映射到从50到300的范围,再映射到从0到200的范围,得到矩形的高度rect_height。

  4. np.interp函数将指尖的长度line_len映射到从50到300的范围,再映射到从0到100的范围,得到矩形百分比显示的数值rect_percent_text。

  5. 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)

                # 显示刷新率FPS
                cTime = time.time()
                fps_text = 1 / (cTime - fpsTime)
                fpsTime = cTime
                cv2.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:
                    break
            cap.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 np


class HandControlVolume:
    def __init__(self):
        # 初始化medialpipe
        self.mp_drawing = mp.solutions.drawing_utils
        self.mp_drawing_styles = mp.solutions.drawing_styles
        self.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 = 640
        resize_h = 480

        # 画面显示初始化参数
        rect_height = 0
        rect_percent_text = 0

        with 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
                # 转为RGB
                image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
                # 镜像
                image = cv2.flip(image, 1)
                # mediapipe模型处理
                results = hands.process(image)

                image.flags.writeable = True
                image = 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)

                # 显示刷新率FPS
                cTime = time.time()
                fps_text = 1 / (cTime - fpsTime)
                fpsTime = cTime
                cv2.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:
                    break
            cap.release()
control = HandControlVolume()
control.recognize()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/153148.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Java】智慧工地管理系统源码(SaaS模式)

智慧工地是聚焦工程施工现场&#xff0c;紧紧围绕人、机、料、法、环等关键要素&#xff0c;综合运用物联网、云计算、大数据、移动计算和智能设备等软硬件信息技术&#xff0c;与施工生产过程相融合。 一、什么是智慧工地 智慧工地是指利用移动互联、物联网、智能算法、地理信…

【Java小知识点】类加载器的区别

&#x1f384;欢迎来到边境矢梦的csdn博文&#x1f384; &#x1f384;本文主要梳理Java类加载器的区别&#x1f384; &#x1f308;我是边境矢梦&#xff0c;一个正在为秋招和算法竞赛做准备的学生&#x1f308; &#x1f386;喜欢的朋友可以关注一下&#x1faf0;&#x1faf…

【ARM Trace32(劳特巴赫) 使用介绍 2.2 -- TRACE32 进阶命令之 DIAG 弹框命令】

请阅读【ARM Coresight SoC-400/SoC-600 专栏导读】 上篇文章&#xff1a;【ARM Trace32(劳特巴赫) 使用介绍 2.1 – TRACE32 Practice 脚本 cmm 脚本学习】 下篇文章&#xff1a;【ARM Trace32(劳特巴赫) 使用介绍 3 - trace32 访问运行时的内存】 文章目录 DIALOG.OK 命令DIA…

实测文心一言4.0,真的比GPT-4毫不逊色吗?

10月17日&#xff0c;李彦宏在百度世界2023上表示。当天&#xff0c;李彦宏以《手把手教你做AI原生应用》为主题发表演讲&#xff0c;发布文心大模型4.0版本。 今天&#xff0c;咱们就开门见山啊。这一回要测一测&#xff0c;昨天才发布的文心一言大模型 4.0。 之所以要测它&…

【YOLOX简述】

YOLOX的简述 一、 原因1. 背景2. 概念 二、 算法介绍2.1 YOLOX算法结构图&#xff1a;2.2 算法独特点2.3 Focus网络结构2.4 FPN&#xff0c;PAN2.5 BaseConv2.6 SPP2.7 CSPDarknet2.8 YOlO Head 三、预测曲线3.1 曲线 一、 原因 1. 背景 工业的缺陷检测是计算机视觉中不可缺少…

如何快速搭建Spring Boot接口调试环境并实现公网访问

文章目录 前言1. 本地环境搭建1.1 环境参数1.2 搭建springboot服务项目 2. 内网穿透2.1 安装配置cpolar内网穿透2.1.1 windows系统2.1.2 linux系统 2.2 创建隧道映射本地端口2.3 测试公网地址 3. 固定公网地址3.1 保留一个二级子域名3.2 配置二级子域名3.2 测试使用固定公网地址…

探索Java中最常用的框架:Spring、Spring MVC、Spring Boot、MyBatis和Netty

文章目录 Spring框架Spring MVC框架Spring Boot框架MyBatis框架Netty框架总结 &#x1f389;欢迎来到Java面试技巧专栏~探索Java中最常用的框架&#xff1a;Spring、Spring MVC、Spring Boot、MyBatis和Netty ☆* o(≧▽≦)o *☆嗨~我是IT陈寒&#x1f379;✨博客主页&#xff…

深度学习之基于YoloV5苹果新鲜程度检测识别系统

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 深度学习之基于 YOLOv5 苹果新鲜程度检测识别系统介绍YOLOv5 简介苹果新鲜程度检测系统系统架构应用场景 二、功能三、系统四. 总结 一项目简介 深度学习之…

作为HR是看重学历还是工作经验?

作为HR是看重学历还是工作经验&#xff1f; 这个没有绝对的统一的看法&#xff0c;如果我是HR我更看重工作经验&#xff0c;如果是中小企业&#xff0c;对于人才嘛&#xff0c;那肯定是要到岗就能干活的&#xff0c;底子好不好先不说&#xff0c;关键是要能干活的。 不过近些…

介绍几种Go语言开发的IDE

文章目录 1.前言2.几种ide2.1 Goland2.2 VsCode示例 2.3 LiteIDE2.4 Eclipse插件GoClipse2.5 Atom2.6 Vim2.7 Sublime Text 3.总结写在最后 1.前言 Go语言作为一种新兴的编程语言&#xff0c;近年来受到了越来越多的关注。 它以其简洁、高效和并发性能而闻名&#xff0c;被广…

干货分享!各大跨境电商平台入驻指南及跨境电商实用工具推荐!

当跨境电商成为一个所有人都耳熟能详的名词&#xff0c;各类跨境电商平台和软件都一拥而上&#xff0c;跨境电商平台和工具千千万&#xff0c;那么很多人就在问了&#xff0c;该怎么入驻这些电商平台呢&#xff1f;又该选择什么样的跨境电商软件呢&#xff1f;今天这期干货分享…

进阶JAVA篇- Java 综合基本语法实践(习题一)

路漫漫其修远兮&#xff0c;吾将上下而求索。—— 屈原 目录 第一道题&#xff1a;集合的灵活运用 第二道题&#xff1a;基础编程能力 第三道题&#xff1a; 手写 ArrayList 集合&#xff08;模拟实现 ArrayList 核心API&#xff09; 第四道题&#xff1a;二分查找的应用 第五道…

简单的 UDP 网络程序

文章目录&#xff1a; 简单的UDP网络程序服务端创建套接字服务端绑定启动服务器udp客户端本地测试INADDR_ANY 地址转换函数关于 inet_ntoa 简单的UDP网络程序 服务端创建套接字 我们将服务端封装为一个类&#xff0c;当定义一个服务器对象之后&#xff0c;需要立即进行初始化…

【用unity实现100个游戏之15】开发一个类保卫萝卜的Unity2D塔防游戏1(附项目源码)

文章目录 先看本次实现的最终效果前言素材一、绘制路径点和连线1. 新建Waypoint &#xff0c;绘制路径点和连线2. 绘制路径点按钮效果3. 显示路径顺序文本4. 实时修改路径点位置 二、生成敌人1. 固定生成敌人配置2. 随机生成敌人配置 三、对象池创造敌人四、控制敌人沿前面绘制…

SpringBoot3自动配置流程及原理、SpringBootApplication注解详解

参考尚硅谷课程: https://www.yuque.com/leifengyang/springboot3/vznmdeb4kgn90vrx https://www.yuque.com/leifengyang/springboot3/lliphvul8b19pqxp 1.自动配置流程及原理 核心流程总结: 1.导入starter&#xff0c;就会导入autoconfigure包 2.autoconfigure 包里面 有一个…

Leetcode hot100之“结合递归+二分“题目详解

1 总结 题目 215 (“数组中的第 K 个最大元素”) 和题目 4 (“寻找两个正序数组的中位数”) 之间的联系主要体现在它们都涉及到寻找一个有序集合中的第 k 个元素的问题。尽管这两个问题的具体应用场景和所处理的数据结构不同&#xff0c;它们共享相似的算法思想和技术。 题目…

在3+1的方向上展开结构加法4a3+4a14

4a3 4a14 - - 1 - - - - - - - - - - - - - 1 1 1 - 1 1 - 1 - - 1 - - - 要求得到的图片只能有4个点&#xff0c;并且需要最大限度的保留4a3和4a14两张图片的内在结构特征。 4个点的结构总可以认为是3个点的结构1合成的 - - 1 - - …

[PyTorch][chapter 63][强化学习-时序差分学习]

目录&#xff1a; 蒙特卡罗强化学习的问题 基于转移的策略评估 时序差分评估 Sarsa-算法 Q-学习算法 一 蒙特卡罗强化学习的的问题 有模型学习&#xff1a; Bellman 等式 免模型学习: 蒙特卡罗强化学习 迭代&#xff1a; 使用策略 生成一个轨迹&#xff0c; for t…

【网络奇遇记】我和因特网的初相遇2 —— 三种交换方式

&#x1f308;个人主页&#xff1a;聆风吟 &#x1f525;系列专栏&#xff1a;网络奇遇记、数据结构 &#x1f516;少年有梦不应止于心动&#xff0c;更要付诸行动。 文章目录 前言一. 电路交换1.1 电路交换讲解1.2 电路交换实例 二. 分组交换1.1 分组交换讲解1.2 分组交换实例…

损失函数——KL散度(Kullback-Leibler Divergence,KL Divergence)

KL散度&#xff08;Kullback-Leibler Divergence&#xff0c;简称KL散度&#xff09;是一种度量两个概率分布之间差异的指标&#xff0c;也被称为相对熵&#xff08;Relative Entropy&#xff09;。KL散度被广泛应用于信息论、统计学、机器学习和数据科学等领域。 KL散度衡量的…