23年电赛e题-->自动追踪系统openmv代码(讲解+视觉完整代码)

                openmv很常用了,会有几个很明显的问题,看不见,找不到红色激光。

                第四问找到的矩形,的四个点顺序不对,应该怎么描点(细分多少份好一点)。

这个就是问题了。

现在一个一个解决。

1.关于看不见的问题

sensor.set_brightness(-3)
sensor.set_contrast(-3)

调试这两个函数。

2.关于找到四个矩形框,四个点不是顺时针问题。

先是找矩形框:

for i in range(10):
    img = sensor.snapshot().lens_corr(strength = 1.5, zoom = 1)
    #img.binary(heikuang)#.erode(1)
    for r in img.find_rects(threshold = 10000,roi=(75,5,191,203)):
         #img.draw_rectangle(r.rect(), color = (255, 0, 0))
         for p in r.corners():
            a+=1
            img.draw_circle(p[0], p[1], 5, color = (0, 255, 0))
            #print(p)
            if a<=4:
                dian.add(p)

我找10次就好了,然后画出来。

看找的对不对。

这块的代码就是对点进行排序。(思路是,x最小为第一个点,x最大为第三个点,y最大为第四个,y最小为第二个。)

完美解决!!! 

3.细分多少份。

我这里有绝妙的方法,我细分了无数份。---》我上面求出了矩形的四个点,并且·对他进行排序了。然后我就可以求出这,四条边的直线了,然后让直线·向内收缩,收缩到中心位置。

我的细分点为,目标点,红色点为当前值。我用当前值+1个像素,作为目标点的x,再把x代直线求y。就是完美的细分。

具体代码:

1. 给点求直线。 

2.求出直线并向内收缩

(我这里等分了,这个不用管,我在下面将这几个点画出来,看我找的对不对!!!)

 

 3.细分(我这里求目标点和现在点的差值,来进行换点!!!)

其实具体代码思路就那样,具体代码要靠自己去写。 

完整代码:

# Untitled - By: 24882 - Tue Jun 25 2024
heikuang =[(0, 107)]
roi1=[(79,32,165,163),(81,12,401,404)]
bai_se=0
red = [(0, 60, 2, 68, 53, -24)]
green=[(59, 85, -78, 23, -11, 60)]

import sensor, image, time,pyb
from pyb import Pin, ExtInt
from pyb import LED
from pyb import UART
from pid import PID
from machine import UART
sensor.reset()
sensor.set_pixformat(sensor.RGB565)

sensor.set_framesize(sensor.QVGA)
sensor.skip_frames(time = 20)
sensor.set_hmirror(True)
sensor.set_vflip(True)
clock = time.clock()
uart = UART(3, 115200)
uart1 = UART(1, 115200)
dian=set()
a=0
b=()
c=()
d=()
e=0
dian1=[]
dian2=[]
dian3=[]
dian4=[]
zuobiao=[]
zhongjian=()
def sending_data3(a1,a2,a3,a4,a5,a6,a7,a8):
    FH= bytearray([0x01,a1,a2,a3,a4,a5,a6,a7,a8,0x64])
    uart.write(FH)
def sending_data1(a1,a2,a3,a4,a5,a6,a7,a8):
    FH= bytearray([0x01,a1,a2,a3,a4,a5,a6,a7,a8,0x64])
    uart1.write(FH)
for i in range(10):
    img = sensor.snapshot().lens_corr(strength = 1.5, zoom = 1)
    #img.binary(heikuang)#.erode(1)
    for r in img.find_rects(threshold = 10000,roi=(75,5,191,203)):
         #img.draw_rectangle(r.rect(), color = (255, 0, 0))
         for p in r.corners():
            a+=1
            img.draw_circle(p[0], p[1], 5, color = (0, 255, 0))
            #print(p)
            if a<=4:
                dian.add(p)
ge=0
diyi=0
def takeSecond(elem):
    return elem[0]
sensor.set_pixformat(sensor.RGB565)
z1x=0
z1y=0
z2x=0
z2y=0
z3x=0
z3y=0
z4x=0
z4y=0
k1=0
b1=0
k2=0
b2=0
k2=0
b2=0
k3=0
b3=0
k4=0
b4=0
def zhixianwai1(ax,ay,bx,by):
    global k1,b1
    k1=(ay-by)/(ax-bx)
    b1=ay-k1*ax
def zhixianwai2(ax,ay,bx,by):
    global k2,b2
    k2=(ay-by)/(ax-bx)
    b2=ay-k2*ax
def zhixianwai3(ax,ay,bx,by):
    global k3,b3
    k3=(ay-by)/(ax-bx)
    b3=ay-k3*ax
def zhixianwai4(ax,ay,bx,by):
    global k4,b4
    k4=(ay-by)/(ax-bx)
    b4=ay-k4*ax
def find_max(blobs):
    max_blob = 0
    max_size = 0
    for blob in blobs:
        if blob[4]>max_size:
            max_blob = blob
            max_size = blob[4]
    return max_blob
i=0
flaghuan=0
countflag=0
dian1x=0
dian1y=0
dian2x=0
dian2y=0
sensor.set_pixformat(sensor.RGB565)
sensor.set_brightness(-3)
sensor.set_contrast(-3)

mode=0
while(True):
    mode=2
    dian1=list(dian)
    dian1.sort(key=takeSecond)
    #print(dian1)
    img = sensor.snapshot().lens_corr(strength = 1.5, zoom = 1)*
    sorted_indices = sorted(enumerate(dian1), key=lambda x: x[1][0])
    sorted_matrix = [dian1[idx] for idx, _ in sorted_indices]

    z1x=sorted_matrix[0][0]
    z1y=sorted_matrix[0][1]
    z3x=sorted_matrix[3][0]
    z3y=sorted_matrix[3][1]

    sorted_indices2 = sorted(enumerate(dian1), key=lambda y: y[1][1])
    sorted_matrix2 = [dian1[idy] for idy, _ in sorted_indices2]
    z2x=sorted_matrix2[0][0]
    z2y=sorted_matrix2[0][1]
    z4x=sorted_matrix2[3][0]
    z4y=sorted_matrix2[3][1]

    zhixianwai1(z1x,z1y,z2x,z2y)
    dengfen1=abs(z2x-z1x)/3
    mubiao1x=z1x+dengfen1
    mubiao1y=mubiao1x*k1+b1+5

    mubiao2x=z1x+dengfen1*2
    mubiao2y=mubiao2x*k1+b1+5

    zhixianwai2(z2x,z2y,z3x,z3y)
    dengfen2=abs(z3x-z2x)/3
    mubiao3x=z2x+dengfen2
    mubiao3y=mubiao3x*k2+b2+5

    mubiao4x=z2x+dengfen2*2
    mubiao4y=mubiao4x*k2+b2+5

    zhixianwai3(z4x,z4y,z3x,z3y)
    dengfen3=abs(z2x-z1x)/3
    mubiao6x=z4x+dengfen3
    mubiao6y=mubiao6x*k3+b3-5

    mubiao5x=z4x+dengfen3*2
    mubiao5y=mubiao5x*k3+b3-5

    zhixianwai4(z1x,z1y,z4x,z4y)
    dengfen4=abs(z1x-z4x)/3
    mubiao8x=z1x+dengfen4
    mubiao8y=b4+mubiao8x*k4-5

    mubiao7x=z1x+dengfen4*2
    mubiao7y=b4+mubiao7x*k4-5
    img.draw_cross(int(mubiao1x),int(mubiao1y), size=1, color=(255,0,0))
    img.draw_cross(int(mubiao2x),int(mubiao2y), size=1, color=(255,0,0))
    img.draw_cross(int(mubiao3x),int(mubiao3y), size=1, color=(255,0,0))
    img.draw_cross(int(mubiao4x),int(mubiao4y), size=1, color=(255,0,0))
    img.draw_cross(int(mubiao5x),int(mubiao5y), size=1, color=(255,0,0))
    img.draw_cross(int(mubiao6x),int(mubiao6y), size=1, color=(255,0,0))
    img.draw_cross(int(mubiao7x),int(mubiao7y), size=1, color=(255,0,0))
    img.draw_cross(int(mubiao8x),int(mubiao8y), size=1, color=(255,0,0))


    #print(i)
    if (i==0):
           mubx=z1x
           muby=z1y
    are1 = img.find_blobs(green,roi=(0,0,317,237),merge=True)
    are0 = img.find_blobs(red,roi=(93,4,202,216),merge=True)
    blobs1 = find_max(are1)
    blobs0 = find_max(are0)
    if(blobs0):
        img.draw_rectangle(blobs0.rect(),color=(255,255,0))
        print(flaghuan)
        sending_data3(blobs0.cx(),blobs0.cy(),abs(int(mubx)),abs(int(muby)),0,0,0,0)

        if(abs(blobs0.cx()-z3x)<=10):
            flaghuan=1
        if(abs(blobs0.cy()-z4y)<=5):
            flaghuan=2
        if(abs(blobs0.cx()-z1x)<=5):
            flaghuan=0

        if((abs(blobs0.cx()-mubx)<=3) and(abs(blobs0.cy()-muby)<=3)):
            i=i+1
            if((blobs0.cx()>z1x)and(blobs0.cx()<z2x-5)and(flaghuan==0)):
                mubx=mubx+1
                muby=mubx*k1+b1+5

            if((blobs0.cx()>z2x-5)and(blobs0.cx()<z3x)and(flaghuan==0)):
                mubx=mubx+1
                muby=mubx*k2+b2+5
                
            if((blobs0.cy()<=z4y+1)and(blobs0.cy()>=z3y-10)and(flaghuan==1)):
 
                mubx=mubx-1
                muby=mubx*k3+b3-5

            if((blobs0.cy()<z4y+5)and(blobs0.cy()>z1y)and(flaghuan==2)):
    
                mubx=mubx-1
                muby=mubx*k4+b4-5
        dian2x=blobs0.cx()
        dian2y=blobs0.cy()
    else :
        dian2x=0
        dian2y=0
    if(blobs1):
        img.draw_rectangle(blobs1.rect(),color=(255,255,0))
        dian1x=blobs1.cx()
        dian1y=blobs1.cy()
        sending_data1(dian1x,dian1y,dian2x,dian2y,0,0,0,0)
        print(dian1x,dian1y,dian2x,dian2y,0,0,0,0)
    else:
        dian2x=0
        dian2y=0










 

<think>由于问描述为2023E,这是一个具体的竞目,我首先需要回顾该目的要求。 根据回忆,2023全国大学生子设计竞E“运动目标控制与自动追踪系统”要求设计一个能够自动追踪运动目标的系统。通常,这类系统包括目标检测、目标跟踪、控制云台转动等模块。 由于目要求的是编程解决方案,我们将重点放在软件部分,特别是目标检测和跟踪算法,以及控制逻辑。 考虑到实际应用,我们可能会使用OpenCV库进行图像处理,使用PID控制算法进行云台控制。 由于目没有提供具体的硬件接口,我们假设摄像头通过USB连接,云台通过串口或USB转串口控制。 以下是一个简化的解决方案框架,包括: 1. 使用摄像头捕获视频帧。 2. 使用目标检测算法(如颜色跟踪、模板匹配或深度学习模型)在帧中定位目标。 3. 计算目标在图像中的位置与图像中心之间的偏差。 4. 根据偏差计算云台需要转动的角度(使用PID控制器)。 5. 通过串口发送控制指令给云台。 由于中可能要求实时性,且硬件资源有限,我们选择简单高效的颜色跟踪方法(例如基于HSV颜色空间的阈值分割)。 注意:实际比中,目会给出具体的目标特征(比如红色小球、特定形状等),这里假设目标是一个红色小球。 步骤: 1. 初始化摄像头。 2. 设置云台串口通信。 3. 循环读取视频帧。 4. 将帧转换为HSV颜色空间,并设定红色阈值。 5. 通过阈值分割得到二值图像,然后进行形态学操作去除噪声。 6. 查找二值图像中的轮廓,找到最大的轮廓,计算其中心坐标。 7. 计算目标中心与图像中心的偏差(dx, dy)。 8. 使用PID控制(这里为了简化,使用比例控制)计算云台转动的角度(pan, tilt)。 9. 将角度转换为云台的控制指令,通过串口发送。 代码示例(Python + OpenCV + pyserial): 注意:由于没有具体的云台通信协议,这里假设云台使用简单的字符串指令,如"PAN{角度}\n"和"TILT{角度}\n"。 我们将实现一个简单的版本,仅使用比例控制(P控制)来调整云台。</think>### 2023E解决方案:运动目标控制与自动追踪系统 #### 核心思路 1. **目标检测**:使用OpenCV进行实时视频处理 2. **运动控制**:通过PID算法实现云台精准追踪 3. **坐标转换**:将图像坐标映射到云台控制角度 #### 完整代码实现(Python + OpenCV + PID控制) ```python import cv2 import numpy as np import time import serial # 初始化串口通信(连接云台) # ser = serial.Serial('/dev/ttyUSB0', 9600) # 根据实际端口修改 # PID控制器类 class PID: def __init__(self, Kp, Ki, Kd): self.Kp = Kp self.Ki = Ki self.Kd = Kd self.prev_error = 0 self.integral = 0 def compute(self, error, dt): self.integral += error * dt derivative = (error - self.prev_error) / dt output = self.Kp * error + self.Ki * self.integral + self.Kd * derivative self.prev_error = error return output # 初始化PID控制器(X轴和Y轴) pid_x = PID(0.5, 0.01, 0.1) pid_y = PID(0.5, 0.01, 0.1) # 目标颜色阈值(HSV格式,示例为红色目标) lower_red = np.array([0, 100, 100]) upper_red = np.array([10, 255, 255]) # 初始化摄像头 cap = cv2.VideoCapture(0) cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480) # 云台控制函数 def move_gimbal(pan_angle, tilt_angle): # 限制角度范围 pan_angle = max(-90, min(90, pan_angle)) tilt_angle = max(-90, min(90, tilt_angle)) # 生成控制指令(示例协议) command = f"PAN{pan_angle:.1f},TILT{tilt_angle:.1f}\n" # ser.write(command.encode()) print(f"Sent: {command.strip()}") # 主循环 last_time = time.time() while True: ret, frame = cap.read() if not ret: break # 转换为HSV颜色空间 hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) # 创建颜色掩膜 mask = cv2.inRange(hsv, lower_red, upper_red) # 形态学操作(去噪) kernel = np.ones((5,5), np.uint8) mask = cv2.erode(mask, kernel, iterations=2) mask = cv2.dilate(mask, kernel, iterations=2) # 查找轮廓 contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) if contours: # 获取最大轮廓 largest_contour = max(contours, key=cv2.contourArea) # 计算最小外接圆 ((x, y), radius) = cv2.minEnclosingCircle(largest_contour) center = (int(x), int(y)) if radius > 10: # 忽略小噪点 # 绘制目标标记 cv2.circle(frame, center, int(radius), (0, 255, 0), 2) cv2.circle(frame, center, 5, (0, 0, 255), -1) # 计算与画面中心的偏差 frame_center = (frame.shape[1]//2, frame.shape[0]//2) error_x = center[0] - frame_center[0] error_y = center[1] - frame_center[1] # 计算时间增量 current_time = time.time() dt = current_time - last_time last_time = current_time # PID计算控制量 pan_angle = pid_x.compute(error_x, dt) tilt_angle = pid_y.compute(error_y, dt) # 发送云台控制指令 move_gimbal(pan_angle, tilt_angle) # 显示画面中心标记 cv2.circle(frame, (frame.shape[1]//2, frame.shape[0]//2), 10, (255, 0, 0), 1) # 显示处理结果 cv2.imshow('Tracking', frame) cv2.imshow('Mask', mask) if cv2.waitKey(1) & 0xFF == ord('q'): break cap.release() cv2.destroyAllWindows() # ser.close() # 关闭串口 ``` #### 代码解析 1. **目标检测模块** - 使用HSV颜色空间进行目标识别(第30-44行) - 通过形态学操作(腐蚀+膨胀)去除噪声(第39-40行) - 轮廓分析找到最大有效目标(第47行) - 计算目标中心坐标(第50行) 2. **PID控制模块** - 实现离散PID控制器(第12-22行) - 分别控制X轴(水平)和Y轴(垂直)移动(第25-26行) - 根据目标位置偏差计算控制量(第70-73行) 3. **坐标转换与控制** - 将像素偏差转换为云台角度(第70-73行) - 通过串口发送控制指令(第28-34行) - 角度范围限制保护云台(第29-30行) 4. **可视化调试** - 实时显示原始视频和掩膜(第80-81行) - 标记目标位置和画面中心(第53-55行,77行) #### 关键参数调整建议 1. **颜色阈值**:根据目标颜色调整`lower_red`和`upper_red` 2. **PID参数**: - Kp:增大可加快响应速度,但可能引起震荡 - Ki:消除静态误差,过大会导致超调 - Kd:抑制震荡,对噪声敏感 3. **形态学操作**:调整kernel大小和迭代次数优化去噪效果 #### 优化方向 1. 加入卡尔曼滤波预测目标轨迹 2. 使用深度学习模型(YOLO)提升检测精度 3. 实现运动目标速度预测的提前量控制 4. 增加通信协议的校验机制
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值