# 条件:白色漫散射背景;逆光;启动或光源有大改变时,要进行白平衡矫正。
# 反光强时,减少纵向条块,可增加抗反光的干扰。
import sensor, image, time
from pyb import LED,Timer,Pin
#------------------------求矩形轮廓的上边直线
def fit_line(x,y):#最小二乘法拟合
NX=len(x)
NY=len(y)
if NX<2:return('N')
sxy=sxx=0
for i in range(NX):
sxy+=x[i]*y[i]
sxx+=x[i]*x[i]
sx=sum(x)
sy=sum(y)
T=sx**2-NX*sxx#防备分母是0
if abs(T)<1e-6:#斜率无穷大,x=sx/NX
return('N')
else:
k=(sx*sy-NX*sxy)/T#斜率
b=(sx*sxy-sy*sxx)/T#截距
# for i in range(NX):
# if i==0 or i==NX-1:#头尾偏差允许大一些
# if x[i]*k+b-y[i]>2*GAP:
# err+=x[i]*k+b-y[i]
# break
# else:
# if x[i]*k+b-y[i]>GAP:
# err+=x[i]*k+b-y[i]
# break
#return([k,b,err])
return([k,b])
#------------------------求矩形轮廓的上边直线
def deviation(x,y,k,b):
NX=len(x)
NY=len(y)
if NX<2:
return('N')
else:
err = 0
for i in range(NX):
if i==0 or i==NX-1:#头尾偏差允许大一些
if x[i]*k+b-y[i]>2*GAP and x[i]*k+b-y[i]<55:#剔除袋外扰动
#err+=x[i]*k+b-y[i]
err=x[i]*k+b-y[i]
break
else:
if x[i]*k+b-y[i]>GAP and x[i]*k+b-y[i]<55:
#err+=x[i]*k+b-y[i]
err=x[i]*k+b-y[i]
break
return(err)
W_W=(640)#定义显示窗口宽度
W_H=(240)#定义显示窗口高度
GAP=8#边缘与袋腔之间的间隙,在此间隙内不检测
Col=32 #屏幕纵向平均分成Col个块,可以使得图像分割精细
p_out = Pin('P7', Pin.OUT_PP)#设置p_out为输出引脚,点亮发光二极管
p_out.high()#设置p_out引脚为高
sensor.reset()
sensor.set_pixformat(sensor.RGB565) # grayscale is faster
sensor.set_framesize(sensor.VGA)#VGA: 640x480
sensor.set_windowing((W_W,W_H)) # 设置屏幕有效大小W_W*W_H
sensor.skip_frames(time = 3000) #在3秒内,适应光照环境(放大倍数,白平衡)
sensor.set_auto_gain(False) # 关闭放大倍数自动调节功能
sensor.set_auto_whitebal(False) # 关闭白平衡自动调节功能
p_out.low()#设置p_out引脚为低,指示白平衡和放大倍数学习完成,可以开始工作。
#brown_thresholds =[(10,70,15,100,20,100)]#大粗块棕色
brown_thresholds =[(35, 70, -5, 45, 20, 60)]
light_brown=[(10,50,15,50,20,80)]#淡棕色
#棕色的初始值很重要,影响能否准确分割出大棕色块区域,此值是反复试验得到,不一定最优。
def tick(timer):#时间中断函数,定时熄灭LED
p_out.low()#设置p_out引脚为低
#LED(3).off()
tim = Timer(4, freq=2) # create a timer object using timer 4 - trigger at 0.25Hz
tim.callback(tick) # set the callback to our tick function
clock = time.clock()
while(True):
clock.tick()
img = sensor.snapshot()#摄取一幅图像
BY=[]#棕色块y坐标暂存
BX=[]#棕色块x坐标暂存
BH=[]#棕色块高度暂存
BW=[]#棕色块宽度暂存
###################################新子集
BYY=[]
BXX=[]
BHH=[]
BWW=[]
#########################################
BY1=[]#棕色块y坐标暂存
BX1=[]#棕色块x坐标暂存
BH1=[]#棕色块高度暂存
BW1=[]#棕色块宽度暂存
Y_Thresholds=[]#自校正阈值暂存
for i in range(Col):#处理屏幕各纵向块
IMG=img.find_blobs(brown_thresholds,pixels_threshold=50,area_threshold=20,merge=True,\
roi=[i*W_W//Col,0,W_W//Col,W_H],margin=W_H,x_stride=1,y_stride=1)#找大块棕色
if IMG and IMG[0].w()>640/2/Col:
BY.append(IMG[0].y())
BX.append(IMG[0].x())
BH.append(IMG[0].h())
BW.append(IMG[0].w())
img.draw_rectangle([BX[-1],BY[-1],BW[-1],BH[-1]],color=(255,0,0))#画大棕色块的红色矩形框39
if len(BY)>=5 and min(BY)>GAP and max(BY)<W_H-2*GAP:#要至少检测到5个色块
SROI=[BX[1],max(BY),BX[-1]-BX[1],W_H-max(BY)]
stat=img.get_statistics(roi=SROI)#获得像素的统计量
b_thresholds=[(stat.l_lq(),stat.l_max(),10,stat.a_max(),10,stat.b_max())]#自校正阈值
print(b_thresholds)#自校正之后的阈值
for i in range(Col):#处理屏幕各纵向块
IMG=img.find_blobs(b_thresholds,pixels_threshold=50,area_threshold=20,merge=True,\
roi=[i*W_W//Col,0,W_W//Col,W_H],margin=W_H,x_stride=1,y_stride=1)#找大块棕色
if IMG and IMG[0].w()>640/2/Col:
BY1.append(IMG[0].y())
BX1.append(IMG[0].x())
BH1.append(IMG[0].h())
BW1.append(IMG[0].w())
MinV=min(BY1)#y的最小值
MinI=BY1.index(MinV)#y的最小值的索引
if MinI!=len(BX1)-1 and MinI!=0:#y的最小值在中间挑选长边侧
P1=fit_line(BX1[1:MinI+2],BY1[0:MinI+1])#寻找y的最小值左侧直线参数纵坐标不变,横坐标平移
P2=fit_line(BX1[MinI:],BY1[MinI:])#寻找y的最小值右侧直线参数
if abs(P1[0]*P2[0]+1)<0.7:#直角在中间判断垂直情况,0.7为可调参数
if MinI<len(BX)/2:
BX1=BX1[MinI:]
BY1=BY1[MinI:]
BW1=BW1[MinI:]
BH1=BH1[MinI:]
else:
BX1=BX1[:MinI+1]
BY1=BY1[:MinI+1]
BW1=BW1[:MinI+1]
BH1=BH1[:MinI+1]
P=fit_line(BX1,BY1)#这时候拟合了所有点
print(len(BX1))
TX=BX1[-1]+BW1[-1]
img.draw_line(BX1[0],round(BX1[0]*P[0]+P[1]),\
TX,round(TX*P[0]+P[1]),color=[0,0,255])#拟合蓝线
NXX=len(BX1)
if NXX>2:
for i in range(NXX):
if i==0 or i==NXX-1:#头尾偏差允许大一些
AbsDev = BX1[i]*P[0]+P[1]-BY1[i]
if abs(AbsDev)<round(0.5*GAP):##########此处参数可调小于此参数保留
BYY.append(BY1[i])
BXX.append(BX1[i])
BHH.append(BH1[i])
BWW.append(BW1[i])
# break
else:
Absdev1 = BX1[i]*P[0]+P[1]-BY1[i]
if abs(Absdev1)<round(0.2*GAP):
BYY.append(BY1[i])
BXX.append(BX1[i])
BHH.append(BH1[i])
BWW.append(BW1[i])
# break buzhida
print(len(BXX))
PR=fit_line(BXX,BYY)#重新拟合一条直线返回新的k,b
print(PR)
if len(PR)>1:
TXX=BXX[-1]+BWW[-1]
img.draw_line(BXX[0],round(BXX[0]*PR[0]+PR[1]),\
TXX,round(TXX*PR[0]+PR[1]),color=[0,255,0])#绿线拟合
dev=deviation(BX1,BY1,PR[0],PR[1])
print(dev)
if dev>GAP:
p_out.high()#设置p_out引脚为高
print(P)
continue
# if dev>GAP:
# p_out.high()#设置p_out引脚为高
# print(P)
# continue
#stat=img.get_statistics(roi=[BX[1],max(BY)+GAP,BX[-2]-BX[1],max(W_H-max(BY)-GAP,1)])#获得像素的统计量3993
#b_thresholds=[stat.l_lq(),stat.l_max(),10,stat.a_max(),10,stat.b_max()]#自校正阈值
# for i in range((BX[-1]+BW[-1]-BX[0])//8+1):#棕色块的宽度除以
#img.draw_line(BX[0]+8*i,round(max(P[0]*(BX[0]+4*i)+P[1]-60,0)),BX[0]+4*i,round(P[0]*(BX[0]+4*i)+P[1]),color=[0,255,0])
# ey=round(P[0]*(BX[0]+8*i)+P[1])
# eyy=max(ey-50,0)
# if round(ey-eyy-1.5*GAP)>0:
# #ROI=[BX[0]+8*i,eyy,8,round(ey-eyy-1.5*GAP)]
# ROI=[min(BX[0]+8*i,W_W-9),eyy,8,round(ey-eyy)]
# IMG1=img.find_blobs(light_brown,pixels_threshold=1,area_threshold=1,merge=True,\
# roi=ROI,margin=W_H,x_stride=1,y_stride=1)#找大块棕色
# if IMG1:
# #img.draw_rectangle(ROI,color=(0,255,0),fill=True)#找到的精细黄色的矩形区域(绿色)
# p_out.high()#设置p_out引脚为高
# continue
print(clock.fps())
I
i5to
@i5to
0
声望
2
楼层
144
资料浏览
0
粉丝
0
关注
i5to 发布的帖子
-
为什么升级成最新版本固件之后会弹出这个警告?