计算机视觉 | OpenCV 实现手势虚拟控制亮度和音量

news2024/9/22 5:07:11

Hi,大家好,我是半亩花海。在当今科技飞速发展的时代,我们身边充斥着各种智能设备,然而,如何更便捷地与这些设备进行交互却是一个不断被探索的课题。本文将主要介绍一个基于 OpenCV 手势识别项目,通过手势来控制电脑屏幕亮度音量大小,为用户提供了一种全新的交互方式。


目录

一、代码拆解

1. 导入必要库

2. 手部关键点类

3. 数据格式转换

4. 画手势关键点

5. 手势状态缓冲处理

6. 画直线

7. 屏幕亮度和音量控制

8. 初始化摄像头和手部关键点识别器

9. Pygame 界面初始化和事件监听

二、实战演示

1. 亮度——light

2. 音量——voice

3. 菜单——menu

三、完整代码


一、代码拆解

1. 导入必要库

在开始介绍项目的实现细节之前,我们首先需要导入项目所需的必要库。这些库包括:

  • OpenCV:用于处理图像和视频数据。
  • Mediapipe:提供了对手部关键点的识别和跟踪功能。
  • Pygame:用于创建图形界面和显示摄像头捕获的图像。
  • WMI:用于调节电脑屏幕亮度。
  • pycaw:用于控制电脑的音量。
# 导入必要库
import math
import sys
import numpy as np
import cv2
import pygame
import wmi
import mediapipe as mp
from ctypes import cast, POINTER
from comtypes import CLSCTX_ALL
from pycaw.pycaw import AudioUtilities, IAudioEndpointVolume
import warnings  # 忽略警告
warnings.filterwarnings("ignore")

2. 手部关键点类

首先创建一个 HandKeyPoint 类,用于初始化手部关键点检测器,并提供对图像进行处理的方法。

# 手部关键点类
class HandKeyPoint:
    def __init__(self,
                 static_image_mode=False,
                 max_num_hands=2,
                 model_complexity=1,
                 min_detection_confidence=0.5,
                 min_tracking_confidence=0.5):
        # 手部识别api
        self.mp_hands = mp.solutions.hands
        # 获取手部识别类
        self.hands = self.mp_hands.Hands(static_image_mode=static_image_mode,
                                         max_num_hands=max_num_hands,
                                         model_complexity=model_complexity,
                                         min_detection_confidence=min_detection_confidence,
                                         min_tracking_confidence=min_tracking_confidence)

    def process(self, image):
        # 将BGR转换为RGB
        img = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
        # 识别图像中的手势,并返回结果
        results = self.hands.process(img)
        # numpy格式的数据
        np_arr = landmarks_to_numpy(results)
        return results, np_arr

3. 数据格式转换

手部关键点的检测结果(将 landmarks 格式的数据)转换为 numpy 数组,以便后续的处理和分析。

# 将landmarks格式的数据转换为numpy格式的数据
def landmarks_to_numpy(results):
    """
    将landmarks格式的数据转换为numpy格式的数据
    numpy shape:(2, 21, 3)
    :param results:
    :return:
    """
    shape = (2, 21, 3)
    landmarks = results.multi_hand_landmarks
    if landmarks is None:
        # 没有检测到手
        return np.zeros(shape)
    elif len(landmarks) == 1:
        # 检测出一只手,先判断是左手还是右手
        label = results.multi_handedness[0].classification[0].label
        hand = landmarks[0]
        # print(label)
        if label == "Left":
            return np.array(
                [np.array([[hand.landmark[i].x, hand.landmark[i].y, hand.landmark[i].z] for i in range(21)]),
                 np.zeros((21, 3))])
        else:
            return np.array([np.zeros((21, 3)),
                             np.array(
                                 [[hand.landmark[i].x, hand.landmark[i].y, hand.landmark[i].z] for i in range(21)])])
    elif len(landmarks) == 2:
        # print(results.multi_handedness)
        lh_idx = 0
        rh_idx = 0
        for idx, hand_type in enumerate(results.multi_handedness):
            label = hand_type.classification[0].label
            if label == 'Left':
                lh_idx = idx
            if label == 'Right':
                rh_idx = idx

        lh = np.array(
            [[landmarks[lh_idx].landmark[i].x, landmarks[lh_idx].landmark[i].y, landmarks[lh_idx].landmark[i].z] for i
             in range(21)])
        rh = np.array(
            [[landmarks[rh_idx].landmark[i].x, landmarks[rh_idx].landmark[i].y, landmarks[rh_idx].landmark[i].z] for i
             in range(21)])
        return np.array([lh, rh])
    else:
        return np.zeros((2, 21, 3))

4. 画手势关键点

# 画手势关键点
def draw_landmark(img, results):
    if results.multi_hand_landmarks:
        for hand_landmark in results.multi_hand_landmarks:
            mp.solutions.drawing_utils.draw_landmarks(img,
                                                      hand_landmark,
                                                      mp.solutions.hands.HAND_CONNECTIONS,
                                                      mp.solutions.drawing_styles.get_default_hand_landmarks_style(),
                                                      mp.solutions.drawing_styles.get_default_hand_connections_style())

    return img

5. 手势状态缓冲处理

为了平滑处理手势状态的变化,我们实现了一个 Buffer 类,用于缓存手势状态的变化,并提供了添加正例和负例的方法。

# 缓冲区类
class Buffer:
    def __init__(self, volume=20):
        self.__positive = 0
        self.state = False
        self.__negative = 0
        self.__volume = volume
        self.__count = 0

    def add_positive(self):
        self.__count += 1
        if self.__positive >= self.__volume:
            # 如果正例个数大于容量,将状态定为True
            self.state = True
            self.__negative = 0
            self.__count = 0
        else:
            self.__positive += 1

        if self.__count > self.__volume:
            # 如果大于容量次操作后还没有确定状态
            self.__positive = 0
            self.__count = 0

    def add_negative(self):
        self.__count += 1
        if self.__negative >= self.__volume:
            # 如果负例个数大于容量,将状态定为False
            self.state = False
            self.__positive = 0
        else:
            self.__negative += 1

        if self.__count > self.__volume:
            # 如果大于容量次操作后还没有确定状态
            self.__positive = 0
            self.__count = 0
        # print(f"pos:{self.__positive} neg:{self.__negative} count:{self.__count}")

    def clear(self):
        self.__positive = 0
        self.state = False
        self.__negative = 0
        self.__count = 0

6. 画直线

# 画线函数
def draw_line(frame, p1, p2, color=(255, 127, 0), thickness=3):
    """
    画一条直线
    :param p1:
    :param p2:
    :return:
    """
    return cv2.line(frame, (int(p1[0] * CAM_W), int(p1[1] * CAM_H)), (int(p2[0] * CAM_W), int(p2[1] * CAM_H)), color,
                    thickness)

7. 屏幕亮度和音量控制

# 控制屏幕亮度
def screen_change(percent):  # percent/2即为亮度百分比
    SCREEN = wmi.WMI(namespace='root/WMI')
    a = SCREEN.WmiMonitorBrightnessMethods()[0]
    a.WmiSetBrightness(Brightness=percent, Timeout=500)

# 初始化音量控制
def init_voice():
    devices = AudioUtilities.GetSpeakers()
    interface = devices.Activate(
        IAudioEndpointVolume._iid_, CLSCTX_ALL, None)
    volume = cast(interface, POINTER(IAudioEndpointVolume))
    volume.SetMute(0, None)
    volume_range = volume.GetVolumeRange()
    min_volume = volume_range[0]
    max_volume = volume_range[1]
    return (min_volume, max_volume), volume

8. 初始化摄像头和手部关键点识别器

在项目的初始化阶段,我们需要加载摄像头实例和手部关键点识别实例,以便后续对手势进行识别和处理。

# 加载摄像头实例
cap = cv2.VideoCapture(0)
CAM_W = 640
CAM_H = 480
CAM_SCALE = CAM_W / CAM_H

# 加载手部关键点识别实例
hand = HandKeyPoint()

9. Pygame 界面初始化和事件监听

为了展示手势控制效果,并提供交互界面,我们使用了 Pygame 库。在初始化阶段,我们创建了一个窗口,并设置了标题。同时,我们实现了事件监听功能,以便在需要时退出程序

具体来说,我们使用 Pygame 创建了一个窗口,并将摄像头捕获的图像显示在窗口中。同时,我们利用 Pygame 的事件监听功能,监听用户的键盘事件,例如按下"q"键时退出程序。这样,用户就可以通过手势控制屏幕亮度和音量大小,同时在 Pygame 窗口中观察手势识别效果。

# 初始化pygame
pygame.init()
# 设置窗口全屏
screen = pygame.display.set_mode((800, 600))
pygame.display.set_caption("virtual_control_screen")
# 获取当前窗口大小
window_size = list(screen.get_size())

# 主循环
while True:
······
    # 事件监听 若按q则退出程序
    for event in pygame.event.get():
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_q:
                sys.exit(0)

二、实战演示

1. 亮度——light

如果 20 < angle < 90,那么“light ready”即手势控制亮度

2. 音量——voice

如果 -20 > angle > -50,那么“voice ready”即手势控制音量

3. 菜单——menu

上述两种情况除外,那么处于“menu”状态即进入菜单

通过演示可以发现,食指与大拇指在屏幕中的距离越远,亮度越高(音量越大),反之越小,实现了通过手势对亮度和音量的控制。


三、完整代码

#!/usr/bin/env python
# -*- coding:utf-8 -*-
"""
@Project : virtual
@File    : virtual_control.py
@IDE     : PyCharm
@Author  : 半亩花海
@Date    : 2024:02:06 18:01
"""
# 导入模块
import math
import sys
import numpy as np
import cv2
import pygame
import wmi
import mediapipe as mp
from ctypes import cast, POINTER
from comtypes import CLSCTX_ALL
from pycaw.pycaw import AudioUtilities, IAudioEndpointVolume
import warnings  # 忽略警告
warnings.filterwarnings("ignore")


# 手部关键点类
class HandKeyPoint:
    def __init__(self,
                 static_image_mode=False,
                 max_num_hands=2,
                 model_complexity=1,
                 min_detection_confidence=0.5,
                 min_tracking_confidence=0.5):
        # 手部识别api
        self.mp_hands = mp.solutions.hands
        # 获取手部识别类
        self.hands = self.mp_hands.Hands(static_image_mode=static_image_mode,
                                         max_num_hands=max_num_hands,
                                         model_complexity=model_complexity,
                                         min_detection_confidence=min_detection_confidence,
                                         min_tracking_confidence=min_tracking_confidence)

    def process(self, image):
        # 将BGR转换为RGB
        img = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
        # 识别图像中的手势,并返回结果
        results = self.hands.process(img)
        # numpy格式的数据
        np_arr = landmarks_to_numpy(results)
        return results, np_arr


# 将landmarks格式的数据转换为numpy格式的数据
def landmarks_to_numpy(results):
    """
    将landmarks格式的数据转换为numpy格式的数据
    numpy shape:(2, 21, 3)
    :param results:
    :return:
    """
    shape = (2, 21, 3)
    landmarks = results.multi_hand_landmarks
    if landmarks is None:
        # 没有检测到手
        return np.zeros(shape)
    elif len(landmarks) == 1:
        # 检测出一只手,先判断是左手还是右手
        label = results.multi_handedness[0].classification[0].label
        hand = landmarks[0]
        # print(label)
        if label == "Left":
            return np.array(
                [np.array([[hand.landmark[i].x, hand.landmark[i].y, hand.landmark[i].z] for i in range(21)]),
                 np.zeros((21, 3))])
        else:
            return np.array([np.zeros((21, 3)),
                             np.array(
                                 [[hand.landmark[i].x, hand.landmark[i].y, hand.landmark[i].z] for i in range(21)])])
    elif len(landmarks) == 2:
        # print(results.multi_handedness)
        lh_idx = 0
        rh_idx = 0
        for idx, hand_type in enumerate(results.multi_handedness):
            label = hand_type.classification[0].label
            if label == 'Left':
                lh_idx = idx
            if label == 'Right':
                rh_idx = idx

        lh = np.array(
            [[landmarks[lh_idx].landmark[i].x, landmarks[lh_idx].landmark[i].y, landmarks[lh_idx].landmark[i].z] for i
             in range(21)])
        rh = np.array(
            [[landmarks[rh_idx].landmark[i].x, landmarks[rh_idx].landmark[i].y, landmarks[rh_idx].landmark[i].z] for i
             in range(21)])
        return np.array([lh, rh])
    else:
        return np.zeros((2, 21, 3))


# 画手势关键点
def draw_landmark(img, results):
    if results.multi_hand_landmarks:
        for hand_landmark in results.multi_hand_landmarks:
            mp.solutions.drawing_utils.draw_landmarks(img,
                                                      hand_landmark,
                                                      mp.solutions.hands.HAND_CONNECTIONS,
                                                      mp.solutions.drawing_styles.get_default_hand_landmarks_style(),
                                                      mp.solutions.drawing_styles.get_default_hand_connections_style())

    return img


# 缓冲区类
class Buffer:
    def __init__(self, volume=20):
        self.__positive = 0
        self.state = False
        self.__negative = 0
        self.__volume = volume
        self.__count = 0

    def add_positive(self):
        self.__count += 1
        if self.__positive >= self.__volume:
            # 如果正例个数大于容量,将状态定为True
            self.state = True
            self.__negative = 0
            self.__count = 0
        else:
            self.__positive += 1

        if self.__count > self.__volume:
            # 如果大于容量次操作后还没有确定状态
            self.__positive = 0
            self.__count = 0

    def add_negative(self):
        self.__count += 1
        if self.__negative >= self.__volume:
            # 如果负例个数大于容量,将状态定为False
            self.state = False
            self.__positive = 0
        else:
            self.__negative += 1

        if self.__count > self.__volume:
            # 如果大于容量次操作后还没有确定状态
            self.__positive = 0
            self.__count = 0
        # print(f"pos:{self.__positive} neg:{self.__negative} count:{self.__count}")

    def clear(self):
        self.__positive = 0
        self.state = False
        self.__negative = 0
        self.__count = 0


# 画线函数
def draw_line(frame, p1, p2, color=(255, 127, 0), thickness=3):
    """
    画一条直线
    :param p1:
    :param p2:
    :return:
    """
    return cv2.line(frame, (int(p1[0] * CAM_W), int(p1[1] * CAM_H)), (int(p2[0] * CAM_W), int(p2[1] * CAM_H)), color,
                    thickness)


# 控制屏幕亮度
def screen_change(percent):  # percent/2即为亮度百分比
    SCREEN = wmi.WMI(namespace='root/WMI')
    a = SCREEN.WmiMonitorBrightnessMethods()[0]
    a.WmiSetBrightness(Brightness=percent, Timeout=500)


# 初始化音量控制
def init_voice():
    devices = AudioUtilities.GetSpeakers()
    interface = devices.Activate(
        IAudioEndpointVolume._iid_, CLSCTX_ALL, None)
    volume = cast(interface, POINTER(IAudioEndpointVolume))
    volume.SetMute(0, None)
    volume_range = volume.GetVolumeRange()
    min_volume = volume_range[0]
    max_volume = volume_range[1]
    return (min_volume, max_volume), volume


# 加载摄像头实例
cap = cv2.VideoCapture(0)
CAM_W = 640
CAM_H = 480
CAM_SCALE = CAM_W / CAM_H

# 加载手部关键点识别实例
hand = HandKeyPoint()

# 初始化pygame
pygame.init()
# 设置窗口全屏
screen = pygame.display.set_mode((800, 600))
pygame.display.set_caption("virtual_control_screen")
# 获取当前窗口大小
window_size = list(screen.get_size())

# 设置缓冲区
buffer_light = Buffer(10)
buffer_voice = Buffer(10)

last_y = 0
last_2_y = 1
last_2_x = 0

# 初始化声音控制
voice_range, volume = init_voice()

# 设置亮度条参数
bright_bar_length = 300
bright_bar_height = 20
bright_bar_x = 50
bright_bar_y = 100

# 设置音量条参数
vol_bar_length = 300
vol_bar_height = 20
vol_bar_x = 50
vol_bar_y = 50

# 主循环 每次循环就是对每帧的处理
while True:
    img_menu = None
    lh_index = -1
    # 读取摄像头画面
    success, frame = cap.read()

    # 将opencv中图片格式的BGR转换为常规的RGB
    frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
    # 镜面反转
    frame = cv2.flip(frame, 1)

    # 处理图像
    res, arr = hand.process(frame)
    frame = draw_landmark(frame, res)

    scale = math.hypot((arr[0, 7, 0] - arr[0, 8, 0]),
                       (arr[0, 7, 1] - arr[0, 8, 1]),
                       (arr[0, 7, 2] - arr[0, 8, 2]))

    # 计算tan值
    tan = (arr[0, 0, 1] - arr[0, 12, 1]) / (arr[0, 0, 0] - arr[0, 12, 0])
    # 计算角度
    angle = np.arctan(tan) * 180 / np.pi
    # print(angle)

    if 20 < angle < 90:
        path = 'resources/menu/light.png'
        buffer_light.add_positive()
        buffer_voice.add_negative()
        # 显示亮度条和亮度刻度值
        show_brightness = True
        show_volume = False
    elif -20 > angle > -50:
        path = 'resources/menu/voice.png'
        buffer_voice.add_positive()
        buffer_light.add_negative()
        # 显示音量条和音量刻度值
        show_brightness = False
        show_volume = True
    else:
        path = 'resources/menu/menu.png'
        buffer_light.add_negative()
        buffer_voice.add_negative()
        # 不显示刻度值和百分比
        show_brightness = False
        show_volume = False

    # 计算拇指与食指之间的距离
    dis = math.hypot(int((arr[1, 4, 0] - arr[1, 8, 0]) * CAM_W), int((arr[1, 4, 1] - arr[1, 8, 1]) * CAM_H))
    # 右手映射时的缩放尺度
    s = math.hypot((arr[1, 5, 0] - arr[1, 9, 0]), (arr[1, 5, 1] - arr[1, 9, 1]), (arr[1, 5, 2] - arr[1, 9, 2]))

    # 调节亮度
    if buffer_light.state:
        frame = cv2.putText(frame, 'light ready', (10, 35), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 127, 0))
        frame = draw_line(frame, arr[1, 4], arr[1, 8], thickness=5, color=(255, 188, 66))
        if dis != 0:
            # 线性插值,可以理解为将一个区间中的一个值映射到另一区间内
            light = np.interp(dis, [int(500 * s), int(3000 * s)], (0, 100))
            # 调节亮度
            screen_change(light)
    # 调节声音
    elif buffer_voice.state:
        frame = cv2.putText(frame, 'voice ready', (10, 35), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 127, 0))
        frame = draw_line(frame, arr[1, 4], arr[1, 8], thickness=5, color=(132, 134, 248))
        if dis != 0:
            vol = np.interp(dis, [int(500 * s), int(3000 * s)], voice_range)
            # 调节音量
            volume.SetMasterVolumeLevel(vol, None)

    # 将图片改为与窗口一样的大小
    frame = cv2.resize(frame, (int(window_size[1] * CAM_SCALE), window_size[1]))
    frame = cv2.transpose(frame)
    # 渲染图片
    frame = pygame.surfarray.make_surface(frame)
    screen.blit(frame, (int(0.5 * (CAM_W - CAM_H * CAM_SCALE)), 0))

    img_menu = pygame.image.load(path).convert_alpha()
    img_w, img_h = img_menu.get_size()
    img_menu = pygame.transform.scale(img_menu, (int(img_w * scale * 5), int(img_h * scale * 5)))
    x = (arr[0][9][0] + arr[0][13][0] + arr[0][0][0]) / 3
    y = (arr[0][9][1] + arr[0][13][1] + arr[0][0][1]) / 3
    x = int(x * window_size[0] - window_size[0] * scale * 3.5)
    y = int(y * window_size[1] - window_size[1] * scale * 12)
    # print(x, y)
    screen.blit(img_menu, (x, y))

    # 绘制音量条和亮度条的外框
    if show_volume:
        pygame.draw.rect(screen, (255, 255, 255), (vol_bar_x, vol_bar_y, vol_bar_length, vol_bar_height), 3)
    elif show_brightness:
        pygame.draw.rect(screen, (255, 255, 255), (bright_bar_x, bright_bar_y, bright_bar_length, bright_bar_height),
                         3)

    # 计算当前音量和亮度在条上的位置和大小,并绘制已填充的条
    if show_volume:
        vol = volume.GetMasterVolumeLevel()
        vol_range = voice_range[1] - voice_range[0]
        vol_bar_fill_length = int((vol - voice_range[0]) / vol_range * vol_bar_length)
        pygame.draw.rect(screen, (0, 255, 0), (vol_bar_x, vol_bar_y, vol_bar_fill_length, vol_bar_height))
        # 显示音量刻度值和当前音量大小
        vol_text = f"Volume: {int((vol - voice_range[0]) / vol_range * 100)}%"
        vol_text_surface = pygame.font.SysFont(None, 24).render(vol_text, True, (255, 255, 255))
        screen.blit(vol_text_surface, (vol_bar_x + vol_bar_length + 10, vol_bar_y))
    elif show_brightness:
        brightness = wmi.WMI(namespace='root/WMI').WmiMonitorBrightness()[0].CurrentBrightness
        bright_bar_fill_length = int(brightness / 100 * bright_bar_length)
        pygame.draw.rect(screen, (255, 255, 0), (bright_bar_x, bright_bar_y, bright_bar_fill_length, bright_bar_height))
        # 显示亮度刻度值和当前亮度大小
        bright_text = f"Brightness: {brightness}%"
        bright_text_surface = pygame.font.SysFont(None, 24).render(bright_text, True, (255, 255, 255))
        screen.blit(bright_text_surface, (bright_bar_x + bright_bar_length + 10, bright_bar_y))

    pygame.display.flip()

    # 事件监听 若按q则退出程序
    for event in pygame.event.get():
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_q:
                sys.exit(0)

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Qt程序设计-导出PDF

本文讲解如何实现导出PDF,包含如何使用HTML格式和添加图片。 实例如下: 创建项目,添加两个按钮,并在D盘提前准备好图片。 窗体的头文件 #ifndef MAINWINDOW_H #define MAINWINDOW_H#include <QMainWindow>#include <QPrinter> #include <QPainter> #i…

Oracle systemstate、gdb、dbx介绍

当数据库出现严重的性能问题或者hang了的时候&#xff0c; 可能最常用的办法就是重启数据库&#xff0c;简单有效解决问题&#xff1b;但是重启后如何追踪问题的根本原因成了难题&#xff0c;很多信息随着重启也消失不见了&#xff0c;让追查问题变的十分棘手&#xff0c;这时就…

ElementUI鼠标拖动没列宽度

其实 element ui 表格Table有提供给我们一个resizable属性 按官方文档上描述 它就是控制是否允许拖拽表格列大小的属性 而且 它的默认值就是 true 但是依旧很多人会反应拖拽不了 首先 表格要有边框 如果没有变宽 确实是拖拽不了 给 el-table加上 border属性 运行结果如下 但…

Android用setRectToRect实现Bitmap基于Matrix矩阵scale缩放RectF动画,Kotlin(二)

Android用setRectToRect实现Bitmap基于Matrix矩阵scale缩放RectF动画&#xff0c;Kotlin&#xff08;二&#xff09; 文章 https://zhangphil.blog.csdn.net/article/details/135980821 实现了基于Matrix缩放Bitmap的动画&#xff0c;但是从左上角&#xff08;0,0&#xff09;位…

cesium-相机的使用

直接上代码 <template><div id"cesiumContainer" style"height: 100vh;"></div><div id"toolbar" style"position: fixed;top:20px;left:220px;"><el-breadcrumb><el-breadcrumb-item>场景设置实…

基于Springboot的考编论坛网站的设计与实现(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的考编论坛网站的设计与实现&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层…

C++ 哈希表(unordered_map与unordered_set)

文章目录 unordered_map 与 unordered_set哈希表 (Hash Table)哈希函数哈希冲突模拟实现封装 补充&#xff1a;unordered_map 与 unordered_set 的使用 unordered_map 与 unordered_set 就和名字一样&#xff0c;这是 map、set 的无序版本&#xff08;数据遍历出来是无序的&am…

如何选择性能测试工具?ab和其它工具的对比分析!

性能测试是保证应用程序高效可靠的重要手段之一&#xff0c;在进行性能测试时&#xff0c;选择合适的性能测试工具非常重要。应当根据测试需求来选择适合的测试工具&#xff0c;本文将会详细介绍ApacheBench&#xff08;简称ab&#xff09;和其他性能测试工具的区别以及如何选择…

RFID手持终端_智能pda手持终端设备定制方案

手持终端是一款多功能、适用范围广泛的安卓产品&#xff0c;具有高性能、大容量存储、高端扫描头和全网通数据连接能力。它能够快速平稳地运行&#xff0c;并提供稳定的连接表现和快速的响应时&#xff0c;适用于医院、物流运输、零售配送、资产盘点等苛刻的环境。通过快速采集…

ROS笔记一:工作空间和功能包

目录 工作空间 如何创建工作空间&#xff1a; 编译工作空间 设置环境变量 功能包 创建功能包 CMakeLists.txt package.xml 工作空间 ROS的工作空间是用来存放工程文件代码的文件夹 ROS的开发依赖于工作空间&#xff0c;包括编写代码、编译等都是在工作空间下进行的 工作空…

ACK One Argo工作流:实现动态 Fan-out/Fan-in 任务编排

作者&#xff1a;庄宇 什么是 Fan-out Fan-in 在工作流编排过程中&#xff0c;为了加快大任务处理的效率&#xff0c;可以使用 Fan-out Fan-in 任务编排&#xff0c;将大任务分解成小任务&#xff0c;然后并行运行小任务&#xff0c;最后聚合结果。 由上图&#xff0c;可以使…

【Vitis】基于C++函数开发组件的步骤

目录 基本步骤 关键领域 • 硬件接口&#xff1a; 任务级并行度&#xff1a; 存储器架构&#xff1a; 微观级别的最优化&#xff1a; 基本步骤 1. 基于 设计原则 建立算法架构。 2. &#xff08;C 语言仿真&#xff09; 利用 C/C 语言测试激励文件验证 C/C 代码的逻辑。…

2024/2/6学习记录

ts 因为已经学习过了 js &#xff0c;下面的都是挑了一些 ts 与 js 不同的地方来记录。 安装 npm install -g typescript 安装好之后&#xff0c;可以看看自己的版本 ts基础语法 模块 函数 变量 语法和表达式 注释 编译 ts 文件需要用 tsc xxx.ts &#xff0c;js 文件…

Dockerfile文件参数配置和使用

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

动态扩缩容下的全局流水号设计

关于全局流水号&#xff0c;业内用的比较多的就是雪花算法&#xff0c;一直没理解在动态扩缩容下其中的workId和 datacenterId如何设置&#xff0c;查到了几个方法&#xff1a;reidis中取&#xff0c;待后期实践下。 先简单的介绍一下雪花算法&#xff0c;雪花算法生成的Id由…

【Zookeeper】what is Zookeeper?

官网地址&#xff1a;https://zookeeper.apache.org/https://zookeeper.apache.org/ 以下来自官网的介绍 ZooKeeper is a centralized service for maintaining configuration information, naming, providing distributed synchronization, and providing group services. A…

AI专题:AI应用落地的商业模式探索

今天分享的是AI 系列深度研究报告&#xff1a;《AI专题&#xff1a;AI应用落地的商业模式探索》。 &#xff08;报告出品方&#xff1a;国金证券&#xff09; 报告共计&#xff1a;27页 AI基座模型提供按量收费服务 以 ChatGPT 为代表的大模型能力涌现,为基座模型厂商带来增…

“小手艺”有“大情怀”, 《青春手艺人》赋能乡村振兴,传承新时代文化

文化传承发展要坚持“守正创新”&#xff0c;以守正创新的正气和锐气&#xff0c;赓续历史文脉、谱写当代华章。中央广播电视总台农业农村节目中心推出的聚焦年轻手艺人故事的微纪录片《青春手艺人》&#xff0c;为守正创新的文化传承增添了新的鲜活的青春故事。节目积极响应二…

MATLAB Fundamentals>>>(2/2) Project - Analyze Vehicle Data

#创作灵感# MATLAB基础知识官方课程学习笔记 MATLAB Fundamentals>Common Data Analysis Techniques>Summary of Common Data Analysis Techniques>(2/2) Project - Analyze Vehicle Data 任务名称&#xff1a;Fuel Economy Analysis 任务1&#xff1a; The variabl…

华为机考入门python3--(10)牛客10-字符个数统计

分类&#xff1a;字符 知识点&#xff1a; 字符的ASCII码 ord(char) 题目来自【牛客】 def count_unique_chars(s): # 创建一个空集合来保存不同的字符 unique_chars set() # 遍历字符串中的每个字符 for char in s: # 将字符转换为 ASCII 码并检查是否在范围内 #…