k210 table tennis recognition module table tennis recognition program-first edition

import sensor, image, time,lcd,utime
from machine import UART
from fpioa_manager import fm

fm.register(10, fm.fpioa.UART1_TX, force=True)#映射串口引脚
fm.register(9, fm.fpioa.UART1_RX, force=True)#映射串口引脚

uart = UART(UART.UART1, 115200, 8, 0, 0, timeout=1000, read_buf_len=4096)

clock = time.clock()
lcd.init() #显示屏初始化
sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QQVGA) #QQVGA: 160x120、QVGA: 320x240、
sensor.run(1)
sensor.skip_frames(20)#跳过刚启动开始的30帧照片
lcd.rotation(2)#LCD屏幕翻转,范围是0~3,上和下反转,左和右反转
sensor.set_hmirror(True)#摄像头镜像
sensor.set_auto_gain(False) # must be turned off for color tracking
sensor.set_auto_whitebal(False) # must be turned off for color tracking,关闭白平衡

#sensor.set_brightness(3) #-3至+3,亮度越大,图片越亮
#sensor.set_saturation(2)#-3至+3,饱和度越大,色彩越鲜艳
#sensor.set_contrast(2)#-3至+3,对比度越大,颜色之间的反差越大

def find_max(blobs):
    max_size=0
    for blob in blobs:
        if blob[2]*blob[3] > max_size:
            max_blob=blob
            max_size = blob[2]*blob[3]
    return max_blob
    

#存放不同的颜色阈值,依次为白色、黄色、绿色
color = ((99, 100, -4, 4, -3, 3),(50, 96, -28, 18, 48, 90))
size_threshold = 4500 #若检测到的小球框的面积小于size_threshold表明小球距离小车太远,小车需要前进。这个参数的大小需要根据实际情况修改
target=()
flag = 0 #用于标记一个while循环中是否检测到小球,falg==1表示本轮发现了小球
count = 0
bug_open = False # True or False
previous_ball_location = 'r'
location_count=0 #用来防止误识别,保持识别结果的稳定性

def stable_output(location):
    global location_count,previous_ball_location
    if previous_ball_location != location:
        location_count = 1
        previous_ball_location = location
    else:
        location_count = location_count + 1
    if location_count >=2:
        uart.write(location) #通过串口向外发送数据,控制小车向location方向运动
        #print(location)
        
clock.tick()#开始追踪运行时间。
#print("FPS %f" % clock.fps())#停止追踪运行时间,并返回当前FPS(每秒帧数)。在调用该函数前始终首先调用 tick 。

while(True):
    img = sensor.snapshot().histeq(adaptive=True, clip_limit=3)
    img.lens_corr(1.8) #镜头畸变矫正(lens correction),lens_corr 为了去除畸变, 1.8 是默认参数,可以根据自己实际情况调整
    
    #专门检测黄色小球
    blobs = img.find_blobs([color[1]])
    if blobs:
        max_blob = find_max(blobs)
        x_error = max_blob[5]-img.width()/2#若x_error<0,则说明小球在左边,小车需要左转,若x_error>0,则说明小球在右边,小车需要右转
        h_error = max_blob[2]*max_blob[3]-size_threshold#若h_error<0,则小车距离小球还有距离,需要前进。
        
        if(x_error<-10 and max_blob.density()>0.5 and 70>max_blob.w()>10):#设为-5是留有一定的误差空间,因为不一定小球非要在正中间才能被收集
            stable_output('l')
            #if previous_ball_location != 'l':
                #location_count = 1
                #previous_ball_location = 'l'
            #else:
                #location_count = location_count + 1
            #if location_count >=5:
                #uart.write('l') #通过串口向外发送数据,控制小车左转
            #utime.sleep_ms(300)
            flag = 1 #标记本轮发现过目标
            lcd.draw_string(10, 10, "Left", lcd.RED, lcd.YELLOW)
            
            if bug_open == True:
                print("黄球,串口发送l,","blob.density(): ", max_blob.density(),"blob.w(): ", max_blob.w())

        if(x_error>10 and max_blob.density()>0.5 and 70>max_blob.w()>10):#设为-5是留有一定的误差空间,因为不一定小球非要在正中间才能被收集
            stable_output('r')
            #uart.write('r') #通过串口向外发送数据,控制小车右转
            #utime.sleep_ms(300)
            flag = 1 #标记本轮发现过目标
            lcd.draw_string(10, 20, "Right", lcd.RED, lcd.WHITE)
            
            if bug_open == True:
                print("黄球,串口发送:r,","blob.density(): ", max_blob.density(),"blob.w(): ", max_blob.w())
            
        if(-10<x_error<10 and h_error<0 and max_blob.density()>0.5 and 70>max_blob.w()>10):
            stable_output('h')
            #uart.write('h') #通过串口向外发送数据,控制小车前进
            #utime.sleep_ms(300)
            flag = 1 #标记本轮发现过目标
            lcd.draw_string(10, 30, "Head", lcd.RED, lcd.GREEN)
            
            if bug_open == True:
                print("黄球,串口发送:h,","blob.density(): ", max_blob.density(),"blob.w(): ", max_blob.w())
    else:
        stable_output('t')
        #uart.write('t') #通过串口向外发送数据,没有持续检测到黄色小球,使小车静止
        if bug_open == True:
            print("无黄,串口发送:t,")
        #print("黄色你好")
        #先识别出圆形,在识别圆的颜色
        #img.find_circles:控制从霍夫变换中监测到的圆。
        #只返回大于或等于 threshold 的圆。意思是图像中太小的圆将被忽视。threshold = 400,控制检测的最小的圆在图像中的尺寸是20*20
        #`x_margin`, `y_margin`, and `r_margin`:控制相似圆的合并,就是说多大范围的圆,将其认为是同一个圆。
        for c in img.find_circles(threshold = 3500, x_margin = 10, y_margin = 10, r_margin = 10,
                r_min = 2, r_max = 100, r_step = 2):
            #area为识别到的圆的区域,即圆的外接矩形框
            area = (c.x()-c.r(), c.y()-c.r(), 2*c.r(), 2*c.r())
            
            #保存检测到的其中一个圆的一些参数,用于控制小车方向的计算
            target = (c.x(), c.y(), c.r())
            
            #像素颜色统计,roi 是感兴趣区域的矩形元组(x,y,w,h)。如果未指定,ROI即整个图像的图像矩形。操作范围仅限于 roi 区域内的像素。                
            statistics = img.get_statistics(roi=area)
            #print(statistics)
            
            #(0,100,0,120,0,120)是红色的阈值,所以当区域内的众数(也就是最多的颜色),范围在这个阈值内,就说明是红色的圆。
            #l_mode(),a_mode(),b_mode()是L通道,A通道,B通道的众数。
            if color[0][0]<statistics.l_mode()<color[0][1] and color[0][2]<statistics.a_mode()<color[0][3] and color[0][4]<statistics.b_mode()<color[0][5]:#if the circle is red
                img.draw_circle(c.x(), c.y(), c.r(), color = (255, 255, 255))#识别到的白色圆形用白色的圆框出来
                #保存检测到的其中一个圆的一些参数,用于控制小车方向的计算
                target = (c.x(), c.y(), c.r())
            #elif color[1][0]<statistics.l_mode()<color[1][1] and color[1][2]<statistics.a_mode()<color[1][3] and color[1][4]<statistics.b_mode()<color[1][5]:#if the circle is red
                #img.draw_circle(c.x(), c.y(), c.r(), color = (255, 255, 0))#识别到的黄色圆形用黄色的圆框出来
                ##保存检测到的其中一个圆的一些参数,用于控制小车方向的计算
                #target = (c.x(), c.y(), c.r())
            else:
                img.draw_rectangle(area, color = (0, 0, 0))
                #将其他颜色的圆用黑色的矩形框出来
        if target:
            flag = 1 #标记本轮发现过目标
            #一张图只保留一个小球的信息,只追一个小球
            x_error = target[0]-img.width()/2 #若x_error<0,则说明小球在左边,小车需要左转,若x_error>0,则说明小球在右边,小车需要右转
            h_error = 2*target[2]*2*target[2]-size_threshold #若h_error<0,则小车距离小球还有距离,需要前进。
            
            if(x_error<-10):#设为-5是留有一定的误差空间,因为不一定小球非要在正中间才能被收集
                stable_output('l')
                #uart.write('l') #通过串口向外发送数据,控制小车左转
                
                if bug_open == True:
                    print("白球,左转,发串口:l")
                lcd.draw_string(10, 10, "Left", lcd.RED, lcd.YELLOW)
            if(x_error>10):#设为-5是留有一定的误差空间,因为不一定小球非要在正中间才能被收集
                stable_output('r')
                #uart.write('r') #通过串口向外发送数据,控制小车右转
                
                if bug_open == True:
                    print("白球,右转,发串口:r")
                lcd.draw_string(10, 20, "Right", lcd.RED, lcd.WHITE)
            if(10>x_error>-10 and h_error<0):
                stable_output('h')
                #uart.write('h') #通过串口向外发送数据,控制小车前进
                
                if bug_open == True:
                    print("白球,前进,发串口:h")
                lcd.draw_string(10, 30, "Head", lcd.RED, lcd.GREEN)
        else:
            stable_output('t')
            #uart.write('t') #通过串口向外发送数据,没有持续检测到白色小球,使小车静止
            
            if bug_open == True:
                print("无白色球,发串口:t")
        target=()#清空target

    if flag == 0:
        count = count+1
        if count%10 == 0:
            uart.write('s')
            utime.sleep_ms(100)
            uart.write('n') #通过串口向外发送数据,没有检测到黄色或白色小球
            
            if bug_open == True:
                print("视野无球,发串口:n")
            lcd.draw_string(250, 10, "FPS %f" % clock.fps(), lcd.BLACK, lcd.RED)
            count = 0
    flag = 0 #重置标记
    if bug_open == True:
        #print("FPS %f" % clock.fps())#停止追踪运行时间,并返回当前FPS(每秒帧数)。在调用该函数前始终首先调用 tick 。
        print("flag:",flag,"count:",count)
    lcd.display(img) #LCD 显示图片
    

Lite

import sensor, image, time,lcd,utime
from machine import UART
from fpioa_manager import fm

fm.register(10, fm.fpioa.UART1_TX, force=True)#映射串口引脚
fm.register(9, fm.fpioa.UART1_RX, force=True)#映射串口引脚

uart = UART(UART.UART1, 115200, 8, 0, 0, timeout=1000, read_buf_len=4096)

clock = time.clock()
lcd.init() #显示屏初始化
sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QQVGA) #QQVGA: 160x120、QVGA: 320x240、
sensor.run(1)
sensor.skip_frames(20)#跳过刚启动开始的30帧照片
lcd.rotation(2)#LCD屏幕翻转,范围是0~3,上和下反转,左和右反转
sensor.set_hmirror(True)#摄像头镜像
sensor.set_auto_gain(False) # must be turned off for color tracking
sensor.set_auto_whitebal(False) # must be turned off for color tracking,关闭白平衡

#sensor.set_brightness(3) #-3至+3,亮度越大,图片越亮
#sensor.set_saturation(2)#-3至+3,饱和度越大,色彩越鲜艳
#sensor.set_contrast(2)#-3至+3,对比度越大,颜色之间的反差越大

def find_max(blobs):
    max_size=0
    for blob in blobs:
        if blob[2]*blob[3] > max_size:
            max_blob=blob
            max_size = blob[2]*blob[3]
    return max_blob
    

#存放不同的颜色阈值,依次为白色、黄色、绿色
color = ((99, 100, -4, 4, -3, 3),(50, 96, -28, 18, 48, 90))
size_threshold = 4500 #若检测到的小球框的面积小于size_threshold表明小球距离小车太远,小车需要前进。这个参数的大小需要根据实际情况修改
target=()
flag = 0 #用于标记一个while循环中是否检测到小球,falg==1表示本轮发现了小球
count = 0
bug_open = False # True or False
previous_ball_location = 'r'
location_count=0 #用来防止误识别,保持识别结果的稳定性

def stable_output(location):
    global location_count,previous_ball_location
    if previous_ball_location != location:
        location_count = 1
        previous_ball_location = location
    else:
        location_count = location_count + 1
    if location_count >=2:
        uart.write(location) #通过串口向外发送数据,控制小车向location方向运动
        #print(location)
        
clock.tick()#开始追踪运行时间。
#print("FPS %f" % clock.fps())#停止追踪运行时间,并返回当前FPS(每秒帧数)。在调用该函数前始终首先调用 tick 。

while(True):
    clock.tick()#开始追踪运行时间。
    img = sensor.snapshot().histeq(adaptive=True, clip_limit=3)
    img.lens_corr(1.8) #镜头畸变矫正(lens correction),lens_corr 为了去除畸变, 1.8 是默认参数,可以根据自己实际情况调整
    
    #专门检测黄色小球
    blobs = img.find_blobs([color[1]])
    if blobs:
        max_blob = find_max(blobs)
        x_error = max_blob[5]-img.width()/2#若x_error<0,则说明小球在左边,小车需要左转,若x_error>0,则说明小球在右边,小车需要右转
        h_error = max_blob[2]*max_blob[3]-size_threshold#若h_error<0,则小车距离小球还有距离,需要前进。
        
        if(x_error<-10 and max_blob.density()>0.5 and 70>max_blob.w()>10):#设为-5是留有一定的误差空间,因为不一定小球非要在正中间才能被收集
            stable_output('l')

            flag = 1 #标记本轮发现过目标
            #lcd.draw_string(10, 10, "Left", lcd.RED, lcd.YELLOW)
            
            #if bug_open == True:
                #print("黄球,串口发送l,","blob.density(): ", max_blob.density(),"blob.w(): ", max_blob.w())

        if(x_error>10 and max_blob.density()>0.5 and 70>max_blob.w()>10):#设为-5是留有一定的误差空间,因为不一定小球非要在正中间才能被收集
            stable_output('r')
            #uart.write('r') #通过串口向外发送数据,控制小车右转
            #utime.sleep_ms(300)
            flag = 1 #标记本轮发现过目标
            #lcd.draw_string(10, 20, "Right", lcd.RED, lcd.WHITE)
            
            #if bug_open == True:
                #print("黄球,串口发送:r,","blob.density(): ", max_blob.density(),"blob.w(): ", max_blob.w())
            
        if(-10<x_error<10 and h_error<0 and max_blob.density()>0.5 and 70>max_blob.w()>10):
            stable_output('h')
            #uart.write('h') #通过串口向外发送数据,控制小车前进
            #utime.sleep_ms(300)
            flag = 1 #标记本轮发现过目标
            #lcd.draw_string(10, 30, "Head", lcd.RED, lcd.GREEN)
            
            #if bug_open == True:
                #print("黄球,串口发送:h,","blob.density(): ", max_blob.density(),"blob.w(): ", max_blob.w())
    else:
        #stable_output('t')
        #uart.write('t') #通过串口向外发送数据,没有持续检测到黄色小球,使小车静止
        #if bug_open == True:
            #print("无黄,串口发送:t,")
        #print("黄色你好")
        #先识别出圆形,在识别圆的颜色
        #img.find_circles:控制从霍夫变换中监测到的圆。
        #只返回大于或等于 threshold 的圆。意思是图像中太小的圆将被忽视。threshold = 400,控制检测的最小的圆在图像中的尺寸是20*20
        #`x_margin`, `y_margin`, and `r_margin`:控制相似圆的合并,就是说多大范围的圆,将其认为是同一个圆。
        for c in img.find_circles(threshold = 3500, x_margin = 10, y_margin = 10, r_margin = 10,
                r_min = 2, r_max = 100, r_step = 2):
            #area为识别到的圆的区域,即圆的外接矩形框
            area = (c.x()-c.r(), c.y()-c.r(), 2*c.r(), 2*c.r())
            
            #保存检测到的其中一个圆的一些参数,用于控制小车方向的计算
            target = (c.x(), c.y(), c.r())
            
            #像素颜色统计,roi 是感兴趣区域的矩形元组(x,y,w,h)。如果未指定,ROI即整个图像的图像矩形。操作范围仅限于 roi 区域内的像素。                
            statistics = img.get_statistics(roi=area)
            #print(statistics)
            
            #(0,100,0,120,0,120)是红色的阈值,所以当区域内的众数(也就是最多的颜色),范围在这个阈值内,就说明是红色的圆。
            #l_mode(),a_mode(),b_mode()是L通道,A通道,B通道的众数。
            if color[0][0]<statistics.l_mode()<color[0][1] and color[0][2]<statistics.a_mode()<color[0][3] and color[0][4]<statistics.b_mode()<color[0][5]:#if the circle is red
                img.draw_circle(c.x(), c.y(), c.r(), color = (255, 255, 255))#识别到的白色圆形用白色的圆框出来
                #保存检测到的其中一个圆的一些参数,用于控制小车方向的计算
                target = (c.x(), c.y(), c.r())
            #elif color[1][0]<statistics.l_mode()<color[1][1] and color[1][2]<statistics.a_mode()<color[1][3] and color[1][4]<statistics.b_mode()<color[1][5]:#if the circle is red
                #img.draw_circle(c.x(), c.y(), c.r(), color = (255, 255, 0))#识别到的黄色圆形用黄色的圆框出来
                ##保存检测到的其中一个圆的一些参数,用于控制小车方向的计算
                #target = (c.x(), c.y(), c.r())
            else:
                img.draw_rectangle(area, color = (0, 0, 0))
                #将其他颜色的圆用黑色的矩形框出来
        if target:
            flag = 1 #标记本轮发现过目标
            #一张图只保留一个小球的信息,只追一个小球
            x_error = target[0]-img.width()/2 #若x_error<0,则说明小球在左边,小车需要左转,若x_error>0,则说明小球在右边,小车需要右转
            h_error = 2*target[2]*2*target[2]-size_threshold #若h_error<0,则小车距离小球还有距离,需要前进。
            
            if(x_error<-10):#设为-5是留有一定的误差空间,因为不一定小球非要在正中间才能被收集
                stable_output('l')
                #uart.write('l') #通过串口向外发送数据,控制小车左转
                
                #if bug_open == True:
                    #print("白球,左转,发串口:l")
                #lcd.draw_string(10, 10, "Left", lcd.RED, lcd.YELLOW)
            if(x_error>10):#设为-5是留有一定的误差空间,因为不一定小球非要在正中间才能被收集
                stable_output('r')
                #uart.write('r') #通过串口向外发送数据,控制小车右转
                
                #if bug_open == True:
                    #print("白球,右转,发串口:r")
                #lcd.draw_string(10, 20, "Right", lcd.RED, lcd.WHITE)
            if(10>x_error>-10 and h_error<0):
                stable_output('h')
                #uart.write('h') #通过串口向外发送数据,控制小车前进
                
                #if bug_open == True:
                    #print("白球,前进,发串口:h")
                #lcd.draw_string(10, 30, "Head", lcd.RED, lcd.GREEN)
        else:
            stable_output('t')
            #uart.write('t') #通过串口向外发送数据,没有持续检测到白色小球,使小车静止
            
            #if bug_open == True:
                #print("无白色球,发串口:t")
        target=()#清空target

    if flag == 0:
        count = count+1
        if count%10 == 0:
            #uart.write('s')
            #utime.sleep_ms(100)
            uart.write('n') #通过串口向外发送数据,没有检测到黄色或白色小球
            
            #if bug_open == True:
                #print("视野无球,发串口:n")
            #lcd.draw_string(250, 10, "FPS %f" % clock.fps(), lcd.BLACK, lcd.RED)
            count = 0
    flag = 0 #重置标记
    #if bug_open == True:
        ##print("FPS %f" % clock.fps())#停止追踪运行时间,并返回当前FPS(每秒帧数)。在调用该函数前始终首先调用 tick 。
        #print("flag:",flag,"count:",count)
    lcd.display(img) #LCD 显示图片
    print("FPS %f" % clock.fps())#停止追踪运行时间,并返回当前FPS(每秒帧数)。在调用该函数前始终首先调用 tick 。

More streamlined version

import sensor, image, time,lcd,utime
from machine import UART
from fpioa_manager import fm

fm.register(10, fm.fpioa.UART1_TX, force=True)#映射串口引脚
fm.register(9, fm.fpioa.UART1_RX, force=True)#映射串口引脚

uart = UART(UART.UART1, 115200, 8, 0, 0, timeout=1000, read_buf_len=4096)

clock = time.clock()
lcd.init() #显示屏初始化
sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QQVGA) #QQVGA: 160x120、QVGA: 320x240、
sensor.run(1)
sensor.skip_frames(20)#跳过刚启动开始的30帧照片
lcd.rotation(2)#LCD屏幕翻转,范围是0~3,上和下反转,左和右反转
sensor.set_hmirror(True)#摄像头镜像
sensor.set_auto_gain(False) # must be turned off for color tracking
sensor.set_auto_whitebal(False) # must be turned off for color tracking,关闭白平衡

def find_max(blobs):
    max_size=0
    for blob in blobs:
        if blob[2]*blob[3] > max_size:
            max_blob=blob
            max_size = blob[2]*blob[3]
    return max_blob
    

#存放不同的颜色阈值,依次为白色、黄色、绿色
color = ((99, 100, -4, 4, -3, 3),(50, 96, -28, 18, 48, 90))
size_threshold = 4500 #若检测到的小球框的面积小于size_threshold表明小球距离小车太远,小车需要前进。这个参数的大小需要根据实际情况修改
target=()
flag = 0 #用于标记一个while循环中是否检测到小球,falg==1表示本轮发现了小球
count = 0
bug_open = False # True or False
previous_ball_location = 'r'
location_count=0 #用来防止误识别,保持识别结果的稳定性

def stable_output(location):
    global location_count,previous_ball_location
    if previous_ball_location != location:
        location_count = 1
        previous_ball_location = location
    else:
        location_count = location_count + 1
    if location_count >=2:
        uart.write(location) #通过串口向外发送数据,控制小车向location方向运动
        
clock.tick()#开始追踪运行时间。

while(True):
    clock.tick()#开始追踪运行时间。
    img = sensor.snapshot().histeq(adaptive=True, clip_limit=3)
    img.lens_corr(1.8) #镜头畸变矫正(lens correction),lens_corr 为了去除畸变, 1.8 是默认参数,可以根据自己实际情况调整
    
    #专门检测黄色小球
    blobs = img.find_blobs([color[1]])
    if blobs:
        max_blob = find_max(blobs)
        x_error = max_blob[5]-img.width()/2#若x_error<0,则说明小球在左边,小车需要左转,若x_error>0,则说明小球在右边,小车需要右转
        h_error = max_blob[2]*max_blob[3]-size_threshold#若h_error<0,则小车距离小球还有距离,需要前进。
        
        if(x_error<-10 and max_blob.density()>0.5 and 70>max_blob.w()>10):#设为-5是留有一定的误差空间,因为不一定小球非要在正中间才能被收集
            stable_output('l')

            flag = 1 #标记本轮发现过目标
        if(x_error>10 and max_blob.density()>0.5 and 70>max_blob.w()>10):#设为-5是留有一定的误差空间,因为不一定小球非要在正中间才能被收集
            stable_output('r')
            flag = 1 #标记本轮发现过目标
        if(-10<x_error<10 and h_error<0 and max_blob.density()>0.5 and 70>max_blob.w()>10):
            stable_output('h')
            flag = 1 #标记本轮发现过目标
    else:
        for c in img.find_circles(threshold = 3500, x_margin = 10, y_margin = 10, r_margin = 10,
                r_min = 2, r_max = 100, r_step = 2):
            area = (c.x()-c.r(), c.y()-c.r(), 2*c.r(), 2*c.r())
            target = (c.x(), c.y(), c.r())
            statistics = img.get_statistics(roi=area)
            if color[0][0]<statistics.l_mode()<color[0][1] and color[0][2]<statistics.a_mode()<color[0][3] and color[0][4]<statistics.b_mode()<color[0][5]:#if the circle is red
                img.draw_circle(c.x(), c.y(), c.r(), color = (255, 255, 255))#识别到的白色圆形用白色的圆框出来
                #保存检测到的其中一个圆的一些参数,用于控制小车方向的计算
                target = (c.x(), c.y(), c.r())
             else:
                img.draw_rectangle(area, color = (0, 0, 0))
                #将其他颜色的圆用黑色的矩形框出来
        if target:
            flag = 1 #标记本轮发现过目标
            #一张图只保留一个小球的信息,只追一个小球
            x_error = target[0]-img.width()/2 #若x_error<0,则说明小球在左边,小车需要左转,若x_error>0,则说明小球在右边,小车需要右转
            h_error = 2*target[2]*2*target[2]-size_threshold #若h_error<0,则小车距离小球还有距离,需要前进。
            
            if(x_error<-10):#设为-5是留有一定的误差空间,因为不一定小球非要在正中间才能被收集
                stable_output('l')
            if(x_error>10):#设为-5是留有一定的误差空间,因为不一定小球非要在正中间才能被收集
                stable_output('r')
            if(10>x_error>-10 and h_error<0):
                stable_output('h')
        else:
            stable_output('t')
        target=()#清空target

    if flag == 0:
        count = count+1
        if count%10 == 0:
            uart.write('n') #通过串口向外发送数据,没有检测到黄色或白色小球
            count = 0
    flag = 0 #重置标记
    lcd.display(img) #LCD 显示图片
    print("FPS %f" % clock.fps())#停止追踪运行时间,并返回当前FPS(每秒帧数)。在调用该函数前始终首先调用 tick 。、

Improved version:

After improvement, the yellow ball turns off the white balance, and the white ball turns on the white balance (so the accuracy of detecting the white ball is higher).

import sensor, image, time,lcd,utime
from machine import UART
from fpioa_manager import fm

fm.register(10, fm.fpioa.UART1_TX, force=True)#映射串口引脚
fm.register(9, fm.fpioa.UART1_RX, force=True)#映射串口引脚

uart = UART(UART.UART1, 115200, 8, 0, 0, timeout=1000, read_buf_len=4096)

clock = time.clock()
lcd.init() #显示屏初始化
sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QQVGA) #QQVGA: 160x120、QVGA: 320x240、
sensor.run(1)
sensor.skip_frames(20)#跳过刚启动开始的30帧照片
lcd.rotation(2)#LCD屏幕翻转,范围是0~3,上和下反转,左和右反转
sensor.set_hmirror(True)#摄像头镜像
sensor.set_auto_gain(False) # must be turned off for color tracking
#sensor.set_auto_whitebal(False) # must be turned off for color tracking,关闭白平衡

#sensor.set_brightness(3) #-3至+3,亮度越大,图片越亮
#sensor.set_saturation(2)#-3至+3,饱和度越大,色彩越鲜艳
#sensor.set_contrast(2)#-3至+3,对比度越大,颜色之间的反差越大

def find_max(blobs):
    max_size=0
    for blob in blobs:
        if blob[2]*blob[3] > max_size:
            max_blob=blob
            max_size = blob[2]*blob[3]
    return max_blob
    

#存放不同的颜色阈值,依次为白色、黄色、绿色(白天光的上流:(82, 100, -3, 8, -3, 2))(晚上:(62, 100, -30, 4, -9, 31))
color = ((82, 100, -3, 8, -3, 2),(50, 96, -28, 18, 48, 90))
size_threshold = 4500 #若检测到的小球框的面积小于size_threshold表明小球距离小车太远,小车需要前进。这个参数的大小需要根据实际情况修改
target=()
flag = 0 #用于标记一个while循环中是否检测到小球,falg==1表示本轮发现了小球
count = 0
bug_open = False # True or False
previous_ball_location = 'r'
location_count=0 #用来防止误识别,保持识别结果的稳定性

def stable_output(location):
    global location_count,previous_ball_location
    if previous_ball_location != location:
        location_count = 1
        previous_ball_location = location
    else:
        location_count = location_count + 1
    if location_count >=10:
        uart.write(location) #通过串口向外发送数据,控制小车向location方向运动
        
clock.tick()#开始追踪运行时间。

while(True):
    sensor.set_auto_whitebal(False) # must be turned off for color tracking,检测黄球时,关闭白平衡,检测白球时开启白平衡
    img = sensor.snapshot().histeq(adaptive=True, clip_limit=3)
    img.lens_corr(1.8) #镜头畸变矫正(lens correction),lens_corr 为了去除畸变, 1.8 是默认参数,可以根据自己实际情况调整
    
    #专门检测黄色小球
    blobs = img.find_blobs([color[1]])
    if blobs:
        max_blob = find_max(blobs)
        x_error = max_blob[5]-img.width()/2#若x_error<0,则说明小球在左边,小车需要左转,若x_error>0,则说明小球在右边,小车需要右转
        h_error = max_blob[2]*max_blob[3]-size_threshold#若h_error<0,则小车距离小球还有距离,需要前进。
        img.draw_circle(max_blob.x()+int(max_blob.w()/2), max_blob.y()+int(max_blob.w()/2), int(max_blob.w()/2), color = (255, 255, 0),thickness=5)#识别到的白色圆形用白色的圆框出来
        #print("blob.density(): ", max_blob.density(),"blob.w(): ", max_blob.w())
        #给黄球标注框框
        #for b in blobs:
            #img.draw_circle(b.x()+int(b.w()/2), b.y()+int(b.w()/2), int(b.w()/2), color = (255, 255, 0),thickness=5)#识别到的白色圆形用白色的圆框出来
        if(x_error<-10 and max_blob.density()>0.7 and 70>max_blob.w()>8):#设为-5是留有一定的误差空间,因为不一定小球非要在正中间才能被收集
            #stable_output('l')
            uart.write('l')
            flag = 1 #标记本轮发现过目标
            count = 0 #发现目标,count置为0,从头开始计数
            lcd.draw_string(10, 10, "Left", lcd.RED, lcd.YELLOW)
            
            if bug_open == True:
                print("黄球,串口发送l,","blob.density(): ", max_blob.density(),"blob.w(): ", max_blob.w())

        if(x_error>10 and max_blob.density()>0.7 and 70>max_blob.w()>8):#设为-5是留有一定的误差空间,因为不一定小球非要在正中间才能被收集
            #stable_output('r')
            uart.write('r')
            flag = 1 #标记本轮发现过目标
            count = 0 #发现目标,count置为0,从头开始计数
            lcd.draw_string(10, 20, "Right", lcd.RED, lcd.WHITE)
            
            if bug_open == True:
                print("黄球,串口发送:r,","blob.density(): ", max_blob.density(),"blob.w(): ", max_blob.w())
            
        if(-10<x_error<10 and h_error<0 and max_blob.density()>0.7 and 70>max_blob.w()>8):
            #stable_output('h')
            uart.write('h')
            flag = 1 #标记本轮发现过目标
            count = 0 #发现目标,count置为0,从头开始计数
            lcd.draw_string(10, 30, "Head", lcd.RED, lcd.GREEN)
            
            if bug_open == True:
                print("黄球,串口发送:h,","blob.density(): ", max_blob.density(),"blob.w(): ", max_blob.w())
    else:
        stable_output('t')
        if bug_open == True:
            print("无黄,串口发送:t,")
        
        #检测白球时,开启白平衡效果会更好一点
        sensor.set_auto_whitebal(True) # must be turned off for color tracking,开启白平衡
        img = sensor.snapshot().histeq(adaptive=True, clip_limit=3)
        img.lens_corr(1.8) #镜头畸变矫正(lens correction),lens_corr 为了去除畸变, 1.8 是默认参数,可以根据自己实际情况调整
        #思想:先识别出圆形,再识别圆的颜色
        #img.find_circles:控制从霍夫变换中监测到的圆。
        for c in img.find_circles(threshold = 3500, x_margin = 10, y_margin = 10, r_margin = 10,
                r_min = 2, r_max = 100, r_step = 2):
            #area为识别到的圆的区域,即圆的外接矩形框
            area = (c.x()-c.r(), c.y()-c.r(), 2*c.r(), 2*c.r())    
            ##保存检测到的其中一个圆的一些参数,用于控制小车方向的计算
            #target = (c.x(), c.y(), c.r())          
            
            #像素颜色统计,roi 是感兴趣区域的矩形元组(x,y,w,h)。如果未指定,ROI即整个图像的图像矩形。操作范围仅限于 roi 区域内的像素。                
            statistics = img.get_statistics(roi=area)
            #l_mode(),a_mode(),b_mode()是L通道,A通道,B通道的众数。
            if color[0][0]<statistics.l_mode()<color[0][1] and color[0][2]<statistics.a_mode()<color[0][3] and color[0][4]<statistics.b_mode()<color[0][5]:#if the circle is red
                img.draw_circle(c.x(), c.y(), c.r(), color = (255, 255, 255),thickness=5)#识别到的白色圆形用白色的圆框出来
                #保存检测到的其中一个圆的一些参数,用于控制小车方向的计算
                target = (c.x(), c.y(), c.r())
            #elif color[1][0]<statistics.l_mode()<color[1][1] and color[1][2]<statistics.a_mode()<color[1][3] and color[1][4]<statistics.b_mode()<color[1][5]:#if the circle is red
                #img.draw_circle(c.x(), c.y(), c.r(), color = (255, 255, 0))#识别到的黄色圆形用黄色的圆框出来
                ##保存检测到的其中一个圆的一些参数,用于控制小车方向的计算
                #target = (c.x(), c.y(), c.r())
            else:
                img.draw_circle(c.x(), c.y(), c.r(), color = (0, 0, 0),thickness=5)#识别到的白色圆形用白色的圆框出来
                target = (c.x(), c.y(), c.r())#其实这里应该不加这一句,但为了演示效果更好,让小车也追一下圆形
                
        if target:
            flag = 1 #标记本轮发现过目标
            #一张图只保留一个小球的信息,只追一个小球
            x_error = target[0]-img.width()/2 #若x_error<0,则说明小球在左边,小车需要左转,若x_error>0,则说明小球在右边,小车需要右转
            h_error = 2*target[2]*2*target[2]-size_threshold #若h_error<0,则小车距离小球还有距离,需要前进。
            
            if(x_error<-10):#设为-5是留有一定的误差空间,因为不一定小球非要在正中间才能被收集
                #stable_output('l')
                uart.write('l')
                count = 0 #发现目标,count置为0,从头开始计数
                if bug_open == True:
                    print("白球,左转,发串口:l")
                lcd.draw_string(10, 10, "Left", lcd.RED, lcd.YELLOW)
            if(x_error>10):#设为-5是留有一定的误差空间,因为不一定小球非要在正中间才能被收集
                #stable_output('r')
                uart.write('r')
                count = 0 #发现目标,count置为0,从头开始计数
                if bug_open == True:
                    print("白球,右转,发串口:r")
                lcd.draw_string(10, 20, "Right", lcd.RED, lcd.WHITE)
            if(10>x_error>-10 and h_error<0):
                #stable_output('h')
                uart.write('h')
                count = 0 #发现目标,count置为0,从头开始计数
                if bug_open == True:
                    print("白球,前进,发串口:h")
                lcd.draw_string(10, 30, "Head", lcd.RED, lcd.GREEN)
        else:
            stable_output('t')          
            if bug_open == True:
                print("无白色球,发串口:t")
        target=()#清空target
        
    #控制视野内无球时,自动慢速右转
    if flag == 0:
        count = count+1
        if count%10 == 0:
            uart.write('s')
            utime.sleep_ms(10)
            uart.write('n') #通过串口向外发送数据,没有检测到黄色或白色小球
            
            if bug_open == True:
                print("视野无球,发串口:n")
            lcd.draw_string(250, 10, "FPS %f" % clock.fps(), lcd.BLACK, lcd.RED)
            count = 0
    flag = 0 #重置标记
    if bug_open == True:
        print("FPS %f" % clock.fps())#停止追踪运行时间,并返回当前FPS(每秒帧数)。在调用该函数前始终首先调用 tick 。
        print("flag:",flag,"count:",count)
    lcd.display(img) #LCD 显示图片
    

Binary processing of images has the advantage that it is easier to detect white balls. Disadvantages: it is easy to misidentify, and measures need to be taken to reduce the degree of misidentification.

import sensor, image, time,lcd,utime
from machine import UART
from fpioa_manager import fm

fm.register(10, fm.fpioa.UART1_TX, force=True)#映射串口引脚
fm.register(9, fm.fpioa.UART1_RX, force=True)#映射串口引脚

uart = UART(UART.UART1, 115200, 8, 0, 0, timeout=1000, read_buf_len=4096)

clock = time.clock()
lcd.init() #显示屏初始化
sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QQVGA) #QQVGA: 160x120、QVGA: 320x240、
sensor.run(1)
sensor.skip_frames(20)#跳过刚启动开始的30帧照片
lcd.rotation(2)#LCD屏幕翻转,范围是0~3,上和下反转,左和右反转
sensor.set_hmirror(True)#摄像头镜像
sensor.set_auto_gain(False) # must be turned off for color tracking
#sensor.set_auto_whitebal(False) # must be turned off for color tracking,关闭白平衡

#sensor.set_brightness(3) #-3至+3,亮度越大,图片越亮
#sensor.set_saturation(2)#-3至+3,饱和度越大,色彩越鲜艳
#sensor.set_contrast(2)#-3至+3,对比度越大,颜色之间的反差越大

def find_max(blobs):
    max_size=0
    for blob in blobs:
        if blob[2]*blob[3] > max_size:
            max_blob=blob
            max_size = blob[2]*blob[3]
    return max_blob
    

#存放不同的颜色阈值,依次为白色、黄色、绿色(白天光的上流:(82, 100, -3, 8, -3, 2))(晚上:(62, 100, -30, 4, -9, 31))
color = ((82, 100, -3, 8, -3, 2),(50, 96, -28, 18, 48, 90))
size_threshold = 4500 #若检测到的小球框的面积小于size_threshold表明小球距离小车太远,小车需要前进。这个参数的大小需要根据实际情况修改
target=()
flag = 0 #用于标记一个while循环中是否检测到小球,falg==1表示本轮发现了小球
count = 0
bug_open = False # True or False
previous_ball_location = 'r'
location_count=0 #用来防止误识别,保持识别结果的稳定性

kernel_size = 1 # kernel width = (size*2)+1, kernel height = (size*2)+1
kernel = [-1, -1, -1,\
          -1, +8, -1,\
          -1, -1, -1]


thresholds = [(90, 100, -128, 127, -128, 127)]
#thresholds = [(100, 255)] # grayscale thresholds
#thresholds = [(0, 100, -38, 37, -47, 58)]



def stable_output(times,location):
    global location_count,previous_ball_location
    if previous_ball_location != location:
        location_count = 1
        previous_ball_location = location
    else:
        location_count = location_count + 1
    if location_count >=times:
        uart.write(location) #通过串口向外发送数据,控制小车向location方向运动
        
clock.tick()#开始追踪运行时间。

while(True):
    sensor.set_auto_whitebal(False) # must be turned off for color tracking,检测黄球时,关闭白平衡,检测白球时开启白平衡
    img = sensor.snapshot().histeq(adaptive=True, clip_limit=3)
    img.lens_corr(1.8) #镜头畸变矫正(lens correction),lens_corr 为了去除畸变, 1.8 是默认参数,可以根据自己实际情况调整
    
    #专门检测黄色小球
    blobs = img.find_blobs([color[1]])
    if blobs:
        max_blob = find_max(blobs)
        x_error = max_blob[5]-img.width()/2#若x_error<0,则说明小球在左边,小车需要左转,若x_error>0,则说明小球在右边,小车需要右转
        h_error = max_blob[2]*max_blob[3]-size_threshold#若h_error<0,则小车距离小球还有距离,需要前进。
        img.draw_circle(max_blob.x()+int(max_blob.w()/2), max_blob.y()+int(max_blob.w()/2), int(max_blob.w()/2), color = (255, 255, 0),thickness=5)#识别到的白色圆形用白色的圆框出来
        #print("blob.density(): ", max_blob.density(),"blob.w(): ", max_blob.w())
        #给黄球标注框框
        #for b in blobs:
            #img.draw_circle(b.x()+int(b.w()/2), b.y()+int(b.w()/2), int(b.w()/2), color = (255, 255, 0),thickness=5)#识别到的白色圆形用白色的圆框出来
        if(x_error<-10 and max_blob.density()>0.7 and 70>max_blob.w()>8):#设为-5是留有一定的误差空间,因为不一定小球非要在正中间才能被收集
            #stable_output('l')
            uart.write('l')
            flag = 1 #标记本轮发现过目标
            count = 0 #发现目标,count置为0,从头开始计数
            lcd.draw_string(10, 10, "Left", lcd.RED, lcd.YELLOW)
            
            if bug_open == True:
                print("黄球,串口发送l,","blob.density(): ", max_blob.density(),"blob.w(): ", max_blob.w())

        if(x_error>10 and max_blob.density()>0.7 and 70>max_blob.w()>8):#设为-5是留有一定的误差空间,因为不一定小球非要在正中间才能被收集
            #stable_output('r')
            uart.write('r')
            flag = 1 #标记本轮发现过目标
            count = 0 #发现目标,count置为0,从头开始计数
            lcd.draw_string(10, 20, "Right", lcd.RED, lcd.WHITE)
            
            if bug_open == True:
                print("黄球,串口发送:r,","blob.density(): ", max_blob.density(),"blob.w(): ", max_blob.w())
            
        if(-10<x_error<10 and h_error<0 and max_blob.density()>0.7 and 70>max_blob.w()>8):
            #stable_output('h')
            uart.write('h')
            flag = 1 #标记本轮发现过目标
            count = 0 #发现目标,count置为0,从头开始计数
            lcd.draw_string(10, 30, "Head", lcd.RED, lcd.GREEN)
            
            if bug_open == True:
                print("黄球,串口发送:h,","blob.density(): ", max_blob.density(),"blob.w(): ", max_blob.w())
    else:
        stable_output(10,'t')
        if bug_open == True:
            print("无黄,串口发送:t,")
        
        #检测白球时,开启白平衡效果会更好一点
        #sensor.set_auto_whitebal(True) # must be turned off for color tracking,开启白平衡
        #img = sensor.snapshot().histeq(adaptive=True, clip_limit=3)
        #img.lens_corr(1.8) #镜头畸变矫正(lens correction),lens_corr 为了去除畸变, 1.8 是默认参数,可以根据自己实际情况调整
        
        #sensor.set_brightness(0) #-3至+3,亮度越大,图片越亮
        #sensor.set_saturation(-1)#-3至+3,饱和度越大,色彩越鲜艳
        #sensor.set_contrast(-3)#-3至+3,对比度越大,颜色之间的反差越大

        img.binary(thresholds)
        img.morph(kernel_size, kernel) #边缘锐化,方便检测圆形
        #img.binary(thresholds)


        #思想:先识别出圆形,再识别圆的颜色
        #img.find_circles:控制从霍夫变换中监测到的圆。
        for c in img.find_circles(threshold = 3500, x_margin = 10, y_margin = 10, r_margin = 10,
                r_min = 2, r_max = 100, r_step = 2):
            #area为识别到的圆的区域,即圆的外接矩形框
            area = (c.x()-c.r(), c.y()-c.r(), 2*c.r(), 2*c.r())    
            ##保存检测到的其中一个圆的一些参数,用于控制小车方向的计算
            #target = (c.x(), c.y(), c.r())          
            
            #像素颜色统计,roi 是感兴趣区域的矩形元组(x,y,w,h)。如果未指定,ROI即整个图像的图像矩形。操作范围仅限于 roi 区域内的像素。                
            statistics = img.get_statistics(roi=area)
            
            #print(statistics)
            #l_mode(),a_mode(),b_mode()是L通道,A通道,B通道的众数。
            if color[0][0]<statistics.l_mode()<color[0][1] and color[0][2]<statistics.a_mode()<color[0][3] and color[0][4]<statistics.b_mode()<color[0][5]:#if the circle is red
                img.draw_circle(c.x(), c.y(), c.r(), color = (255, 255, 255),thickness=5)#识别到的白色圆形用白色的圆框出来
                #保存检测到的其中一个圆的一些参数,用于控制小车方向的计算
                target = (c.x(), c.y(), c.r())
            #elif color[1][0]<statistics.l_mode()<color[1][1] and color[1][2]<statistics.a_mode()<color[1][3] and color[1][4]<statistics.b_mode()<color[1][5]:#if the circle is red
                #img.draw_circle(c.x(), c.y(), c.r(), color = (255, 255, 0))#识别到的黄色圆形用黄色的圆框出来
                ##保存检测到的其中一个圆的一些参数,用于控制小车方向的计算
                #target = (c.x(), c.y(), c.r())
            else:
                img.draw_circle(c.x(), c.y(), c.r(), color = (0, 0, 0),thickness=5)#识别到的白色圆形用白色的圆框出来
                target = (c.x(), c.y(), c.r())#其实这里应该不加这一句,但为了演示效果更好,让小车也追一下圆形
                
        if target:
            flag = 1 #标记本轮发现过目标
            #一张图只保留一个小球的信息,只追一个小球
            x_error = target[0]-img.width()/2 #若x_error<0,则说明小球在左边,小车需要左转,若x_error>0,则说明小球在右边,小车需要右转
            h_error = 2*target[2]*2*target[2]-size_threshold #若h_error<0,则小车距离小球还有距离,需要前进。
            
            if(x_error<-10):#设为-5是留有一定的误差空间,因为不一定小球非要在正中间才能被收集
                #stable_output('l')
                uart.write('l')
                count = 0 #发现目标,count置为0,从头开始计数
                
                print("白球,左转,发串口:l")
                if bug_open == True:
                    print("白球,左转,发串口:l")
                lcd.draw_string(10, 10, "Left", lcd.RED, lcd.YELLOW)
            if(x_error>10):#设为-5是留有一定的误差空间,因为不一定小球非要在正中间才能被收集
                #stable_output('r')
                uart.write('r')
                count = 0 #发现目标,count置为0,从头开始计数
                
                print("白球,右转,发串口:r")
                if bug_open == True:
                    print("白球,右转,发串口:r")
                lcd.draw_string(10, 20, "Right", lcd.RED, lcd.WHITE)
            if(10>x_error>-10 and h_error<0):
                #stable_output('h')
                uart.write('h')
                count = 0 #发现目标,count置为0,从头开始计数
                
                print("白球,前进,发串口:h")
                if bug_open == True:
                    print("白球,前进,发串口:h")
                lcd.draw_string(10, 30, "Head", lcd.RED, lcd.GREEN)
        else:
            stable_output(15,'t')   
            
            print("无白色球,发串口:t")
            if bug_open == True:
                print("无白色球,发串口:t")
        target=()#清空target
        
    #控制视野内无球时,自动慢速右转
    if flag == 0:
        count = count+1
        if count%10 == 0:
            uart.write('s')
            utime.sleep_ms(10)
            uart.write('n') #通过串口向外发送数据,没有检测到黄色或白色小球
            
            if bug_open == True:
                print("视野无球,发串口:n")
            lcd.draw_string(250, 10, "FPS %f" % clock.fps(), lcd.BLACK, lcd.RED)
            count = 0
    flag = 0 #重置标记
    if bug_open == True:
        print("FPS %f" % clock.fps())#停止追踪运行时间,并返回当前FPS(每秒帧数)。在调用该函数前始终首先调用 tick 。
        print("flag:",flag,"count:",count)
    lcd.display(img) #LCD 显示图片
    

Guess you like

Origin blog.csdn.net/quxuexi/article/details/131255074