亚博microros小车-原生ubuntu支持系列:22 物体识别追踪

news2025/2/6 14:58:28

背景知识

跟上一个颜色追踪类似。也是基于opencv的,不过背后的算法有很多

  • BOOSTING:算法原理类似于Haar cascades (AdaBoost),是一种很老的算法。这个算法速度慢并且不是很准。
  • MIL:BOOSTING准一点。
  • KCF:速度比BOOSTINGMIL更快,与BOOSTINGMIL一样不能很好地处理遮挡问题。
  • CSRT:KCF更准一些,但是速度比KCF稍慢。
  • MedianFlow:对于快速移动的目标和外形变化迅速的目标效果不好。
  • TLD:会产生较多的false-positives。
  • MOSSE:算法速度非常快,但是准确率比不上KCFCSRT。在一些追求算法速度的场合很适用。
  • GOTURN:OpenCV中自带的唯一一个基于深度学习的算法。运行算法需要提前下载好模型文件。

对算法背后的原理干兴趣的,推荐看看大佬的

几个目标跟踪算法_视频目标跟踪算法-CSDN博客


    def initWorking(self, frame, box):
        '''
        Tracker work initialization 追踪器工作初始化
        frame:初始化追踪画面
        box:追踪的区域
        '''
        if not self.tracker: raise Exception("追踪器未初始化Tracker is not initialized")
        status = self.tracker.init(frame, box)
        #if not status: raise Exception("追踪器工作初始化失败Failed to initialize tracker job")
        self.coord = box
        self.isWorking = True

    def track(self, frame):
        if self.isWorking:#更新跟踪器
            status, self.coord = self.tracker.update(frame)
            if status:#如果跟踪成功,则绘制跟踪框:获取的坐标位置(x,y,w,h)画框就是(x,y),(x+w,y+h)
                p1 = (int(self.coord[0]), int(self.coord[1]))
                p2 = (int(self.coord[0] + self.coord[2]), int(self.coord[1] + self.coord[3]))
                cv.rectangle(frame, p1, p2, (255, 0, 0), 2, 1)
                return frame, p1, p2
            else:
                # 跟踪失败
		# Tracking failed
                cv.putText(frame, "Tracking failure detected", (100, 80), cv.FONT_HERSHEY_SIMPLEX, 0.75, (0, 0, 255), 2)
                return frame, (0, 0), (0, 0)
        else: return frame, (0, 0), (0, 0)

#!/usr/bin/env python3
# encoding: utf-8
import getpass
import threading
from yahboom_esp32ai_car.astra_common import *
from sensor_msgs.msg import CompressedImage,Image
from std_msgs.msg import Int32, Bool,UInt16
import rclpy
from rclpy.node import Node
from cv_bridge import CvBridge

from rclpy.time import Time
import datetime
from ament_index_python.packages import get_package_share_directory #获取shares目录绝对路径


class mono_Tracker(Node):
    def __init__(self,name):
        super().__init__(name)
        self.pub_Servo1 = self.create_publisher(Int32,"servo_s1" , 10)#舵机控制
        self.pub_Servo2 = self.create_publisher(Int32,"servo_s2" , 10) 
        #初始化参数
        self.declare_param()
        self.target_servox = 0 #目标中心点x坐标
        self.target_servoy = 10 #目标中心点y坐标
        self.point_pose = (0, 0, 0)  #目标点位置 (x,y,z)
        self.circle = (0, 0, 0) #目标点圆信息 (x,y,radius)
        self.hsv_range = ()  #hsv 颜色范围
        self.dyn_update = True
        self.select_flags = False
        self.gTracker_state = False
        self.windows_name = 'frame'
        self.cols, self.rows = 0, 0 #鼠标选择区域坐标
        self.Mouse_XY = (0, 0) #鼠标点击坐标
        self.index = 2
        self.end = 0
        self.color = color_follow()
    
        self.tracker_types = ['BOOSTING', 'MIL', 'KCF']
        self.tracker_type = ['KCF'] 
        self.VideoSwitch = True
        self.img_flip = False

        self.last_stamp = None
        self.new_seconds = 0
        self.fps_seconds = 1

        ser1_angle = Int32()#舵机初始角度
        ser1_angle.data = int(self.target_servox)
        ser2_angle = Int32()
        ser2_angle.data = int(self.target_servoy)

        #确保角度正常处于中间
        for i in range(10):
            self.pub_Servo1.publish(ser1_angle)
            self.pub_Servo2.publish(ser2_angle)
            time.sleep(0.1)
        


        self.hsv_text = get_package_share_directory('yahboom_esp32ai_car')+'/resource/colorHSV.text'
        self.mono_PID = (12, 0, 0.9)
        self.scale = 1000
        self.PID_init()

        print("OpenCV Version: ",cv.__version__)
        self.gTracker = Tracker(tracker_type=self.tracker_type)
        self.tracker_type = self.tracker_types[self.index]
        self.Track_state = 'init'

        #USB
        #self.capture = cv.VideoCapture(0)
        #self.timer = self.create_timer(0.001, self.on_timer)

        #ESP32_wifi
        self.bridge = CvBridge()
        self.sub_img = self.create_subscription(
            CompressedImage, '/espRos/esp32camera', self.handleTopic, 1) #获取esp32传来的图像


    def declare_param(self):
        #PID
        self.declare_parameter("Kp",12)
        self.Kp = self.get_parameter('Kp').get_parameter_value().integer_value
        self.declare_parameter("Ki",0)
        self.Ki = self.get_parameter('Ki').get_parameter_value().integer_value
        self.declare_parameter("Kd",0.9)
        self.Kd = self.get_parameter('Kd').get_parameter_value().integer_value
    
    def get_param(self):
        self.Kd = self.get_parameter('Kd').get_parameter_value().integer_value
        self.Ki = self.get_parameter('Ki').get_parameter_value().integer_value
        self.Kp = self.get_parameter('Kp').get_parameter_value().integer_value
        self.mono_PID = (self.Kp,self.Ki,self.Kd)
        

    def cancel(self):     
        self.Reset()
        if self.VideoSwitch==False: self.__sub_img.unregister()
        cv.destroyAllWindows()

    # USB
    # def on_timer(self):
    #     self.get_param()
    #     ret, frame = self.capture.read()
    #     action = cv.waitKey(10) & 0xFF
    #     frame, binary =self.process(frame, action)
    #     start = time.time()
    #     fps = 1 / (start - self.end)
    #     text = "FPS : " + str(int(fps))
    #     self.end = start
    #     cv.putText(frame, text, (20, 30), cv.FONT_HERSHEY_SIMPLEX, 0.9, (0, 0, 255), 1)
    #     if len(binary) != 0: cv.imshow('frame', ManyImgs(1, ([frame, binary])))
    #     else:cv.imshow('frame', frame)
    #     if action == ord('q') or action == 113:
    #         self.capture.release()
    #         cv.destroyAllWindows()

    #ESP32_wifi  图像回调函数
    def handleTopic(self, msg):
        self.last_stamp = msg.header.stamp  
        if self.last_stamp:
            total_secs = Time(nanoseconds=self.last_stamp.nanosec, seconds=self.last_stamp.sec).nanoseconds
            delta = datetime.timedelta(seconds=total_secs * 1e-9)
            seconds = delta.total_seconds()*100

            if self.new_seconds != 0:
                self.fps_seconds = seconds - self.new_seconds

            self.new_seconds = seconds#保留这次的值

        self.get_param()
        start = time.time()
        frame = self.bridge.compressed_imgmsg_to_cv2(msg)#图像格式转换
        frame = cv.resize(frame, (640, 480))

        action = cv.waitKey(10) & 0xFF #获取按键事件
        frame, binary =self.process(frame, action)#核心处理逻辑
        
        
        end = time.time()
        fps = 1 / ((end - start)+self.fps_seconds)
        
        text = "FPS : " + str(int(fps))
        cv.putText(frame, text, (10,20), cv.FONT_HERSHEY_SIMPLEX, 0.8, (0,255,255), 2)
        cv.imshow('frame', frame)

        if action == ord('q') or action == 113:
            cv.destroyAllWindows()




    def Reset(self):
        self.hsv_range = ()
        self.circle = (0, 0, 0)
        self.Mouse_XY = (0, 0)
        self.Track_state = 'init'
        self.target_servox = 0
        self.target_servoy = 10
    
    #控制舵机
    def execute(self, point_x, point_y):
        # rospy.loginfo("point_x: {}, point_y: {}".format(point_x, point_y))
        #通过PID计算舵机调整量(参数是计算目标位置与图像中心的偏差,图像中心坐标(320,240))
        [x_Pid, y_Pid] = self.PID_controller.update([point_x - 320, point_y - 240])
        if self.img_flip == True:#根据图像翻转标识调整方向
            self.target_servox -= x_Pid
            self.target_servoy += y_Pid
        else:
            self.target_servox -= x_Pid
            self.target_servoy += y_Pid
        #角度控制(保护舵机)    
        if self.target_servox >= 45:
            self.target_servox = 45
        elif self.target_servox <= -45:
            self.target_servox = -45
        if self.target_servoy >= 20:
            self.target_servoy = 20
        elif self.target_servoy <= -90:
            self.target_servoy = -90
        print("servo1",self.target_servox)
        servo1_angle = Int32()
        servo1_angle.data = int(self.target_servox)
        servo2_angle = Int32()
        servo2_angle.data = int(self.target_servoy)
        self.pub_Servo1.publish(servo1_angle)
        self.pub_Servo2.publish(servo2_angle)

    def dynamic_reconfigure_callback(self, config, level):
        self.scale = config['scale']
        self.mono_PID = (config['Kp'], config['Ki'], config['Kd'])
        self.hsv_range = ((config['Hmin'], config['Smin'], config['Vmin']),
                          (config['Hmax'], config['Smax'], config['Vmax']))
        self.PID_init()
        return config

    def PID_init(self):
        self.PID_controller = simplePID(
            [0, 0],
            [self.mono_PID[0] / float(self.scale), self.mono_PID[0] / float(self.scale)],
            [self.mono_PID[1] / float(self.scale), self.mono_PID[1] / float(self.scale)],
            [self.mono_PID[2] / float(self.scale), self.mono_PID[2] / float(self.scale)])
    #鼠标回调,除了param其他都是自动获取  
    def onMouse(self, event, x, y, flags, param):
        if event == 1:#左键点击
            self.Track_state = 'init'
            self.select_flags = True
            self.Mouse_XY = (x,y)
        if event == 4:#左键放开
            self.select_flags = False
            self.Track_state = 'identify'
        if self.select_flags == True:
            self.cols = min(self.Mouse_XY[0], x), min(self.Mouse_XY[1], y)
            self.rows = max(self.Mouse_XY[0], x), max(self.Mouse_XY[1], y)
            self.Roi_init = (self.cols[0], self.cols[1], self.rows[0], self.rows[1])
    #图像处理主流程
    def process(self, rgb_img, action):
        # param action: [113 or 'q':退出],[114 or 'r':重置],[105 or 'i':识别],[32:开始追踪]
        rgb_img = cv.resize(rgb_img, (640, 480))
        binary = []
        if self.img_flip == True: rgb_img = cv.flip(rgb_img, 1)#图像翻转
        #按键处理
        if action == 32: self.Track_state = 'tracking'
        elif action == ord('i') or action == 105: self.Track_state = "identify"
        elif action == ord('r') or action == 114: self.Reset()
        elif action == ord('q') or action == 113: self.cancel()
        if self.Track_state == 'init':#初始化状态
            cv.namedWindow(self.windows_name, cv.WINDOW_AUTOSIZE)
            cv.setMouseCallback(self.windows_name, self.onMouse, 0)
            if self.select_flags == True:#绘制选择区域
                cv.line(rgb_img, self.cols, self.rows, (255, 0, 0), 2)
                cv.rectangle(rgb_img, self.cols, self.rows, (0, 255, 0), 2)
                if self.Roi_init[0] != self.Roi_init[2] and self.Roi_init[1] != self.Roi_init[3]:
                    if self.tracker_type == "color": rgb_img, self.hsv_range = self.color.Roi_hsv(rgb_img, self.Roi_init)#提取roi区域hsv范围
                    self.gTracker_state = True
                    self.dyn_update = True
                else: self.Track_state = 'init'
        if self.Track_state != 'init':#跟踪模式
            if self.tracker_type == "color" and len(self.hsv_range) != 0:
                rgb_img, binary, self.circle = self.color.object_follow(rgb_img, self.hsv_range)#颜色追踪
                if self.dyn_update == True:
                    params = {'Hmin': self.hsv_range[0][0], 'Hmax': self.hsv_range[1][0],
                              'Smin': self.hsv_range[0][1], 'Smax': self.hsv_range[1][1],
                              'Vmin': self.hsv_range[0][2], 'Vmax': self.hsv_range[1][2]}
                    self.dyn_client.update_configuration(params)#更新动态参数
                    self.dyn_update = False
            if self.tracker_type != "color":#其他跟踪模式
                if self.gTracker_state == True:
                    Roi = (self.Roi_init[0], self.Roi_init[1], self.Roi_init[2] - self.Roi_init[0], self.Roi_init[3] - self.Roi_init[1])
                    self.gTracker = Tracker(tracker_type=self.tracker_type)
                    self.gTracker.initWorking(rgb_img, Roi)
                    self.gTracker_state = False
                rgb_img, (targBegin_x, targBegin_y), (targEnd_x, targEnd_y) = self.gTracker.track(rgb_img)#执行追踪
                center_x = targEnd_x / 2 + targBegin_x / 2
                center_y = targEnd_y / 2 + targBegin_y / 2
                width = targEnd_x - targBegin_x
                high = targEnd_y - targBegin_y
                self.point_pose = (center_x, center_y, min(width, high))
        if self.Track_state == 'tracking':#执行追踪
            if self.circle[2] != 0: threading.Thread(target=self.execute, args=(self.circle[0], self.circle[1])).start()
            if self.point_pose[0] != 0 and self.point_pose[1] != 0: threading.Thread(target=self.execute, args=(self.point_pose[0], self.point_pose[1])).start()
        if self.tracker_type != "color": cv.putText(rgb_img, " Tracker", (260, 20), cv.FONT_HERSHEY_SIMPLEX, 0.75, (50, 170, 50), 2)
        return rgb_img, binary

class simplePID:
    '''very simple discrete PID controller'''

    def __init__(self, target, P, I, D):
        '''Create a discrete PID controller
        each of the parameters may be a vector if they have the same length
        Args:
        target (double) -- the target value(s)
        P, I, D (double)-- the PID parameter
        '''
        # check if parameter shapes are compatabile.
        if (not (np.size(P) == np.size(I) == np.size(D)) or ((np.size(target) == 1) and np.size(P) != 1) or (
                np.size(target) != 1 and (np.size(P) != np.size(target) and (np.size(P) != 1)))):
            raise TypeError('input parameters shape is not compatable')
       # rospy.loginfo('P:{}, I:{}, D:{}'.format(P, I, D))
        self.Kp = np.array(P)
        self.Ki = np.array(I)
        self.Kd = np.array(D)
        self.last_error = 0
        self.integrator = 0
        self.timeOfLastCall = None
        self.setPoint = np.array(target)
        self.integrator_max = float('inf')

    def update(self, current_value):
        '''Updates the PID controller.
        Args:
            current_value (double): vector/number of same legth as the target given in the constructor
        Returns:
            controll signal (double): vector of same length as the target
        '''
        current_value = np.array(current_value)
        if (np.size(current_value) != np.size(self.setPoint)):
            raise TypeError('current_value and target do not have the same shape')
        if (self.timeOfLastCall is None):
            # the PID was called for the first time. we don't know the deltaT yet
            # no controll signal is applied
            self.timeOfLastCall = time.perf_counter()
            return np.zeros(np.size(current_value))
        error = self.setPoint - current_value#计算误差
        P = error
        currentTime = time.perf_counter()
        deltaT = (currentTime - self.timeOfLastCall)
        # integral of the error is current error * time since last update  计算I
        self.integrator = self.integrator + (error * deltaT)
        I = self.integrator
        # derivative is difference in error / time since last update 计算P
        D = (error - self.last_error) / deltaT
        self.last_error = error
        self.timeOfLastCall = currentTime
        # return controll signal 计算输出
        return self.Kp * P + self.Ki * I + self.Kd * D


def main():
    rclpy.init()
    mono_tracker = mono_Tracker("monoIdentify")
    try:
        rclpy.spin(mono_tracker)
    except KeyboardInterrupt:
        pass
    finally:
        mono_tracker.destroy_node()
        rclpy.shutdown()
    
    

关键功能:

  • 支持多种跟踪算法(KCF/BOOSTING/MIL)

  • 颜色跟踪模式可自动提取HSV范围

  • 多线程控制确保流畅性

  • 完善的异常处理机制

  • 实时显示处理帧率

这个系统可以实现对运动目标或特定颜色物体的自动跟踪,通过PID算法保持目标在画面中心位置,典型应用于智能监控、机器人视觉跟随等场景。这个做上一篇的颜色追踪类似:亚博microros小车-原生ubuntu支持系列:21 颜色追踪-CSDN博客

都是根据目标的中心坐标和来计算s1、s2舵机转动角度,然后发布给底盘。

程序说明

程序启动后,通过鼠标选中需要跟踪的物体,按下空格键,小车的云台舵机进入跟踪模式。小车云台会跟随 被跟踪的物体移动,并且时刻保证被追踪的物体保持在画面中心。

测试

启动小车代理

 sudo docker run -it --rm -v /dev:/dev -v /dev/shm:/dev/shm --privileged --net=host microros/micro-ros-agent:humble udp4 --port 8090 -v4

启动图像代理

docker run -it --rm -v /dev:/dev -v /dev/shm:/dev/shm --privileged --net=host microros/micro-ros-agent:humble udp4 --port 9999 -v4

(选做)调整舵机

ros2 run yahboom_esp32_mediapipe control_servo

启动脚本

ros2 run yahboom_esp32ai_car mono_Tracker

启动之后,进入选择模式,用鼠标选中目标所在位置,如下图所示,松开即开始识别。

把我的镇宅之宝小黄鸭拿出来了

键盘按键控制:

【r】:选择模式,可用鼠标选择要识别目标的区域,如上图。

【q】:退出程序。

【空格键】:目标追踪;在跟随的时候缓慢移动目标即可,移动太快将会丢失目标。

按下空格能看到通过pid算出来的运动角度。

ohu@bohu-TM1701:~/yahboomcar/yahboomcar_ws$ ros2 run yahboom_esp32ai_car mono_Tracker 
OpenCV Version:  4.11.0
servo1 0.0
servo1 1.6740220783505821
servo1 2.981003373069086
servo1 4.277003373069086
servo1 5.418249937784921
servo1 6.018073510048205
servo1 6.0159973543603105
servo1 5.71860954302583
servo1 4.775629931904761
servo1 3.8326030635678214
servo1 2.9206030635678215
servo1 1.9081850712547614
servo1 0.7822878210318385
servo1 0.18899249274645924
servo1 -0.2834846440358629
servo1 -0.7540859436953311
servo1 -1.234085943695331
servo1 -1.6484508720535367
servo1 -2.1135512406099104
servo1 -2.5695512406099104
servo1 -3.058080514019669
servo1 -3.538080514019669
servo1 -4.171699309150052
servo1 -4.530007470444837
servo1 -4.800294859267008
servo1 -4.8453324923276115
servo1 -4.865291304517047
servo1 -4.94373365090143
servo1 -5.136952220684027
servo1 -5.469228000644295
servo1 -6.027853281852513
servo1 -6.710800306564447
servo1 -7.6552821486406
servo1 -8.052589780593427
servo1 -9.223112314977138
servo1 -10.319161974550278
servo1 -11.591078854236214
servo1 -12.416221902691895
servo1 -13.360740214236708
servo1 -14.51497408279646
servo1 -14.780085181765932
servo1 -14.310165362425591
servo1 -14.15717444041632
servo1 -14.435688173088373
servo1 -15.32025424018754
servo1 -16.531503721252605
servo1 -17.836778372955706
servo1 -19.017197794387748
servo1 -20.28310463824062
servo1 -21.166754300006183
servo1 -21.242287643352327
servo1 -21.1565011124945
servo1 -21.707825159200315
servo1 -23.013047473734893
servo1 -24.58221911876973
servo1 -26.81213675078672
servo1 -28.374622533573962
servo1 -29.871810297867736
servo1 -31.217257596323204
servo1 -32.31216336848393
servo1 -33.601930296065284
servo1 -34.03160970476731
2查看节点话题通讯图

可以通过rqt查看节点之间的话题通讯,

对比下颜色追踪的,

不足:

移动速度稍快一点就跟丢了。

以上

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

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

相关文章

java进阶之并发编程一ReentrantLock的实际应用和线程中断EXAMPLE

引言:继上一篇ReentrantLock的介绍来做俩个小demo。 实现3个线程分别打印指定数字和线程死锁进行线程中断。 上一篇:<<java进阶之并发编程一ReentrantLock同步锁的学习和syncthronized的区别>> **demo1:**ReentrantLock搭配三个线程分别打印指定的数字,直接上代…

分享2款 .NET 开源且强大的翻译工具

前言 对于程序员而言永远都无法逃避和英文打交道&#xff0c;今天大姚给大家分享2款 .NET 开源、功能强大的翻译工具&#xff0c;希望可以帮助到有需要的同学。 STranslate STranslate是一款由WPF开源的、免费的&#xff08;MIT License&#xff09;、即开即用、即用即走的翻…

SpringBoot+Dubbo+zookeeper 急速入门案例

项目目录结构&#xff1a; 第一步&#xff1a;创建一个SpringBoot项目&#xff0c;这里选择Maven项目或者Spring Initializer都可以&#xff0c;这里创建了一个Maven项目&#xff08;SpringBoot-Dubbo&#xff09;&#xff0c;pom.xml文件如下&#xff1a; <?xml versio…

[LeetCode] 二叉树 I — 深度优先遍历(前中后序遍历) | 广度优先遍历(层序遍历):递归法迭代法

二叉树 基础知识深度优先遍历递归法迭代法&#xff08;栈&#xff09;144# 二叉树的前序遍历94# 二叉树的中序遍历145# 二叉树的后序遍历 广度优先遍历递归法迭代法&#xff08;队列&#xff09;102# 二叉树的层序遍历107# 二叉树的层序遍历 II199# 二叉树的右视图637# 二叉树的…

Python aiortc API

本研究的主要目的是基于Python aiortc api实现抓取本地设备&#xff08;摄像机、麦克风&#xff09;媒体流实现Web端预览。本文章仅仅描述实现思路&#xff0c;索要源码请私信我。 demo-server解耦 原始代码解析 http服务器端 import argparse import asyncio import json…

OpenCV4,快速入门,第二讲:图像色彩空间转换

文章目录 引言一、色彩空间概述1.1 RGB与HSV的区别1.2 HSV的详细含义cvtColor二、cvtColor函数详解2.1 函数原型2.2 参数说明2.3 使用示例三、imwrite函数详解3.1 函数原型3.2 参数说明3.3 使用示例四、完整示例代码五、应用场景与注意事项5.1 HSV的典型应用5.2 注意事项结语引…

86.(2)攻防世界 WEB PHP2

之前做过&#xff0c;回顾一遍&#xff0c;详解见下面这篇博客 29.攻防世界PHP2-CSDN博客 既然是代码审计题目&#xff0c;打开后又不显示代码&#xff0c;肯定在文件里 <?php // 首先检查通过 GET 请求传递的名为 "id" 的参数值是否严格等于字符串 "admi…

RK3588——解决Linux系统触摸屏坐标方向相反问题

问题描述&#xff1a;触摸正常产生中断&#xff0c;但系统上报的触摸坐标不正确&#xff0c;是反向的坐标。 解决办法通过修改设备树添加属性翻转坐标。 注&#xff1a;需确认对应的驱动是否有解析该属性的具体内容&#xff0c;否则仍然无法生效。

面对全球化的泼天流量,出海企业如何观测多地域网络质量?

作者&#xff1a;俞嵩、白玙 泼天富贵背后&#xff0c;技术挑战接踵而至 随着全球化进程&#xff0c;出海、全球化成为很多 Toc 产品的必经之路&#xff0c;保障不同地域、不同网络环境的一致的用户体验成为全球化应用的不得不面对的问题。在跨运营商、跨地域的网络环境中&am…

YOLOv11实时目标检测 | 摄像头视频图片文件检测

在上篇文章中YOLO11环境部署 || 从检测到训练https://blog.csdn.net/2301_79442295/article/details/145414103#comments_36164492&#xff0c;我们详细探讨了YOLO11的部署以及推理训练&#xff0c;但是评论区的观众老爷就说了&#xff1a;“博主博主&#xff0c;你这个只能推理…

自定义序列化数据类型

目录 1. WritableComparable1.1 Writable1.2 Comparable1.3 IntWritable 2. 自定义序列化数据类型RectangleWritable3. 矩形面积计算3.1 Map3.2 Reduce 4. 代码和结果4.1 pom.xml中依赖配置4.2 工具类util4.3 矩形面积计算4.4 结果 参考 本文引用的Apache Hadoop源代码基于Apac…

【Linux网络编程】:URL(encode),HTTP协议,telnet工具

&#x1f381;个人主页&#xff1a;我们的五年 &#x1f50d;系列专栏&#xff1a;Linux网络编程 &#x1f337;追光的人&#xff0c;终会万丈光芒 &#x1f389;欢迎大家点赞&#x1f44d;评论&#x1f4dd;收藏⭐文章 ​ Linux网络编程笔记&#xff1a; https://mp.csdn…

C语言基础系列【3】VSCode使用

前面我们提到过VSCode有多么的好用&#xff0c;本文主要介绍如何使用VSCode编译运行C语言代码。 安装 首先去官网&#xff08;https://code.visualstudio.com/&#xff09;下载安装包&#xff0c;点击Download for Windows 获取安装包后&#xff0c;一路点击Next就可以。 配…

学前端框架之前,你需要先理解 MVC

MVC 软件架构设计模式鼎鼎大名&#xff0c;相信你已经听说过了&#xff0c;但你确定自己已经完全理解到 MVC 的精髓了吗&#xff1f; 如果你是新同学&#xff0c;没听过 MVC&#xff0c;那可以到网上搜一些文章来看看&#xff0c;不过你要有心理准备&#xff0c;那些文章大多都…

Mysql:数据库

Mysql 一、数据库概念&#xff1f;二、MySQL架构三、SQL语句分类四、数据库操作4.1 数据库创建4.2 数据库字符集和校验规则4.3 数据库修改4.4 数据库删除4.4 数据库备份和恢复其他 五、表操作5.1 创建表5.2 修改表5.3 删除表 六、表的增删改查6.1 Create(创建):数据新增1&#…

熟练掌握Http协议

目录 基本概念请求数据Get请求方式和Post请求方式 响应数据响应状态码 基本概念 Http协议全称超文本传输协议(HyperText Transfer Protocol)&#xff0c;是网络通信中应用层的协议&#xff0c;规定了浏览器和web服务器数据传输的格式和规则 Http应用层协议具有以下特点&#…

C++的 I/O 流

本文把复杂的基类和派生类的作用和关系捋出来&#xff0c;具体的接口请参考相关文档 C的 I/O 流相关的类&#xff0c;继承关系如下图所示 https://zh.cppreference.com/w/cpp/io I / O 的概念&#xff1a;内存和外设进行数据交互称为 I / O &#xff0c;例如&#xff1a;把数…

【PDF多区域识别】如何批量PDF指定多个区域识别改名,基于Windows自带的UWP的文字识别实现方案

海关在对进口货物进行查验时,需要核对报关单上的各项信息。对报关单 PDF 批量指定区域识别改名后,海关工作人员可以更高效地从文件名中获取关键信息,如货物来源地、申报价值等。例如文件名 “[原产国]_[申报价值].pdf”,有助于海关快速筛选重点查验对象,提高查验效率和监管…

【大数据技术】本机PyCharm远程连接虚拟机Python

本机PyCharm远程连接虚拟机Python 注意:本文需要使用PyCharm专业版。 pycharm-professional-2024.1.4VMware Workstation Pro 16CentOS-Stream-10-latest-x86_64-dvd1.iso写在前面 本文主要介绍如何使用本地PyCharm远程连接虚拟机,运行Python脚本,提高编程效率。 注意: …

数字化转型:概念性名词浅谈(第四讲)

​大家好&#xff0c;本篇文章是在新年之际写的&#xff0c;所以在这里先给大家拜个年。 今天要介绍的名词为ETL: ETL&#xff0c;是英文Extract-Transform-Load的缩写&#xff0c;用来描述将数据从来源端经过抽取&#xff08;extract&#xff09;、转换&#xff08;transfor…