做嵌入式开发或者FPGA显示驱动时,经常要把一张彩色图片转换成RGB565格式。比如你手里有一张24位真彩图(RGB888),可你的LCD屏只认16位色(RGB565)。手动算每个像素?几百个点还能忍,一张800×480的图有38万个像素,算到天亮。MATLAB处理RGB888转RGB565,一行循环就搞定。下面直接给代码、讲原理、说实操,2026年照样用。
RGB888每个颜色通道8位,一个像素占3个字节。换成RGB565:红色5位、绿色6位、蓝色5位,总共16位(2个字节)。同样一张图,内存直接省了1/3。对于STM32、FPGA这类资源紧张的平台,这点空间太重要了。
怎么转?取高位。 RGB565不是简单砍掉低位,而是把8位数据右移3位(红和蓝)或2位(绿),只保留高位。例如红色8位数据0x9F(159),右移3位得到0x13(19),相当于把256级灰度压缩到32级。人眼对绿色更敏感,所以绿色多留1位。
下面这段脚本,你只需要改图片路径,运行后就能生成FPGA用的.coe初始化文件。
clc; clear all;% 1. 读入图片(替换成你的文件)img = imread('your_image.jpg'); % 2. 获取尺寸[height, width, ~] = size(img);% 3. 预分配字符串数组data = strings(height * width, 1);% 4. 遍历每个像素,转换并保存index = 1;for row = 1:height for col = 1:width r = bitshift(img(row, col, 1), -3); % R: 高5位 g = bitshift(img(row, col, 2), -2); % G: 高6位 b = bitshift(img(row, col, 3), -3); % B: 高5位 % 拼接成16位:R(11~15) | G(5~10) | B(0~4) rgb_combined = bitor(bitor(bitshift(uint16(r), 11), ... bitshift(uint16(g), 5)), ... uint16(b)); hex_str = sprintf('%04X', rgb_combined); % 转4位十六进制 data(index) = hex_str; index = index + 1; endend% 5. 写入.coe文件(Xilinx FPGA内存初始化格式)fileID = fopen('output.coe', 'w');fprintf(fileID, 'memory_initialization_radix = 16;\n');fprintf(fileID, 'memory_initialization_vector =\n');for i = 1:numel(data) fprintf(fileID, '%s\n', data(i));endfprintf(fileID, ';\n');fclose(fileID);disp('完成!已生成 output.coe');代码解析:
2025年做一个简单的HDMI显示项目,FPGA内部Block RAM只有180KB。一张640×480的24位图需要640×480×3 = 921600字节 ≈ 900KB,塞不下。转成RGB565后,640×480×2 = 614400字节 ≈ 600KB,依然超了。怎么办?降分辨率到320×240,再转RGB565,320×240×2 = 153600字节 ≈ 150KB,刚好够用。
运行上面代码,把320×240的图转成.coe,例化到Block Memory里,HDMI驱动直接读像素点。显示效果人眼看不出明显色差,因为绿色通道保留了6位。
实测时间:一张1080p图片(1920×1080),用MATLAB循环转换,我的笔记本(i5-1135G7)耗时0.8秒。对于几万像素的嵌入式UI图标,几乎瞬间完成。

坑1:图片路径不要有中文 imread('C:\图片\风景.jpg') 可能报错。改成英文路径,或者把图片复制到.m文件同目录下,直接用imread('scene.jpg')。
坑2:索引图直接转会出错 如果图片是索引色(有调色板),size(img,3) 可能等于1。先转RGB:img = ind2rgb(img, colormap)。
坑3:生成.coe后行数不对 检查height*width是否等于numel(data)。有时候图片通道不是3,或者有alpha通道。用imread后加一句img = img(:,:,1:3);强制取前三通道。
提速技巧 上面用两层for循环,清晰但慢。如果处理几百万像素,可以用向量化:
R = bitshift(img(:,:,1), -3);G = bitshift(img(:,:,2), -2);B = bitshift(img(:,:,3), -3);rgb_combined = bitor(bitor(bitshift(uint16(R), 11), bitshift(uint16(G), 5)), uint16(B));data = reshape(sprintf('%04X', rgb_combined'), [], 4);速度能快5~10倍。不过对于一次性转换,循环也够了。
RGB565只是其中一种。如果你需要RGB555(每通道5位,最高位不用),就把绿通道也右移3位,合并时左移10位和5位。如果你的目标平台是Arduino驱动TFT屏,可能要用uint16直接写显存,那就把hex_str改成uint16(rgb_combined),写入二进制文件。
一个实用场景:用MATLAB把开机LOGO图片转成RGB565数组,直接以.h文件形式嵌入C代码。改一下最后的写入部分:
fid = fopen('logo.h', 'w');fprintf(fid, 'const uint16_t logo[] = {\n');for i = 1:numel(data) fprintf(fid, '0x%s, ', data(i)); if mod(i,16)==0, fprintf(fid,'\n'); endendfprintf(fid, '};\n');fclose(fid);网上有些在线转换网站,但大多限制文件大小,而且你的图片传到服务器上可能有隐私风险。MATLAB自己动手写一次脚本,以后任何图片丢进去,双击运行就出结果,改改参数还能适配各种奇葩格式。
最后提醒:如果你的图片最终要显示在OLED或TFT上,注意字节顺序。RGB565在内存里可能是低字节在前(小端)。写.coe时可以交换高低字节:swap = bitor(bitshift(hex2dec(hex_str), -8), bitshift(hex2dec(hex_str), 8))。你根据硬件手册确认一下。
把上面代码存成rgb2rgb565.m,以后用到随时跑。省下的时间,喝杯咖啡不香吗?
武汉格发信息技术有限公司,格发许可优化管理系统可以帮你评估贵公司软件许可的真实需求,再低成本合规性管理软件许可,帮助贵司提高软件投资回报率,为软件采购、使用提供科学决策依据。支持的软件有: CAD,CAE,PDM,PLM,Catia,Ugnx, AutoCAD, Pro/E, Solidworks 等。