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