• 串口传图: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教程

  • 相关阅读:
    leetCode21. 合并两个有序链表
    (flag)每日三道面试题(4.25)
    每日三加一面试题(4.21)
    按照顺序执行异步函数
    javascript Proxy 代理模式深度监听对象、数组变化
    数据结构与算法(二) 线性表一
    This关键字
    数据结构与算法(一)
    Git报错信息
    MakeDown语法学习
  • 原文地址:https://www.cnblogs.com/xianyufpga/p/12395595.html
Copyright © 2020-2023  润新知