k210乒乓球识别模块乒乓球识别程序-初版

该代码实现了一个自动小车控制系统,通过摄像头捕获图像,对图像进行颜色识别(主要识别黄色和白色小球),然后根据小球的位置信息通过UART串口发送指令控制小车行驶。程序包括镜头畸变矫正、颜色阈值设置、圆形检测等功能,以确保小车能准确跟踪小球移动。
摘要由CSDN通过智能技术生成
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 显示图片
    

精简版

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 。

更精简版

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 。、

改进后版本:

改进后,黄球关闭白平衡,白球开启白皮平衡(这样检测白球准确率更高)。

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 显示图片
    

二值化处理图像,优点,更容易检测到白色小球,缺点:容易误识别,需要采取措施降低误识别程度

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 显示图片
    
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值