前言
软件版本
vivado
:2020.1
Quartus
:17.1
正文
边缘检测需要用到的IP核在两款软件中是不一样的
因此,下面分别在两款软件中进行实现
一、在vivado中实现
1.算法流程:
1)、将3×3的窗口和Gx、Gy分别相乘,Gx、Gy均已知
2)、将相乘得到的2个结果各自平方
3)、将平方得到的2个数相加
4)、将相加的结果放入求根的IP核猴子那个开根号
5)、开完根号后和阈值比较,大于阈值的部分置1
2.sobel算子
Gx:x方向的边缘 Gy:y方向的边缘 Pixel
[ -1 0 +1 ] [ +1 +2 +1 ] [ P11 P12 P13 ]
[ -2 0 +2 ] [ 0 0 0 ] [ P21 P22 P23 ]
[ -1 0 +1 ] [ -1 -2 -1 ] [ P31 P32 P33 ]
`timescale 1ns / 1ps
//
// 1.算法流程:
// 1)、将3×3的窗口和Gx、Gy分别相乘,Gx、Gy均已知
// 2)、将相乘得到的2个结果各自平方
// 3)、将平方得到的2个数相加
// 4)、将相加的结果放入求根的IP核猴子那个开根号
// 5)、开完根号后和阈值比较,大于阈值的部分置1
//
//
//
`timescale 1ns/1ns
module Sobel_Edge_Detector
(
//global clock
input clk, //cmos video pixel clock
input rst_n, //global reset
//Image data prepred to be processd
input per_frame_vsync, //Prepared Image data vsync valid signal
input per_frame_href, //Prepared Image data href vaild signal
input per_frame_clken, //Prepared Image data output/capture enable clock
input [7:0] per_img_Y, //Prepared Image brightness input
//Image data has been processd
output post_frame_vsync, //Processed Image data vsync valid signal
output post_frame_href, //Processed Image data href vaild signal
output post_frame_clken, //Processed Image data output/capture enable clock
output post_img_Bit, //Processed Image Bit flag outout(1: Value, 0:inValid)
//user interface
input [7:0] Sobel_Threshold //Sobel Threshold for image edge detect
);
//----------------------------------------------------
//Generate 8Bit 3X3 Matrix for Video Image Processor.
//Image data has been processd
wire matrix_frame_vsync; //Prepared Image data vsync valid signal
wire matrix_frame_href; //Prepared Image data href vaild signal
wire matrix_frame_clken; //Prepared Image data output/capture enable clock
wire [7:0] matrix_p11, matrix_p12, matrix_p13; //3X3 Matrix output
wire [7:0] matrix_p21, matrix_p22, matrix_p23;
wire [7:0] matrix_p31, matrix_p32, matrix_p33;
Shift_RAM_3X3 Shift_RAM_3X3_inst
(
//global clock
.clk (clk), //cmos video pixel clock
.rst_n (rst_n), //global reset
.per_frame_vsync (per_frame_vsync), //Prepared Image data vsync valid signal
.per_frame_href (per_frame_href), //Prepared Image data href vaild signal
.per_frame_clken (per_frame_clken), //Prepared Image data output/capture enable clock
.per_img_Y (per_img_Y), //Prepared Image brightness input
//Image data has been processd
.matrix_frame_vsync (matrix_frame_vsync), //Prepared Image data vsync valid signal
.matrix_frame_href (matrix_frame_href), //Prepared Image data href vaild signal
.matrix_frame_clken (matrix_frame_clken), //Prepared Image data output/capture enable clock
.matrix_p11(matrix_p11), .matrix_p12(matrix_p12), .matrix_p13(matrix_p13), //3X3 Matrix output
.matrix_p21(matrix_p21), .matrix_p22(matrix_p22), .matrix_p23(matrix_p23),
.matrix_p31(matrix_p31), .matrix_p32(matrix_p32), .matrix_p33(matrix_p33)
);
//Sobel Parameter
// Gx:x方向的边缘 Gy:y方向的边缘 Pixel
// [ -1 0 +1 ] [ +1 +2 +1 ] [ P11 P12 P13 ]
// [ -2 0 +2 ] [ 0 0 0 ] [ P21 P22 P23 ]
// [ -1 0 +1 ] [ -1 -2 -1 ] [ P31 P32 P33 ]
// localparam P11 = 8'd15, P12 = 8'd94, P13 = 8'd136;
// localparam P21 = 8'd31, P22 = 8'd127, P23 = 8'd231;
// localparam P31 = 8'd44, P32 = 8'd181, P33 = 8'd249;
//Caculate horizontal Grade with |abs|
//Step 1-2
reg [9:0] Gx_temp1; //postive result
reg [9:0] Gx_temp2; //negetive result
reg [9:0] Gx_data; //Horizontal grade data
//========================================================================
//矩阵相乘
//========================================================================
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
begin
Gx_temp1 <= 0;
Gx_temp2 <= 0;
Gx_data <= 0;
end
else
begin
Gx_temp1 <= matrix_p13 + (matrix_p23 << 1) + matrix_p33; //postive result
Gx_temp2 <= matrix_p11 + (matrix_p21 << 1) + matrix_p31; //negetive result
Gx_data <= (Gx_temp1 >= Gx_temp2) ? Gx_temp1 - Gx_temp2 : Gx_temp2 - Gx_temp1;
end
end
//---------------------------------------
//Caculate vertical Grade with |abs|
//Step 1-2
reg [9:0] Gy_temp1; //postive result
reg [9:0] Gy_temp2; //negetive result
reg [9:0] Gy_data; //Vertical grade data
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
begin
Gy_temp1 <= 0;
Gy_temp2 <= 0;
Gy_data <= 0;
end
else
begin
Gy_temp1 <= matrix_p11 + (matrix_p12 << 1) + matrix_p13; //postive result
Gy_temp2 <= matrix_p31 + (matrix_p32 << 1) + matrix_p33; //negetive result
Gy_data <= (Gy_temp1 >= Gy_temp2) ? Gy_temp1 - Gy_temp2 : Gy_temp2 - Gy_temp1;
end
end
//===================================================================
//---------------------------------------
//Caculate the square of distance = (Gx^2 + Gy^2)
//Step 3
reg [20:0] Gxy_square;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
Gxy_square <= 0;
else
Gxy_square <= Gx_data * Gx_data + Gy_data * Gy_data;
end
//---------------------------------------
//Caculate the distance of P5 = (Gx^2 + Gy^2)^0.5
//Step 4
wire [15:0] result_root;
Square_root Square_root_inst(
.aclk(clk), // input wire aclk
.s_axis_cartesian_tvalid(1'b1), // input wire s_axis_cartesian_tvalid
.s_axis_cartesian_tdata({3'b0,Gxy_square}), // input wire [23 : 0] s_axis_cartesian_tdata
.m_axis_dout_tvalid(), // output wire m_axis_dout_tvalid
.m_axis_dout_tdata(result_root) // output wire [15 : 0] m_axis_dout_tdata
);
//---------------------------------------
//Compare and get the Sobel_data
//Step 5
reg post_img_Bit_r;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
post_img_Bit_r <= 1'b0; //Default None
else if(result_root >= Sobel_Threshold)
post_img_Bit_r <= 1'b1; //Edge Flag
else
post_img_Bit_r <= 1'b0; //Not Edge
end
//------------------------------------------
//lag 5 clocks signal sync
reg [4:0] per_frame_vsync_r;
reg [4:0] per_frame_href_r;
reg [4:0] per_frame_clken_r;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
begin
per_frame_vsync_r <= 0;
per_frame_href_r <= 0;
per_frame_clken_r <= 0;
end
else
begin
per_frame_vsync_r <= {per_frame_vsync_r[3:0], matrix_frame_vsync};
per_frame_href_r <= {per_frame_href_r [3:0], matrix_frame_href};
per_frame_clken_r <= {per_frame_clken_r[3:0], matrix_frame_clken};
end
end
assign post_frame_vsync = per_frame_vsync_r[4];
assign post_frame_href = per_frame_href_r [4];
assign post_frame_clken = per_frame_clken_r[4];
assign post_img_Bit = post_frame_href ? post_img_Bit_r : 1'b0;
endmodule
二、在Quartus中实现
推荐阅读:图像高斯滤波的FPGA实现
/*
Filename : Sobel.v
Compiler : Quartus II 13.0
Description : implement Sobel Edge Detector
*/
module sobel (
input iCLK,
input iRST_N,
input [7:0] iTHRESHOLD,//阈值
input iDVAL,
input [9:0] iDATA,
output reg oDVAL,
output reg [9:0] oDATA
);
//==========================================parameter===========================================================
// mask x
parameter X1 = 8'hff, X2 = 8'h00, X3 = 8'h01;
parameter X4 = 8'hfe, X5 = 8'h00, X6 = 8'h02;
parameter X7 = 8'hff, X8 = 8'h00, X9 = 8'h01;
// mask y
parameter Y1 = 8'h01, Y2 = 8'h02, Y3 = 8'h01;
parameter Y4 = 8'h00, Y5 = 8'h00, Y6 = 8'h00;
parameter Y7 = 8'hff, Y8 = 8'hfe, Y9 = 8'hff;
//==========================================reg=================================================================
//==========================================wire=================================================================
wire [7:0] Line0;
wire [7:0] Line1;
wire [7:0] Line2;
wire [17:0] Mac_x0;
wire [17:0] Mac_x1;
wire [17:0] Mac_x2;
wire [17:0] Mac_y0;
wire [17:0] Mac_y1;
wire [17:0] Mac_y2;
wire [19:0] Pa_x;
wire [19:0] Pa_y;
wire [15:0] Abs_mag;
//==========================================always=================================================================
always@(posedge iCLK, negedge iRST_N) begin
if (!iRST_N)
oDVAL <= 0;
else begin
oDVAL <= iDVAL;
if (iDVAL)
oDATA <= (Abs_mag > iTHRESHOLD) ? 0 : 1023;
else
oDATA <= 0;//输出的10位图像数据
end
end
//==========================================状态机=================================================================
//==========================================模块例化=================================================================
LineBuffer LineBuffer_inst (
.clken(iDVAL),
.clock(iCLK),
.shiftin(iDATA[9:2]),
.taps0x(Line0),
.taps1x(Line1),
.taps2x(Line2)
);
// X
MAC_3 x0 (
.aclr3(!iRST_N),
.clock0(iCLK),
.dataa_0(Line0),
.datab_0(X9),
.datab_1(X8),
.datab_2(X7),
.result(Mac_x0)
);
MAC_3 x1 (
.aclr3(!iRST_N),
.clock0(iCLK),
.dataa_0(Line1),
.datab_0(X6),
.datab_1(X5),
.datab_2(X4),
.result(Mac_x1)
);
MAC_3 x2 (
.aclr3(!iRST_N),
.clock0(iCLK),
.dataa_0(Line2),
.datab_0(X3),
.datab_1(X2),
.datab_2(X1),
.result(Mac_x2)
);
// Y
MAC_3 y0 (
.aclr3(!iRST_N),
.clock0(iCLK),
.dataa_0(Line0),
.datab_0(Y9),
.datab_1(Y8),
.datab_2(Y7),
.result(Mac_y0)
);
MAC_3 y1 (
.aclr3(!iRST_N),
.clock0(iCLK),
.dataa_0(Line1),
.datab_0(Y6),
.datab_1(Y5),
.datab_2(Y4),
.result(Mac_y1)
);
MAC_3 y2 (
.aclr3(!iRST_N),
.clock0(iCLK),
.dataa_0(Line2),
.datab_0(Y3),
.datab_1(Y2),
.datab_2(Y1),
.result(Mac_y2)
);
PA_3 pa0 (
.clock(iCLK),
.data0x(Mac_x0),
.data1x(Mac_x1),
.data2x(Mac_x2),
.result(Pa_x)
);
PA_3 pa1 (
.clock(iCLK),
.data0x(Mac_y0),
.data1x(Mac_y1),
.data2x(Mac_y2),
.result(Pa_y)
);
SQRT sqrt0 (
.clk(iCLK),
.radical(Pa_x * Pa_x + Pa_y * Pa_y),
.q(Abs_mag)
);
endmodule