串口传图:RGB332格式和RGB565格式

  之前记录过串口模块、SDRAM模块、VGA和TFT屏模块的开发,把他们结合起来就能做出串口传图工程了。

  很多人一直没做好这个工程,很大的原因是 SDRAM 控制器没有写好,所以采用了ROM或RAM来做缓存,最终显示的图片分辨率非常小。如果SDRAM控制器搞好了,那就可以传大图了,我在之前的博客已经记录了 SDRAM 控制器的开发过程,那时候最后也进行了传图,但是没有记录上。这次做图像处理系列工程,专门整理一下传图的整个过程和注意事项。

一、RGB332格式

  串口一次传输 8bit 的数据,所以最开始设计时,我想的也是一个串口 8bit 数据就代表一个 8bit 的像素,这样用之前的串口模块来接收就可以了,非常简洁。

1、生成 RGB332 的 Hex 文本(学自V3学院FPGA教程)

  日常见到的图片大多是 24bit 的,称为 RGB888,而我们这次要用 8bit 代表一个像素值,则要使用 RGB332。此外还需要将一张图片里所有的像素值转化为 Hex 文本,串口那边才能识别。这个过程看起来很复杂,实际上用 MATLAB 软件很容易就可以实现。

(1)网上找到一张喜欢的图片,将分辨率调整为 VGA 或 TFT 显示的分辨率,例如我找到一张美女的图片,命名为 woman.jpg。很多软件进行图片分辨率调整,最后要么是图片变形,要么是简单的裁剪,如果是分辨率大的图,按分辨率裁剪就只能看到图片的一小部分了。我采用的调整工具是光影魔术手,可以指定分辨率的纵横比,调整框可以继续调大调小,最大限度的获得原图的有效部分,而图片本身也不会变形。

(2)打开MATLAB,新建 .m 文件,将刚刚的图片和 .m 文件放在同一个文件夹,输入如下程序。程序都写了注释,还是比较好理解的,bitshift函数是移位函数,正数为左移,负数为右移,不懂的可以在MATLAB软件中查看具体用法。

 1 %--------------------------------------------------------------------------
 2 %--           图片数据转换:1个像素转换成1个 8bit hex 数据
 3 %--------------------------------------------------------------------------
 4 clear all;
 5 RGB24 = imread('woman.jpg');                %读取图片文件
 6 
 7 R = bitshift(RGB24(1:end,1:end,1),-5);      %取R高3位,{5'b0,R[7:5]}
 8 G = bitshift(RGB24(1:end,1:end,2),-5);      %取G高3位,{5'd0,G[7:5]}
 9 B = bitshift(RGB24(1:end,1:end,3),-6);      %取B高2位,{6'd0,B[7:6]}
10 rgb332 = bitshift(R,5) + bitshift(G,2) + B; %拼接{R[7:5],G[7:5],B[7:6]}
11 
12 fid=fopen('rgb332.txt','w+');               %打开文件
13 fprintf(fid,'%02x ',rgb332');               %将字符打印到txt文件中

(3)点击运行,MATLAB就在文件夹里新建并打印了好了 hex 文件,这就是我们待会串口要用到的图像数据,其格式为RGB332,一个8bit hex 字符代表一个 RGB332 像素。

2、搭建工程

  如上是我本次搭建的模块,如果基础扎实,这些都算比较简单的,总而言之就是“串口接收 - SDRAM缓存 - TFT屏显示”,如果有摄像头,那串口部分换成摄像头也是可以的。

3、RGB332转RGB565

  如果VGA或TFT屏的图像接口也是8位的,那直接发送后就可以看到图像了。如果是16位的,那串口接收到RGB332的像素数据后还得进行 RGB332 转 RGB565 的操作,这样才能和屏幕像素格式相匹配。

  转换的方式非常简单,不够的低位直接补0,或者不够的低位继续填充原像素值的低位,就算是转RGB888也是一样的思想。这块代码比较简单,我直接写在了顶层的top模块,如下所示:

assign wr_data = {uart_data[7:5],uart_data[6:5], //SDRAM写数据
                  uart_data[4:2],uart_data[4:2],
                  uart_data[1:0],uart_data[1:0],uart_data[0]};

assign wr_en   = uart_data_vld;                  //SDRAM写使能

4、实验效果

 

  实际的效果是肉眼可见图片慢慢的加载,直到加载完成。加载速度受串口传输速度的影响,尽可能把串口传输速度提高,如比特率设置为115200,虽然还是比较慢,但可以忍受。

 二、RGB565格式

  上面RGB332的传输方式,导致图片质量不好,因此改为直接传输RGB565格式,看看效果是否会变好。

1、生成 RGB565 的 Hex 文本(学自V3学院FPGA教程)

(1)网上找到一张喜欢的图片,将分辨率调整为 VGA 或 TFT 显示的分辨率。

(2)打开MATLAB,新建 .m 文件,将刚刚的图片和 .m 文件放在同一个文件夹,输入如下程序。bitshift函数是移位函数,bitand函数是位与函数,把数字转化为二进制来看就能想通了。

 1 %--------------------------------------------------------------------------
 2 %--           图片数据转换:1个像素转换成2个 8bit hex 数据
 3 %--------------------------------------------------------------------------
 4 clear all;
 5 RGB24 = imread('woman.jpg');            %读取图片文件
 6 
 7 fid = fopen('rgb565.txt','w+');         %打开文件
 8 [ROW,COL,N] = size(RGB24);              %获得图片尺寸[高度,长度,维度]
 9 
10 for i = 1:ROW
11     for j = 1:COL
12         RG = bitand(RGB24(i,j,1),248) + bitshift(RGB24(i,j,2),-5); %{R[7:3],3'd0} + {5'd0,G[7:5]}
13         G = bitand(RGB24(i,j,2),28);                               %{3'd0,G[4:2],2'd0}
14         GB = bitshift( G,3) + bitshift(RGB24(i,j,3),-3);           %{G[4:2],5'd0} + {3'd0,B[7:3]}
15         fprintf(fid,'%02x %02x ',RG,GB);%将字符打印到txt文件中
16     end
17 end

(3)点击运行,MATLAB就在文件夹里新建并打印了好了 hex 文件,这就是我们待会串口要用到的图像数据,其格式为RGB565,两个 8bit hex 字符代表一个 RGB565 像素,第一个字符是R5G3,第二个字符是G3B5。

2、搭建工程

  和上面是一样的,串口模块变为了16bit,因为我在串口模块内部增加了 8bit 转 16bit 数据的操作。

3、8bit转16bit

  串口接收后的 2 个数据代表 1 个 RGB565 像素,因此我们要把串口的一个个 8bit 数据进行拼接,还原为 16bit RGB565 像素,这一块代码用到时序逻辑,我写在了串口模块里面。

always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        byte_cnt <= 'd0;
    else if(add_byte_cnt) begin
        if(end_byte_cnt)
            byte_cnt <= 0;
        else
            byte_cnt <= byte_cnt + 1'b1;
    end
end

assign add_byte_cnt = rx_data_vld;
assign end_byte_cnt = add_byte_cnt && byte_cnt== 2-1;

always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        dout <= 0;
    else if(add_byte_cnt)
        dout <= {dout[7:0],rx_data};
end

always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        dout_vld <= 1'b0;
    else if (end_byte_cnt)
        dout_vld <= 1'b1;
    else
        dout_vld <= 1'b0;
end

4、实验效果

  可以看到,图片效果比上面好太多了,几乎与电脑上的原图无异。既是如此,那以后做图像处理就用这个版本的工程吧!

参考资料:

[1]V3学院FPGA教程

[2]小梅哥FPGA教程

[3]正点原子FPGA教程

猜你喜欢

转载自www.cnblogs.com/xianyufpga/p/12395595.html
今日推荐