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

AI项目二十一:视频动态手势识别

若该文为原创文章,转载请注明原文出处。

一、简介

人工智能的发展日新月异,也深刻的影响到人机交互领域的发展。手势动作作为一种自然、快捷的交互方式,在智能驾驶、虚拟现实等领域有着广泛的应用。手势识别的任务是,当操作者做出某个手势动作后,计算机能够快速准确的判断出该手势的类型。本文将使用ModelArts开发训练一个视频动态手势识别的算法模型,对上滑、下滑、左滑、右滑、打开、关闭等动态手势类别进行检测,实现类似隔空手势的功能。

在前面也有使用mediapipe实现类似功能。具体自行参考。

本文章参考CNN-VIT 视频动态手势识别【玩转华为云】-云社区-华为云

二、环境

使用的是AUTODL,配置如下:

镜像:PyTorch  1.7.0   Python  3.8(ubuntu18.04)   Cuda  11.0

GPU :RTX 2080 Ti(11GB) * 1升降配置

CPU12 vCPU Intel(R) Xeon(R) Platinum 8255C CPU @ 2.50GHz

三、环境搭建

1、创建虚拟环境

conda create -n cnn_hand_gesture_env python=3.8

2、激活

conda activate cnn_hand_gesture_env

3、安装依赖项

conda install cudatoolkit=11.3.1 cudnn=8.2.1 -y --override-channels --channel https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main

pip install tensorflow-gpu==2.5.0 -i https://pypi.doubanio.com/simple --userpip install opencv-contrib-python
pip install imageio
pip install imgaug
pip install tqdm
pip install IPythonpip install numpy==1.19.3 -i https://pypi.tuna.tsinghua.edu.cn/simple
pip install matplotlib==3.6

这里需要注意的是numpy版本和matplotlib版本,tensorflow2.5版本对应的numpy版本是1.19.3

如果版本过高会一直出错错误。

四、数据下载

下载数据使用的是华为云,可以自行下载或联系我。

import os
import moxing as moxif not os.path.exists('hand_gesture'):mox.file.copy_parallel('obs://modelbox-course/hand_gesture', 'hand_gesture')

五、算法简介

视频动态手势识别算法首先使用预训练网络InceptionResNetV2逐帧提取视频动作片段特征,然后输入Transformer Encoder进行分类。我们使用动态手势识别样例数据集对算法进行测试,总共包含108段视频,数据集包含无效手势、上滑、下滑、左滑、右滑、打开、关闭等7种手势的视频,具体操作流程如下:

六、流程

1、将采集的视频文件解码抽取关键帧,每隔4帧保存一次,然后对图像进行中心裁剪和预处理

2、创建图像特征提取器,使用预训练模型InceptionResNetV2提取图像特征

3、提取视频特征向量,如果视频不足40帧就创建全0数组进行补白

4、创建VIT Mode

5、视频推理

6、加载VIT Model,获取视频类别索引标签

7、使用图像特征提取器InceptionResNetV2提取视频特征

8、将视频序列的特征向量输入Transformer Encoder进行预测

9、打印模型预测结果

七、测试

Autodl自带有JupyterLab, 直接运行一遍。

代码解析:

1、创建视频输入管道获取视频类别标签

videos = glob.glob('hand_gesture/*.mp4')
np.random.shuffle(videos)
labels = [int(video.split('_')[-2]) for video in videos]
videos[:5], len(videos), labels[:5], len(videos)

2、视频抽帧预处理

def load_video(file_name):cap = cv2.VideoCapture(file_name) # 每隔多少帧抽取一次frame_interval = 4frames = []count = 0while True:ret, frame = cap.read()if not ret:break# 每隔frame_interval帧保存一次if count % frame_interval == 0:# 中心裁剪    frame = crop_center_square(frame)# 缩放frame = cv2.resize(frame, (IMG_SIZE, IMG_SIZE))# BGR -> RGB  [0,1,2] -> [2,1,0]frame = frame[:, :, [2, 1, 0]]frames.append(frame)count += 1return np.array(frames)   

3、创建图像特征提取器

def get_feature_extractor():feature_extractor = keras.applications.inception_resnet_v2.InceptionResNetV2(weights = 'imagenet',include_top = False,pooling = 'avg',input_shape = (IMG_SIZE, IMG_SIZE, 3))preprocess_input = keras.applications.inception_resnet_v2.preprocess_inputinputs = keras.Input((IMG_SIZE, IMG_SIZE, 3))preprocessed = preprocess_input(inputs)outputs = feature_extractor(preprocessed)model = keras.Model(inputs, outputs, name = 'feature_extractor')return model

4、提取视频图像特征

def load_data(videos, labels):video_features = []for video in tqdm(videos):frames = load_video(video)counts = len(frames)# 如果帧数小于MAX_SEQUENCE_LENGTHif counts < MAX_SEQUENCE_LENGTH:# 补白diff = MAX_SEQUENCE_LENGTH - counts# 创建全0的numpy数组padding = np.zeros((diff, IMG_SIZE, IMG_SIZE, 3))# 数组拼接frames = np.concatenate((frames, padding))# 获取前MAX_SEQUENCE_LENGTH帧画面frames = frames[:MAX_SEQUENCE_LENGTH, :]# 批量提取特征video_feature = feature_extractor.predict(frames)video_features.append(video_feature)return np.array(video_features), np.array(labels)

5、编码器

# 编码器
class TransformerEncoder(layers.Layer):def __init__(self, num_heads, embed_dim):super().__init__()self.p_embedding = PositionalEmbedding(MAX_SEQUENCE_LENGTH, NUM_FEATURES)self.attention = layers.MultiHeadAttention(num_heads=num_heads, key_dim=embed_dim, dropout=0.1)self.layernorm = layers.LayerNormalization()def call(self,x):# positional embeddingpositional_embedding = self.p_embedding(x)# self attentionattention_out = self.attention(query = positional_embedding,value = positional_embedding,key = positional_embedding,attention_mask = None)# layer norm with residual connection        output = self.layernorm(positional_embedding + attention_out)return output

6、训练模式

history = model.fit(train_dataset,epochs = 1000,steps_per_epoch = train_count // batch_size, validation_steps = test_count // batch_size, validation_data = test_dataset,callbacks = [checkpoint, earlyStopping, rlp])

7、测试

# 视频预测
def testVideo():test_file = random.sample(videos, 1)[0]label = test_file.split('_')[-2]print('文件名:{}'.format(test_file) )print('真实类别:{}'.format(label_to_name.get(int(label))) )# 读取视频每一帧frames = load_video(test_file)# 挑选前帧MAX_SEQUENCE_LENGTH显示frames = frames[:MAX_SEQUENCE_LENGTH].astype(np.uint8)# 保存为GIFimageio.mimsave('animation.gif', frames, duration=10)# 获取特征feat = getVideoFeat(frames)# 模型推理prob = model.predict(tf.expand_dims(feat, axis=0))[0]print('预测类别:')for i in np.argsort(prob)[::-1][:5]:print('{}: {}%'.format(label_to_name[i], round(prob[i]*100, 2)))#return display(Image(open('animation.gif', 'rb').read()))

8、源码

import cv2
import glob
import numpy as np
from tqdm import tqdm
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
import matplotlib.pyplot as pltfrom collections import Counter
import random
import imageio
from IPython.display import Imagefrom tensorflow.keras.callbacks import ModelCheckpoint, EarlyStopping, ReduceLROnPlateau#%matplotlib inlineMAX_SEQUENCE_LENGTH = 40
IMG_SIZE = 299
NUM_FEATURES = 1536# 图像中心裁剪
def crop_center_square(img):h, w = img.shape[:2]square_w = min(h, w)start_x = w // 2 - square_w // 2end_x = start_x + square_wstart_y = h // 2 - square_w // 2end_y = start_y + square_wresult = img[start_y:end_y, start_x:end_x]return result# 视频抽帧预处理
def load_video(file_name):cap = cv2.VideoCapture(file_name) # 每隔多少帧抽取一次frame_interval = 4frames = []count = 0while True:ret, frame = cap.read()if not ret:break# 每隔frame_interval帧保存一次if count % frame_interval == 0:# 中心裁剪    frame = crop_center_square(frame)# 缩放frame = cv2.resize(frame, (IMG_SIZE, IMG_SIZE))# BGR -> RGB  [0,1,2] -> [2,1,0]frame = frame[:, :, [2, 1, 0]]frames.append(frame)count += 1return np.array(frames) # 创建图像特征提取器
def get_feature_extractor():feature_extractor = keras.applications.inception_resnet_v2.InceptionResNetV2(weights = 'imagenet',include_top = False,pooling = 'avg',input_shape = (IMG_SIZE, IMG_SIZE, 3))preprocess_input = keras.applications.inception_resnet_v2.preprocess_inputinputs = keras.Input((IMG_SIZE, IMG_SIZE, 3))preprocessed = preprocess_input(inputs)outputs = feature_extractor(preprocessed)model = keras.Model(inputs, outputs, name = 'feature_extractor')return model# 提取视频图像特征
def load_data(videos, labels):video_features = []for video in tqdm(videos):frames = load_video(video)counts = len(frames)# 如果帧数小于MAX_SEQUENCE_LENGTHif counts < MAX_SEQUENCE_LENGTH:# 补白diff = MAX_SEQUENCE_LENGTH - counts# 创建全0的numpy数组padding = np.zeros((diff, IMG_SIZE, IMG_SIZE, 3))# 数组拼接frames = np.concatenate((frames, padding))# 获取前MAX_SEQUENCE_LENGTH帧画面frames = frames[:MAX_SEQUENCE_LENGTH, :]# 批量提取特征video_feature = feature_extractor.predict(frames)video_features.append(video_feature)return np.array(video_features), np.array(labels)# 位置编码
class PositionalEmbedding(layers.Layer):def __init__(self, seq_length, output_dim):super().__init__()# 构造从0~MAX_SEQUENCE_LENGTH的列表self.positions = tf.range(0, limit=MAX_SEQUENCE_LENGTH)self.positional_embedding = layers.Embedding(input_dim=seq_length, output_dim=output_dim)def call(self,x):# 位置编码positions_embedding = self.positional_embedding(self.positions)# 输入相加return x + positions_embedding# 编码器
class TransformerEncoder(layers.Layer):def __init__(self, num_heads, embed_dim):super().__init__()self.p_embedding = PositionalEmbedding(MAX_SEQUENCE_LENGTH, NUM_FEATURES)self.attention = layers.MultiHeadAttention(num_heads=num_heads, key_dim=embed_dim, dropout=0.1)self.layernorm = layers.LayerNormalization()def call(self,x):# positional embeddingpositional_embedding = self.p_embedding(x)# self attentionattention_out = self.attention(query = positional_embedding,value = positional_embedding,key = positional_embedding,attention_mask = None)# layer norm with residual connection        output = self.layernorm(positional_embedding + attention_out)return outputdef video_cls_model(class_vocab):# 类别数量classes_num = len(class_vocab)# 定义模型model = keras.Sequential([layers.InputLayer(input_shape=(MAX_SEQUENCE_LENGTH, NUM_FEATURES)),TransformerEncoder(2, NUM_FEATURES),layers.GlobalMaxPooling1D(),layers.Dropout(0.1),layers.Dense(classes_num, activation="softmax")])# 编译模型model.compile(optimizer = keras.optimizers.Adam(1e-5), loss = keras.losses.SparseCategoricalCrossentropy(from_logits=False),metrics = ['accuracy'])return model# 获取视频特征
def getVideoFeat(frames):frames_count = len(frames)# 如果帧数小于MAX_SEQUENCE_LENGTHif frames_count < MAX_SEQUENCE_LENGTH:# 补白diff = MAX_SEQUENCE_LENGTH - frames_count# 创建全0的numpy数组padding = np.zeros((diff, IMG_SIZE, IMG_SIZE, 3))# 数组拼接frames = np.concatenate((frames, padding))# 取前MAX_SEQ_LENGTH帧frames = frames[:MAX_SEQUENCE_LENGTH,:]# 计算视频特征 N, 1536video_feat = feature_extractor.predict(frames)return video_feat# 视频预测
def testVideo():test_file = random.sample(videos, 1)[0]label = test_file.split('_')[-2]print('文件名:{}'.format(test_file) )print('真实类别:{}'.format(label_to_name.get(int(label))) )# 读取视频每一帧frames = load_video(test_file)# 挑选前帧MAX_SEQUENCE_LENGTH显示frames = frames[:MAX_SEQUENCE_LENGTH].astype(np.uint8)# 保存为GIFimageio.mimsave('animation.gif', frames, duration=10)# 获取特征feat = getVideoFeat(frames)# 模型推理prob = model.predict(tf.expand_dims(feat, axis=0))[0]print('预测类别:')for i in np.argsort(prob)[::-1][:5]:print('{}: {}%'.format(label_to_name[i], round(prob[i]*100, 2)))#return display(Image(open('animation.gif', 'rb').read()))if __name__ == '__main__':print('Tensorflow version: {}'.format(tf.__version__))print('GPU available: {}'.format(tf.config.list_physical_devices('GPU')))# 创建视频输入管道获取视频类别标签videos = glob.glob('hand_gesture/*.mp4')np.random.shuffle(videos)labels = [int(video.split('_')[-2]) for video in videos]videos[:5], len(videos), labels[:5], len(videos)print(labels)# 显示数据分布情况counts = Counter(labels)print(counts)plt.figure(figsize=(8, 4))plt.bar(counts.keys(), counts.values())plt.xlabel('Class label')plt.ylabel('Number of samples')plt.title('Class distribution in videos')plt.show()# 显示视频label_to_name = {0:'无效手势', 1:'上滑', 2:'下滑', 3:'左滑', 4:'右滑', 5:'打开', 6:'关闭', 7:'放大', 8:'缩小'}print(label_to_name.get(labels[0]))frames = load_video(videos[0])frames = frames[:MAX_SEQUENCE_LENGTH].astype(np.uint8)imageio.mimsave('test.gif', frames, durations=10)print('mim save test.git')#display(Image(open('test.gif', 'rb').read()))#frames.shapeprint(frames.shape)feature_extractor = get_feature_extractor()feature_extractor.summary()video_features, classes = load_data(videos, labels)video_features.shape, classes.shapeprint(video_features.shape)print(classes.shape)# Datasetbatch_size = 16dataset = tf.data.Dataset.from_tensor_slices((video_features, classes))dataset = dataset.shuffle(len(videos))test_count = int(len(videos) * 0.2)train_count = len(videos) - test_countdataset_train = dataset.skip(test_count).cache().repeat()dataset_test = dataset.take(test_count).cache().repeat()train_dataset = dataset_train.shuffle(train_count).batch(batch_size)test_dataset = dataset_test.shuffle(test_count).batch(batch_size)train_dataset, train_count, test_dataset, test_countprint(train_dataset)print(train_count)print(test_dataset)print(test_count)# 模型实例化model = video_cls_model(np.unique(labels))# 打印模型结构model.summary()# 保存检查点checkpoint = ModelCheckpoint(filepath='best.h5', monitor='val_loss', save_weights_only=True, save_best_only=True, verbose=1, mode='min')# 提前终止earlyStopping = EarlyStopping(monitor='loss', patience=50, mode='min', baseline=None)# 减少learning raterlp = ReduceLROnPlateau(monitor='loss', factor=0.7, patience=30, min_lr=1e-15, mode='min', verbose=1)# 开始训练history = model.fit(train_dataset,epochs = 1000,steps_per_epoch = train_count // batch_size, validation_steps = test_count // batch_size, validation_data = test_dataset,callbacks = [checkpoint, earlyStopping, rlp])# 绘制结果plt.plot(history.epoch, history.history['loss'], 'r', label='loss')plt.plot(history.epoch, history.history['val_loss'], 'g--', label='val_loss')plt.title('VIT Model')plt.xlabel('Epoch')plt.ylabel('Loss')plt.legend()plt.plot(history.epoch, history.history['accuracy'], 'r', label='acc')plt.plot(history.epoch, history.history['val_accuracy'], 'g--', label='val_acc')plt.title('VIT Model')plt.xlabel('Epoch')plt.ylabel('Accuracy')plt.legend()# 加载训练最优权重model.load_weights('best.h5')# 模型评估model.evaluate(dataset.batch(batch_size))# 保存模型model.save('saved_model')print('save model')# 手势识别# 加载模型model = tf.keras.models.load_model('saved_model')# 类别标签label_to_name = {0:'无效手势', 1:'上滑', 2:'下滑', 3:'左滑', 4:'右滑', 5:'打开', 6:'关闭', 7:'放大', 8:'缩小'}# 视频推理for i in range(20):testVideo()

运行后会训练模型

并保存模型测试,

测试结果

如有侵权,或需要完整代码,请及时联系博主。

相关文章:

AI项目二十一:视频动态手势识别

若该文为原创文章&#xff0c;转载请注明原文出处。 一、简介 人工智能的发展日新月异&#xff0c;也深刻的影响到人机交互领域的发展。手势动作作为一种自然、快捷的交互方式&#xff0c;在智能驾驶、虚拟现实等领域有着广泛的应用。手势识别的任务是&#xff0c;当操作者做出…...

浅拷贝与深拷贝面试问题及回答

1. 浅拷贝和深拷贝的区别是什么&#xff1f; 答&#xff1a; 浅拷贝&#xff08;Shallow Copy&#xff09;仅复制对象的引用而不复制引用的对象本身&#xff0c;因此原始对象和拷贝对象会引用同一个对象。而深拷贝&#xff08;Deep Copy&#xff09;则是对对象内部的所有元素进…...

推荐算法顶会论文合集

SIGIR SIGIR 2022 | 推荐系统相关论文分类整理&#xff1a;8.74 https://mp.weixin.qq.com/s/vH0qJ-jGHL7s5wSn7Oy_Nw SIGIR2021推荐系统论文集锦 https://mp.weixin.qq.com/s/N7V_9iqLmVI9_W65IQpOtg SIGIR2020推荐系统论文聚焦&#xff1a; https://mp.weixin.qq.com/s…...

组合模式(Composite)——结构型模式

组合模式(Composite)——结构型模式 组合模式是一种结构型设计模式&#xff0c; 你可以使用它将对象组合成树状结构&#xff0c; 并且能通过通用接口像独立整体对象一样使用它们。如果应用的核心模型能用树状结构表示&#xff0c; 在应用中使用组合模式才有价值。 例如一个场景…...

利用大模型提升个性化推荐的异构知识融合方法

在推荐系统中&#xff0c;分析和挖掘用户行为是至关重要的&#xff0c;尤其是在美团外卖这样的平台上&#xff0c;用户行为表现出多样性&#xff0c;包括不同的行为主体&#xff08;如商家和产品&#xff09;、内容&#xff08;如曝光、点击和订单&#xff09;和场景&#xff0…...

Dockerfile 里 ENTRYPOINT 和 CMD 的区别

ENTRYPOINT 和 CMD 的区别&#xff1a; 在 Dockerfile 中同时设计 CMD 和 ENTRYPOINT 是为了提供更灵活的容器启动方式。ENTRYPOINT 定义了容器启动时要执行的命令&#xff0c;而 CMD 则提供了默认参数。通过结合使用这两个指令&#xff0c;可以在启动容器时灵活地指定额外的参…...

腾讯的EdgeONE是什么?

腾讯的EdgeONE是一项边缘计算解决方案&#xff0c;具有一系列优势&#xff1a; 边缘计算能力强大&#xff1a;EdgeONE利用腾讯云在全球范围内的分布式基础设施&#xff0c;提供强大的边缘计算能力&#xff0c;可以实现低延迟和高可用性的服务。 智能化和自动化&#xff1a;Edg…...

SVM直观理解

https://tangshusen.me/2018/10/27/SVM/ https://www.bilibili.com/video/BV16T4y1y7qj/?spm_id_from333.337.search-card.all.click&vd_source8272bd48fee17396a4a1746c256ab0ae SVM是什么? 先来看看维基百科上对SVM的定义: 支持向量机&#xff08;英语&#xff1a;su…...

Nessus 部署实验

一、下载安装https://www.tenable.com/downloads/nessus 安装好之后&#xff0c;Nessus会自动打开浏览器&#xff0c;进入到初始化选择安装界面&#xff0c;这里我们要选择 Managed Scanner 点击继续&#xff0c;下一步选择Tenable.sc 点击继续&#xff0c;设置用户名和密码 等…...

基于Springboot的水产养殖系统(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的水产养殖系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&…...

Java性能优化(五)-多线程调优-Lock同步锁的优化

作者主页&#xff1a; &#x1f517;进朱者赤的博客 精选专栏&#xff1a;&#x1f517;经典算法 作者简介&#xff1a;阿里非典型程序员一枚 &#xff0c;记录在大厂的打怪升级之路。 一起学习Java、大数据、数据结构算法&#xff08;公众号同名&#xff09; ❤️觉得文章还…...

WPF (Windows Presentation Foundation) 中 Attribute(属性)和 Property(属性)

在 WPF (Windows Presentation Foundation) 中&#xff0c;Attribute&#xff08;属性&#xff09;和 Property&#xff08;属性&#xff09;是两个相关但不同的概念。 Attribute&#xff08;属性&#xff09;是一种元数据&#xff0c;用于给类型、成员或其他代码元素添加附加…...

环形链表理解||QJ141.环形链表

在链表中&#xff0c;不光只有普通的单链表。之前写过的的一个约瑟夫环形链表是尾直接连向头的。这里的环形链表是从尾节点的next指针连向这链表的任意位置。 那么给定一个链表&#xff0c;判断这个链表是否带环。qj题141.环形链表就是一个这样的题目。 这里的思路是用快慢指…...

java本地锁与分布式锁-个人笔记 @by_TWJ

目录 1. 本地锁1.1. 悲观锁与乐观锁1.2. 公平锁与非公平锁1.3. CAS1.4. synchronized1.5. volatile 可见性1.6. ReentrantLock 可重入锁1.7. AQS1.8. ReentrantReadWriteLock 可重入读写锁 2. 分布式锁3. 额外的3.1. synchronized 的锁升级原理3.2. synchronized锁原理 1. 本地…...

【每日刷题】Day33

【每日刷题】Day33 &#x1f955;个人主页&#xff1a;开敲&#x1f349; &#x1f525;所属专栏&#xff1a;每日刷题&#x1f34d; &#x1f33c;文章目录&#x1f33c; 1. 20. 有效的括号 - 力扣&#xff08;LeetCode&#xff09; 2. 445. 两数相加 II - 力扣&#xff08;…...

vivado刷题笔记46

题目&#xff1a; Design a 1-12 counter with the following inputs and outputs: Reset Synchronous active-high reset that forces the counter to 1 Enable Set high for the counter to run Clk Positive edge-triggered clock input Q[3:0] The output of the counter c…...

网络基础——校验

网络基础——校验 网络通信的层次化模型&#xff08;如OSI七层模型或TCP/IP四层模型&#xff09;中&#xff0c;每一层都有其特定的校验机制来确保数据传输的正确性和完整性。 物理层 校验方式 不直接涉及校验和&#xff0c;但会采用信号编码技术&#xff08;如曼彻斯特编码…...

SparkSQL与Hive整合 、SparkSQL函数操作

SparkSQL与Hive整合 SparkSQL和Hive的整合&#xff0c;是一种比较常见的关联处理方式&#xff0c;SparkSQL加载Hive中的数据进行业务处理&#xff0c;同时将计算结果落地回Hive中。 整合需要注意的地方 1)需要引入hive的hive-site.xml&#xff0c;添加classpath目录下面即可…...

K8s: Helm搭建mysql集群(2)

搭建 mysql 集群 应用中心&#xff0c;mysql 文档参考https://artifacthub.io/packages/helm/bitnami/mysql 1 &#xff09;helm 搭建 mysql A. 无存储&#xff0c;重启数据丢失 添加源 $ helm repo add mysql-repo https://charts.bitnami.com/bitnami安装 $ helm install…...

matlab期末知识

1.期末考什么&#xff1f; 1.1 matlab操作界面 &#xff08;1&#xff09;matlab主界面 &#xff08;2&#xff09;命令行窗口 &#xff08;3&#xff09;当前文件夹窗口 &#xff08;4&#xff09;工作区窗口 &#xff08;5&#xff09;命令历史记录窗口 1.2 matlab搜索…...

k8s从入门到放弃之Ingress七层负载

k8s从入门到放弃之Ingress七层负载 在Kubernetes&#xff08;简称K8s&#xff09;中&#xff0c;Ingress是一个API对象&#xff0c;它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress&#xff0c;你可…...

【入坑系列】TiDB 强制索引在不同库下不生效问题

文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...

【JVM】- 内存结构

引言 JVM&#xff1a;Java Virtual Machine 定义&#xff1a;Java虚拟机&#xff0c;Java二进制字节码的运行环境好处&#xff1a; 一次编写&#xff0c;到处运行自动内存管理&#xff0c;垃圾回收的功能数组下标越界检查&#xff08;会抛异常&#xff0c;不会覆盖到其他代码…...

ffmpeg(四):滤镜命令

FFmpeg 的滤镜命令是用于音视频处理中的强大工具&#xff0c;可以完成剪裁、缩放、加水印、调色、合成、旋转、模糊、叠加字幕等复杂的操作。其核心语法格式一般如下&#xff1a; ffmpeg -i input.mp4 -vf "滤镜参数" output.mp4或者带音频滤镜&#xff1a; ffmpeg…...

【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】

1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件&#xff08;System Property Definition File&#xff09;&#xff0c;用于声明和管理 Bluetooth 模块相…...

自然语言处理——循环神经网络

自然语言处理——循环神经网络 循环神经网络应用到基于机器学习的自然语言处理任务序列到类别同步的序列到序列模式异步的序列到序列模式 参数学习和长程依赖问题基于门控的循环神经网络门控循环单元&#xff08;GRU&#xff09;长短期记忆神经网络&#xff08;LSTM&#xff09…...

AI书签管理工具开发全记录(十九):嵌入资源处理

1.前言 &#x1f4dd; 在上一篇文章中&#xff0c;我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源&#xff0c;方便后续将资源打包到一个可执行文件中。 2.embed介绍 &#x1f3af; Go 1.16 引入了革命性的 embed 包&#xff0c;彻底改变了静态资源管理的…...

Mac下Android Studio扫描根目录卡死问题记录

环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中&#xff0c;提示一个依赖外部头文件的cpp源文件需要同步&#xff0c;点…...

稳定币的深度剖析与展望

一、引言 在当今数字化浪潮席卷全球的时代&#xff0c;加密货币作为一种新兴的金融现象&#xff0c;正以前所未有的速度改变着我们对传统货币和金融体系的认知。然而&#xff0c;加密货币市场的高度波动性却成为了其广泛应用和普及的一大障碍。在这样的背景下&#xff0c;稳定…...

浪潮交换机配置track检测实现高速公路收费网络主备切换NQA

浪潮交换机track配置 项目背景高速网络拓扑网络情况分析通信线路收费网络路由 收费汇聚交换机相应配置收费汇聚track配置 项目背景 在实施省内一条高速公路时遇到的需求&#xff0c;本次涉及的主要是收费汇聚交换机的配置&#xff0c;浪潮网络设备在高速项目很少&#xff0c;通…...