关于2021年国赛F题送药小车OpenMv巡线代码的注释

最近在看送药小车用OpenMv巡线的代码,正好看到http://t.csdn.cn/3ad9D这篇文章的代码,博主非常赞,直接把全部代码贴了出来,但是关于main函数函数注释比较少,所以看的比较困难,所以我想对这代码做一些注释,让自己能够有一个更好的理解,方便让大家阅读。话不多说,开始贴代码。

GeometryFeature.py

class GeometryFeature:

    def __init__(self, img):
        self.img = img

    def trans_line_format(line):
        '''
        将原来由两点坐标确定的直线,转换为 y = ax + b 的格式
        '''
        x1 = line.x1()
        y1 = line.y1()
        x2 = line.x2()
        y2 = line.y2()

        if x1 == x2:
            # 避免完全垂直,x坐标相等的情况
            x1 += 0.1
        # 计算斜率 a
        a = (y2 - y1) / (x2 - x1)
        # 计算常数项 b
        # y = a*x + b -> b = y - a*x
        b = y1 - a * x1
        return a,b

    def calculate_angle(line1, line2):
        '''
        利用四边形的角公式, 计算出直线夹角
        '''
        angle  = (180 - abs(line1.theta() - line2.theta()))
        if angle > 90:
            angle = 180 - angle
        return angle
    def find_verticle_lines(lines, angle_threshold=(70, 90)):
        '''
        寻找相互垂直的两条线
        '''
        return GeometryFeature.find_interserct_lines(lines, angle_threshold=angle_threshold)

    def find_interserct_lines(lines, angle_threshold=(10,90), window_size=None):
        '''
        根据夹角阈值寻找两个相互交叉的直线, 且交点需要存在于画面中
        '''
        line_num = len(lines)
        for i in range(line_num -1):
            for j in range(i, line_num):
                # 判断两个直线之间的夹角是否为直角
                angle = GeometryFeature.calculate_angle(lines[i], lines[j])
                # 判断角度是否在阈值范围内
                if not(angle >= angle_threshold[0] and angle <=  angle_threshold[1]):
                    continue

                # 判断交点是否在画面内
                if window_size is not None:
                    # 获取串口的尺寸 宽度跟高度
                    win_width, win_height = window_size
                    # 获取直线交点
                    intersect_pt = GeometryFeature.calculate_intersection(lines[i], lines[j])
                    if intersect_pt is None:
                        # 没有交点
                        continue
                    x, y = intersect_pt
                    if not(x >= 0 and x < win_width and y >= 0 and y < win_height):
                        # 交点如果没有在画面中
                        continue
                return (lines[i], lines[j])
        return None

    def calculate_intersection(line1, line2):
        '''
        计算两条线的交点
        '''
        a1 = line1.y2() - line1.y1()
        b1 = line1.x1() - line1.x2()
        c1 = line1.x2()*line1.y1() - line1.x1()*line1.y2()

        a2 = line2.y2() - line2.y1()
        b2 = line2.x1() - line2.x2()
        c2 = line2.x2() * line2.y1() - line2.x1()*line2.y2()

        if (a1 * b2 - a2 * b1) != 0 and (a2 * b1 - a1 * b2) != 0:
            cross_x = int((b1*c2-b2*c1)/(a1*b2-a2*b1))
            cross_y = int((c1*a2-c2*a1)/(a1*b2-a2*b1))
            return (cross_x, cross_y)
        return None

redlinemain.py

import sensor
import image
import time
import math
import pyb
from pyb import Pin, Timer,LED
from GeometryFeature import GeometryFeature
LED(4).on()
is_debug = True
DISTORTION_FACTOR = 1.5#畸变矫正因子
IMG_WIDTH  = 64#像素点宽度
IMG_HEIGHT = 64#像素点高度
def init_sensor():#初始化感光器
    sensor.reset()
    sensor.set_pixformat(sensor.GRAYSCALE)#设置为灰度图
    sensor.set_framesize(sensor.B64X64)  #设置像素大小
    sensor.skip_frames(time=2000)        #最大像素点个数
    sensor.set_auto_gain(False)          #颜色追踪关闭自动增益
    sensor.set_auto_whitebal(False)      #颜色追踪关闭自动白平衡
init_sensor()
INTERSERCT_ANGLE_THRESHOLD = (45,90)     #设置角度阈值
LINE_COLOR_THRESHOLD = [(0, 120)]        #设置巡线的颜色阈值
ROIS = {                                 #ROIS将镜头的画面分割为5个区域分别找寻色块
    'down': (0, 55, 64, 8),
    'middle': (0, 28, 64, 8),
    'up': (0, 0, 64, 8),
    'left': (0, 0, 8, 64),
    'right': (56, 0, 8, 64)
}
def find_blobs_in_rois(img): #在ROIS中寻找色块,获取ROI中色块的中心区域与是否有色块的信息
    global ROIS
    global is_debug
    roi_blobs_result = {}#定义dict
    for roi_direct in ROIS.keys():#遍历dict中的键
        roi_blobs_result[roi_direct] = {
            'cx': -1,
            'cy': -1,
            'blob_flag': False
        }
    for roi_direct, roi in ROIS.items():#遍历dict中每一组的键与值
        blobs=img.find_blobs(LINE_COLOR_THRESHOLD, roi=roi, merge=True, pixels_area=10)
        if len(blobs) == 0:#如果没有找到
            continue
        largest_blob = max(blobs, key=lambda b: b.pixels())#lambda函数,值为b色块的像素值
        x,y,width,height = largest_blob[:4]
        if not(width >=5 and width <= 15 and height >= 5 and height <= 15):
            continue
        roi_blobs_result[roi_direct]['cx'] = largest_blob.cx()
        roi_blobs_result[roi_direct]['cy'] = largest_blob.cy()
        roi_blobs_result[roi_direct]['blob_flag'] = True
        if is_debug:#if true
            img.draw_rectangle((x,y,width, height), color=(127))
    return roi_blobs_result#返回最大色块的cx,cy值
def visualize_result(canvas, cx_mean, cx, cy, is_turn_left, is_turn_right, is_t, is_cross):#此函数作用为将判断的结果用直线或圆或其他圈出来
          #可视化结果
    
    if not(is_turn_left or is_turn_right or is_t or is_cross):#当处在直线时
        mid_x = int(canvas.width()/2)
        mid_y = int(canvas.height()/2)
        print("mid_x= %d,cx_mean= %d,mid_x-cx_mean =%dsd       ",mid_x,cx_mean,(mid_x-cx_mean)*2)
        canvas.draw_circle(int(cx_mean), mid_y, 5, color=(255))
        canvas.draw_circle(mid_x, mid_y, 8, color=(0))
        canvas.draw_line((mid_x, mid_y, int(cx_mean), mid_y), color=(255))

    turn_type = 'N'   #判断为直线
    if is_t or is_cross:#当在T字或十字路口时
        canvas.draw_cross(int(cx), int(cy), size=10, color=(255))
        canvas.draw_circle(int(cx), int(cy), 5, color=(255))
    if is_t:
        turn_type = 'T'  #判断为T字路口
    elif is_cross:
        turn_type = 'C'  #判断为十字路口
    canvas.draw_string(0, 0, turn_type, color=(0))
last_cx = 0
last_cy = 0
while True:
    img = sensor.snapshot()     #拍取一张图片
    img.lens_corr(DISTORTION_FACTOR)  #进行镜头畸形矫正,里面的参数是进行鱼眼矫正的程度
    lines = img.find_lines(threshold=1000, theta_margin = 50, rho_margin = 50)
    intersect_pt = GeometryFeature.find_interserct_lines(lines, angle_threshold=(45,90), window_size=(IMG_WIDTH, IMG_HEIGHT))#GeometryFeature文件中的找直线交点的函数
    if intersect_pt is None:
        intersect_x = 0
        intersect_y = 0
    else:
        intersect_x, intersect_y = intersect_pt
    reslut = find_blobs_in_rois(img)
    is_turn_left = False
    is_turn_right = False
#转弯命令仅由单片机发出,openmv作用仅为发送数据,故可注释掉
    #if (not reslut['up']['blob_flag'] ) and reslut['down']['blob_flag']:
      #  if reslut['left']['blob_flag']:
          #  is_turn_left = True
       # if reslut['right']['blob_flag']:
         #   is_turn_right = True
    is_t = False
    is_cross = False
    cnt = 0
    for roi_direct in ['up', 'down', 'left', 'right']:#遍历上下左右
        if reslut[roi_direct]['blob_flag']:#当识别到其中一个便可以+1
            cnt += 1
    is_t = cnt == 3#识别到了T字路口,即识别到三个
    is_cross = cnt == 4#识别到了十字路口,即识别到四个
    cx_mean = 0
    for roi_direct in ['up', 'down', 'middle']:#遍历上中下
        if reslut[roi_direct]['blob_flag']:#每识别到一个中心横坐标相加
            cx_mean += reslut[roi_direct]['cx']
        else:#否则识别色块的一半的长相累加
            cx_mean += IMG_WIDTH / 2#像素宽度除以2
    cx_mean /= 3  #表示为直线时区域的中心x坐标#累加之和除以三即得平均坐标
    cx = 0        #cx,cy表示当测到为T型或者十字型的时候计算的交叉点的坐标
    cy = 0
    if is_cross or is_t:#当识别到T字或者十字路口
        cnt = 0
        for roi_direct in ['up', 'down']:
            if reslut[roi_direct]['blob_flag']:
                cnt += 1#cnt作用为计数,累计识别到了几个,最终cx的累加除以该数便是平均值
                cx += reslut[roi_direct]['cx']
        if cnt == 0:
            cx = last_cx
        else:
            cx /= cnt
        cnt = 0
        for roi_direct in ['left', 'right']:
            if reslut[roi_direct]['blob_flag']:
                cnt += 1
                cy += reslut[roi_direct]['cy']
        if cnt == 0:#即没有识别到
            cy = last_cy#返回为0
        else:
            cy /= cnt
    last_cx = cx
    last_cy = cy
    if is_debug:
        visualize_result(img, cx_mean, cx, cy, is_turn_left, is_turn_right, is_t, is_cross)

如有不对,欢迎大家指正!

注解:

关于dict(字典):

1、items()方法将字典里对应的一对键和值以元组的形式(键, 值),存储为所生成序列里的单个元素
2、keys()方法将字典里的每个键以字符串的形式,存储为所生成序列里的单个元素
3、values()方法将字典里的每个值以字符串的形式,存储为所生成序列里的单个元素

关于lambda:

lambda argument_list: expression

其中,lambda是Python预留的关键字,argument_list和expression由用户自定义。

1. 这里的argument_list是参数列表,它的结构与Python中函数(function)的参数列表是一样的。具体来说,argument_list可以有非常多的形式。例如:

  • a, b
  • a=1, b=2
  •  *args
  •  **kwargs
  •  a, b=1, *args

2. 这里的expression是一个关于参数的表达式。表达式中出现的参数需要在argument_list中有定义,并且表达式只能是单行的。以下都是合法的表达式:

1
 None
a + b
sum(a)
1 if a >10 else 0
 ......
3.  这里的lambda argument_list: expression表示的是一个函数。这个函数叫做lambda函数。

猜你喜欢

转载自blog.csdn.net/qq_62185266/article/details/125817164
今日推荐