- 作者:
- 分类:项目&制作->小制作
- 阅读:9947
- 点赞:83
- 难度:
- 版权:CC BY-SA 4.0
- 创建:2019-10-15
- 更新:2020-02-26
原文链接(持续更新):https://neucrack.com/p/189
效果图:
K210 对图像画出了热力图,并标记几个重要点(中心店和最高温)的温度

PC Python 实现

K210 与摄像头数据融合了的图

传感器及参数


几个关键参数如下,更多看芯片手册:
分辨率: 32x24
传感器驱动协议
IIC,也有模块加了块单片机做成了串口协议
主控芯片
用 K210(RISC-V双核,针对AIOT领域, 能胜任本应用,而且使用MaixPy(Micropython)能快速实现看到效果

实现过程
获得硬件(K210 和
MLX90640(选用串口模块可以更快上手,这里用的也是串口模块))下载
MaixPy固件并测试运行通过(查看maixpy.sipeed.com获得教程)驱动
MLX90640,由于是串口模块,只需要接收输出的数据即可,协议看模块文档,非常简单;如果是IIC协议会复杂一点点,多花点时间就好了. 然后我们会得到32x24的温度数据然后用得到的
32x24阵列的温度数据构造Image对象(这里需要将温度数据映射到[0,255]的数值,为了对比明显,最好从得到所有像素点的极端值比如[20℃,45℃],然后按比例映射到8bit灰度值空间[0,255]), 对图像进行基本的处理,比如放大(resize,插值),然后伪彩映射可以得到一张好看的图后面这些部分就是锦上添花的了, 在图片上画十字来标记最高温度点以及可以在图片中心标记温度,这样方便读数
将摄像头数据和传感器图像融合,得到有轮廓的热力图, 摄像头图像需要经过边缘标记,然后根据两个摄像头(图像摄像头和红外成像摄像头)的相对位置调整一下摄像头图片的位置,使用偏移旋转放大缩小达到与热力图吻合的效果
然后显示到显示器即可
代码 (没有优化,比较粗糙,可以运行,上面的图片来自于下面程序的截图):
import lcd, image, sensorfrom fpioa_manager import *from machine import UARTimport gcauto_color = Truemax_temp_limit = 300 # max 300min_temp_limit = 0 # min -40edge = (-1,-1,-1,-1,8,-1,-1,-1,-1)offset_x = 0offset_y = 50zoom = 1.2rotate = 0START_FLAG = 0x5Asensor_width = 32sensor_height = 24lcd_w = 320lcd_h = 240fm.register(9, fm.fpioa.UART1_TX)fm.register(10, fm.fpioa.UART1_RX)com = UART(UART.UART1, 460800, timeout=1000, read_buf_len=4096)lcd.init()sensor.reset()sensor.set_pixformat(sensor.RGB565)sensor.set_framesize(sensor.QVGA)clock = time.clock()find_frame_flag = Falsewhile 1:clock.tick()if not find_frame_flag:data = 0flag_count = 0while 1:if com.any() <= 0:continuedata = com.read(1)if int.from_bytes(data, 'little') == START_FLAG:flag_count += 1if flag_count == 2:find_frame_flag = Truebreakelse:flag_count = 0else:find_frame_flag = Falsemax_temp_pos=Nonedata = com.read(2)data_len = int.from_bytes(data[:2], "little")sum = START_FLAG * 256 + START_FLAG + data_lenif auto_color:min_temp = max_temp_limitmax_temp = min_temp_limitdata = com.read(data_len-2)target_temp = []for i in range(data_len//2-1):v = int.from_bytes(data[i*2:i*2+2], 'little')sum += vv = v/100.0if auto_color:if v < min_temp:if v < min_temp_limit:min_temp = min_temp_limitelse:min_temp = vif v > max_temp:if v > max_temp_limit:min_temp = max_temp_limitelse:max_temp = vmax_temp_pos = (i%sensor_width, i//sensor_width)target_temp.append( v )data = com.read(2)v = int.from_bytes(data, 'little')sum += vmachine_temp = v/100.0data = com.read(2)parity_sum = int.from_bytes(data, 'little')if len(target_temp) != sensor_height*sensor_width:print("err")continue# print("{:02x} {:02x}".format(parity_sum, sum%0xffff))# TODO: parity not correct according to the doc# if parity_sum != sum%0xffff:# print("parity sum error")# continuecenter_temp = target_temp[int(sensor_width/2 + sensor_height/2*sensor_width)]# print("data length:", len(target_temp))# print("machine temperature:", machine_temp)# print("center temperature:", center_temp)img = image.Image(size=(sensor_width, sensor_height))img = img.to_grayscale()if max_temp == min_temp:max_temp += 1for i in range(sensor_height):for j in range(sensor_width):color = (target_temp[i*sensor_width+j]-min_temp)/(max_temp-min_temp)*255img[sensor_width*i + j] = int(color)img = img.resize(lcd_w, lcd_h)del target_tempimg = img.to_rainbow(1)img2 = sensor.snapshot()img2.conv3(edge)img2 = img2.rotation_corr(z_rotation=rotate, x_translation=offset_x, y_translation=offset_y, zoom=zoom)img = img.blend(img2)del img2img = img.draw_rectangle(lcd_w//2+4, lcd_h//2, 80, 22, color=(0xff,112,0xff), fill=True)img = img.draw_string(lcd_w//2+4, lcd_h//2, "%.2f" %(center_temp), color=(0xff,0xff,0xff), scale=2)img = img.draw_cross(lcd_w//2, lcd_h//2, color=(0xff,0xff,0xff), thickness=3)if max_temp_pos:max_temp_pos = (int(lcd_w/sensor_width*max_temp_pos[0]), int(lcd_h/sensor_height*max_temp_pos[1]))img = img.draw_rectangle(max_temp_pos[0]+4, max_temp_pos[1], 80, 22, color=(0xff,112,0xff), fill=True)img = img.draw_string(max_temp_pos[0]+4, max_temp_pos[1], "%.2f" %(max_temp), color=(0xff,0xff,0xff), scale=2)img = img.draw_cross(max_temp_pos[0], max_temp_pos[1], color=(0xff,0xff,0xff), thickness=3)fps =clock.fps()img = img.draw_string(2,2, ("%2.1ffps" %(fps)), color=(0xff,0xff,0xff), scale=2)lcd.display(img)img = com.read()del imggc.collect()# gc.mem_free()
或者在PC 使用pyserial上读取并显示:
import serialimport pygamefrom pygame.locals import QUIT, KEYDOWN, K_f, K_F11, FULLSCREENfrom PIL import Image, ImageDrawimport matplotlib.pyplot as pltimport numpy as npimport timeSTART_FLAG = 0x5Awidth = 32height = 24dis_width = 320dis_height = 240auto_color = Truemax_temp_limit = 300min_temp_limit = -40com = serial.Serial()com.baudrate = 460800com.port = "/dev/ttyACM0"com.bytesize = 8com.stopbits = 1com.parity = "N"com.timeout = Nonecom.rts = Truecom.dtr = Truecom.open()pygame.init()pygame.display.set_caption("pic from client")screen = pygame.display.set_mode((dis_width, dis_height), 0, 32)def get_hot_color_map():hot_map = plt.get_cmap("hot")color_map = np.zeros((256,3), np.uint8)for i in range(256):color_map[i][0] = np.int_(hot_map(i)[0]*255.0)color_map[i][1] = np.int_(hot_map(i)[1]*255.0)color_map[i][2] = np.int_(hot_map(i)[2]*255.0)return color_mapdef temp_list2bytes(temperature_list):ret = b''for temp in temperature_list:ret += bytes( [int(temp*10/2)] )return retdef get_dis_temp_by_target_temp(target_temp, in_size, out_size):# (in_w, in_h), (out_w, out_h)passhot_color_map = get_hot_color_map()color_array = np.zeros((height, width, 3), np.uint8)find_frame_flag = Falsewhile 1:if not find_frame_flag:data = 0flag_count = 0while 1:data = com.read(1)if int.from_bytes(data, byteorder='little') == START_FLAG:flag_count += 1if flag_count == 2:find_frame_flag = Truebreakelse:flag_count = 0else:find_frame_flag = Falsemax_temp_pos=Nonedata = com.read(2)data_len = int.from_bytes(data[:2], byteorder="little")sum = START_FLAG * 256 + START_FLAG + data_lenif auto_color:min_temp = max_temp_limitmax_temp = min_temp_limitdata = com.read(data_len-2)target_temp = []for i in range(data_len//2-1):v = int.from_bytes(data[i*2:i*2+2], byteorder='little')sum += vv /= 100.0if auto_color:if v < min_temp:if v < min_temp_limit:min_temp = min_temp_limitelse:min_temp = vif v > max_temp:if v > max_temp_limit:min_temp = max_temp_limitelse:max_temp = vmax_temp_pos = (i%width, i//width)target_temp.append( v )data = com.read(2)v = int.from_bytes(data, byteorder='little')sum += vmachine_temp = v/100.0data = com.read(2)parity_sum = int.from_bytes(data, byteorder='little')print("{:02x} {:02x}".format(parity_sum, sum%0xffff))# TODO: parity not correct according to the doc# if parity_sum != sum%0xffff:# print("parity sum error")# continueprint("data length:", len(target_temp))print("machine temperature:", machine_temp)temp_bytes = temp_list2bytes(target_temp)if max_temp == min_temp:max_temp += 1# dis_temperature = get_dis_temp_by_target_temp(target_temp, (width, height), (dis_width, dis_height))try:for i in range(0, height):for j in range(0, width):color = (target_temp[i*width+j]-min_temp)/(max_temp-min_temp)*255color_array[i, j] = hot_color_map[int(color)]img = Image.fromarray(color_array)img = img.resize( (dis_width,dis_height), resample=Image.LANCZOS)draw = ImageDraw.Draw(img)draw.line((img.width/2-4, img.height/2, img.width/2+4, img.height/2), fill=0xff3ef8, width=1)draw.line((img.width/2, img.height/2-4, img.width/2, img.height/2+4), fill=0xff3ef8, width=1)draw.rectangle([(img.width/2+10, img.height/2), (img.width/2+40, img.height/2+10)], fill=0x10bd87)center_temp = target_temp[int(width/2 + height/2*width)]draw.text((img.width/2+10, img.height/2), "{}".format(center_temp), fill=0xffff)if max_temp_pos:max_temp_pos = (int(dis_width/width*max_temp_pos[0]), int(dis_height/height*max_temp_pos[1]))draw.line((max_temp_pos[0]-4, max_temp_pos[1], max_temp_pos[0]+4, max_temp_pos[1]), fill=0xff3ef8, width=1)draw.line((max_temp_pos[0], max_temp_pos[1]-4, max_temp_pos[0], max_temp_pos[1]+4), fill=0xff3ef8, width=1)draw.rectangle([(max_temp_pos[0]+10, max_temp_pos[1]), (max_temp_pos[0]+40, max_temp_pos[1]+10)], fill=0x10bd87)draw.text((max_temp_pos[0]+10, max_temp_pos[1]), "{}".format(max_temp), fill=0xffff)surface = pygame.image.fromstring(img.tobytes(), img.size, img.mode).convert()screen.blit(surface,(0, 0))pygame.display.update()print("recieve ok")except Exception as e:print(e)com.close()

