串口获取RGB565(uint16)数组生成320x240图像异常排查
RGB565格式图像转存时出现重复问题的解决
问题描述
我从串口获取RGB565格式的uint16数值,数组对应320×240图像的76800个像素数据。发送测试条图像后,生成的图像出现重复问题(见附图)。我使用Python的PIL库将数组数值转换为像素生成图像,但结果不符合预期。最初怀疑是编码问题,后认为可能与图像生成方式有关,发现论坛中多采用numpy数组处理此类问题。
原代码如下:
def TakePicture(): xdim = 320 ydim = 240 i=0 RGB_list.pop(0) im = Image.new("RGB",(xdim,ydim)) for k in range(76800): value1=int(RGB_list[k]) RGB_values.append(value1) for y in range(ydim): for x in range(xdim): px = RGB_values[i] i = i+1 im.putpixel((x,y),((px&0xF800) >> 8, (px&0x07E0) >> 3, (px&0x001F) << 3)) im.save('image.png') im.show() def main(): try: serialPort=serial.Serial(port='/dev/ttyUSB1', baudrate=115200,bytesize=8,parity=serial.PARITY_NONE,stopbits=1,timeout=0) except: print("unable to open port") while(1): if(serialPort.in_waiting>0): incoming=serialPort.readline().decode('ascii','ignore') incoming=incoming.rstrip() if('ET' not in incoming): if(not incoming): incoming='0' print(incoming) RGB_list.append(incoming) else: with open('serial_python.txt','w',newline='',encoding='utf-8') as txtfile: writer=csv.writer(txtfile) for i in RGB_list: writer.writerow([i]) TakePicture()
问题分析
- 全局变量未清理:
RGB_values和RGB_list未做初始化/清空处理,每次调用TakePicture()时会累积旧数据,导致图像重复。 - 逐像素操作低效且易出错:
putpixel是单像素写入,不仅速度慢,循环过程中一旦索引出错就会导致图像错位或重复。 - 数据转换时机不合理:在
TakePicture()中才批量转换字符串为int,增加了出错概率。
修复方案
改用numpy批量处理RGB格式转换,同时规范变量生命周期:
import serial import csv from PIL import Image import numpy as np def TakePicture(rgb_data): width, height = 320, 240 # 转换为uint16数组,跳过第一个元素(对应原代码的pop(0)) rgb565 = np.array(rgb_data[1:], dtype=np.uint16) # 批量转换RGB565到RGB888 r = ((rgb565 & 0xF800) >> 8).astype(np.uint8) g = ((rgb565 & 0x07E0) >> 3).astype(np.uint8) b = ((rgb565 & 0x001F) << 3).astype(np.uint8) # 组合为(height, width, 3)的RGB数组 rgb_array = np.stack([r, g, b], axis=1).reshape(height, width, 3) # 生成并保存图像 img = Image.fromarray(rgb_array) img.save('image.png') img.show() def main(): rgb_list = [] try: ser = serial.Serial(port='/dev/ttyUSB1', baudrate=115200, bytesize=8, parity=serial.PARITY_NONE, stopbits=1, timeout=0) except Exception as e: print(f"无法打开串口: {str(e)}") return while True: if ser.in_waiting > 0: line = ser.readline().decode('ascii', 'ignore').rstrip() if 'ET' not in line: # 空行替换为0并转成int val = int(line) if line else 0 print(val) rgb_list.append(val) else: # 保存接收的数据 with open('serial_python.txt', 'w', newline='', encoding='utf-8') as f: writer = csv.writer(f) for num in rgb_list: writer.writerow([num]) # 生成图像 TakePicture(rgb_list) # 清空列表,准备下一次接收 rgb_list.clear() if __name__ == "__main__": main()
核心优化点
- 变量本地化:将
rgb_list作为局部变量传递,避免全局变量的累积问题 - 批量处理:用numpy一次性完成格式转换,比逐像素操作快数十倍且逻辑更可靠
- 即时转换:串口接收时直接将字符串转为int,减少后续步骤的错误
- 清理机制:每次生成图像后清空数据列表,确保下一次接收的是全新数据
内容的提问来源于stack exchange,提问作者Gaston Melo
相关产品推荐
相关产品推荐

