【电设控制与图像训练题】【激光打靶】【openmv测试代码以及效果】

1,266 阅读2分钟

9.4加入串口通讯,送出靶心坐标、激光坐标、激光所在环数、方位;加入防误判操作


目录

规则

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

坐标系

代码

# 激光打靶 openmv测试代码
# author:DYY
# 识别靶心和激光坐标并计算两者距离
# 靶子与摄像头距离为67厘米
#9.4号增加防误判操作以及串口通信
import sensor, image, time
import math
from pyb import UART
import json
import ustruct
sensor.reset() # Initialize the camera sensor.
sensor.set_pixformat(sensor.RGB565) # or sensor.RGB565  565
sensor.set_framesize(sensor.QQVGA) # or sensor.QVGA (or others)
sensor.skip_frames(30) # Let new settings take affect.
sensor.set_gainceiling(8)




#参数初始化
canny_thred=5
fps_cnt=0
fps_cnt_set=10000
show_fps_set=50
last_target_x=0
last_target_y=0
last_graylight_X=0
last_graylight_Y=0
target_x=0
target_y=0
graylight_x=0
graylight_y=0
distance=0
direction=0
two_point_angle=0
times=0
last_times=0
PI=3.14159
exist_time=0
not_exist_times=0
real_exist_times=0
set_target_X=0
set_target_Y=0
#靶心阈值
target_thred=(0,70)
#激光阈值
graylight_thred=(230,255)

#获取靶心坐标函数
def get_target(grayMat,paint):
   #计算连通域
   center_X=0
   center_Y=0
   for blob in grayMat.find_blobs([target_thred], pixels_threshold=100, area_threshold=100, merge=True, margin=10):
    pixels=blob.pixels()
    #利用圆度来限制
    Roundness= blob.roundness()
    '''if(fps_cnt%show_fps_set==0):
        print("靶子圆形度",Roundness)
        print("靶子像素个数",pixels)'''
    if Roundness>=0.6 and pixels<=400:
        center_X=blob.cx()
        center_Y=blob.cy()
        #paint.draw_circle(center_X,center_Y,6, color =255, thickness = 8, fill = True)
   return (center_X,center_Y)
#获取激光坐标函数
def get_graylight(grayMat,paint):
   #global real_exist_times
   #mask1=grayMat.binary([graylight_thred])
   #计算连通域
   center_X=0
   center_Y=0
   for blob in grayMat.find_blobs([graylight_thred], pixels_threshold=0, area_threshold=0, merge=True, margin=0):
    pixels=blob.pixels()
    Roundness= blob.roundness()
    '''if(fps_cnt%show_fps_set==0):
        print("圆形度",Roundness)
        print("像素个数",pixels)'''
    #光亮像素过大或者圆形度过小视作无
    if pixels>=60 :
        center_X=0
        center_Y=0
    else:
        center_X=blob.cx()
        center_Y=blob.cy()
        #paint.draw_circle(center_X,center_Y,4, color =0, thickness = 3, fill = True)
   return (center_X,center_Y)
#获取两个点之间的距离
def get_distance(point1_X,point1_Y,point2_X,point2_Y):
    #获取距离
    dx = abs(point1_X - point2_X)
    dy = abs(point1_Y - point2_Y)
    distance =math.sqrt(dx * dx + dy * dy)
    return distance
#计算两点方位,返回point1在point2的哪个方位
def get_direction(point1_X,point1_Y,point2_X,point2_Y):
    direct =0
    dx = point1_X - point2_X
    dy = point1_Y - point2_Y
    if dx==0 and dy==0:
        direct = 1  #重合
    elif dx == 0 and dy > 0:
        direct = 2  #正下方
    elif dx == 0 and dy < 0:
        direct = 3  #正上方
    elif dx > 0 and dy == 0:
        direct = 4  #正右方
    elif dx > 0 and dy > 0:
        direct = 5  #右下方
    elif dx > 0 and dy < 0:
        direct = 6  #右上方
    elif dx < 0 and dy == 0:
        direct = 7  #正左方
    elif dx < 0 and dy > 0:
        direct = 8  #左下方
    elif dx < 0 and dy < 0:
        direct = 9  #左上方
    else:
        direct = 0  #无方向
    return direct
#计算角度
def get_angle(point1_X,point1_Y,point2_X,point2_Y):
    dx = point1_X - point2_X
    dy = point1_Y - point2_Y
    angle=0
    if dx==0 and dy>=0 :
        angle=0
    elif dx==0 and dy<0:
        angle=180
    elif dy==0 and dx>0:
        angle=90
    elif dy==0 and dx<0:
        angle =270
    elif dx>0 and dy>0:
        angle=math.atan(dx/dy)*180/PI
    elif dx<0 and dy>0:
        angle=360+math.atan(dx/dy)*180/PI
    elif dx<0 and dy<0:
        angle=180+math.atan(dx/dy)*180/PI
    elif dx>0 and dy<0:
        angle=180+math.atan(dx/dy)*180/PI
    return angle
#计算两点方位,返回point1在point2的哪个方位
def get_direction_with_angle(angle):
    direct =0
    if (angle>=0 and angle<=22.5) or (angle>337.5 and angle<=360):
        direct = 1  #正下
    elif angle>22.5 and angle<=67.5:
        direct = 2  #右下
    elif angle>67.5 and angle<=112.5:
        direct = 3  #正右
    elif angle>112.5 and angle<=157.5:
        direct = 4  #右上
    elif angle>157.5 and angle<=202.5:
        direct = 5  #正上
    elif angle>202.5 and angle<=247.5:
        direct = 6  #左上
    elif angle>247.5 and angle<=292.5:
        direct = 7  #正左
    elif angle>292.5 and angle<=337.5:
        direct = 8  #左下
    else:
        direct = 0  #无方向
    return direct





#显示方位信息
def show_direction(direct):
    if direct==1 :
        print("正下")
    elif direct==2 :
        print("右下")  #正下方
    elif direct==3 :
        print("正右")  #正上方
    elif direct==4 :
        print("右上")  #正右方
    elif direct==5 :
        print("正上")  #右下方
    elif direct==6 :
        print("左上")  #右上方
    elif direct==7 :
        print("正左")  #正左方
    elif direct==8 :
        print("左下")  #左下方
    else:
        print("无方向")  #无方向


#防误判靶心
def Prevent_misjudgment(point1_X,point1_Y,lastpoint1_X,lastpoint1_Y,set_X,set_Y):
    global exist_time
    if abs(lastpoint1_X-point1_X)<=30 and abs(lastpoint1_Y-point1_Y)<=30 and point1_X!=0 and point1_Y!=0:
        exist_time+=1
        if(exist_time>=4):
            set_X=point1_X
            set_Y=point1_Y
    if exist_time>=5 and (point1_X==0 or point1_Y==0):
        point1_X=set_X
        point1_Y=set_Y
    return point1_X,point1_Y,set_X,set_Y
#防丢激光 如果上一帧有值,这帧没值,或者上一帧有值且两者坐标相差太大,则这帧的坐标延续上一帧
#如果连续当前5帧没有找到激光,则认为脱靶
def Prevent_missgraylight(point1_X,point1_Y,lastpoint1_X,lastpoint1_Y):
    global not_exist_times
    global last_times
    if point1_X==0 and point1_Y==0:
        not_exist_times+=1
    if point1_X==0 and point1_Y==0 and lastpoint1_X!=0 and lastpoint1_Y!=0:
        point1_X=lastpoint1_X
        point1_Y=lastpoint1_Y
    if lastpoint1_X!=0 and lastpoint1_Y!=0 and (abs(lastpoint1_X-point1_X)>=70 or abs(lastpoint1_Y-point1_Y)>=70):
        point1_X=lastpoint1_X
        point1_Y=lastpoint1_Y
    if not_exist_times>=5 and last_times<=6:
        point1_X=0
        point1_Y=0
        not_exist_times=0
    return point1_X,point1_Y
#获取所在环数
'''
弃用代码
def get_ring_nums(paintMat,cannyMat,oldimg,method):
    mask=oldimg.clear()
    times=0
    for i in range(1,cannyMat.height()-1):
        for j in range(1,cannyMat.width()-1):
            if cannyMat.get_pixel(i,j)==255 and paintMat.get_pixel(i,j)==0:
                mask.set_pixel(i,j,255)
                times=times+1
            if times>0:
                print("次数",times)
            #判断每个格子八领域是否有白色的,如果有,消除掉
            if (mask.get_pixel(i - 1, j - 1)==255 or mask.get_pixel(i - 1, j )==255 or mask.get_pixel(i - 1, j + 1)==255
                or mask.get_pixel(i , j - 1)==255 or mask.get_pixel(i , j + 1)==255
                or mask.get_pixel(i + 1 , j - 1)==255 or mask.get_pixel(i + 1 , j)==255 or mask.get_pixel(i + 1 , j + 1)==255):
                    mask.set_pixel(i,j,0)
                    times=times-1
    return times
'''
def get_ring_nums_type2(distance,dis1,dis2,dis3,dis4,dis5,dis6):
    ring=0
    if distance <=dis1:
        ring=10
    elif distance >dis1 and distance <=dis2:
        ring=9
    elif distance >dis2 and distance <=dis3:
        ring=8
    elif distance >dis3 and distance <=dis4:
        ring=7
    elif distance >dis4 and distance <=dis5:
        ring=6
    elif distance >dis5 and distance <=dis6:
        ring=5
    else:
        ring=0
    return ring

clock = time.clock() # Tracks FPS.


#设置串口
uart = UART(3,115200)   #定义串口3变量
uart.init(115200, bits=8, parity=None, stop=0) # init with given parameters


#我们要传送的数据有:靶心坐标、激光坐标、环数、方位、以及回车
def sending_data(cx,cy,gx,gy,rings,direct):    #发送函数(我这里没用的,还是留着吧)
    global uart
    data = ustruct.pack("<bbbbbbbb",
                   cx,
                   cy,
                   gx,
                   gy,
                   rings,
                   direct,
                   0x0D,
                   0x0A)
    uart.write(data)

def recive_data():   #接收函数
    global uart
    if uart.any():
        tmp_data = uart.readline().decode()
        print(tmp_data)

#图像循环
while(True):
    clock.tick() # Track elapsed milliseconds between snapshots().
    #获取彩图
    srcimg = sensor.snapshot() # Take a picture and return the image.
    fps_cnt=fps_cnt+1
    #转成灰度
    grayimg =srcimg.to_grayscale()
    paintimg = grayimg
    #前fps_cnt_set帧找靶心,用来定位
    if(fps_cnt<=fps_cnt_set):
        #找到靶心的位置并且画出来get_target
        (target_x,target_y)=get_target(grayimg,paintimg)
        #防误判程序加入
        (target_x,target_y,set_target_X,set_target_Y)=Prevent_misjudgment(target_x,target_y,last_target_x,last_target_y,set_target_X,set_target_Y)
    #找到激光的位置并且画出来
    (graylight_x,graylight_y)=get_graylight(grayimg,paintimg)
    (graylight_x,graylight_y)=Prevent_missgraylight(graylight_x,graylight_y,last_graylight_X,last_graylight_Y)
    #当激光和靶心都存在的时候
    if target_x!=0 and target_y!=0 and graylight_x!=0 and graylight_y!=0:
        #计算两者距离
        distance = get_distance(target_x,target_y,graylight_x,graylight_y)
        #获取方位
        #direction =get_direction(graylight_x,graylight_y,target_x,target_y)
        #获取角度
        two_point_angle=get_angle(graylight_x,graylight_y,target_x,target_y)
        #获取方位
        direction=get_direction_with_angle(two_point_angle)
        #canny检测
        #cannyimg=grayimg.find_edges(image.EDGE_CANNY, threshold=(canny_thred,canny_thred*2))
        #画出直线
        paintimg.draw_line(target_x,target_y,graylight_x,graylight_y, color = 0, thickness = 1)
        #获取环数
        #method1
        #times=get_ring_nums(paintimg,cannyimg,srcimg)
        #method2
        times=get_ring_nums_type2(distance,10,20,30,40,50,60)
        #每30帧显示一组数据
        if(fps_cnt%show_fps_set==0):
            print("靶心坐标",target_x,target_y)
            print("两点距离",distance)
            #显示方位
            show_direction(direction)
            #显示环数
            print("环数",times)
            #print("环数",(10-times))
    else:
        distance=0
        times=0
        #每30帧显示一组数据
        if(fps_cnt%show_fps_set==0):
            print("没有找到靶点或者激光")
            print("脱靶")
    #发送和接收数据
    #recive_data()
    sending_data(target_x,target_y,graylight_x,graylight_y,times,direction)
    #更新数据
    if(fps_cnt%show_fps_set==0):
        print(target_x,target_y,graylight_x,graylight_y)
    last_target_x=target_x
    last_target_y=target_y
    last_graylight_X=graylight_x
    last_graylight_Y=graylight_y
    last_times=times
    # Faster simpler edge detection
    #img.find_edges(image.EDGE_SIMPLE, threshold=(100, 255))
    #print(clock.fps()) # Note: Your OpenMV Cam runs about half as fast while

总结

之前用的opencv写的测试代码,转用openmv时出现了不少问题。有些地方做了简化。
之前的opencv代码:
blog.csdn.net/qq_42604176…

相关openmv使用文档:

docs.openmv.io/library/omv…
singtown.com/learn/50029…