opencv实战项目 手势识别-实现尺寸缩放效果

news2024/11/22 20:31:30

 手势识别系列文章目录

手势识别是一种人机交互技术,通过识别人的手势动作,从而实现对计算机、智能手机、智能电视等设备的操作和控制。

1.  opencv实现手部追踪(定位手部关键点)

2.opencv实战项目 实现手势跟踪并返回位置信息(封装调用)

3.手势识别-手势音量控制(opencv)

4.opencv实战项目 手势识别-手势控制鼠标

5.opencv实战项目 手势识别-手部距离测量

6.opencv实战项目 手势识别-实现尺寸缩放效果

未完待续

目录

 手势识别系列文章目录

1.HandTraqckModule模块

2、主模块


 本项目是使用了谷歌开源的框架mediapipe,里面有非常多的模型提供给我们使用,例如面部检测,身体检测,手部检测等

在这里插入图片描述

代码需要用到opencv   HandTraqckModule模块   mediapipe模块

1.HandTraqckModule模块

如下:

定义 HandDetector 类,用于检测手势并提取相关信息:

class HandDetector:
    def __init__(self, mode=False, maxHands=2, detectionCon=0.5, minTrackCon=0.5):
        # 初始化函数,设置参数
        self.mode = mode
        self.maxHands = maxHands
        self.detectionCon = detectionCon
        self.minTrackCon = minTrackCon
        # 初始化 Mediapipe 模块和相关对象
        self.mpHands = mp.solutions.hands
        self.hands = self.mpHands.Hands(static_image_mode=self.mode, max_num_hands=self.maxHands,
                                        min_detection_confidence=self.detectionCon, min_tracking_confidence=self.minTrackCon)
        self.mpDraw = mp.solutions.drawing_utils
        self.tipIds = [4, 8, 12, 16, 20]
        self.fingers = []
        self.lmList = []

findHands 函数:在图像中找到手部,并返回手部信息以及绘制的图像。

    def findHands(self, img, draw=True, flipType=True):
        # 找到手部,并绘制相关信息
        imgRGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
        self.results = self.hands.process(imgRGB)
        allHands = []

        # 处理每个检测到的手
        if self.results.multi_hand_landmarks:
            for handType, handLms in zip(self.results.multi_handedness, self.results.multi_hand_landmarks):
                # 提取手部关键点和边界框信息
                myHand = {}
                mylmList = []
                xList = []
                yList = []

                for id, lm in enumerate(handLms.landmark):
                    px, py = int(lm.x * w), int(lm.y * h)
                    mylmList.append([px, py])
                    xList.append(px)
                    yList.append(py)

                # 计算边界框信息
                xmin, xmax = min(xList), max(xList)
                ymin, ymax = min(yList), max(yList)
                boxW, boxH = xmax - xmin, ymax - ymin
                bbox = xmin, ymin, boxW, boxH
                cx, cy = bbox[0] + (bbox[2] // 2), bbox[1] + (bbox[3] // 2)

                myHand["lmList"] = mylmList
                myHand["bbox"] = bbox
                myHand["center"] = (cx, cy)

                # 根据手的方向进行翻转
                if flipType:
                    if handType.classification[0].label == "Right":
                        myHand["type"] = "Left"
                    else:
                        myHand["type"] = "Right"
                else:
                    myHand["type"] = handType.classification[0].label
                allHands.append(myHand)

                # 绘制手部信息
                if draw:
                    self.mpDraw.draw_landmarks(img, handLms, self.mpHands.HAND_CONNECTIONS)
                    cv2.rectangle(img, (bbox[0] - 20, bbox[1] - 20), (bbox[0] + bbox[2] + 20, bbox[1] + bbox[3] + 20),
                                  (255, 0, 255), 2)
                    cv2.putText(img, myHand["type"], (bbox[0] - 30, bbox[1] - 30), cv2.FONT_HERSHEY_PLAIN,
                                2, (255, 0, 255), 2)
        if draw:
            return allHands, img
        else:
            return allHands

fingersUp 函数:检测手指的状态,返回一个列表表示手指是否抬起。

    def fingersUp(self, myHand):
        # 检测手指状态,返回列表表示手指是否抬起
        myHandType = myHand["type"]
        myLmList = myHand["lmList"]
        if self.results.multi_hand_landmarks:
            fingers = []

            # 大拇指
            if myHandType == "Right":
                if myLmList[self.tipIds[0]][0] > myLmList[self.tipIds[0] - 1][0]:
                    fingers.append(1)
                else:
                    fingers.append(0)
            else:
                if myLmList[self.tipIds[0]][0] < myLmList[self.tipIds[0] - 1][0]:
                    fingers.append(1)
                else:
                    fingers.append(0)

            # 其他四指
            for id in range(1, 5):
                if myLmList[self.tipIds[id]][1] < myLmList[self.tipIds[id] - 2][1]:
                    fingers.append(1)
                else:
                    fingers.append(0)
        return fingers

findDistance 函数:计算两点间的距离,可选是否在图像上绘制。

    def findDistance(self, p1, p2, img=None):
        # 计算两点间的距离,可绘制在图像上
        x1, y1 = p1
        x2, y2 = p2
        cx, cy = (x1 + x2) // 2, (y1 + y2) // 2
        length = math.hypot(x2 - x1, y2 - y1)
        info = (x1, y1, x2, y2, cx, cy)
        if img is not None:
            cv2.circle(img, (x1, y1), 15, (255, 0, 255), cv2.FILLED)
            cv2.circle(img, (x2, y2), 15, (255, 0, 255), cv2.FILLED)
            cv2.line(img, (x1, y1), (x2, y2), (255, 0, 255), 3)
            cv2.circle(img, (cx, cy), 15, (255, 0, 255), cv2.FILLED)
            return length, info, img
        else:
            return length, info

HandTraqckModule模块整体代码

"""
Hand Tracking Module
"""

import cv2
import mediapipe as mp
import math


class HandDetector:
    """
    Finds Hands using the mediapipe library. Exports the landmarks
    in pixel format. Adds extra functionalities like finding how
    many fingers are up or the distance between two fingers. Also
    provides bounding box info of the hand found.
    """

    def __init__(self, mode=False, maxHands=2, detectionCon=0.5, minTrackCon=0.5):
        """
        :param mode: In static mode, detection is done on each image: slower
        :param maxHands: Maximum number of hands to detect
        :param detectionCon: Minimum Detection Confidence Threshold
        :param minTrackCon: Minimum Tracking Confidence Threshold
        """
        self.mode = mode
        self.maxHands = maxHands
        self.detectionCon = detectionCon
        self.minTrackCon = minTrackCon

        self.mpHands = mp.solutions.hands
        self.hands = self.mpHands.Hands(static_image_mode=self.mode, max_num_hands=self.maxHands,
                                        min_detection_confidence=self.detectionCon, min_tracking_confidence = self.minTrackCon)
        self.mpDraw = mp.solutions.drawing_utils
        self.tipIds = [4, 8, 12, 16, 20]
        self.fingers = []
        self.lmList = []

    def findHands(self, img, draw=True, flipType=True):
        """
        Finds hands in a BGR image.
        :param img: Image to find the hands in.
        :param draw: Flag to draw the output on the image.
        :return: Image with or without drawings
        """
        imgRGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
        self.results = self.hands.process(imgRGB)
        allHands = []
        h, w, c = img.shape
        if  self.results.multi_hand_landmarks:
            for handType,handLms in zip(self.results.multi_handedness,self.results.multi_hand_landmarks):
                myHand={}
                ## lmList
                mylmList = []
                xList = []
                yList = []
                for id, lm in enumerate(handLms.landmark):
                    px, py = int(lm.x * w), int(lm.y * h)
                    mylmList.append([px, py])
                    xList.append(px)
                    yList.append(py)

                ## bbox
                xmin, xmax = min(xList), max(xList)
                ymin, ymax = min(yList), max(yList)
                boxW, boxH = xmax - xmin, ymax - ymin
                bbox = xmin, ymin, boxW, boxH
                cx, cy = bbox[0] + (bbox[2] // 2), \
                         bbox[1] + (bbox[3] // 2)

                myHand["lmList"] = mylmList
                myHand["bbox"] = bbox
                myHand["center"] =  (cx, cy)

                if flipType:
                    if handType.classification[0].label =="Right":
                        myHand["type"] = "Left"
                    else:
                        myHand["type"] = "Right"
                else:myHand["type"] = handType.classification[0].label
                allHands.append(myHand)

                ## draw
                if draw:
                    self.mpDraw.draw_landmarks(img, handLms,
                                               self.mpHands.HAND_CONNECTIONS)
                    cv2.rectangle(img, (bbox[0] - 20, bbox[1] - 20),
                                  (bbox[0] + bbox[2] + 20, bbox[1] + bbox[3] + 20),
                                  (255, 0, 255), 2)
                    cv2.putText(img,myHand["type"],(bbox[0] - 30, bbox[1] - 30),cv2.FONT_HERSHEY_PLAIN,
                                2,(255, 0, 255),2)
        if draw:
            return allHands,img
        else:
            return allHands

    def findPosition(self, img, handNo=0, draw=True):
        """
        Finds landmarks of a single hand and puts them in a list
        in pixel format. Also finds the bounding box around the hand.
        :param img: main image to find hand in
        :param handNo: hand id if more than one hand detected
        :param draw: Flag to draw the output on the image.
        :return: list of landmarks in pixel format; bounding box
        """

        xList = []
        yList = []
        bbox = []
        bboxInfo = []
        self.lmList = []
        if self.results.multi_hand_landmarks:
            myHand = self.results.multi_hand_landmarks[handNo]
            for id, lm in enumerate(myHand.landmark):
                h, w, c = img.shape
                px, py = int(lm.x * w), int(lm.y * h)
                xList.append(px)
                yList.append(py)
                self.lmList.append([px, py])
                if draw:
                    cv2.circle(img, (px, py), 5, (255, 0, 255), cv2.FILLED)
            xmin, xmax = min(xList), max(xList)
            ymin, ymax = min(yList), max(yList)
            boxW, boxH = xmax - xmin, ymax - ymin
            bbox = xmin, ymin, boxW, boxH
            cx, cy = bbox[0] + (bbox[2] // 2), \
                     bbox[1] + (bbox[3] // 2)
            bboxInfo = {"id": id, "bbox": bbox, "center": (cx, cy)}

            if draw:
                cv2.rectangle(img, (bbox[0] - 20, bbox[1] - 20),
                              (bbox[0] + bbox[2] + 20, bbox[1] + bbox[3] + 20),
                              (0, 255, 0), 2)

        return self.lmList, bboxInfo

    def fingersUp(self,myHand):
        """
        Finds how many fingers are open and returns in a list.
        Considers left and right hands separately
        :return: List of which fingers are up
        """
        myHandType =myHand["type"]
        myLmList = myHand["lmList"]
        if self.results.multi_hand_landmarks:
            fingers = []
            # Thumb
            if myHandType == "Right":
                if myLmList[self.tipIds[0]][0] > myLmList[self.tipIds[0] - 1][0]:
                    fingers.append(1)
                else:
                    fingers.append(0)
            else:
                if myLmList[self.tipIds[0]][0] < myLmList[self.tipIds[0] - 1][0]:
                    fingers.append(1)
                else:
                    fingers.append(0)

            # 4 Fingers
            for id in range(1, 5):
                if myLmList[self.tipIds[id]][1] < myLmList[self.tipIds[id] - 2][1]:
                    fingers.append(1)
                else:
                    fingers.append(0)
        return fingers

    def findDistance(self,p1, p2, img=None):
        """
        Find the distance between two landmarks based on their
        index numbers.
        :param p1: Point1
        :param p2: Point2
        :param img: Image to draw on.
        :param draw: Flag to draw the output on the image.
        :return: Distance between the points
                 Image with output drawn
                 Line information
        """

        x1, y1 = p1
        x2, y2 = p2
        cx, cy = (x1 + x2) // 2, (y1 + y2) // 2
        length = math.hypot(x2 - x1, y2 - y1)
        info = (x1, y1, x2, y2, cx, cy)
        if img is not None:
            cv2.circle(img, (x1, y1), 15, (255, 0, 255), cv2.FILLED)
            cv2.circle(img, (x2, y2), 15, (255, 0, 255), cv2.FILLED)
            cv2.line(img, (x1, y1), (x2, y2), (255, 0, 255), 3)
            cv2.circle(img, (cx, cy), 15, (255, 0, 255), cv2.FILLED)
            return length,info, img
        else:
            return length, info


def main():
    cap = cv2.VideoCapture(0)
    detector = HandDetector(detectionCon=0.8, maxHands=2)
    while True:
        # Get image frame
        success, img = cap.read()
        # Find the hand and its landmarks
        hands, img = detector.findHands(img)  # with draw
        # hands = detector.findHands(img, draw=False)  # without draw

        if hands:
            # Hand 1
            hand1 = hands[0]
            lmList1 = hand1["lmList"]  # List of 21 Landmark points
            bbox1 = hand1["bbox"]  # Bounding box info x,y,w,h
            centerPoint1 = hand1['center']  # center of the hand cx,cy
            handType1 = hand1["type"]  # Handtype Left or Right

            fingers1 = detector.fingersUp(hand1)

            if len(hands) == 2:
                # Hand 2
                hand2 = hands[1]
                lmList2 = hand2["lmList"]  # List of 21 Landmark points
                bbox2 = hand2["bbox"]  # Bounding box info x,y,w,h
                centerPoint2 = hand2['center']  # center of the hand cx,cy
                handType2 = hand2["type"]  # Hand Type "Left" or "Right"

                fingers2 = detector.fingersUp(hand2)

                # Find Distance between two Landmarks. Could be same hand or different hands
                length, info, img = detector.findDistance(lmList1[8], lmList2[8], img)  # with draw
                # length, info = detector.findDistance(lmList1[8], lmList2[8])  # with draw
        # Display
        cv2.imshow("Image", img)
        cv2.waitKey(1)


if __name__ == "__main__":
    main()

2、主模块

原理:

  1. 当检测到两只手时,并且两只手的拇指和食指都抬起时,通过计算拇指指尖之间的距离来获取初始距离 startDist

  2. 当两只手的拇指和食指都抬起时,计算当前拇指指尖之间的距离,并根据距离变化来调整缩放因子 scale。这个变化可以通过当前距离减去初始距离得到。

  3. 根据计算得到的 scale 值,调整图像的尺寸,将另一张图像按照 scale 进行缩放。

这样,当你用两只手的拇指和食指模拟捏取的动作时,可以实现图像的放大和缩小效果。两只手之间的距离越大,图像缩小得越多;两只手之间的距离越小,图像放大得越多。

这个应用可以在许多场景中使用,比如在展示图像、视频播放或地图应用中,通过手势来实现图像的交互式缩放效果。这个示例,展示了手势识别在图像处理和交互中的潜在应用。

导入所需的库:

import cv2
from HandTrackingModule import *

配置摄像头,创建手势检测器对象:

cap = cv2.VideoCapture(0)
cap.set(3, 1280)  # 设置摄像头的宽度
cap.set(4, 720)   # 设置摄像头的高度

detector = HandDetector(detectionCon=0.8)  # 创建手势检测器对象,设置检测置信度阈值

定义变量用于手势缩放操作:

startDist = None  # 用于存储初始距离
scale = 0  # 缩放值
cx, cy = 500, 500  # 缩放中心的坐标

进入主循环,读取视频帧并执行手势识别和图像操作:

while True:
    success, img = cap.read()  # 读取视频帧
    hands, img = detector.findHands(img)  # 手势检测

    # 读取一张图像用于操作
    img1 = cv2.imread("cvarduino.jpg")

    if len(hands) == 2:
        # 如果检测到两只手
        if detector.fingersUp(hands[0]) == [1, 1, 0, 0, 0] and \
                detector.fingersUp(hands[1]) == [1, 1, 0, 0, 0]:

            lmList1 = hands[0]["lmList"]  # 第一只手的关键点列表
            lmList2 = hands[1]["lmList"]  # 第二只手的关键点列表
            
            # 计算两个手指尖之间的距离作为缩放参考
            if startDist is None:
                length, info, img = detector.findDistance(lmList1[8], lmList2[8], img)
                startDist = length

            length, info, img = detector.findDistance(lmList1[8], lmList2[8], img)
            scale = int((length - startDist) // 2)  # 计算缩放值
            cx, cy = info[4:]  # 获取缩放中心的坐标
            print(scale)  # 打印缩放值
    else:
        startDist = None

    try:
        h1, w1, _ = img1.shape
        newH, newW = ((h1 + scale) // 2) * 2, ((w1 + scale) // 2) * 2
        img1 = cv2.resize(img1, (newW, newH))

        # 在指定位置绘制缩放后的图像
        img[cy - newH // 2:cy + newH // 2, cx - newW // 2:cx + newW // 2] = img1
    except:
        pass

    cv2.imshow("Image", img)  # 显示处理后的图像
    cv2.waitKey(1)  # 等待按键

主模块

全部代码:

import cv2
# from cvzone.HandTrackingModule import HandDetector
from HandTrackingModule import *
cap = cv2.VideoCapture(0)
cap.set(3, 1280)
cap.set(4, 720)

detector = HandDetector(detectionCon=0.8)
startDist = None
scale = 0
cx, cy = 500,500
while True:
    success, img = cap.read()
    hands, img = detector.findHands(img)
    img1 = cv2.imread("cvarduino.jpg")

    if len(hands) == 2:
        # print('Zoom Gesture')
        # print(detector.fingersUp(hands[0]),detector.fingersUp(hands[1]))
        if detector.fingersUp(hands[0]) == [1, 1, 0, 0, 0] and \
                detector.fingersUp(hands[1]) == [1, 1, 0, 0, 0]:

            # print('zhenque ')
            lmList1 = hands[0]["lmList"]
            lmList2 = hands[1]["lmList"]
            # point 8 is the tip of the index finger
            if startDist is None:
                length, info, img = detector.findDistance(lmList1[8], lmList2[8], img)
                # print(length)
                startDist = length

            length, info, img = detector.findDistance(lmList1[8], lmList2[8], img)
            scale = int((length - startDist) // 2)
            cx, cy = info[4:]
            print(scale)
    else:
        startDist = None

    try:
        h1, w1, _= img1.shape
        newH, newW = ((h1+scale)//2)*2, ((w1+scale)//2)*2
        img1 = cv2.resize(img1, (newW,newH))

        img[cy-newH//2:cy+ newH//2, cx-newW//2:cx+ newW//2] = img1
    except:
        pass

    cv2.imshow("Image", img)
    cv2.waitKey(1)

 

有遇到的问题欢迎评论区留言!

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

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

相关文章

【Git】安装以及基本操作

目录 一、初识Git二、 在Linux底下安装Git一&#xff09;centOS二&#xff09;Ubuntu 三、 Git基本操作一&#xff09; 创建本地仓库二&#xff09;配置本地仓库三&#xff09;认识工作区、暂存区、版本库四&#xff09;添加文件五&#xff09;查看.git文件六&#xff09;修改文…

问道管理:旅游酒店板块逆市拉升,桂林旅游、华天酒店涨停

游览酒店板块14日盘中逆市拉升&#xff0c;到发稿&#xff0c;桂林游览、华天酒店涨停&#xff0c;张家界涨超8%&#xff0c;君亭酒店涨超5%&#xff0c;众信游览、云南游览涨逾4%。 音讯面上&#xff0c;8月10日&#xff0c;文旅部办公厅发布康复出境团队游览第三批名单&#…

Flink源码之StreamTask启动流程

每个ExecutionVertex分配Slot后&#xff0c;JobMaster就会向Slot所在的TaskExecutor提交RPC请求执行Task&#xff0c;接口为TaskExecutorGateway::submitTask CompletableFuture<Acknowledge> submitTask(TaskDeploymentDescriptor tdd, JobMasterId jobMasterId, RpcTi…

无涯教程-Perl - select函数

描述 此函数将输出的默认文件句柄设置为FILEHANDLE,如果未指定文件句柄,则设置由print和write等功能使用的文件句柄。如果未指定FILEHANDLE,则它将返回当前默认文件句柄的名称。 select(RBITS,WBITS,EBITS,TIMEOUT)使用指定的位调用系统功能select()。 select函数设置用于处理…

Postgresql 基础使用语法

1.数据类型 1.数字类型 类型 长度 说明 范围 与其他db比较 Smallint 2字节 小范围整数类型 32768到32767 integer 4字节 整数类型 2147483648到2147483647 bigint 8字节 大范围整数类型 -9233203685477808到9223203685477807 decimal 可变 用户指定 精度小…

用友Java后端笔试2023-8-5

计算被直线划分区域 在笛卡尔坐标系&#xff0c;存在区域[A,B],被不同线划分成多块小的区域&#xff0c;简单起见&#xff0c;假设这些不同线都直线并且不存在三条直线相交于一点的情况。 img 那么&#xff0c;如何快速计算某个时刻&#xff0c;在 X 坐标轴上[ A&#xff0c;…

读书笔记 |【项目思维与管理】➾ 项目成为一种生存方式

读书笔记 |【项目思维与管理】➾ 项目成为一种生存方式 一、理解项目固有的挑战二、项目对企业的价值三、知识型企业的经营逻辑四、做项目管理的推进者 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 项目无处不在&#xff0c;项目已经成为…

【佳佳怪文献分享】安全人机交互的学习责任分配与自动驾驶应用

标题&#xff1a;Learning Responsibility Allocations for Safe Human-Robot Interaction with Applications to Autonomous Driving 作者&#xff1a;Ryan K. Cosner, Yuxiao Chen, Karen Leung, and Marco Pavone 来源&#xff1a;2023 IEEE International Conference on …

鸿蒙开发学习笔记2——实现页面之间跳转

鸿蒙开发学习笔记2——实现页面之间跳转 问题背景 上篇文章中&#xff0c;介绍了鸿蒙开发如何新建一个项目跑通hello world&#xff0c;本文将介绍在新建的项目中实现页面跳转的功能。 问题分析 ArkTS工程目录结构&#xff08;FA模型&#xff09; 各目录和路径的介绍如下…

iOS手机无法安装Charles 的ssl证书

问题描述 iOS客户端安装证书时一直卡在下载这一步&#xff0c;无法抓包 1、打开Charles&#xff0c;选择help→SSL Proxying→Install Charles Root Certificate on a Mobile Device or Remote Browser 2、按照步骤1中的提示进行操作&#xff0c;手机连接电脑代理&#xff0c;…

C语言学习笔记---结构体初阶

C语言程序设计笔记---014 C语言结构体初阶1、结构的基础与概念1.1、结构体基础例程1 --- 描述一个学生属性 2、结构体成员的类型2.1、结构体类型例程1 --- 描述一个学生属性 3、结构体的变量定义与初识化3.1、结构体的变量定义与初识化例程13.2、结构体的变量定义与初识化例程2…

C++多线程场景中的变量提前释放导致栈内存异常

多线程场景中的栈内存异常 在子线程中尝试使用当前函数的资源&#xff0c;是非常危险的&#xff0c;但是C支持这么做。因此C这么做可能会造成栈内存异常。 正常代码 #include <iostream> #include <thread> #include <windows.h>// 线程函数&#xff0c;用…

截止到目前全量主体总数有多少?

企业主体类型 企业主体类型有很多种&#xff0c;一般我们会分为公司&#xff08;有限责任&#xff09;、合伙企业、个人独资企业、个体经营户这些类别。 今天我们按照企业&#xff0c;个体&#xff0c;组织的分类方式来看各个主体的总数。 企业&#xff1a;统一社会信用代码…

三、性能测试场景设计

性能测试场景设计 一、引言&#xff1a;如果公司要求你去做性能测试&#xff0c;遇到这些场景&#xff0c;我们要如何设计&#xff1f;二、6种常见设计方法1、普通性能场景设计2、负载测试性能场景 一、引言&#xff1a;如果公司要求你去做性能测试&#xff0c;遇到这些场景&am…

读高性能MySQL(第4版)笔记01_MySQL架构(上)

1. 逻辑架构 1.1. 大多数基于网络的客户端/服务器工具或服务器都有类似的服务 1.1.1. 连接处理 1.1.2. 身份验证 1.1.3. 确保安全性 1.2. 核心层 1.2.1. 查询解析、分析、优化、以及所有的内置函数 1.2.2. 跨存储引擎的功能 1.2.2.1. 存储过程 1.2.2.2. 触发器 1.2.2…

kafka的位移

文章目录 概要消费位移__consumer_offsets主题位移提交 概要 本文主要总结kafka的位移是如何管理的&#xff0c;在broker端如何通过命令行查看到位移信息&#xff0c;并从代码层面总结了位移的提交方式。 消费位移 对于 Kafka 中的分区而言&#xff0c;它的每条消息都有唯一…

Python爬虫(十二)_XPath与lxml类库

Python学习指南 有同学说&#xff0c;我正则用的不好&#xff0c;处理HTML文档很累&#xff0c;有没有其他的方法&#xff1f; 有&#xff01;那就是XPath,我们可以用先将HTML文档转换成XML文档&#xff0c;然后用XPath查找HTML节点或元素。 什么是XML XML指可扩展标记语言(E…

Spring Boot + Vue3前后端分离实战wiki知识库系统十二--用户管理单点登录开发一...

目标&#xff1a; 在上一次https://www.cnblogs.com/webor2006/p/17533745.html我们已经完成了文档管理的功能模块开发&#xff0c;接下来则开启新模块的学习---用户登录&#xff0c;这块还是有不少知识点值得学习的&#xff0c;先来看一下整体的效果&#xff0c;关于效果官网有…

算法|Day38 动态规划6

完全背包问题&#xff0c;也就是一个物品可以取多次&#xff0c;我们只需要正序遍历背包容量就可以了。因为一维数组是按左边的状态来进行推导&#xff0c;我们正序&#xff0c;那样就会将前一次取的状态带到下一个位置&#xff0c;也就实现了多次取。如果倒序&#xff0c;左边…

麦肯锡发布《2023科技趋势展望报告》,生成式AI、下一代软件开发成为趋势,软件测试如何贴合趋势?

近日&#xff0c;麦肯锡公司发布了《2023科技趋势展望报告》。报告列出了15个趋势&#xff0c;并把他们分为5大类&#xff0c;人工智能革命、构建数字未来、计算和连接的前沿、尖端工程技术和可持续发展。 类别一&#xff1a;人工智能革命 生成式AI 生成型人工智能标志着人工智…