本文基于本人在视觉学习中所遇到的问题以及所完成的题目所作
1.关于代码整体结构
以下是我为了让是自己使用更加方便所以写的一个比较简单实用的代码框架
#main.py -- put your code here!
import cpufreq
import pyb
import sensor,image, time,math,struct
from image import SEARCH_EX, SEARCH_DS
from pyb import LED,Timer,UART
sensor.reset() # Reset and initialize the sensor.
sensor.set_pixformat(sensor.RGB565) # Set pixel format to RGB565 (or GRAYSCALE)
sensor.set_framesize(sensor.QQVGA) # Set frame size to QVGA (320x240)
sensor.skip_frames(time=2000) #延时跳过一些帧,等待感光元件变稳定
sensor.set_auto_gain(False) #黑线不易识别时,将此处写False
sensor.set_auto_whitebal(False)
#sensor.set_auto_exposure(False, exposure_us=111000)#关闭自动曝光
clock = time.clock() # Create a clock object to track the FPS.
#sensor.set_auto_exposure(True, exposure_us=5000) # 设置自动曝光sensor.get_exposure_us()
uart=UART(3,115200)
THRESHOLD = (0,100) # Grayscale threshold for dark things... (5, 70, -23, 15, -57, 0)(18, 100, 31, -24, -21, 70)
IMAGE_WIDTH=sensor.snapshot().width()
IMAGE_HEIGHT=sensor.snapshot().height()
IMAGE_DIS_MAX=(int)(math.sqrt(IMAGE_WIDTH*IMAGE_WIDTH+IMAGE_HEIGHT*IMAGE_HEIGHT)/2)
class target_check(object):
x=0 #int16_t
y=0 #int16_t
pixel=0 #uint16_t
flag=0 #uint8_t
state=0 #uint8_t
angle=0 #int16_t
distance=0 #uint16_t
apriltag_id=0#uint16_t
img_width=0 #uint16_t
img_height=0 #uint16_t
reserved1=0 #uint8_t
reserved2=0 #uint8_t
reserved3=0 #uint8_t
reserved4=0 #uint8_t
fps=0 #uint8_t
range_sensor1=0
range_sensor2=0
range_sensor3=0
range_sensor4=0
camera_id=0
reserved1_int32=0
reserved2_int32=0
reserved3_int32=0
reserved4_int32=0
class rgb(object):
def __init__(self):
self.red=LED(1)
self.green=LED(2)
self.blue=LED(3)
class uart_buf_prase(object):
uart_buf = []
_data_len = 0
_data_cnt = 0
state = 0
class singleline_check():
rho_err = 0
theta_err = 0
state = 0
class mode_ctrl(object):
work_mode = 0x01 #工作模式.默认是点检测,可以通过串口设置成其他模式
check_show = 1 #开显示,在线调试时可以打开,离线使用请关闭,可提高计算速度
class KalmanFilter:
def __init__(self):
self.x = 0 # initial state
self.p = 1 # initial state covariance
self.q = 0.1 # process noise covariance
self.r = 1 # measurement noise covariance
self.k = 0 # kalman gain
def update(self, measurement):
# Prediction update
self.p = self.p + self.q
# Measurement update
self.k = self.p / (self.p + self.r)
self.x = self.x + self.k * (measurement - self.x)
self.p = (1 - self.k) * self.p
return self.x
ctr=mode_ctrl()
rgb=rgb()
R=uart_buf_prase()
target=target_check();
target.camera_id=0x01
target.reserved1_int32=65536
target.reserved2_int32=105536
target.reserved3_int32=65537
target.reserved4_int32=105537
f_x = (2.8 / 3.984) * 160 # 默认值
f_y = (2.8 / 2.952) * 120 # 默认值
c_x = 160 * 0.5 # 默认值(image.w * 0.5)
c_y = 120 * 0.5 # 默认值(image.h * 0.5)
last_send_time = pyb.millis()
k=21.62
singleline = singleline_check()
b=0
#标签测距
def degrees(radians):
return (180 * radians) / math.pi
def uart_data_read():
buf_len=uart.any()
for i in range(0,buf_len):
uart_data_prase(uart.readchar())
def time_callback(info):
rgb.red.toggle()
timer=Timer(2,freq=4)
timer.callback(time_callback)
#找最大
def find_max(blobs):
max_size=0
for blob in blobs:
if blob[2]*blob[2] > max_size:
max_blob=blob
max_size = blob[2]*blob[2]
return max_blob
#找最小
def find_min(blobs):
min_blob = None
min_size = 0
for blob in blobs:
if blob[5] * blob[6] > min_size:
min_blob = blob
min_size = blob[5] * blob[6]
return min_blob
'''
def find_min(blobs):
min_size=10000
for blob in blobs:
if blob[2]*blob[2]<min_size:
min_blob=blob
min_size = blob[2]*blob[2]
return min_blob
'''
# 绘制水平线
def draw_hori_line(img, x0, x1, y, color):
for x in range(x0, x1):
img.set_pixel(x, y, color)
# 绘制竖直线
def draw_vec_line(img, x, y0, y1, color):
for y in range(y0, y1):
img.set_pixel(x, y, color)
# 绘制矩形
def draw_rect(img, x, y, w, h, color):
draw_hori_line(img, x, x+w, y, color)
draw_hori_line(img, x, x+w, y+h, color)
draw_vec_line(img, x, y, y+h, color)
draw_vec_line(img, x+w, y, y+h, color)
#寻Apriltag
def opv_find_april_tag():
img=sensor.snapshot()
target.img_width=IMAGE_WIDTH
target.img_height=IMAGE_HEIGHT
apriltag_area=0
apriltag_dis=IMAGE_DIS_MAX
target.flag = 0
for tag in img.find_apriltags(): # defaults to TAG36H11 without "families".
img.draw_rectangle(tag.rect(), color = (255, 0, 0))
b=(tag.rect()[2]/(abs(math.sin(tag.rotation()))+abs(math.cos(tag.rotation()))))
#print(tag.rect()[2],b*b)
#保存最大像素面积得apritag信息
apriltag_dis_tmp=math.sqrt((tag.cx()-80)*(tag.cx()-80)+(tag.cy()-60)*(tag.cy()-60))
apriltag_area_tmp=tag.w()*tag.h()
if apriltag_dis>apriltag_dis_tmp:
apriltag_area=tag.w()*tag.h()
target.x = tag.cx()
target.y = tag.cy()
target.apriltag_id=tag.id()
target.pixel=int(b*b)#apriltag_area
apriltag_dis=apriltag_dis_tmp
target.flag = 1
if target.flag==1:
img.draw_cross(target.x,target.y, color=127, size = 15)
# img.draw_circle(target.x,target.y, 15, color = 127)
# print(target.x,target.y,target.pixel,target.apriltag_id,apriltag_dis)
#识别条形码
def openmv_find_txm():
sensor.set_framesize(sensor.QVGA)
img = sensor.snapshot()
#img.lens_corr(1.8) # Adjust this parameter as needed
# Find barcodes
codes = img.find_barcodes()
if codes:
for code in codes:
# Update Kalman Filter with measurementswd
x_est = kf_x.update(code.rect()[0])
y_est = kf_y.update(code.rect()[1])
# Get barcode data
barcode_data = code.payload()
# Pack barcode data
data_length = len(barcode_data)
data_to_send = bytearray()
data_to_send.extend(bytearray([0xAA, 0xAA])) # frame header
data_to_send.extend(struct.pack('<H', data_length)) # data length
data_to_send.extend(barcode_data.encode('utf-8')) # data content
data_to_send.extend(bytearray([0x55, 0x55])) # frame tail
# Send data
uart.write(data_to_send)
print("Sent barcode data:", barcode_data, "Estimated position:", x_est, y_est)
#模板
def openmv_find_moban():
sensor.reset()
# Set sensor settings
sensor.set_contrast(1)
sensor.set_gainceiling(16)
# Max resolution for template matching with SEARCH_EX is QQVGA
sensor.set_framesize(sensor.QQVGA)
sensor.set_pixformat(sensor.GRAYSCALE)
templates = [ "/1.pgm", "/2.pgm", "/6.pgm"] #保存多个模板
#加载模板图片
clock = time.clock()
# Run template matching
while (True):
clock.tick()
img = sensor.snapshot()
uart_data_read()
if ctr.work_mode==0x07:#april测距ok
for t in templates:
template = image.Image(t)
#对每个模板遍历进行模板匹配
r = img.find_template(template, 0.70, step=4, search=SEARCH_EX) #, roi=(10, 0, 60, 60))
if r:
img.draw_rectangle(r)
print(t) #打印模板名字
else:
break
#数据包头和模式定义
HEADER=[0xFA,0xFB]
MODE=[0x01,0x02,0x03,0x04,0x05]
ENDER=[0x3B,0x2B]
def uart_data_prase(buf):
if R.state==0 and buf==0xFA:#帧头1
R.state=1
R.uart_buf.append(buf)
elif R.state==1 and buf==0xFB:#帧头2
R.state=2
R.uart_buf.append(buf)
elif R.state==2 and buf<50:#数据长度小于50
R.state=3
R._data_len=buf #有效数据长度
R._data_cnt=buf+5#总数据长度
R.uart_buf.append(buf)
elif R.state==3 and R._data_len>0:#存储对应长度数据
R._data_len=R._data_len-1
R.uart_buf.append(buf)
if R._data_len==0:
R.state=4
elif R.state==4 and buf==0x3B:#帧尾1
R.state=5
R.uart_buf.append(buf)
elif R.state==5 and buf==0x2B:#帧尾2
R.state=0
R.uart_buf.append(buf)
ctr.work_mode = R.uart_buf[3]
R.uart_buf=[]#清空缓冲区,准备下次接收数据
else:
R.state=0
R.uart_buf=[]#清空缓冲区,准备下次接收数据
b=0
ctr.work_mode=0x00 #0x0B
last_ticks=0
ticks=0
ticks_delta=0;
while True:
#sensor.set_auto_exposure(False, exposure_us=111000)#关闭自动曝光
clock.tick()
if ctr.work_mode==0x00:#april测距ok
find_apriltag_ceju()
rgb.blue.toggle()
elif ctr.work_mode==0x01:#识别圆环发送8个点ok
find_circle_send_eight()
rgb.blue.off()
elif ctr.work_mode==0x02:#寻Apriltag
opv_find_april_tag()
rgb.blue.off()
elif ctr.work_mode==0x03:#巡线模式
found_line()
rgb.blue.off()
elif ctr.work_mode==0x04:#二维码识别ok
send_ewm()
rgb.blue.off()
elif ctr.work_mode==0x05:#识别黑色矩形框ok
find_rect_crop()
rgb.blue.toggle()
elif ctr.work_mode==0x06:#条形码识别
openmv_find_txm()
rgb.blue.toggle()
elif ctr.work_mode==0x07:#模板识别
openmv_find_moban()
rgb.blue.toggle()
elif ctr.work_mode==0x0B:
rgb.blue.toggle()
else:
rgb.blue.toggle()
#uart.write((ctr.work_mode))
uart_data_read()
此代码为删减版(删除了部分函数定义),但整体结构不变
二.代码详解
逻辑嵌套:我们直接看到while循环中所运行的代码,层层递进的分析使代码清晰易懂
while True:
#sensor.set_auto_exposure(False, exposure_us=111000)#关闭自动曝光
clock.tick()
if ctr.work_mode==0x00:#april测距ok
find_apriltag_ceju()
rgb.blue.toggle()
elif ctr.work_mode==0x01:#识别圆环发送8个点ok
find_circle_send_eight()
rgb.blue.off()
elif ctr.work_mode==0x02:#寻Apriltag
opv_find_april_tag()
rgb.blue.off()
elif ctr.work_mode==0x03:#巡线模式
found_line()
rgb.blue.off()
elif ctr.work_mode==0x04:#二维码识别ok
send_ewm()
rgb.blue.off()
elif ctr.work_mode==0x05:#识别黑色矩形框ok
find_rect_crop()
rgb.blue.toggle()
elif ctr.work_mode==0x06:#条形码识别
openmv_find_txm()
rgb.blue.toggle()
elif ctr.work_mode==0x07:#模板识别
openmv_find_moban()
rgb.blue.toggle()
elif ctr.work_mode==0x0B:
rgb.blue.toggle()
else:
rgb.blue.toggle()
#uart.write((ctr.work_mode))
uart_data_read()
可以看到,循环中一直在对ctr.work_mode的值进行判断并进行下一步动作,关于ctr.work_mode的定义如下:
def uart_data_prase(buf):
if R.state==0 and buf==0xFA:#帧头1
R.state=1
R.uart_buf.append(buf)
elif R.state==1 and buf==0xFB:#帧头2
R.state=2
R.uart_buf.append(buf)
elif R.state==2 and buf<50:#数据长度小于50
R.state=3
R._data_len=buf #有效数据长度
R._data_cnt=buf+5#总数据长度
R.uart_buf.append(buf)
elif R.state==3 and R._data_len>0:#存储对应长度数据
R._data_len=R._data_len-1
R.uart_buf.append(buf)
if R._data_len==0:
R.state=4
elif R.state==4 and buf==0x3B:#帧尾1
R.state=5
R.uart_buf.append(buf)
elif R.state==5 and buf==0x2B:#帧尾2
R.state=0
R.uart_buf.append(buf)
ctr.work_mode = R.uart_buf[3]
R.uart_buf=[]#清空缓冲区,准备下次接收数据
else:
R.state=0
R.uart_buf=[]#清空缓冲区,准备下次接收数据
可以看到,在这个函数中,我们对ctr.work_mode进行了赋值,这个函数是我们接收单片机数据的函数,通过解析数据对ctr.work_mode进行赋值
所以,这个代码整体的逻辑就是:
1.解析从单片机接收到的数据包
2.对ctr.work_mode进行赋值
3.执行函数
3.作者的话。。。。。。。。。
如果有想加的函数大家可以按照模板直接在循环之前def,然后在循环中加上相对应的ctr.work_mode的值,这样就算def的函数有问题也不会影响其他函数的执行,非常安全
其实我觉得最麻烦的部分是串口通信,因为大家可以看到我前面class了一段很长的函数却并没有用到,因为这一段函数发送的数据包过长,当然如果大家发送的数据很长也可以参考这个函数,不然就自己在定义的函数里面重新进行数据解析(一定要发送数据包,一定要发字节(取高八位,低八位))为了防止数据有问题最好设置帧头帧尾:
if R.state==0 and buf==0xFA:#帧头1
R.state=1
R.uart_buf.append(buf)
elif R.state==1 and buf==0xFB:#帧头2
R.state=2
R.uart_buf.append(buf)
就像是接收里面所进行的判断,要保证数据的准确性,当然,最好加一个校验位,好了,不多说了,差不多了,关于函数就不想讲了,注释还算比较清楚,希望大家有所收获
2024-8.17 by--leader.w