You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

串口获取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()

问题分析

  1. 全局变量未清理:RGB_values和RGB_list未做初始化/清空处理,每次调用TakePicture()时会累积旧数据,导致图像重复。
  2. 逐像素操作低效且易出错:putpixel是单像素写入,不仅速度慢,循环过程中一旦索引出错就会导致图像错位或重复。
  3. 数据转换时机不合理:在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 14:37:34