将yolov5视觉识别到的坐标信息用于云台跟踪(使用socket将YOLOv5检测到的坐标信息传输出去)

概要

我们一般使用yolo检测之后会得到目标的目标框坐标,检测是比较方便的,但用于工程的话,检测肯定是不够的,需要结合对象进行运动,这就需要传输信息了。今天记录使用socket将YOLOv5检测到的坐标信息传输出去。
我需要做一个云台的视觉控制程序,目前的方案是yolov5检测输出坐标信息,使用socket发送到客户端后,再打包成字节发送出去,发送时使用struct包发送给串口即可,也可在发送前处理数据,比如云台的话是将检测到的目标框中心坐标信息跟图像中心做比较,这个误差输入pid进行修正稳定,之后转换数据格式为二进制字节,变为电机可接收的数据,即可通过串口传出去。实现云台转动。主要难点在于:
1、socket传输坐标信息。2、数据传输要匹配电机通讯协议。3、pid调参。

1. Socket介绍

Socket是一种通信模式,它提供了一种标准化的接口,允许应用程序通过网络进行通信。Socket是网络通信的基本构建块,它封装了网络协议的复杂性,使得应用程序可以方便地进行数据传输。
发送条件: 在Socket通信中,每台计算机都有一个唯一的IP地址,而每个正在运行的网络应用程序都需要绑定到一个特定的端口号。IP地址用于标识计算机,端口号用于标识应用程序。
通信协议: Socket通信可以基于不同的网络协议,如TCP(传输控制协议)和UDP(用户数据报协议)。TCP提供了可靠的、面向连接的通信,而UDP提供了不可靠的、面向无连接的通信。
关于TCP:
主要是需要三次握手。自行百度,面试常考。大概可理解为建立连接需要至少三次握手,发送数据需要校验。
使用TCP协议的套接字,提供可靠的、面向连接的通信。流套接字通过建立连接,实现了数据的有序传输和错误检测,适用于需要可靠性的应用程序,如文件传输、HTTP等。
关于UDP:
使用UDP协议的套接字,提供不可靠的、面向无连接的通信。数据报套接字将数据分割成小的数据包(数据报)进行传输,适用于实时性要求高的应用程序,如音频、视频流等。

2. Socket编程的基本步骤:

Socket编程通常包括以下步骤:

  • 创建Socket:使用socket()函数创建一个Socket对象,指定通信协议(TCP或UDP)和套接字类型(流套接字或数据报套接字)。
  • 绑定地址和端口:如果是服务器,需要将Socket绑定到一个特定的IP地址和端口号上,以便监听来自客户端的连接请求。
  • 建立连接:如果是客户端,可以使用connect()方法连接到远程服务器。如果是服务器,使用listen()方法监听客户端的连接请求,一旦有连接请求,使用accept()方法接受连接。
  • 数据传输:通过Socket对象的send()和recv()方法进行数据的发送和接收。在TCP中,数据传输是可靠的;在UDP中,数据传输是不可靠的。
  • 关闭连接:通信完成后,使用close()方法关闭Socket连接,释放资源。

3. 服务端发送检测坐标:

主要是将检测的中心点坐标发送出去,然后客户端再接收,接收后处理数据,之后通过struct发送给串口。
现在yolo检测后会有坐标信息。可以处理为中心点坐标,一般是左上角x坐标加宽的一半,左上角y坐标加高的一半。
我的代码是跟踪的,所以已经处理好了中心点,所以下面演示中心店如何通过socket发送出去。
在输出中心点xy之后,即可发送,使用多线程发送,需要提前导入ThreadPoolExecutor,并提前创建好线程。

print(f"Center points: ", x_center,y_center)
# 在线程池中提交发送XY坐标的任务*/
thread_pool.submit(send_xy, x_center, y_center)  # 传递 x 和 y 参数

提前导入并设置好线程。

from concurrent.futures import ThreadPoolExecutor  # 导入 ThreadPoolExecutor
# 创建一个线程池,最多可以同时运行4个线程
thread_pool = ThreadPoolExecutor(max_workers=4)

提交坐标的任务中有涉及一个send_xy,提前定义好,这个部分主要负责发送信息到这个地址上。地址写客户接收端的地址,端口号相同就行,随便写,但一次只能用一个。

# 定义一个函数,用于在单独的线程中发送XY坐标
def send_xy(x, y):
    # 创建一个新的套接字并连接到目标 IP 和端口
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    target_ip = '192.168.1.131'
    target_port = 456
    s.connect((target_ip, target_port))
    # 发送坐标数据
    data = f"{x},{y}".encode()
    s.send(data)
    s.close()

这就是我发送的数据,红色框。
在这里插入图片描述

4. 客户端接收检测坐标:

代码同样使用了多线程,而且,接收数据支持小数 。
接收端注意要在局域网中,那种需要账号密码验证的公开网没用,普通局域网都可以用。如果你的服务端和客户端都在一台电脑上也可以的,只是注意ip写成本机ip就行。

import socket
import threading
import re
# 定义处理连接的函数
def handle_connection(conn):
    try:
        while True:
            data = conn.recv(4096)  # 接收数据(最大字节)
            if not data:
                break  # 如果没有数据,跳出循环
            message = data.decode()  # 解码收到的数据
            # print("接收到的数据:", message)
            # 使用正则表达式解析数据(匹配包含小数的数字)
            match = re.match(r'(\d+\.\d+),(\d+\.\d+)', message)
            if match:
                X = float(match.group(1))
                Y = float(match.group(2))
                print('X:', X, 'Y:', Y,)

    except Exception as e:
        print("处理连接时发生错误:", e)
    finally:
        conn.close()  # 关闭连接
# 创建Socket对象
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 指定IP地址和端口号
host = '192.168.1.133'  # 监听所有接口
port = 456
# 绑定Socket到地址和端口
server_socket.bind((host, port))
# 开始监听连接
server_socket.listen(1)
print("等待连接...")
try:
    while True:
        # 等待连接请求
        conn, addr = server_socket.accept()
        # print('连接来自:', addr)
        # 创建并启动新线程处理连接
        thread = threading.Thread(target=handle_connection, args=(conn,))
        thread.start()
except KeyboardInterrupt:
    print('手动关闭连接')
    server_socket.close()

这是我接收到的地址,暂时没有处理数据,也没有添加串口发送。后面的处理数据和串口发送,以及pid调节才是重头戏。
在这里插入图片描述

小结

暂时实现了使用socket将yolov5检测到的坐标信息发送出去,并在另一台客户端可接收,且在一个局域网内实时接收。

评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值