FPGA实现图像灰度转换(1):RGB分量转Gray
Gray灰度图像:即我们常说的黑白图像,由黑到白的灰阶为 0- 255(8bit)。
本博客整理一下 RGB 分量实现 Gray 灰度效果的实验,这个实验非常的简单,简单到看到代码就感觉非常无语......
一、RGB分量转Gray灰度的原理
RGB格式即一个像素由R、G、B三基色构成,例如 RGB565 格式的像素排列为R[4:0]、G[5:0]、B[4:0],RGB三个分量的数值不同,最后合成的像素颜色则不同。
RGB分量转Gray灰度即只挑取 R 或 G 或 B 的 1 个分量,剩下的 2 个分量丢弃,其位置由挑取的分量来替代。
二、MATLAB
此次实验选择了一张 RGB 分量明显的图片,先从 MATLAB 软件中查看效果如何。代码如下所示:
clc; clear all; RGB = imread('flower.bmp'); %读取图像 R_gray = RGB(:,:,1); %提取R分量后的灰度图 G_gray = RGB(:,:,2); %提取G分量后的灰度图 B_gray = RGB(:,:,3); %提取B分量后的灰度图 subplot(2,2,1);imshow(RGB); title('原图'); subplot(2,2,2);imshow(R_gray);title('R分量灰度图'); subplot(2,2,3);imshow(G_gray);title('G分量灰度图'); subplot(2,2,4);imshow(B_gray);title('B分量灰度图');
运行效果如下所示:

可以看出虽然都是灰度图,但不同分量获得的效果是不同的。
三、FPGA中的实现
1、模块划分
本实验基于串口传输,在前面的博客中整理过。
图像处理的模块添加在哪里好呢?一开始我是添加到串口模块到 SDRAM 缓存模块之间的,但是因为这次实验是基于图片的,加在这个位置后 SDRAM 里缓存的是一张处理之后的图片,如果要进行效果切换则必须重新编译下载工程,串口再重新发送图片数据,非常的麻烦。经过思考,我决定不动SDRAM之前的模块,让SDRAM缓存原图,再把图像处理模块添加在 TFT 控制器模块之后,并且引入按键,通过按键切换显示效果。这样原先的TFT控制器模块就相当于一个中转站,图像真正的传输到管脚是在图像处理之后。图像处理模块则命名为 ISP_top,专门进行各种图像处理,最终的信号连接到 FPGA 的 TFT屏管脚。本工程的框架图如下所示:

这篇博客实际算是图像处理的第一篇博客,之前的都是预备知识,所以展示的内容全一点,后续的图像处理工程也都是基于此架构实现,不会再详细说明。
2、完整代码
过于简单,所以直接贴代码吧。
(1)ISP_top
//**************************************************************************
// *** 名称 : ISP_top.v
// *** 作者 : xianyu_FPGA
// *** 博客 : https://www.cnblogs.com/xianyufpga/
// *** 日期 : 2020年3月
// *** 描述 : 图像处理模块的顶层文件
//**************************************************************************
module ISP_top
//========================< 参数 >==========================================
#(
parameter H_DISP = 12'd480 , //图像宽度
parameter V_DISP = 12'd272 //图像高度
)
//========================< 端口 >==========================================
(
input wire clk , //时钟
input wire rst_n , //复位
//RGB -----------------------------------------------
input wire RGB_hsync , //RGB行同步
input wire RGB_vsync , //RGB场同步
input wire [15:0] RGB_data , //RGB数据
input wire RGB_de , //RGB数据使能
//key -----------------------------------------------
input wire [ 1:0] key_vld , //消抖后的按键值
//DISP ----------------------------------------------
output wire DISP_hsync , //最终显示的行同步
output wire DISP_vsync , //最终显示的场同步
output wire [15:0] DISP_data , //最终显示的数据
output wire DISP_de //最终显示的数据使能
);
//========================< 连线 >==========================================
wire [15:0] R_Gray ; //R分量灰度数据
wire [15:0] G_Gray ; //G分量灰度数据
wire [15:0] B_Gray ; //B分量灰度数据
//==========================================================================
//== RGB分量
//==========================================================================
RGB_Gray u_RGB_Gray
(
//RGB -------------------------------------------
.RGB_data (RGB_data ), //原始RGB图像
//Gray ------------------------------------------
.R_Gray (R_Gray ), //R分量灰度数据
.G_Gray (G_Gray ), //G分量灰度数据
.B_Gray (B_Gray ) //B分量灰度数据
);
//==========================================================================
//== 按键选择不同图像效果
//==========================================================================
display u_display
(
.clk (clk ), //时钟
.rst_n (rst_n ), //复位
//RGB -------------------------------------------
.RGB_hsync (RGB_hsync ), //RGB行同步
.RGB_vsync (RGB_vsync ), //RGB场同步
.RGB_data (RGB_data ), //RGB数据
.RGB_de (RGB_de ), //RGB数据使能
//Gray ------------------------------------------
.R_Gray (R_Gray ), //R分量灰度数据
.G_Gray (G_Gray ), //G分量灰度数据
.B_Gray (B_Gray ), //B分量灰度数据
//key -------------------------------------------
.key_vld (key_vld ), //消抖后的按键值
//DISP ------------------------------------------
.DISP_hsync (DISP_hsync ), //最终显示的行同步
.DISP_data (DISP_data ), //最终显示的场同步
.DISP_de (DISP_de ), //最终显示的数据
.DISP_vsync (DISP_vsync ) //最终显示的数据使能
);
endmodule
(2)RGB_Gray
1 //************************************************************************** 2 // *** 名称 : RGB_Gray.v 3 // *** 作者 : xianyu_FPGA 4 // *** 博客 : https://www.cnblogs.com/xianyufpga/ 5 // *** 日期 : 2020年3月 6 // *** 描述 : RGB分量转Gray灰度图 7 //************************************************************************** 8 9 module RGB_Gray 10 //========================< 端口 >========================================== 11 ( 12 input wire [15:0] RGB_data , //原始图像数据 13 output wire [15:0] red , //R分量灰度图 14 output wire [15:0] green , //G分量灰度图 15 output wire [15:0] blue //B分量灰度图 16 ); 17 //========================================================================== 18 //== 代码 19 //========================================================================== 20 assign red = {RGB_data[15:11],RGB_data[15:11],1'b0,RGB_data[15:11]}; 21 assign green = {RGB_data[10:6],RGB_data[10:5],RGB_data[10:6]}; 22 assign blue = {RGB_data[4:0],RGB_data[4:0],1'b0,RGB_data[4:0]}; 23 24 25 26 endmodule
(3)display
//**************************************************************************
// *** 名称 : display.v
// *** 作者 : xianyu_FPGA
// *** 博客 : https://www.cnblogs.com/xianyufpga/
// *** 日期 : 2020年3月
// *** 描述 : 按键切换不同的图像效果
//**************************************************************************
module display
//========================< 端口 >==========================================
(
input wire clk , //时钟
input wire rst_n , //复位
//RGB -----------------------------------------------
input wire RGB_hsync , //RGB行同步
input wire RGB_vsync , //RGB场同步
input wire [15:0] RGB_data , //RGB数据
input wire RGB_de , //RGB数据使能
//RGB_gray ------------------------------------------
input wire [15:0] R_Gray , //R分量灰度数据
input wire [15:0] G_Gray , //G分量灰度数据
input wire [15:0] B_Gray , //B分量灰度数据
//key -----------------------------------------------
input wire [ 1:0] key_vld , //消抖后的按键值
//DISP ----------------------------------------------
output reg DISP_hsync , //最终显示的行同步
output reg DISP_vsync , //最终显示的场同步
output reg [15:0] DISP_data , //最终显示的数据
output reg DISP_de //最终显示的数据使能
);
//========================< 信号 >==========================================
reg [ 3:0] state ; //状态机
//========================< 参数 >==========================================
localparam IDLE = 4'b0001 ; //IDLE状态
localparam R = 4'b0010 ; //R分量状态
localparam G = 4'b0100 ; //G分量状态
localparam B = 4'b1000 ; //B分量状态
//==========================================================================
//== 按键切换不同显示效果
//==========================================================================
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
state <= IDLE;
else begin
case(state)
//--------------------------------------------------- 原图
IDLE: begin
if(key_vld[0])
state <= R;
else if(key_vld[1])
state <= IDLE;
end
//--------------------------------------------------- R分量灰度图
R: begin
if(key_vld[0])
state <= G;
else if(key_vld[1])
state <= IDLE;
end
//--------------------------------------------------- G分量灰度图
G: begin
if(key_vld[0])
state <= B;
else if(key_vld[1])
state <= IDLE;
end
//--------------------------------------------------- B分量灰度图
B: begin
if(key_vld[0])
state <= R;
else if(key_vld[1])
state <= IDLE;
end
//--------------------------------------------------- 默认输出
default:state <= IDLE;
endcase
end
end
//==========================================================================
//== 不同状态对应不同的图像输出
//==========================================================================
always @(*) begin
case(state)
//--------------------------------------------------- 原图
IDLE: begin
DISP_hsync = RGB_hsync;
DISP_vsync = RGB_vsync;
DISP_data = RGB_data;
DISP_de = RGB_de;
end
//--------------------------------------------------- R分量灰度图
R: begin
DISP_hsync = RGB_hsync;
DISP_vsync = RGB_vsync;
DISP_data = R_Gray;
DISP_de = RGB_de;
end
//--------------------------------------------------- G分量灰度图
G: begin
DISP_hsync = RGB_hsync;
DISP_vsync = RGB_vsync;
DISP_data = G_Gray;
DISP_de = RGB_de;
end
//--------------------------------------------------- B分量灰度图
B: begin
DISP_hsync = RGB_hsync;
DISP_vsync = RGB_vsync;
DISP_data = B_Gray;
DISP_de = RGB_de;
end
//--------------------------------------------------- 默认输出
default:begin
DISP_hsync = RGB_hsync;
DISP_vsync = RGB_vsync;
DISP_data = RGB_data;
DISP_de = RGB_de;
end
endcase
end
endmodule
上面说过,这个图像处理非常简单,看到代码就觉得非常无语......连时钟和复位都没有用到,如果不是为了实现按键切换的效果,其实可以直接在顶层assign一下就行了。但是本次实验是后续一系列实验的开篇之作,所以模块什么的都尽可能划科学点,后面就省事了。
四、上板验证
原图:

R分量灰度图:

G分量灰度图:

B分量灰度图:

实验效果和 MATLAB 中呈现的一样,此次实验成功。
实验可以通过按键模块 key_select 切换显示效果,切换顺序为:原图、R分量灰度图、G分量灰度图、B分量灰度图。视频演示如下:
参考资料:
[1]小梅哥FPGA图像处理教程
[2]OpenS Lee:FPGA开源工作室(公众号)

浙公网安备 33010602011771号