基于FPGA的图像浮雕效果实现
项目简述
为什么要做这个小项目,因为最近正在在学习FPGA开源工作室中的FPGA图像处理的文章。发现这个小例子非常容易实现。就把这个小算法给复现了。这个基本上不能称之为一个项目,因为太简单了。但是,这里面涉及了真彩图转变成灰度图像的一个方法,在书写的时候我们也用到了除法器Ip(为了介绍IP专门使用的触除法器),有符号数的使用。所以,这里我们这里进行简单的介绍。
算法原理及MATLAB实现
写了好多博客关于图像处理算法的实现,不知道大家发没发现图像处理算法很容易在FPGA中复现,这是因为图像处理的数据是整数,一般也都针对像素点处理,这在FPGA实现的过程中完全没有压力。所以这也是FPGA在图像处理中的一个优点。
图像实现浮雕效果与SOBEL是非常相似的,只不过SOBEL是与一个像素点周围的像素点有关,而浮雕处理至于自己一行的像素点有关。具体的公式如下:
i m a g e _ n e w ( i , j ) = i m s g e ( i , j ) − i m a g e ( i , j + m ) + T H image\_new(i,j)=imsge(i,j)-image(i,j+m)+TH image_new(i,j)=imsge(i,j)−image(i,j+m)+TH
其中i是图像的行数,j是图像的列,TH是设置的阈值。这里需要注意的是上面的图像是灰度图像。
这里的m可以控制浮雕效果的明显程度,TH控制主背景的明亮程度。
常见的真彩图转换成灰度图像的方法主要有:
1、直接取RGB三分量其中的一种当作灰度化图像
2、将RGB三分量取平均当作灰度化图像
3、进行RGB到YCbCr格式的转换,取Y分量当作灰度化图像
本篇文章中我们使用的是第2中方法。
原理这么简单,也就不多说,MATLAB代码如下:
clc
clear all
image_old = imread('456.bmp');
image_gray= (image_old(:,:,1) + image_old(:,:,2)+image_old(:,:,2))/3;
[Height,Width] = size(image_gray);
image_new = zeros(Height,Width);
TH = 100;
for i = 1:Height
for j=1:Width-2
image_new(i,j)=image_gray(i,j)-image_gray(i,j+2)+TH;
if image_new(i,j) >255
image_new(i,j) = 255;
elseif image_new(i,j) <0
image_new(i,j) = 0;
else
image_new(i,j) = image_new(i,j);
end
end
end
image_new = uint8(image_new);
imshow(image_new);
实验效果如下:

处理后的图像为m=2:

处理后的图像为m=4:

对比上面两张图可以发现m可以控制浮雕效果的明显程度
浮雕效果的FPGA实现
上面的MATLAB代码,我们已经详细写出了算法流程,接下来我们直接给出相应的图像处理代码,并指出几点需要注意的地方:
`timescale 1ns / 1ps
// *********************************************************************************
// Project Name : OSXXXX
// Author : zhangningning
// Email : nnzhang1996@foxmail.com
// Website :
// Module Name : image.v
// Create Time : 2020-05-12 09:40:55
// Editor : sublime text3, tab size (4)
// CopyRight(c) : All Rights Reserved
//
// *********************************************************************************
// Modification History:
// Date By Version Change Description
// -----------------------------------------------------------------------
// XXXX zhangningning 1.0 Original
//
// *********************************************************************************
module image(
//System Interfaces
input sclk ,
input rst_n ,
//Communication Interfaces
input [31:0] rgb_data ,
input rgb_data_en ,
output wire [31:0] data_wr ,
output reg data_wr_en
);
//========================================================================================\
//**************Define Parameter and Internal Signals**********************************
//========================================================================================/
reg [15:0] gray_data ;
reg rgb_data_en_r ;
wire [23:0] divider_data ;
wire divider_data_en ;
reg [23:0] divider_data_r ;
reg [23:0] divider_data_r2 ;
reg signed [10:0] count_data ;
reg [ 7:0] dout ;
//========================================================================================\
//************** Main Code **********************************
//========================================================================================/
assign data_wr = {
8'h00,dout,dout,dout};
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
gray_data <= 16'd0;
else
gray_data <= rgb_data[31:24] + rgb_data[23:16] + rgb_data[15:8] + rgb_data[7:0];
always @(posedge sclk)
rgb_data_en_r <= rgb_data_en;
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)begin
divider_data_r <= 8'd0;
divider_data_r2 <= 8'd0;
end else if(divider_data_en == 1'b1)begin
divider_data_r <= divider_data;
divider_data_r2 <= divider_data_r;
end
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
count_data <= 11'd0;
else if(divider_data_en == 1'b1)
count_data <= divider_data_r2[23:8] - divider_data[23:8] + 100;
else
count_data <= count_data;
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
dout <= 8'd0;
else if(count_data > 255)
dout <= 8'd255;
else if(count_data < 0)
dout <= 8'd0;
else
dout <= count_data[7:0];
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
data_wr_en <= 1'b0;
else
data_wr_en <= divider_data_en;
div_gen_0 div_gen_0_inst (
.aclk (sclk ), // input wire aclk
.s_axis_divisor_tvalid (rgb_data_en_r ), // input wire s_axis_divisor_tvalid
.s_axis_divisor_tdata (8'd3 ), // input wire [7 : 0] s_axis_divisor_tdata
.s_axis_dividend_tvalid (rgb_data_en_r ), // input wire s_axis_dividend_tvalid
.s_axis_dividend_tdata (gray_data ), // input wire [15 : 0] s_axis_dividend_tdata
.m_axis_dout_tvalid (divider_data_en ), // output wire m_axis_dout_tvalid
.m_axis_dout_tdata (divider_data ) // output wire [23 : 0] m_axis_dout_tdata
);
endmodule
1、除法器的输出为什么使用了前16位,这里是引文后面的8位是小数位:

2、这里要使用下面的判断:

count_data必须在程序中定义成有符号数。

FPGA工程代码
这里为了方便大家的学习,我们给出整个FPGA工程的代码,整个项目的流程参考前面的SOBEL边缘检测部分,这里不多家赘述:
`timescale 1ns / 1ps
// *********************************************************************************
// Project Name : OSXXXX
// Author : zhangningning
// Email : nnzhang1996@foxmail.com
// Website :
// Module Name : top.v
// Create Time : 2020-03-01 20:33:42
// Editor : sublime text3, tab size (4)
// CopyRight(c) : All Rights Reserved
//
// *********************************************************************************
// Modification History:
// Date By Version Change Description
// -----------------------------------------------------------------------
// XXXX zhangningning 1.0 Original
//
// *********************************************************************************
module top(
//System Interfaces
input sclk ,
input rst_n ,
//DDR3 Interfaces
output wire [13:0] ddr3_addr ,
output wire [ 2:0] ddr3_ba ,
output wire ddr3_cas_n ,
output wire ddr3_ck_n ,
output wire ddr3_ck_p ,
output wire ddr3_cke ,
output wire ddr3_ras_n ,
output wire ddr3_reset_n ,
output wire ddr3_we_n ,
inout [31:0] ddr3_dq ,
inout [ 3:0] ddr3_dqs_n ,
inout [ 3:0] ddr3_dqs_p ,
output wire [ 0:0] ddr3_cs_n ,
output wire [ 3:0] ddr3_dm ,
output wire [ 0:0] ddr3_odt ,
//Gigbit Interfaces
output wire phy_rst_n ,
input [ 3:0] rx_data ,
input rx_ctrl ,
input rx_clk ,
//USB3 Interfaces
output wire USBSS_EN ,
input USB_clk ,
inout [15:0] data ,
inout [ 1:0] be ,
input rxf_n ,
input txf_n ,
output wire oe_n ,
output wire wr_n ,
output wire siwu_n ,
output wire rd_n ,
output wire wakeup ,
output wire [ 1:0] gpio
);
//========================================================================================\
//**************Define Parameter and Internal Signals**********************************
//========================================================================================/
//clk_wiz_0_inst
wire clk_200m ;
wire locked ;
wire clk_125m ;
//ddr3_drive_inst
wire init_calib_complete ;
wire c3_p0_cmd_clk ;
wire c3_p0_cmd_en ;
wire [ 2:0] c3_p0_cmd_instr ;
wire [27:0] c3_p0_cmd_byte_addr ;
wire [ 6:0] c3_p0_cmd_bl ;
wire c3_p0_wr_clk ;
wire c3_p0_wr_en ;
wire [31:0] c3_p0_wr_mask ;
wire [255:0] c3_p0_wr_data ;
wire [10:0] c3_p0_wr_count ;
wire c3_p1_cmd_clk ;
wire c3_p1_cmd_en ;
wire [ 2:0] c3_p1_cmd_instr ;
wire [27:0] c3_p1_cmd_byte_addr ;
wire [ 6:0] c3_p1_cmd_bl ;
wire c3_p1_rd_clk ;
wire c3_p1_rd_en ;
wire [255:0] c3_p1_rd_data ;
wire [10:0] c3_p1_rd_count ;
//sensor_data_gen_inst
wire clk_24m ;
wire data_wr_en ;
wire [31:0] data_wr ;
//usb3_drive_inst
wire [15:0] data_in ;
wire data_req ;
wire [ 7:0] image_data ;
wire image_data_en ;
wire [31:0] rlst ;
wire rlst_flag ;
wire [31:0] rgb_data ;
wire rgb_data_en ;
//========================================================================================\
//************** Main Code **********************************
//========================================================================================/
clk_wiz_0 clk_wiz_0_inst(
// Clock out ports
.clk_out1 (clk_200m ), // output clk_out1
.clk_out2 (clk_125m ),
.clk_out3 (clk_50m ),
// Status and control signals
.reset (~rst_n ), // input reset
.locked (locked ), // output locked
// Clock in ports
.clk_in1 (sclk )
); // input clk_in1
ddr3_top ddr3_top_inst(
//System Interfaces
.rst_n (rst_n ),
.locked (locked ),
.clk_200m (clk_200m ),
//DDR3 Interfaces
.ddr3_addr (ddr3_addr ),
.ddr3_ba (ddr3_ba ),
.ddr3_cas_n (ddr3_cas_n ),
.ddr3_ck_n (ddr3_ck_n ),
.ddr3_ck_p (ddr3_ck_p ),
.ddr3_cke (ddr3_cke ),
.ddr3_ras_n (ddr3_ras_n ),
.ddr3_reset_n (ddr3_reset_n ),
.ddr3_we_n (ddr3_we_n ),
.ddr3_dq (ddr3_dq ),
.ddr3_dqs_n (ddr3_dqs_n ),
.ddr3_dqs_p (ddr3_dqs_p ),
.ddr3_cs_n (ddr3_cs_n ),
.ddr3_dm (ddr3_dm ),
.ddr3_odt (ddr3_odt ),
//User Interfaces
.init_calib_complete (init_calib_complete ),
.c3_p0_cmd_clk (c3_p0_cmd_clk ),
.c3_p0_cmd_en (c3_p0_cmd_en ),
.c3_p0_cmd_bl (c3_p0_cmd_bl ),
.c3_p0_cmd_byte_addr (c3_p0_cmd_byte_addr ),
.c3_p0_cmd_empty ( ),
.c3_p0_cmd_full ( ),
.c3_p0_wr_clk (c3_p0_wr_clk ),
.c3_p0_wr_en (c3_p0_wr_en ),
.c3_p0_wr_mask (c3_p0_wr_mask ),
.c3_p0_wr_data (c3_p0_wr_data ),
.c3_p0_wr_full ( ),
.c3_p0_wr_empty ( ),
.c3_p0_wr_count (c3_p0_wr_count ),
.c3_p1_cmd_clk ('d0 ),
.c3_p1_cmd_en ('d0 ),
.c3_p1_cmd_bl ('d0 ),
.c3_p1_cmd_byte_addr ('d0 ),
.c3_p1_cmd_empty ( ),
.c3_p1_cmd_full ( ),
.c3_p1_wr_clk ('d0 ),
.c3_p1_wr_en ('d0 ),
.c3_p1_wr_mask ('d0 ),
.c3_p1_wr_data ('d0 ),
.c3_p1_wr_full ( ),
.c3_p1_wr_empty ( ),
.c3_p1_wr_count ( ),
.c3_p2_cmd_clk (c3_p1_cmd_clk ),
.c3_p2_cmd_en (c3_p1_cmd_en ),
.c3_p2_cmd_bl (c3_p1_cmd_bl ),
.c3_p2_cmd_byte_addr (c3_p1_cmd_byte_addr ),
.c3_p2_cmd_empty ( ),
.c3_p2_cmd_full ( ),
.c3_p2_rd_clk (c3_p1_rd_clk ),
.c3_p2_rd_en (c3_p1_rd_en ),
.c3_p2_rd_data (c3_p1_rd_data ),
.c3_p2_rd_full ( ),
.c3_p2_rd_empty ( ),
.c3_p2_rd_count (c3_p1_rd_count ),
.c3_p3_cmd_clk ('d0 ),
.c3_p3_cmd_en ('d0 ),
.c3_p3_cmd_bl ('d0 ),
.c3_p3_cmd_byte_addr ('d0 ),
.c3_p3_cmd_empty ( ),
.c3_p3_cmd_full ( ),
.c3_p3_rd_clk ('d0 ),
.c3_p3_rd_en ('d0 ),
.c3_p3_rd_data ( ),
.c3_p3_rd_full ( ),
.c3_p3_rd_empty ( ),
.c3_p3_rd_count ( )
);
ddr3_drive ddr3_drive_inst(
//System Interfaces
.rst_n (init_calib_complete ),
//DDR3 Interfaces
.c3_p0_cmd_clk (c3_p0_cmd_clk ),
.c3_p0_cmd_en (c3_p0_cmd_en ),
.c3_p0_cmd_instr (c3_p0_cmd_instr ),
.c3_p0_cmd_byte_addr (c3_p0_cmd_byte_addr ),
.c3_p0_cmd_bl (c3_p0_cmd_bl ),
.c3_p0_wr_clk (c3_p0_wr_clk ),
.c3_p0_wr_en (c3_p0_wr_en ),
.c3_p0_wr_mask (c3_p0_wr_mask ),
.c3_p0_wr_data (c3_p0_wr_data ),
.c3_p0_wr_count (c3_p0_wr_count ),
.c3_p1_cmd_clk (c3_p1_cmd_clk ),
.c3_p1_cmd_en (c3_p1_cmd_en ),
.c3_p1_cmd_instr (c3_p1_cmd_instr ),
.c3_p1_cmd_byte_addr (c3_p1_cmd_byte_addr ),
.c3_p1_cmd_bl (c3_p1_cmd_bl ),
.c3_p1_rd_clk (c3_p1_rd_clk ),
.c3_p1_rd_en (c3_p1_rd_en ),
.c3_p1_rd_data (c3_p1_rd_data ),
.c3_p1_rd_count (c3_p1_rd_count ),
//Write DDR3
.clk_24m (clk_125m ),
.data_wr_en (data_wr_en ),
.data_wr (data_wr ),
////Read DDR3
.USB_clk (USB_clk ),
.wr_n (data_req ),
.data_in (data_in )
);
gbit_top gbit_top_inst(
//System Interfaces
.clk_50m (clk_50m ),
.clk_125m (clk_125m ),
.rst_n (locked ),
//Gigbit Interfaces
.phy_rst_n (phy_rst_n ),
.rx_data (rx_data ),
.rx_ctrl (rx_ctrl ),
.rx_clk (rx_clk ),
//Communication Interfaces
.image_data (image_data ),
.image_data_en (image_data_en ),
.rlst (rlst ),
.rlst_flag (rlst_flag )
);
conver_bit conver_bit_inst(
//System Interfaces
.sclk (clk_125m ),
.rst_n (locked ),
//Gigbit Interfaces
.image_data (image_data ),
.image_data_en (image_data_en ),
//Communication Interfaces
.rgb_data (rgb_data ),
.rgb_data_en (rgb_data_en )
);
image image_inst(
//System Interfaces
.sclk (clk_125m ),
.rst_n (locked ),
//Communication Interfaces
.rgb_data (rgb_data ),
.rgb_data_en (rgb_data_en ),
.data_wr ({
data_wr[15:8],data_wr[23:16],data_wr[31:24],data_wr[7:0]} ),
.data_wr_en (data_wr_en )
);
//sensor_data_gen sensor_data_gen_inst(
// .clk (clk_24m ),
// .rst_n (init_calib_complete ),
// .rgb ({data_wr[15:0],data_wr[31:16]} ),
// .de (data_wr_en ),
// .vsync ( ),
// .hsync ( )
//);
//lways @(posedge clk_24m)
// if(init_calib_complete == 1'b0)
// data_wr_en <= 1'b0;
// else
// data_wr_en <= 1'b1;
//lways @(posedge clk_24m)
// if(init_calib_complete == 1'b0)
// data_wr <= 32'd0;
// else if(data_wr_en == 1'b1)
// data_wr <= data_wr + 1'b1;
usb3_drive usb3_drive_inst(
//System Interfaces
.rst_n (init_calib_complete ),
//USB3 Interfaces
.USBSS_EN (USBSS_EN ),
.sclk (USB_clk ),
.data (data ),
.be (be ),
.rxf_n (rxf_n ),
.txf_n (txf_n ),
.oe_n (oe_n ),
.wr_n (wr_n ),
.siwu_n (siwu_n ),
.rd_n (rd_n ),
.wakeup (wakeup ),
.gpio (gpio ),
//Communication Interfaces
.data_in (data_in ),
.data_req (data_req )
);
//========================================================================================\
//******************************* Debug **********************************
//========================================================================================/
ila_3 ila_3_inst (
.clk (clk_125m ), // input wire clk
.probe0 (image_data ), // input wire [7:0] probe0
.probe1 (image_data_en ), // input wire [0:0] probe1
.probe2 (data_wr ), // input wire [31:0] probe2
.probe3 (data_wr_en ) // input wire [0:0] probe3
);
endmodule
ddr3_top模块:
`timescale 1ns / 1ps
// *********************************************************************************
// Project Name : OSXXXX
// Author : zhangningning
// Email : nnzhang1996@foxmail.com
// Website :
// Module Name : ddr3_top.v
// Create Time : 2020-02-27 23:16:16
// Editor : sublime text3, tab size (4)
// CopyRight(c) : All Rights Reserved
//
// *********************************************************************************
// Modification History:
// Date By Version Change Description
// -----------------------------------------------------------------------
// XXXX

最低0.47元/天 解锁文章
6275





