3554浏览
查看: 3554|回复: 1

[教程] 基于Opencv和行空板完成大疆EP自瞄-装甲板检测

[复制链接]
本帖最后由 Cm4iHKyN3ptj 于 2022-9-7 16:43 编辑

去年年底就关注到DF的行空板,从接口和处理器以及价钱来看是一款不错的硬件,因为自己手上也有比较多的DF传感器,所以一直想入手,在漂流活动中,成功的获取到了行空板,自己又在做自瞄,就想尝试一下行空板,刚刚行空板也有货了,所以就果断入手了几块,为了完成任务,就写了这个帖子,有什么不对的地方,请大家多多指教。
整个程序主要分为5部分,分别为图像获取——图像处理——轮廓检测——数据下发——EP控制,这一篇文章先完成前面四部分。
用的硬件主要有DF行空板,Microsoft摄像头,EP机器人,主要用到的语言为python

1.图像获取
因为是才用摄像头和opencv,所以图像获取是采用以下程序。
  1. cap = cv2.VideoCapture(VIDEO_INDEX) # 打开摄像头
  2.     frame_h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) # 480图像的高
  3.     frame_w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) # 640图像的宽
  4.     gun_point = (int(frame_w/2),int(frame_h/2) + GUN_ERROR)#图像的中心
复制代码
2.图像处理
图像处理主要的内容为摄像头的畸变矫正,以及颜色过滤。
  1. areas = []
  2.         ret, frame = cap.read()#视频信息处理
  3.         newcameramtx, roi=cv2.getOptimalNewCameraMatrix(left_camera_matrix,left_distortion,(frame_w,frame_h),1,(frame_w,frame_h))#<span style="color: rgb(77, 77, 77); font-family: -apple-system, "SF UI Text", Arial, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", sans-serif; font-size: 16px; font-variant-ligatures: no-common-ligatures; background-color: rgb(255, 255, 255);">去</span>除畸<span style="color: rgb(77, 77, 77); font-family: -apple-system, "SF UI Text", Arial, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", sans-serif; font-size: 16px; font-variant-ligatures: no-common-ligatures; background-color: rgb(255, 255, 255);">变矫正后图像四周黑色的区域</span>
  4.         frame = cv2.undistort(frame, left_camera_matrix, left_distortion, None, newcameramtx)#<span style="background-color: rgb(255, 255, 255); color: rgb(79, 79, 79); font-family: "PingFang SC", "Microsoft YaHei", SimHei, Arial, SimSun; font-size: 18px; font-variant-ligatures: no-common-ligatures;">像素坐标去畸变</span>
  5.         gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)#灰度处理
  6.         blur = cv2.GaussianBlur(gray, (3,3), 0)#高斯滤波,降噪
  7.         ret,imged = cv2.threshold(blur,HIGHTLIGHT_THR,255, cv2.THRESH_BINARY)#图像阈值处理
  8.         kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (8, 10)) # (5,7)
  9.         highlight_img = cv2.dilate(imged, kernel)#图像膨胀
复制代码
  1. COLOR_TYPE=0
  2.         if COLOR_TYPE == 0: # 红方
  3.             sub_rg = cv2.subtract(r, g)
  4.             sub_rb = cv2.subtract(r, b)
  5.             ret,res_rg = cv2.threshold(sub_rg,COLOR_THR,255, cv2.THRESH_BINARY)
  6.             ret,res_rb = cv2.threshold(sub_rb,COLOR_THR,255, cv2.THRESH_BINARY)
  7.             final = cv2.bitwise_and(res_rg,res_rb)   
  8.         else: # 蓝方
  9.             sub_bg = cv2.subtract(b, g)
  10.             sub_br = cv2.subtract(b, r)
  11.             ret,res_bg = cv2.threshold(sub_bg,COLOR_THR,255, cv2.THRESH_BINARY)
  12.             ret,res_br = cv2.threshold(sub_br,COLOR_THR,255, cv2.THRESH_BINARY)
  13.             final = cv2.bitwise_and(res_bg,res_br)#主要完成红蓝颜色的过滤
复制代码
  1. kernelx = cv2.getStructuringElement(cv2.MORPH_RECT, (8, 8))
  2.         color_img = cv2.dilate(final, kernelx)
  3.         kernele = cv2.getStructuringElement(cv2.MORPH_RECT, (7, 7))
  4.         preprocessed = cv2.bitwise_and(color_img,highlight_img)
  5.         preprocessed = cv2.dilate(preprocessed, kernele)
复制代码

3.轮廓检测
这个部分主要对过滤完的图片信息进行轮廓提取并进行大小区域判断,画出装甲板的框。
  1. contours, hierarchy = cv2.findContours(preprocessed, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)#查找轮廓
  2.         cv2.drawContours(frame,contours,-1,(255,0,0),2)#<font color="#2a2b2e" face="PingFang SC, Segoe UI, Arial, Microsoft YaHei, 微软雅黑, 宋体, Malgun Gothic, sans-serif"><span style="font-size: 12px; background-color: rgb(255, 255, 255);">绘制轮廓</span></font>
  3.         
  4.         for contour in contours:#遍历检测出来的轮廓
  5.             areas.append(cv2.contourArea(contour))
  6.             try:
  7.                 max_id = areas.index(max(areas))
  8.             except:
  9.                 continue
  10.             x, y, w, h = cv2.boundingRect(contours[max_id])#轮廓面积判断,根据装甲板的大小
  11.             if ( w * h > 1000 ) :
  12.                 thetaX = degrees(atan2(x-left_camera_matrix[0][2],left_camera_matrix[0][0]))
  13.                 thetaY = degrees(atan2(y-left_camera_matrix[1][2],left_camera_matrix[1][1]))
  14.                 dist = distance_to_camera(w)
  15.                 yield(thetaX,thetaY,dist)
  16.                 # 绘制
  17.                 cv2.rectangle(frame, (x,y), (x+w,y+h), (0,255,255), 2)#绘制轮廓
  18.         cv2.circle(frame,gun_point,5,(0,0,255),-1)
  19.         cv2.imshow("orgin_pic", frame)
复制代码
4.数据下发
主要的下发的内容是检测出的装甲板的中心点和距离机器人视角的距离,以及距离装甲板的距离
  1. for (yaw,pitch,dist) in aim():
  2.         yaw2=yaw
  3.         pitch=pitch-2
  4.         pitch2=pitch
  5.         if ( abs(yaw) < 1.5 ) :
  6.             yaw = 0
  7.         if ( abs(pitch) < 1.5 ):
  8.             pitch = 0
  9.         if abs(yaw2) and abs(pitch2)<2.5:
  10.             fire = 1
  11.         else:
  12.             fire = 0
  13.         print("%d,%.2f,%.2f,%.2f,%d" % (COLOR_TYPE,yaw,pitch,dist,fire))
复制代码
5.实现效果

6。完整代码
  1. import cv2
  2. #import serial
  3. from math import *
  4. from user_config import *
  5. #import RPi.GPIO as GPIO
  6. # 距离计算函数
  7. def distance_to_camera(perWidth):  
  8.     return (ARMOUR_WIDTH * FOCAL_LENS) / perWidth      
  9.    
  10. def aim():
  11.     global DEBUG_MODE,COLOR_TYPE,HIGHTLIGHT_THR,COLOR_THR
  12.     cap = cv2.VideoCapture(VIDEO_INDEX) # 打开摄像头
  13.     frame_h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) # 480
  14.     frame_w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) # 640
  15.     gun_point = (int(frame_w/2),int(frame_h/2) + GUN_ERROR)
  16.     if DEBUG_MODE == True:
  17.         def get_pixel(event,x,y,flags,param):
  18.             if event == cv2.EVENT_LBUTTONDBLCLK:
  19.                 print(x,y)
  20.         cv2.setMouseCallback('orgin_pic',get_pixel)
  21.         def nothing():
  22.             pass
  23.         cv2.namedWindow("win_control")
  24.         cv2.createTrackbar('hl_thr','win_control',0,255,nothing)
  25.         cv2.createTrackbar('cl_thr','win_control',0,255,nothing)
  26.         cv2.setTrackbarPos('hl_thr','win_control',HIGHTLIGHT_THR)
  27.         cv2.setTrackbarPos('cl_thr','win_control',COLOR_THR)
  28.     while True:
  29.         areas = []
  30.         ret, frame = cap.read()
  31.         newcameramtx, roi=cv2.getOptimalNewCameraMatrix(left_camera_matrix,left_distortion,(frame_w,frame_h),1,(frame_w,frame_h))
  32.       
  33.         if DEBUG_MODE == True:
  34.             COLOR_THR = cv2.getTrackbarPos('cl_thr','win_control')
  35.             HIGHTLIGHT_THR = cv2.getTrackbarPos('hl_thr','win_control')
  36.         # matRotate = cv2.getRotationMatrix2D((frame_w*0.5, frame_h*0.5), 180, 1.0)
  37.         # frame = cv2.warpAffine(frame, matRotate, (frame_w,frame_h))
  38.         gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
  39.         blur = cv2.GaussianBlur(gray, (3,3), 0)
  40.         ret,imged = cv2.threshold(blur,HIGHTLIGHT_THR,255, cv2.THRESH_BINARY)
  41.         kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (8, 10)) # (5,7)
  42.         highlight_img = cv2.dilate(imged, kernel)
  43.         (b,g,r) = cv2.split(frame)
  44.         #COLOR_TYPE = GPIO.input(DETECT_GPIO_PIN)#设置引脚模式:
  45.         COLOR_TYPE=0
  46.         if COLOR_TYPE == 0: # 红方
  47.             sub_rg = cv2.subtract(r, g)
  48.             sub_rb = cv2.subtract(r, b)
  49.             ret,res_rg = cv2.threshold(sub_rg,COLOR_THR,255, cv2.THRESH_BINARY)
  50.             ret,res_rb = cv2.threshold(sub_rb,COLOR_THR,255, cv2.THRESH_BINARY)
  51.             final = cv2.bitwise_and(res_rg,res_rb)   
  52.         else: # 蓝方
  53.             sub_bg = cv2.subtract(b, g)
  54.             sub_br = cv2.subtract(b, r)
  55.             ret,res_bg = cv2.threshold(sub_bg,COLOR_THR,255, cv2.THRESH_BINARY)
  56.             ret,res_br = cv2.threshold(sub_br,COLOR_THR,255, cv2.THRESH_BINARY)
  57.             final = cv2.bitwise_and(res_bg,res_br)
  58.         kernelx = cv2.getStructuringElement(cv2.MORPH_RECT, (8, 8))
  59.         color_img = cv2.dilate(final, kernelx)
  60.         kernele = cv2.getStructuringElement(cv2.MORPH_RECT, (7, 7))
  61.         preprocessed = cv2.bitwise_and(color_img,highlight_img)
  62.         preprocessed = cv2.dilate(preprocessed, kernele)
  63.         contours, hierarchy = cv2.findContours(preprocessed, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
  64.         cv2.drawContours(frame,contours,-1,(255,0,0),2)
  65.         
  66.         for contour in contours:
  67.             areas.append(cv2.contourArea(contour))
  68.             try:
  69.                 max_id = areas.index(max(areas))
  70.             except:
  71.                 continue
  72.             x, y, w, h = cv2.boundingRect(contours[max_id])
  73.             if ( w * h > 1000 ) :
  74.                 thetaX = degrees(atan2(x-left_camera_matrix[0][2],left_camera_matrix[0][0]))
  75.                 thetaY = degrees(atan2(y-left_camera_matrix[1][2],left_camera_matrix[1][1]))
  76.                 dist = distance_to_camera(w)
  77.                 yield(thetaX,thetaY,dist)
  78.                 # 绘制
  79.                 cv2.rectangle(frame, (x,y), (x+w,y+h), (0,255,255), 2)
  80.         cv2.circle(frame,gun_point,5,(0,0,255),-1)
  81.         cv2.imshow("orgin_pic", frame)
  82.         if DEBUG_MODE == True:
  83.             cv2.imshow("hl_pic",highlight_img)
  84.             cv2.imshow("cl_pic",color_img)
  85.             cv2.imshow("final_pic", preprocessed)
  86.             cv2.waitKey(1)
  87.         if cv2.waitKey(1) & 0xFF == ord('q'):
  88.             break
  89.         
  90. if __name__ == "__main__":
  91.    
  92.     #ser = serial.Serial(PORT_NAME,BAUD_RATE,timeout=50)
  93.     fire = 0
  94.     #GPIO.setmode(GPIO.BOARD)#设置引脚模式:
  95.     #GPIO.setup(DETECT_GPIO_PIN, GPIO.IN)#设置引脚为输入:
  96.     for (yaw,pitch,dist) in aim():
  97.         yaw2=yaw
  98.         pitch=pitch-2
  99.         pitch2=pitch
  100.         if ( abs(yaw) < 1.5 ) :
  101.             yaw = 0
  102.         if ( abs(pitch) < 1.5 ):
  103.             pitch = 0
  104.         if abs(yaw2) and abs(pitch2)<2.5:
  105.             fire = 1
  106.         else:
  107.             fire = 0
  108.         print("%d,%.2f,%.2f,%.2f,%d" % (COLOR_TYPE,yaw,pitch,dist,fire))import cv2
  109. #import serial
  110. from math import *
  111. from user_config import *
  112. #import RPi.GPIO as GPIO
  113. # 距离计算函数
  114. def distance_to_camera(perWidth):  
  115.     return (ARMOUR_WIDTH * FOCAL_LENS) / perWidth      
  116.    
  117. def aim():
  118.     global DEBUG_MODE,COLOR_TYPE,HIGHTLIGHT_THR,COLOR_THR
  119.     cap = cv2.VideoCapture(VIDEO_INDEX) # 打开摄像头
  120.     frame_h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) # 480
  121.     frame_w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) # 640
  122.     gun_point = (int(frame_w/2),int(frame_h/2) + GUN_ERROR)
  123.     if DEBUG_MODE == True:
  124.         def get_pixel(event,x,y,flags,param):
  125.             if event == cv2.EVENT_LBUTTONDBLCLK:
  126.                 print(x,y)
  127.         cv2.setMouseCallback('orgin_pic',get_pixel)
  128.         def nothing():
  129.             pass
  130.         cv2.namedWindow("win_control")
  131.         cv2.createTrackbar('hl_thr','win_control',0,255,nothing)
  132.         cv2.createTrackbar('cl_thr','win_control',0,255,nothing)
  133.         cv2.setTrackbarPos('hl_thr','win_control',HIGHTLIGHT_THR)
  134.         cv2.setTrackbarPos('cl_thr','win_control',COLOR_THR)
  135.     while True:
  136.         areas = []
  137.         ret, frame = cap.read()
  138.         newcameramtx, roi=cv2.getOptimalNewCameraMatrix(left_camera_matrix,left_distortion,(frame_w,frame_h),1,(frame_w,frame_h))
  139.       
  140.         if DEBUG_MODE == True:
  141.             COLOR_THR = cv2.getTrackbarPos('cl_thr','win_control')
  142.             HIGHTLIGHT_THR = cv2.getTrackbarPos('hl_thr','win_control')
  143.         # matRotate = cv2.getRotationMatrix2D((frame_w*0.5, frame_h*0.5), 180, 1.0)
  144.         # frame = cv2.warpAffine(frame, matRotate, (frame_w,frame_h))
  145.         gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
  146.         blur = cv2.GaussianBlur(gray, (3,3), 0)
  147.         ret,imged = cv2.threshold(blur,HIGHTLIGHT_THR,255, cv2.THRESH_BINARY)
  148.         kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (8, 10)) # (5,7)
  149.         highlight_img = cv2.dilate(imged, kernel)
  150.         (b,g,r) = cv2.split(frame)
  151.         #COLOR_TYPE = GPIO.input(DETECT_GPIO_PIN)#设置引脚模式:
  152.         COLOR_TYPE=0
  153.         if COLOR_TYPE == 0: # 红方
  154.             sub_rg = cv2.subtract(r, g)
  155.             sub_rb = cv2.subtract(r, b)
  156.             ret,res_rg = cv2.threshold(sub_rg,COLOR_THR,255, cv2.THRESH_BINARY)
  157.             ret,res_rb = cv2.threshold(sub_rb,COLOR_THR,255, cv2.THRESH_BINARY)
  158.             final = cv2.bitwise_and(res_rg,res_rb)   
  159.         else: # 蓝方
  160.             sub_bg = cv2.subtract(b, g)
  161.             sub_br = cv2.subtract(b, r)
  162.             ret,res_bg = cv2.threshold(sub_bg,COLOR_THR,255, cv2.THRESH_BINARY)
  163.             ret,res_br = cv2.threshold(sub_br,COLOR_THR,255, cv2.THRESH_BINARY)
  164.             final = cv2.bitwise_and(res_bg,res_br)
  165.         kernelx = cv2.getStructuringElement(cv2.MORPH_RECT, (8, 8))
  166.         color_img = cv2.dilate(final, kernelx)
  167.         kernele = cv2.getStructuringElement(cv2.MORPH_RECT, (7, 7))
  168.         preprocessed = cv2.bitwise_and(color_img,highlight_img)
  169.         preprocessed = cv2.dilate(preprocessed, kernele)
  170.         contours, hierarchy = cv2.findContours(preprocessed, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
  171.         cv2.drawContours(frame,contours,-1,(255,0,0),2)
  172.         
  173.         for contour in contours:
  174.             areas.append(cv2.contourArea(contour))
  175.             try:
  176.                 max_id = areas.index(max(areas))
  177.             except:
  178.                 continue
  179.             x, y, w, h = cv2.boundingRect(contours[max_id])
  180.             if ( w * h > 1000 ) :
  181.                 thetaX = degrees(atan2(x-left_camera_matrix[0][2],left_camera_matrix[0][0]))
  182.                 thetaY = degrees(atan2(y-left_camera_matrix[1][2],left_camera_matrix[1][1]))
  183.                 dist = distance_to_camera(w)
  184.                 yield(thetaX,thetaY,dist)
  185.                 # 绘制
  186.                 cv2.rectangle(frame, (x,y), (x+w,y+h), (0,255,255), 2)
  187.         cv2.circle(frame,gun_point,5,(0,0,255),-1)
  188.         cv2.imshow("orgin_pic", frame)
  189.         if DEBUG_MODE == True:
  190.             cv2.imshow("hl_pic",highlight_img)
  191.             cv2.imshow("cl_pic",color_img)
  192.             cv2.imshow("final_pic", preprocessed)
  193.             cv2.waitKey(1)
  194.         if cv2.waitKey(1) & 0xFF == ord('q'):
  195.             break
  196.         
  197. if __name__ == "__main__":
  198.    
  199.     #ser = serial.Serial(PORT_NAME,BAUD_RATE,timeout=50)
  200.     fire = 0
  201.     #GPIO.setmode(GPIO.BOARD)#设置引脚模式:
  202.     #GPIO.setup(DETECT_GPIO_PIN, GPIO.IN)#设置引脚为输入:
  203.     for (yaw,pitch,dist) in aim():
  204.         yaw2=yaw
  205.         pitch=pitch-2
  206.         pitch2=pitch
  207.         if ( abs(yaw) < 1.5 ) :
  208.             yaw = 0
  209.         if ( abs(pitch) < 1.5 ):
  210.             pitch = 0
  211.         if abs(yaw2) and abs(pitch2)<2.5:
  212.             fire = 1
  213.         else:
  214.             fire = 0
  215.         print("%d,%.2f,%.2f,%.2f,%d" % (COLOR_TYPE,yaw,pitch,dist,fire))
复制代码
  1. import numpy as np
  2. PORT_NAME = "COM8" # 串口名称
  3. BAUD_RATE = 115200
  4. VIDEO_INDEX = 0 # 摄像头索引
  5. DEBUG_MODE = False
  6. COLOR_TYPE = 0 # 灯条颜色参数,0为红,1为蓝
  7. HIGHTLIGHT_THR = 190 # 高光通道阈值
  8. COLOR_THR = 80 # 颜色通道饱和度阈值
  9. ARMOUR_WIDTH =  55 # 装甲板宽度,mm
  10. ARMOUR_HEIGHT = 35 # 装甲板高度,mm
  11. RATE = ARMOUR_WIDTH / ARMOUR_HEIGHT # 长宽比
  12. ERROR = 0.1 # 识别到的长宽比误差
  13. RATE_RANGE = ( RATE - ERROR , RATE + ERROR ) # 误差范围
  14. FOCAL_LENS = 618.34872 # 焦距,mm
  15. GUN_ERROR = -60 # 枪口pitch轴误差
  16. DETECT_GPIO_PIN = 23 # 检测的GPIO引脚
  17. #  内参矩阵
  18. left_camera_matrix = np.array([[618.34872, 0., 315.38874],
  19.                                [0., 613.77151, 166.87870],
  20.                                [0., 0., 1.]])
  21. # 畸变系数
  22. left_distortion = np.array([[-0.39063 , 0.18552 , 0.00857 , -0.00777, 0.00000]])
复制代码


WedSeptember-202209072548..png
WedSeptember-202209078790..png
WedSeptember-202209079085..png

帅猫  高级技师

发表于 2022-9-9 20:18:13

EP不需要使用额外的摄像头,通过wifi连接后可以通过TCP获取视频流数据。
还有EP的车轮螺丝是红色的,你这个不支持二次开发的S1不是EP,至于为什么带拓展基板我就不知道了,或许你还藏着另一台EP或者厂家给你发了黑色螺丝?
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4

© 2013-2024 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail