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

Python开源工具库使用之运动姿势追踪库mediapipe

文章目录

  • 前言
  • 一、姿势估计
    • 1.1 姿态关键点
    • 1.2 旧版 solution API
    • 1.3 新版 solution API
    • 1.4 俯卧撑计数
  • 二、手部追踪
    • 2.1 手部姿态
    • 2.2 API 使用
    • 2.3 识别手势含义
  • 参考

前言

Mediapipe 是谷歌出品的一种开源框架,旨在为开发者提供一种简单而强大的工具,用于实现各种视觉和感知应用程序。它包括一系列预训练的机器学习模型和用于处理多媒体数据的工具,可以用于姿势估计、手部追踪、人脸检测与跟踪、面部标志、对象检测、图片分割和语言检测等任务

Mediapipe 是支持跨平台的,可以部署在手机端(Android, iOS), web, desktop, edge devices, IoT 等各种平台,编程语言也支持C++, Python, Java, Swift, Objective-C, Javascript等

在本文中,我们将通过Python实现 Mediapipe 在姿势估计和手部追踪不同领域的应用

  • github 地址:https://github.com/google/mediapipe

一、姿势估计

1.1 姿态关键点

在这里插入图片描述

序号部位Pose Landmark
0鼻子PoseLandmark.NOSE
1左眼(内侧)PoseLandmark.LEFT_EYE_INNER
2左眼PoseLandmark.LEFT_EYE
3左眼(外侧)PoseLandmark.LEFT_EYE_OUTER
4右眼(内侧)PoseLandmark.RIGHT_EYE_INNER
5右眼PoseLandmark.RIGHT_EYE
6右眼(外侧)PoseLandmark.RIGHT_EYE_OUTER
7左耳PoseLandmark.LEFT_EAR
8右耳PoseLandmark.RIGHT_EAR
9嘴巴(左侧)PoseLandmark.MOUTH_LEFT
10嘴巴(右侧)PoseLandmark.MOUTH_RIGHT
11左肩PoseLandmark.LEFT_SHOULDER
12右肩PoseLandmark.RIGHT_SHOULDER
13左肘PoseLandmark.LEFT_ELBOW
14右肘PoseLandmark.RIGHT_ELBOW
15左腕PoseLandmark.LEFT_WRIST
16右腕PoseLandmark.RIGHT_WRIST
17左小指PoseLandmark.LEFT_PINKY
18右小指PoseLandmark.RIGHT_PINKY
19左食指PoseLandmark.LEFT_INDEX
20右食指PoseLandmark.RIGHT_INDEX
21左拇指PoseLandmark.LEFT_THUMB
22右拇指PoseLandmark.RIGHT_THUMB
23左臀PoseLandmark.LEFT_HIP
24右臀PoseLandmark.RIGHT_HIP
25左膝PoseLandmark.LEFT_KNEE
26右膝PoseLandmark.RIGHT_KNEE
27左踝PoseLandmark.LEFT_ANKLE
28右踝PoseLandmark.RIGHT_ANKLE
29左脚跟PoseLandmark.LEFT_HEEL
30右脚跟PoseLandmark.RIGHT_HEEL
31左脚趾PoseLandmark.LEFT_FOOT_INDEX
32右脚趾PoseLandmark.RIGHT_FOOT_INDEX

1.2 旧版 solution API

Mediapipe 提供 solution API 来实现快速检测, 不过这种方式在2023年5月10日停止更新了,不过目前还可以使用,可通过 mediapose.solutions.pose.Pose 来实现,配置参数如下

选项含义值范围默认值
static_image_mode如果设置为 False,会将输入图像视为视频流。它将尝试检测第一张图像中最突出的人,并在成功检测后进一步定位姿势。在随后的图像中,它只是跟踪这些标记,而不调用另一个检测,直到它失去跟踪,从而减少计算和延迟。如果设置为 True,则人员检测将运行每个输入图像,非常适合处理一批静态(可能不相关的)图像BooleanFalse
model_complexity模型的复杂度,准确性和推理延迟通常随着模型复杂性的增加而增加{0,1,2}1
smooth_landmarks如果设置为 True,则solution 过滤器会在不同的输入图像中设置标记以减少抖动,但如果 static_image_mode 也设置为 True,则忽略该筛选器BooleanTrue
enable_segmentation如果设置为 True,则除了姿态标记外,还会生成分割蒙版BooleanFalse
smooth_segmentation如果设置为 True,则会过滤不同输入图像中的分割掩码,以减少抖动。如果enable_segmentation为 false 或 static_image_mode为 True,则忽略BooleanTrue
min_detection_confidence人员检测模型的最小置信度值 ,用于将检测视为成功Float [0.0,1.0]0.5
min_tracking_confidence来自姿态跟踪模型的最小置信度值 , 用于将姿态标记视为成功跟踪,否则将在下一个输入图像上自动调用人员检测。将其设置为更高的值可以提高解决方案的可靠性,但代价是延迟更高。如果static_image_mode为 True,则忽略,其中人员检测仅对每个图像运行。Float [0.0,1.0]0.5
import cv2
import numpy as np
import mediapipe as mpdef main():FILE_PATH = 'data/1.png'img = cv2.imread(FILE_PATH)mp_pose = mp.solutions.posepose = mp_pose.Pose(static_image_mode=True,min_detection_confidence=0.5, min_tracking_confidence=0.5)res = pose.process(img)img_copy = img.copy()if res.pose_landmarks is not None:mp_drawing = mp.solutions.drawing_utils# mp_drawing.draw_landmarks(#     img_copy, res.pose_landmarks, mp.solutions.pose.POSE_CONNECTIONS)mp_drawing.draw_landmarks(img_copy,res.pose_landmarks,mp_pose.POSE_CONNECTIONS,  # frozenset,定义了哪些关键点要连接mp_drawing.DrawingSpec(color=(255, 255, 255),  # 姿态关键点thickness=2,circle_radius=2),mp_drawing.DrawingSpec(color=(174, 139, 45),   # 连线颜色thickness=2,circle_radius=2),)cv2.imshow('MediaPipe Pose Estimation', img_copy)cv2.waitKey(0)if __name__ == '__main__':main()

mediapipe_001

import cv2
import numpy as np
import mediapipe as mpdef video():# 读取摄像头# cap = cv2.VideoCapture(0)# 读取视频cap = cv2.VideoCapture('data/1.mp4')mp_pose = mp.solutions.posepose = mp_pose.Pose(static_image_mode=False,min_detection_confidence=0.5, min_tracking_confidence=0.5)while cap.isOpened():ret, frame = cap.read()if not ret:break# 摄像头# continue# 将 BGR 图像转换为 RGBrgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)# 进行姿势估计results = pose.process(rgb_frame)if results.pose_landmarks is not None:# 绘制关键点和连接线mp_drawing = mp.solutions.drawing_utilsmp_drawing.draw_landmarks(frame, results.pose_landmarks, mp_pose.POSE_CONNECTIONS)# 显示结果cv2.imshow('MediaPipe Pose Estimation', frame)if cv2.waitKey(1) & 0xFF == ord('q'):break# 释放资源cap.release()cv2.destroyAllWindows()if __name__ == '__main__':video()

mediapipe_002.gif

1.3 新版 solution API

旧版 API 并不能检测多个姿态,新版 API 可以实现多个姿态检测

选项含义值范围默认值
running_mode设置任务的运行模式,有三种模式可选:
IMAGE: 单一照片输入.
VIDEO: 视频.
LIVE_STREAM: 输入数据(例如来自摄像机)为实时流。在此模式下,必须调用 resultListener 来设置侦听器以异步接收结果.
{IMAGE, VIDEO, LIVE_STREAM}IMAGE
num_poses姿势检测器可以检测到的最大姿势数Integer > 01
min_pose_detection_confidence姿势检测被认为是成功的最小置信度得分Float [0.0,1.0]0.5
min_pose_presence_confidence姿态检测中的姿态存在分数的最小置信度分数Float [0.0,1.0]0.5
min_tracking_confidence姿势跟踪被视为成功的最小置信度分数Float [0.0,1.0]0.5
output_segmentation_masks是否为检测到的姿势输出分割掩码BooleanFalse
result_callback将结果侦听器设置为在Pose Landmark处于LIVE_STREAM模式时异步接收Landmark结果。仅当运行模式设置为LIVE_STREAM时才能使用ResultListenerN/A
from mediapipe import solutions
from mediapipe.framework.formats import landmark_pb2
import cv2
import numpy as np
import mediapipe as mpmp_drawing = mp.solutions.drawing_utils
mp_pose = mp.solutions.posedef draw_landmarks_on_image(rgb_image, detection_result):pose_landmarks_list = detection_result.pose_landmarksannotated_image = np.copy(rgb_image)# Loop through the detected poses to visualize.for idx in range(len(pose_landmarks_list)):pose_landmarks = pose_landmarks_list[idx]# Draw the pose landmarks.pose_landmarks_proto = landmark_pb2.NormalizedLandmarkList()pose_landmarks_proto.landmark.extend([landmark_pb2.NormalizedLandmark(x=landmark.x, y=landmark.y, z=landmark.z) for landmark in pose_landmarks])solutions.drawing_utils.draw_landmarks(annotated_image,pose_landmarks_proto,solutions.pose.POSE_CONNECTIONS,solutions.drawing_styles.get_default_pose_landmarks_style())return annotated_imagedef newSolution():BaseOptions = mp.tasks.BaseOptionsPoseLandmarker = mp.tasks.vision.PoseLandmarkerPoseLandmarkerOptions = mp.tasks.vision.PoseLandmarkerOptionsVisionRunningMode = mp.tasks.vision.RunningModemodel_path = 'data/pose_landmarker_heavy.task'options = PoseLandmarkerOptions(base_options=BaseOptions(model_asset_path=model_path),running_mode=VisionRunningMode.IMAGE,num_poses=10)FILE_PATH = 'data/4.jpg'image = cv2.imread(FILE_PATH)img = mp.Image.create_from_file(FILE_PATH)with PoseLandmarker.create_from_options(options) as detector:res = detector.detect(img)image = draw_landmarks_on_image(image, res)cv2.imshow('MediaPipe Pose Estimation', image)cv2.waitKey(0)if __name__ == '__main__':newSolution()

mediapipe_003

1.4 俯卧撑计数

通过计算胳膊弯曲角度来判断状态,并计算俯卧撑个数

import cv2
import mediapipe as mp
import numpy as npmp_drawing = mp.solutions.drawing_utils
mp_pose = mp.solutions.posedef calculate_angle(a, b, c):radians = np.arctan2(c.y - b.y, c.x - b.x) - \np.arctan2(a.y - b.y, a.x - b.x)angle = np.abs(np.degrees(radians))return angle if angle <= 180 else 360 - angledef angle_of_arm(landmarks, shoulder, elbow, wrist):shoulder_coord = landmarks[mp_pose.PoseLandmark[shoulder].value]elbow_coord = landmarks[mp_pose.PoseLandmark[elbow].value]wrist_coord = landmarks[mp_pose.PoseLandmark[wrist].value]return calculate_angle(shoulder_coord, elbow_coord, wrist_coord)def count_push_up(landmarks, counter, status):left_arm_angle = angle_of_arm(landmarks, "LEFT_SHOULDER", "LEFT_ELBOW", "LEFT_WRIST")right_arm_angle = angle_of_arm(landmarks, "RIGHT_SHOULDER", "RIGHT_ELBOW", "RIGHT_WRIST")avg_arm_angle = (left_arm_angle + right_arm_angle) // 2if status:if avg_arm_angle < 70:counter += 1status = Falseelse:if avg_arm_angle > 160:status = Truereturn counter, statusdef main():cap = cv2.VideoCapture('data/test.mp4')counter = 0status = Falsewith mp_pose.Pose(min_detection_confidence=0.7, min_tracking_confidence=0.7) as pose:while cap.isOpened():success, image = cap.read()if not success:print("empty camera")breakresult = pose.process(image)if result.pose_landmarks:mp_drawing.draw_landmarks(image, result.pose_landmarks, mp_pose.POSE_CONNECTIONS)counter, status = count_push_up(result.pose_landmarks.landmark, counter, status)cv2.putText(image, text=str(counter), org=(100, 100), fontFace=cv2.FONT_HERSHEY_SIMPLEX,fontScale=4, color=(255, 255, 255), thickness=2, lineType=cv2.LINE_AA)cv2.imshow("push-up counter", image)key = cv2.waitKey(1)if key == ord('q'):breakcap.release()if __name__ == '__main__':main()

mediapipe_004

二、手部追踪

2.1 手部姿态

hand-landmarks

2.2 API 使用

照片

选项含义值范围默认值
static_image_mode如果设置为 False,会将输入图像视为视频流。它将尝试在第一个输入图像中检测手,并在成功检测后进一步定位手部标志。在随后的图像中,一旦检测到所有 max_num_hands 手并定位了相应的手部标志,它就会简单地跟踪这些标志,而不会调用其他检测,直到它失去对任何手的跟踪。这减少了延迟,是处理视频帧的理想选择。如果设置为 True,则对每个输入图像运行手动检测,非常适合处理一批静态(可能不相关的)图像BooleanFalse
max_num_hands要检测的最大手数Integer2
model_complexity模型的复杂度,准确性和推理延迟通常随着模型复杂性的增加而增加{0,1}1
min_detection_confidence检测模型的最小置信度值 ,用于将检测视为成功Float [0.0,1.0]0.5
min_tracking_confidence来自手部跟踪模型的最小置信度值 , 用于将手部标记视为成功跟踪,否则将在下一个输入图像上自动调用检测。将其设置为更高的值可以提高解决方案的可靠性,但代价是延迟更高。如果static_image_mode为 True,则忽略,其中手部检测仅对每个图像运行。Float [0.0,1.0]0.5
import cv2
import mediapipe as mpmp_hands = mp.solutions.handsdef main():cv2.namedWindow("MediaPipe Hand", cv2.WINDOW_NORMAL)hands = mp_hands.Hands(static_image_mode=False, max_num_hands=2,min_detection_confidence=0.5, min_tracking_confidence=0.5)img = cv2.imread('data/finger/1.jpg')rgb_frame = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)# 进行手部追踪results = hands.process(rgb_frame)if results.multi_hand_landmarks:# 绘制手部关键点和连接线for hand_landmarks in results.multi_hand_landmarks:mp_drawing = mp.solutions.drawing_utilsmp_drawing.draw_landmarks(img, hand_landmarks, mp_hands.HAND_CONNECTIONS)# 显示结果cv2.imshow('MediaPipe Hand', img)cv2.waitKey(0)if __name__ == '__main__':main()

mediapipe_005_hand_image

import cv2
import mediapipe as mpmp_hands = mp.solutions.handsdef video():hands = mp_hands.Hands(static_image_mode=False, max_num_hands=2,min_detection_confidence=0.4, min_tracking_confidence=0.4)# 读取视频cap = cv2.VideoCapture('data/hand.mp4')while cap.isOpened():ret, frame = cap.read()if not ret:break# 将 BGR 图像转换为 RGBrgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)# 进行手部追踪results = hands.process(rgb_frame)if results.multi_hand_landmarks:# 绘制手部关键点和连接线for hand_landmarks in results.multi_hand_landmarks:mp_drawing = mp.solutions.drawing_utilsmp_drawing.draw_landmarks(frame, hand_landmarks, mp_hands.HAND_CONNECTIONS)# 显示结果cv2.imshow('MediaPipe Hand Tracking', frame)if cv2.waitKey(1) & 0xFF == ord('q'):break# 释放资源cap.release()cv2.destroyAllWindows()if __name__ == '__main__':video()

mediapipe_006.gif

2.3 识别手势含义

使用 KNN 对手势进行预测

import mediapipe as mp
import numpy as np
import cv2
from mediapipe.framework.formats.landmark_pb2 import NormalizedLandmarkList
from sklearn.neighbors import KNeighborsClassifiermp_drawing = mp.solutions.drawing_utils
mp_drawing_styles = mp.solutions.drawing_styles
mp_hands = mp.solutions.hands# 压缩特征点
class Embedder(object):def __init__(self):self._landmark_names = mp.solutions.hands.HandLandmarkdef __call__(self, landmarks):# modify the call func can both handle a 3-dim dataset and a single referencing result.if isinstance(landmarks, np.ndarray):if landmarks.ndim == 3:  # for datasetembeddings = []for lmks in landmarks:embedding = self.__call__(lmks)embeddings.append(embedding)return np.array(embeddings)elif landmarks.ndim == 2:  # for inferenceassert landmarks.shape[0] == len(list(self._landmark_names)), 'Unexpected number of landmarks: {}'.format(landmarks.shape[0])# Normalize landmarks.landmarks = self._normalize_landmarks(landmarks)# Get embedding.embedding = self._get_embedding(landmarks)return embeddingelse:print('ERROR: Can NOT embedding the data you provided !')else:if isinstance(landmarks, list):  # for datasetembeddings = []for lmks in landmarks:embedding = self.__call__(lmks)embeddings.append(embedding)return np.array(embeddings)elif isinstance(landmarks, NormalizedLandmarkList):  # for inference# Normalize landmarks.landmarks = np.array([[lmk.x, lmk.y, lmk.z]for lmk in landmarks.landmark], dtype=np.float32)assert landmarks.shape[0] == len(list(self._landmark_names)), 'Unexpected number of landmarks: {}'.format(landmarks.shape[0])landmarks = self._normalize_landmarks(landmarks)# Get embedding.embedding = self._get_embedding(landmarks)return embeddingelse:print('ERROR: Can NOT embedding the data you provided !')def _get_center(self, landmarks):# MIDDLE_FINGER_MCP:9return landmarks[9]def _get_size(self, landmarks):landmarks = landmarks[:, :2]max_dist = np.max(np.linalg.norm(landmarks - self._get_center(landmarks), axis=1))return max_dist * 2def _normalize_landmarks(self, landmarks):landmarks = np.copy(landmarks)# Normalizecenter = self._get_center(landmarks)size = self._get_size(landmarks)landmarks = (landmarks - center) / sizelandmarks *= 100  # optional, but makes debugging easier.return landmarksdef _get_embedding(self, landmarks):# we can add and delete any embedding featurestest = np.array([np.dot((landmarks[2]-landmarks[0]),(landmarks[3]-landmarks[4])),   # thumb bentnp.dot((landmarks[5]-landmarks[0]), (landmarks[6]-landmarks[7])),np.dot((landmarks[9]-landmarks[0]), (landmarks[10]-landmarks[11])),np.dot((landmarks[13]-landmarks[0]),(landmarks[14]-landmarks[15])),np.dot((landmarks[17]-landmarks[0]), (landmarks[18]-landmarks[19]))]).flatten()return testdef init_knn(file='data/dataset_embedded.npz'):npzfile = np.load(file)X = npzfile['X']y = npzfile['y']neigh = KNeighborsClassifier(n_neighbors=5)neigh.fit(X, y)return neighdef hand_pose_recognition(stream_img):# For static images:stream_img = cv2.cvtColor(stream_img, cv2.COLOR_BGR2RGB)embedder = Embedder()neighbors = init_knn()with mp_hands.Hands(static_image_mode=True,max_num_hands=2,min_detection_confidence=0.5) as hands:results = hands.process(stream_img)if not results.multi_hand_landmarks:return ['no_gesture'], stream_imgelse:annotated_image = stream_img.copy()multi_landmarks = results.multi_hand_landmarks# KNN inferenceembeddings = embedder(multi_landmarks)hand_class = neighbors.predict(embeddings)# hand_class_prob = neighbors.predict_proba(embeddings)# print(hand_class_prob)for landmarks in results.multi_hand_landmarks:mp_drawing.draw_landmarks(annotated_image,landmarks,mp_hands.HAND_CONNECTIONS,mp_drawing_styles.get_default_hand_landmarks_style(),mp_drawing_styles.get_default_hand_connections_style())return hand_class, annotated_image# 手势有10种,数字有8种,1-10之间7和9没有,还有两种是OK手势,和蜘蛛侠spide手势
# `eight_sign`, `five_sign`, `four_sign`, `ok`, `one_sign`, `six_sign`, `spider`, `ten_sign`, `three_sign`, `two_sign`def image():FILE_PATH = 'data/ok.png'img = cv2.imread(FILE_PATH)handclass, img_final = hand_pose_recognition(img)cv2.putText(img_final, text=handclass[0], org=(200, 50), fontFace=cv2.FONT_HERSHEY_SIMPLEX,fontScale=2, color=(255, 255, 255), thickness=2, lineType=cv2.LINE_AA)cv2.imshow('test', cv2.cvtColor(img_final, cv2.COLOR_RGB2BGR))cv2.waitKey(0)def video():cap = cv2.VideoCapture('data/ok.mp4')while cap.isOpened():ret, frame = cap.read()if not ret:breakhandclass, img_final = hand_pose_recognition(frame)cv2.putText(img_final, text=handclass[0], org=(50, 50), fontFace=cv2.FONT_HERSHEY_SIMPLEX,fontScale=2, color=(255, 0, 0), thickness=2, lineType=cv2.LINE_AA)cv2.imshow('test', cv2.cvtColor(img_final, cv2.COLOR_RGB2BGR))if cv2.waitKey(1) & 0xFF == ord('q'):breakif __name__ == '__main__':video()

mediapipe_007

参考

  1. https://developers.google.cn/mediapipe/solutions/
  2. https://github.com/googlesamples/mediapipe
  3. https://github.com/Furkan-Gulsen/Sport-With-AI
  4. https://github.com/Chuanfang-Neptune/DLAV-G9

相关文章:

Python开源工具库使用之运动姿势追踪库mediapipe

文章目录 前言一、姿势估计1.1 姿态关键点1.2 旧版 solution API1.3 新版 solution API1.4 俯卧撑计数 二、手部追踪2.1 手部姿态2.2 API 使用2.3 识别手势含义 参考 前言 Mediapipe 是谷歌出品的一种开源框架&#xff0c;旨在为开发者提供一种简单而强大的工具&#xff0c;用…...

【Android Studio】开启真机调试

1 打开手机的开发者模式 各种款式的手机进入开发者模式的情况不同&#xff0c;但大致是在 【关于手机】中多次点击系统版本即可进入。这里以小米8为例&#xff0c;记录下流程。 1.1 进入手机开发者模式 【设置】->【我的设备】->【全部参数】->【MIUI版本】连续点击3…...

CMakeLists.txt语法规则:部分常用命令说明四

一. 简介 前面几篇文章学习了CMakeLists.txt语法中前面几篇文章学习了CMakeLists.txt语法中部分常用命令。文章如下&#xff1a; CMakeLists.txt语法规则&#xff1a;部分常用命令说明一-CSDN博客 CMakeLists.txt语法规则&#xff1a;部分常用命令说明二-CSDN博客 CMakeLi…...

学习前端第三十二天(Rest 参数与 Spread 语法,变量作用域,闭包)

一、Rest 参数与 Spread 语法 1.rest参数 ...变量名&#xff1a;收集剩余的参数并存进指定数组中&#xff0c;需要放到最后&#xff1b; 2.arguments变量 // arguments,以参数在参数列表中的索引作为键&#xff0c;存储所有参数,以类数组对象的形式输出所有函数参数 // 箭头…...

mysql从入门到起飞+面试基础题

mysql基础 MySQL基础 企业面试题1 代码 select m.id,m.num from ( select t.id as id,count(1) num from ( select ra.requester_id as id from RequestAccepted raunion all select ra.accepter_id as id from RequestAccepted ra ) t group by t.id ) m group by id ord…...

设计模式:命令模式

文章目录 一、什么是命令模式二、命令模式结构三、命令模式实现步骤四、命令模式应用场景 一、什么是命令模式 它允许将请求封装为对象&#xff0c;一个请求对应于一个命令&#xff0c;将发出命令的责任和执行命令的责任分割开。每一个命令都是一个操作&#xff1a;请求的一方…...

setinterval和settimeout区别在于

setinterval和settimeout区别在于 执行次数和执行频率 setInterval和setTimeout的主要区别在于执行次数和执行频率。以下是详细介绍&#xff1a;12 setTimeout是一次性的定时器&#xff0c;它在设定的延迟时间之后执行一次函数&#xff0c;然后停止。setInterval是重复性的定…...

shell_结束进程脚本

结束进程的shell脚本如下&#xff1a; #!/bin/bash# kill all process ps aux|grep "local" | grep -v grep | awk {print $2} | while read line; do kill -9 $line; done 解析&#xff1a; ps aux 命令常用于查看当前系统中运行的进程&#xff0c;以及它们所占用…...

GDPU unity游戏开发 碰撞器与触发器

砰砰叫&#xff0c;谁动了她的奶酪让你的小鹿乱撞了。基于此&#xff0c;亦即碰撞与触发的过程。 碰撞器与触发器的区别 通俗点讲&#xff0c;碰撞器检测碰撞&#xff0c;触发器检测触发&#xff0c;讲了跟没讲似的。碰撞器是用来检测碰撞事件的&#xff0c;在unity中&#xff…...

IP地址定位技术在网络安全中的作用

在当今数字化时代&#xff0c;网络安全已经成为企业、政府和个人面临的重要挑战之一。随着互联网的普及和网络攻击的增加&#xff0c;保护个人隐私和防止网络犯罪变得尤为重要。在这一背景下&#xff0c;IP地址定位技术作为网络安全的重要组成部分之一&#xff0c;发挥着关键作…...

R语言中,查看经安装的包,查看已经加载的包,查看特定包是否已经安装,安装包,更新包,卸载包

创建于&#xff1a;2024.5.4 R语言中&#xff0c;查看经安装的包&#xff0c;查看已经加载的包&#xff0c;查看特定包是否已经安装&#xff0c;安装包&#xff0c;更新包&#xff0c;卸载包 文章目录 1. 查看经安装的包2. 查看已经加载的包3. 查看特定包是否已经安装4. 安装包…...

spring boot3单模块项目工程搭建-下(个人开发模板)

⛰️个人主页: 蒾酒 &#x1f525;系列专栏&#xff1a;《spring boot实战》 目录 写在前面 上文衔接 常用依赖介绍以及整合 web组件 测试组件 样板代码生成 数据库连接器 常用工具包 面向切面编程 ORM框架 数据连接池 接口测试、文档导出 缓存中间件 参数校…...

精准清理 MongoDB 数据:删除集合的正确姿势

在 MongoDB 数据库管理中&#xff0c;数据清理是维护数据库性能和保持数据一致性的关键步骤之一。而删除集合是实现数据清理的重要手段之一。在这个信息爆炸的时代&#xff0c;了解如何正确地执行集合删除操作至关重要。本文将深入探讨 MongoDB 中删除集合的常用方法、最佳实践…...

java 执行修改语句

你可以使用Java中的JDBC&#xff08;Java Database Connectivity&#xff09;来执行修改语句。以下是一个示例&#xff1a; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.sql.Statement;public class Main {public…...

【Linux系统化学习】网络套接字(编写简单的UDP服务端和客户端)

目录 理解源IP地址和目的IP地址 认识端口号 端口号和进程ID的区别 源端口号和目的端口号 认识TCP和UDP协议 TCP协议 UDP协议 网络字节序 socket编程接口 socket常见API sockaddr结构 简单的UDP网络程序 UDP服务端 创建套接字 填充本地网络信息 绑定 收取消息 …...

MFC 列表控件修改实例(源码下载)

1、本程序基于前期我的博客文章《MFC下拉菜单打钩图标存取实例&#xff08;源码下载&#xff09;》 2、程序功能选中列表控件某一项&#xff0c;修改这一项的按钮由禁止变为可用&#xff0c;双击这个按钮弹出对话框可对这一项的记录数据进行修改&#xff0c;点击确定保存修改数…...

QT设计模式:模板模式

基本概念 模板模式&#xff08;Template Pattern&#xff09;是一种行为型设计模式&#xff0c;它定义了一个操作中的算法的模板&#xff0c;而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重新定义该算法的某些特定步骤。 实现的模块有&#xff1…...

8.k8s中网络资源service

目录 一、service资源概述 二、service资源类型 1.ClusterIP类型 2.service的nodeport类型 3.service的loadbalancer类型&#xff08;了解即可&#xff09; 4.service的externalname类型&#xff08;了解即可&#xff09; 三、nodeport的端口范围设置和svc的endpoint列表 1.修…...

51单片机keil编程中遇到的问题(持续更新)

字符无法打印报错 查看特殊功能寄存器名字的时候也会报错&#xff0c;因为无法编译通过&#xff0c;导致头文件的定义内容无法查找 keil编译中 error C127: ‘xx’: invalid storage class 这种一般是在编写头文件或源文件时&#xff0c;在声明函数的结尾没有添加分号&…...

C++类和对象详解(一)

目录 面向过程和面向对象初步认识类的引入类的定义类的两种定义方式声明和定义全部放在类体中 声名定义分离 类的作用域成员变量命名规则建议访问限定符 类的封装类的实例化类对象模型类的对象大小的计算扩展 结构体内存对齐规则 感谢各位大佬对我的支持,如果我的文章对你有用,…...

SCI论文检索报告长什么样?怎么出具?一文了解!

1、SCI检索报告是什么 SCI数据库收录最能反映基础学科研究水平和论文质量&#xff0c;该检索系统收录的科技期刊比较全面&#xff0c;可以说它是集中各个学科高质优秀论文的精粹&#xff0c;评职晋升、项目申报、评奖评优等很多关键时期&#xff0c;都需要开具已经在SCI发表的论…...

UE4_Water插件_Buoyancy组件使用

water插件提供了一个浮力Actor蓝图类。 需要注意的几个问题: 1、StaticMesh需要替换根组件。 2、需要模拟物理设置质量。 3、需要添加浮力组件,设置浮力点,应用水中牵引力。...

OceanBase学习1:分布式数据库与集中式数据库的差异

目录 1. 传统集中式数据库 2. 数据库中间件的分库分表 3. 分布式数据库的基本特点及对比分析 4. OceanBase和传统数据库的对比 5. 小结 1. 传统集中式数据库 优点 成熟稳定:经过近40年的发展&#xff0c;应用到各行各业&#xff0c;产品技术非常成熟稳定行业适配性强:适配…...

计算机网络技术主要学什么内容,有哪些课程

计算机网络技术专业是一个涉及理论与实践紧密结合的学科&#xff0c;主要学习内容有计算机网络基础、网络设备技术、网络编程等内容&#xff0c;以下是上大学网&#xff08;www.sdaxue.com&#xff09;整理的计算机网络技术主要学什么内容&#xff0c;供大家参考&#xff01; 基…...

Mac下安装ffmpeg

1、安装gedit brew install gedit2、配置环境变量&#xff0c;打开~/.zshrc&#xff0c;在末尾添加语句 export PATH$PATH:/usr/local/ffmpeg/bin3、执行语句&#xff0c;使环境变量生效 source ~/.zshrc 4、终端输入 ffmpeg &#xff0c;看环境变量是否配置成功。 至此&a…...

自制AI:Park_01修改bug

修改了一下不能存东西&#xff0c;不能打开东西的bug #include<bits/stdc.h> #include<windows.h> using namespace std; double mem10737418240; map<string,string> jishiben; string mulu"朴同学给你的一封信.memo\n"; int cntnote1; void sta…...

解救应用启动危机:Spring Boot的FailureAnalyzer机制

目录 一、走进FailureAnalyzer 二、在Spring Boot中如何生效 三、为什么可能需要自定义FailureAnalyzer 四、实现自定义基本步骤 &#xff08;一&#xff09;完整步骤要求 &#xff08;二&#xff09;注册方式说明 通过Spring Boot的spring.factories文件&#xff08;建…...

win11个性化锁屏界面怎么关闭?

win11个性化锁屏界面关闭方法对于win11用户来说&#xff0c;关闭个性化锁屏界面是一个常见问题。本文将由php小编苹果详细介绍如何执行此操作&#xff0c;分步指导并提供操作截图。继续阅读以了解具体步骤。 win11个性化锁屏界面关闭方法 第一步&#xff0c;点击底部Windows图…...

白酒:白酒香型与品质消费的关系及影响

云仓酒庄的豪迈白酒作为中国白酒的品牌&#xff0c;其白酒香型与品质消费的关系及影响备受关注。随着消费者对品质的重视程度不断提高&#xff0c;了解白酒香型与品质之间的关系对于云仓酒庄和消费者都具有重要意义。 经云仓酒庄豪迈白酒分析&#xff0c;白酒香型与品质消费的关…...

智能BI(后端)-- 系统优化(安全性,数据存储,限流)

文章目录 安全性todo 数据存储限流限流的几种算法限流粒度限流的实现本地限流&#xff08;单机限流&#xff09;Redisson实现分布式限流(多机限流) 安全性 问题引入&#xff1a;如果用户上传一个超大的文件怎么办&#xff1f;比如1000G&#xff1f; 预防&#xff1a; 只要涉及…...

wordpress h5 视频播放/百度搜索风云榜排名

问题描述: -------- DB2, 使用应用用户import数据时报错: SQL0572N Package "NULLID.SQLUAK20" is inoperative. SQLSTATE51028 原因分析: --------- db2updv105会使一些package失效,如果数据库参数AUTO_REVAL为DISABLED,那么就可能遇到这个问题(从旧版本9.5升级上…...

免费网站模板库/三叶草gy5987

展开全部用“”替换文件中的内32313133353236313431303231363533e78988e69d8331333337626137容达到删除目的import java.io.InputStream;import java.io.BufferedReader;import java.io.BufferedWriter;import java.io.FileReader;import java.io.FileWriter;import java.util.…...

找个建设网站的网管/全网搜索关键词查询

OpenStack 企业私有云的若干需求&#xff08;3&#xff09;&#xff1a;多租户和租户间隔离(multi-tenancy and isolation) 本系列会介绍OpenStack 企业私有云的几个需求&#xff1a; 自动扩展&#xff08;Auto-scaling&#xff09;支持多租户和租户隔离 &#xff08;multi-t…...

商洛做网站多少钱/google推广

某个客户数据库在巡检的时候发现alert日志里不定期会出现ORA-609错误&#xff0c;由于ORA-609的缘故&#xff0c;ospid(xxxx)进程被aborting了&#xff0c;同时还某个客户数据库在巡检的时候发现alert日志里不定期会出现ORA-609错误&#xff0c;大致内容如下&#xff1a;******…...

茂名网站建设解决方案/今日新闻快讯10条

Backup Exec 2012 相对之前的版本2010有了很大的变化,最为明显的就是管理控制台界面。管理界面包括"主页"、"备份和还原"、"存储"、"报告",以及“Backup Exec ” 选项按钮.相比早起的BE2010 各小版本界面也更美观了。1. 软件组成ISO 文…...

武汉关键词优化推广/seo关键词优化培训

2019独角兽企业重金招聘Python工程师标准>>> 【编者按】作者 Aaron Volkmann 是 CERT Division 高级研究员&#xff0c;通过提出了一种集成安全系统到 CI/CD 的方法&#xff0c;让机构保持快速部署到生产环境能力的同时&#xff0c;也大幅度降低安全隐患&#xff0c…...