FPGA图像处理 VGA时序 边缘检测---sobel算子 verilog

目录

1.VGA时序

1.1top.v(顶层文件) 

1.2调用的IP核(Clocking Wizard) PLL, 25.175MHZ。

1.3vga_driver.v(vga驱动)

1.4frame_controller.v(帧控制) 

1.5top_tb.v(测试文件) 

1.6仿真图: 

2.利用VGA显示图像,并进行灰度变换

2.1将图像数据导为.coe文件

2.2调用IP核RAM,将.coe文件导入

2.3修改模块

2.4仿真图

2.5数据总流向

3.边缘检测---sobel算子

3.1图像处理模块

3.2顶层模块

3.3仿真图


1.VGA时序

1.1top.v(顶层文件) 

module top(
    input            sys_clk,//100MHZ
    input            sys_rst_n,
    
    output   [3:0]   VGA_R,
    output   [3:0]   VGA_G,
    output   [3:0]   VGA_B,
    output           VGA_HSYNC,
    output           VGA_VSYNC
);
//========= PPL IP produce vga_clk =====
wire vga_clk;
wire locked;
wire rst_n;
wire [15:0] rgb_data;
wire [11:0] vga_data;
wire [9:0] pos_x;
wire [9:0] pos_y;
assign rst_n = sys_rst_n && locked;
assign VGA_R = vga_data[11:8];
assign VGA_G = vga_data[7:4];
assign VGA_B = vga_data[3:0];
clk_wiz_0 u_clk(
  // Clock out ports  
  .clk_out1(vga_clk),
  // Status and control signals               
  .resetn(sys_rst_n), 
  .locked(locked),
 // Clock in ports
  .clk_in1(sys_clk)
 );
//========== vga_driver =============
vga_driver u0_vga_driver(
.vga_clk(vga_clk),
.rst_n(rst_n),
.rgb_data(rgb_data),//RGB565

.vga_data(vga_data),//RGB444
.vga_hsync(VGA_HSYNC),
.vga_vsync(VGA_VSYNC),
.pos_x(pos_x),
.pos_y(pos_y)
);
//========== frame_controller =======
frame_controller u1_frame_controller(
.vga_clk(vga_clk),
.rst_n(rst_n),
.pos_x(pos_x),
.pos_y(pos_y),
.img_data(rgb_data)//RGB565
);
endmodule

1.2调用的IP核(Clocking Wizard) PLL, 25.175MHZ。

`timescale 1ps/1ps

(* CORE_GENERATION_INFO = "clk_wiz_0,clk_wiz_v6_0_2_0_0,{component_name=clk_wiz_0,use_phase_alignment=true,use_min_o_jitter=false,use_max_i_jitter=false,use_dyn_phase_shift=false,use_inclk_switchover=false,use_dyn_reconfig=false,enable_axi=0,feedback_source=FDBK_AUTO,PRIMITIVE=PLL,num_out_clk=1,clkin1_period=10.000,clkin2_period=10.000,use_power_down=false,use_reset=true,use_locked=true,use_inclk_stopped=false,feedback_type=SINGLE,CLOCK_MGR_TYPE=NA,manual_override=false}" *)

module clk_wiz_0 
 (
  // Clock out ports
  output        clk_out1,
  // Status and control signals
  input         resetn,
  output        locked,
 // Clock in ports
  input         clk_in1
 );

  clk_wiz_0_clk_wiz inst
  (
  // Clock out ports  
  .clk_out1(clk_out1),
  // Status and control signals               
  .resetn(resetn), 
  .locked(locked),
 // Clock in ports
  .clk_in1(clk_in1)
  );

endmodule

1.3vga_driver.v(vga驱动)

module vga_driver(
    input    wire          vga_clk,
    input    wire          rst_n,
    input    wire  [15:0]  rgb_data,//RGB565

    output   wire  [11:0]  vga_data,//RGB444
    output   wire          vga_hsync,
    output   wire          vga_vsync,
    output   wire  [9:0]   pos_x,
    output   wire  [9:0]   pos_y
);

//resolution 640*480
parameter  H_SYNC = 10'd96,
            H_BACK =10'd40,
            H_LEFT = 10'd8,
            H_VAILD = 10'd640,
            H_RIGHT = 10'd8,
            H_FRONT = 10'd8,
            H_TOTAL = 10'd800;

parameter  V_SYNC = 10'd2,
            V_BACK =10'd25,
            V_TOP = 10'd8,
            V_VAILD = 10'd480,
            V_BOTTOM = 10'd8,
            V_FRONT = 10'd2,
            V_TOTAL = 10'd525;

//==============core code============
//===================================
reg   [9:0]   h_cnt;
reg   [9:0]   v_cnt;
wire          vga_data_vaild;
//==============line scan============
always @(posedge vga_clk or negedge rst_n)
begin
    if(!rst_n)
        h_cnt <= 1'b0;
    else if(h_cnt == H_TOTAL-1)//not <= cause the == use less resource
        h_cnt <= 10'd0;
    else
        h_cnt <= h_cnt + 1'b1;
end
//==============column scan============
always @(posedge vga_clk or negedge rst_n)
begin
    if(!rst_n)
        v_cnt <= 1'b0;
    else if((v_cnt == V_TOTAL-1)&&(h_cnt == H_TOTAL-1))//the column tillthe all imge last
        v_cnt <= 10'd0;
    else if(h_cnt == H_TOTAL-1)
        v_cnt <= v_cnt + 1'b1;
end
//===============vga_hsync assignment==
assign  vga_hsync = (h_cnt <= H_SYNC)?1'b1:1'b0;
//===============vga_vsync assignment==
assign  vga_vsync = (v_cnt <= V_SYNC)?1'b1:1'b0;
//===============vga_data_vaild assignment==
assign  vga_data_vaild = (
                            (h_cnt >= H_SYNC+H_BACK+H_LEFT-1'b1)&&
                            (h_cnt <= H_SYNC+H_BACK+H_LEFT+H_VAILD-1'b1)&&
                            (v_cnt >= V_SYNC+V_BACK+V_TOP)&&
                            (v_cnt <= V_SYNC+V_BACK+V_TOP+V_VAILD)
                            )?1'b1:1'b0;//do a square
//===============vga_data assignment==
assign  vga_data = (vga_data_vaild == 1'b1)?{rgb_data[15:12],rgb_data[10:7],rgb_data[4:1]}:12'd0;
//===============pos_x assignment==
assign  pos_x = (vga_data_vaild)?(h_cnt-H_SYNC-H_BACK-H_LEFT+1'b1):10'h3ff;
//===============pos_y assignment==
assign  pos_y = (vga_data_vaild)?(v_cnt-V_SYNC-V_BACK-V_TOP):10'h3ff;

endmodule

1.4frame_controller.v(帧控制) 

module frame_controller(
    input   wire        vga_clk,
    input   wire        rst_n,
    input   wire [9:0]  pos_x,
    input   wire [9:0]  pos_y,
    output  wire [15:0] img_data
);

assign img_data = (pos_x>8'd100 && pos_x<8'd200)?16'hffe2:16'hf800;
endmodule

1.5top_tb.v(测试文件) 

`timescale 1ns / 1ps
module top_tb();

reg clk;
reg rst_n;

initial begin
    clk <= 1'b0;
    rst_n <= 1'b0;
    #20;
    rst_n <= 1'b1;
end
always #5 clk = ~clk;

top u_top(
.sys_clk(clk),//100MHZ
.sys_rst_n(rst_n)
);

endmodule

1.6仿真图: 

2.利用VGA显示图像,并进行灰度变换

2.1将图像数据导为.coe文件

matlab里面导出,.coe文件格式开头为

memory_initialization_radix=16;
memory_initialization_vector=

结尾修改为分号,注意中英文区别,不然导不进ROM中。

img = imread('ganyu.bmp');
%分离通道
r = img(:,:,1);
g = img(:,:,2);
b = img(:,:,3);
%修改位宽
r = uint32(r);
g = uint32(g);
b = uint32(b);
%降维度 2->1,要先转置,再reshape
r = reshape(r',307200,1);
g = reshape(g',307200,1);
b = reshape(b',307200,1);
%rgb888->rgb444
rgb444 = zeros(307200,1);
for i=1:307200
    rgb444(i) = bitshift(bitshift(r(i),-4),8) + bitshift(bitshift(g(i),-4),4) + bitshift(bitshift(b(i),-4),0);
end
%.coe文件前面要加的
file = fopen('img.coe','w+');
fprintf(file,'memory_initialization_radix=16;\nmemory_initialization_vector=\n');
%每行输出三个数,不够在前面补0
for i = 1:307200
    fprintf(file,'%03x,\n',rgb444(i));
end

fclose(file);

2.2调用IP核RAM,将.coe文件导入

注意数据的宽度和深度,要符合FPGA板载资源,深度可以适当多点。

2.3修改模块

top.v

module top(
    input            sys_clk,//100MHZ
    input            sys_rst_n,
    
    output   [3:0]   VGA_R,
    output   [3:0]   VGA_G,
    output   [3:0]   VGA_B,
    output           VGA_HSYNC,
    output           VGA_VSYNC
);
//========= PPL IP produce vga_clk =====
wire vga_clk;
wire locked;
wire rst_n;
wire [11:0] rgb_data;
wire [11:0] vga_data;
wire [9:0] pos_x;
wire [9:0] pos_y;
wire vga_valid;
wire vga_data_valid_pre3;
wire [11:0] gray_data;
assign rst_n = sys_rst_n && locked;
assign VGA_R = vga_data[11:8];
assign VGA_G = vga_data[7:4];
assign VGA_B = vga_data[3:0];
clk_wiz_0 u_clk(
  // Clock out ports  
  .clk_out1(vga_clk),
  // Status and control signals               
  .resetn(sys_rst_n), 
  .locked(locked),
 // Clock in ports
  .clk_in1(sys_clk)
 );
//========== vga_driver =============
vga_driver u0_vga_driver(
.vga_clk(vga_clk),
.rst_n(rst_n),
.rgb_data(gray_data),//RGB444

.vga_data(vga_data),//RGB444
.vga_hsync(VGA_HSYNC),
.vga_vsync(VGA_VSYNC),
.pos_x(pos_x),
.pos_y(pos_y),
.vga_valid(vga_valid),
.vga_data_valid_pre3(vga_data_valid_pre3)
);
//========== frame_controller =======
frame_controller u1_frame_controller(
.vga_clk(vga_clk),
.rst_n(rst_n),
.pos_x(pos_x),
.pos_y(pos_y),

.rgb_data(rgb_data),//RGB444
.vga_data_valid_pre3(vga_data_valid_pre3)
);
//============image processing=======
rgb2gray u_rgb2gray(
.imgPixel_in(rgb_data),
.imgPixel_out(gray_data)
);
endmodule

vga_driver.v

module vga_driver(
    input    wire          vga_clk,
    input    wire          rst_n,
    input    wire  [11:0]  rgb_data,//RGB444

    output   wire  [11:0]  vga_data,//RGB444
    output   wire          vga_hsync,
    output   wire          vga_vsync,
    output   wire  [9:0]   pos_x,
    output   wire  [9:0]   pos_y,
    output   wire          vga_valid,
    output   wire          vga_data_valid_pre3
);

//resolution 640*480
parameter  H_SYNC = 10'd96,
            H_BACK =10'd40,
            H_LEFT = 10'd8,
            H_VAILD = 10'd640,
            H_RIGHT = 10'd8,
            H_FRONT = 10'd8,
            H_TOTAL = 10'd800;

parameter  V_SYNC = 10'd2,
            V_BACK =10'd25,
            V_TOP = 10'd8,
            V_VAILD = 10'd480,
            V_BOTTOM = 10'd8,
            V_FRONT = 10'd2,
            V_TOTAL = 10'd525;

//==============core code============
//===================================
reg   [9:0]   h_cnt;
reg   [9:0]   v_cnt;
wire          vga_data_valid;
//==============line scan============
always @(posedge vga_clk or negedge rst_n)
begin
    if(!rst_n)
        h_cnt <= 1'b0;
    else if(h_cnt == H_TOTAL-1)//not <= cause the == use less resource
        h_cnt <= 10'd0;
    else
        h_cnt <= h_cnt + 1'b1;
end
//==============column scan============
always @(posedge vga_clk or negedge rst_n)
begin
    if(!rst_n)
        v_cnt <= 1'b0;
    else if((v_cnt == V_TOTAL-1)&&(h_cnt == H_TOTAL-1))//the column tillthe all imge last
        v_cnt <= 10'd0;
    else if(h_cnt == H_TOTAL-1)
        v_cnt <= v_cnt + 1'b1;
end
//===============vga_hsync assignment==
assign  vga_hsync = (h_cnt <= H_SYNC)?1'b1:1'b0;
//===============vga_vsync assignment==
assign  vga_vsync = (v_cnt <= V_SYNC)?1'b1:1'b0;
//===============vga_data_vaild assignment==
assign  vga_data_valid = (
                            (h_cnt >= H_SYNC+H_BACK+H_LEFT)&&
                            (h_cnt <= H_SYNC+H_BACK+H_LEFT+H_VAILD)&&
                            (v_cnt >= V_SYNC+V_BACK+V_TOP)&&
                            (v_cnt <= V_SYNC+V_BACK+V_TOP+V_VAILD)
                            )?1'b1:1'b0;//do a square
assign  vga_data_valid_pre3 = (
                            (h_cnt >= H_SYNC+H_BACK+H_LEFT-2'd3)&&
                            (h_cnt <= H_SYNC+H_BACK+H_LEFT+H_VAILD-2'd3)&&
                            (v_cnt >= V_SYNC+V_BACK+V_TOP)&&
                            (v_cnt <= V_SYNC+V_BACK+V_TOP+V_VAILD)
                            )?1'b1:1'b0;//do a square
//=============
assign vga_valid = vga_data_valid;
//===============vga_data assignment==
assign  vga_data = (vga_data_valid == 1'b1)?rgb_data:12'd0;
//===============pos_x assignment==
assign  pos_x = (vga_data_valid)?(h_cnt-H_SYNC-H_BACK-H_LEFT):10'h3ff;
//===============pos_y assignment==
assign  pos_y = (vga_data_valid)?(v_cnt-V_SYNC-V_BACK-V_TOP):10'h3ff;

endmodule

 frame_controller.v

module frame_controller(
    input   wire        vga_clk,
    input   wire        rst_n,
    inout   wire        vga_data_valid_pre3,
    input   wire [9:0]  pos_x,
    input   wire [9:0]  pos_y,
    output  wire [11:0] rgb_data
);
parameter   FRAME_SIZE = 19'd307200;
reg [18:0] read_addr;
always @(posedge vga_clk or negedge rst_n)
    begin
        if(!rst_n)
            read_addr <= 19'h7ffff;
        else if(vga_data_valid_pre3 == 1'b1)
            read_addr <= read_addr + 1'b1;
        else if(read_addr == (FRAME_SIZE - 1'b1))
            read_addr <= 19'd0;
        else
            read_addr <= read_addr;
    end
blk1 u_1
(
    .clka(vga_clk),
    .ena(1'b1),
    .addra(read_addr),
    .douta(rgb_data)
  );
endmodule

rgb2gray.v

module rgb2gray(
input [11:0] imgPixel_in,
output [11:0] imgPixel_out
    );
wire [3:0] R;
wire [3:0] G;
wire [3:0] B;
wire [4:0] gray;
assign R = imgPixel_in[11:8];
assign G = imgPixel_in[7:4];
assign B = imgPixel_in[3:0];
assign gray = (R + G<<1 + B)>>2;
assign imgPixel_out = {gray[4:1],gray[4:1],gray[4:1]};
endmodule

测试文件不变。

2.4仿真图

2.5数据总流向

3.边缘检测---sobel算子

3.1图像处理模块

cov_sobel.v

module cov_sobel(
    input vga_clk,
    input rst_n,
    
    input wire [9:0] pos_x,
    input wire [9:0] pos_y,
    input wire [23:0] rgb_data,//rgb444--rgb888--rgb444
    
    output reg [11:0] sobel_out
    );
parameter THRESHOLD = 4'b0101;
wire [7:0] r;
wire [7:0] g;
wire [7:0] b;
wire [7:0] gray;
wire [23:0] gray_data;
assign r = rgb_data[23:16];
assign g = rgb_data[15:8];
assign b = rgb_data[7:0];

assign gray = r*5/16 + r*9/16 + b*2/16;
assign gray_data = {gray,gray,gray};

reg line_clk;
reg state;//idle
reg [7:0] line_buf0[639:0];
reg [7:0] line_buf1[639:0];
reg [7:0] p0;
reg [7:0] p1;
reg [7:0] p2;
reg [9:0] conv_out;
reg [3:0] tmp;
initial state = 0;

//=============line_clk========
always @(posedge vga_clk)begin
    if(pos_x>0 && pos_y<479)begin
        if(pos_x == 0)
            line_clk <= 1'b1;
        else
            line_clk <= 1'b0;
    end
end
//==========state=========
always @(posedge vga_clk)begin
    case(state)
    1'b0:begin
        line_buf0[pos_x] <= gray;
        line_buf1[pos_x] <= line_buf1[pos_x];
        p2 <= gray;
        p1 <= p2;
        p0 <= p1;
        if(pos_x>=2 && pos_y>=3)begin
            if((p0 + p1*2 + p2)>(line_buf0[pos_x-2] + line_buf0[pos_x-1]*2 + line_buf0[pos_x]))
                conv_out <= (p0 + p1*2 + p2) - (line_buf0[pos_x-2] + line_buf0[pos_x-1]*2 + line_buf0[pos_x]);
            else
                conv_out <= (line_buf0[pos_x-2] + line_buf0[pos_x-1]*2 + line_buf0[pos_x]) - (p0 + p1*2 + p2);
        end
    end
    1'b1:begin
        line_buf1[pos_x] <= gray;
        line_buf0[pos_x] <= line_buf0[pos_x];
        p2 <= gray;
        p1 <= p2;
        p0 <= p1;
        if(pos_x>=2 && pos_y>=3)begin
            if((p0 + p1*2 + p2)>(line_buf1[pos_x-2] + line_buf1[pos_x-1]*2 + line_buf1[pos_x]))
                conv_out <= (p0 + p1*2 + p2) - (line_buf1[pos_x-2] + line_buf1[pos_x-1]*2 + line_buf1[pos_x]);
            else
                conv_out <= (line_buf1[pos_x-2] + line_buf1[pos_x-1]*2 + line_buf1[pos_x]) - (p0 + p1*2 + p2);
        end
    end
    default:begin
        conv_out <= conv_out;
        line_buf0[pos_x] <= line_buf0[pos_x];
        line_buf1[pos_x] <= line_buf1[pos_x];
    end
    endcase
end
//========comparison threshold======

always @(*)begin
    tmp = (conv_out[5:2]>THRESHOLD)?4'hf:4'h0;
    sobel_out = ({tmp,tmp,tmp});
end   
endmodule

3.2顶层模块

module top(
    input            sys_clk,//100MHZ
    input            sys_rst_n,
    
    output   [3:0]   VGA_R,
    output   [3:0]   VGA_G,
    output   [3:0]   VGA_B,
    output           VGA_HSYNC,
    output           VGA_VSYNC
);
//========= PPL IP produce vga_clk =====
wire vga_clk;
wire locked;
wire rst_n;
wire [11:0] rgb_data;
wire [11:0] vga_data;
wire [9:0] pos_x;
wire [9:0] pos_y;
wire vga_valid;
wire vga_data_valid_pre3;
wire [11:0] sobel_data;
assign rst_n = sys_rst_n && locked;
assign VGA_R = vga_data[11:8];
assign VGA_G = vga_data[7:4];
assign VGA_B = vga_data[3:0];
clk_wiz_0 u_clk(
  // Clock out ports  
  .clk_out1(vga_clk),
  // Status and control signals               
  .resetn(sys_rst_n), 
  .locked(locked),
 // Clock in ports
  .clk_in1(sys_clk)
 );
//========== vga_driver =============
vga_driver u0_vga_driver(
.vga_clk(vga_clk),
.rst_n(rst_n),
.rgb_data(sobel_data),//RGB444

.vga_data(vga_data),//RGB444
.vga_hsync(VGA_HSYNC),
.vga_vsync(VGA_VSYNC),
.pos_x(pos_x),
.pos_y(pos_y),
.vga_valid(vga_valid),
.vga_data_valid_pre3(vga_data_valid_pre3)
);
//========== frame_controller =======
frame_controller u1_frame_controller(
.vga_clk(vga_clk),
.rst_n(rst_n),
.pos_x(pos_x),
.pos_y(pos_y),

.rgb_data(rgb_data),//RGB444
.vga_data_valid_pre3(vga_data_valid_pre3)
);
//============image processing=======
cov_sobel u_sobel(
.vga_clk(vga_clk),
.rst_n(rst_n),
.pos_x(pos_x),
.pos_y(pos_y),
.rgb_data({{rgb_data[11:8],4'hf},{rgb_data[7:4],4'hf},{rgb_data[3:0],4'hf}}),
    
.sobel_out(sobel_data)
    );
endmodule

3.3仿真图

  • 2
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值