目录
- 规则
- 坐标系
- 代码
- 总结
- 相关openmv使用文档:
规则
坐标系
代码
# 激光打靶 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代码:
https://blog.csdn.net/qq_42604176/article/details/108342679
相关openmv使用文档:
https://docs.openmv.io/library/omv.image.html?highlight=rgb_to_grayscale#image.image.rgb_to_grayscale
https://singtown.com/learn/50029/