串口傳圖: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教程

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM