本文主要是介绍FPGA 图像边缘检测(Canny算子),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
1 顶层代码
`timescale 1ns / 1ps
//边缘检测二阶微分算子:canny算子module image_canny_edge_detect (input clk,input reset, //复位高电平有效input [10:0] img_width,input [ 9:0] img_height,input [ 7:0] low_threshold,input [ 7:0] high_threshold,input valid_i,input [15:0] rgb_565_i, // 输入的16位RGB图像数据output valid_o,output [15:0] rgb_565_o // 输出的16位RGB图像数据
);//变量声明wire valid_gray;wire [7:0] img_data_gray;wire valid_gf;wire [7:0] img_data_gf;wire valid_sbl;wire [7:0] grad_mag;wire [10:0] grad_dx;wire [10:0] grad_dy;wire valid_nms;wire [7:0] img_data_nms;wire valid_db;wire [7:0] img_data_db;wire [23:0] img_data_i, img_data_o;assign img_data_i = {rgb_565_i[15:11], 3'b000, rgb_565_i[10:5], 2'b00, rgb_565_i[4:0], 3'b000};assign rgb_565_o = {{img_data_o[23:19], img_data_o[15:10], img_data_o[7:3]}};//彩色图像灰度化image_rgb2gray u_image_rgb2gray (.clk (clk),.reset (reset),.valid_i (valid_i),.img_data_i(img_data_i),.valid_o (valid_gray),.img_data_o(img_data_gray));///高斯滤波image_gaussian_filter u_image_gaussian_filter (.clk (clk),.reset (reset),.img_width (img_width),.img_height(img_height),.valid_i (valid_gray),.img_data_i(img_data_gray),.valid_o (valid_gf),.img_data_o(img_data_gf));///Sobel算子image_sobel_edge u_image_sobel_edge (.clk (clk),.reset (reset),.img_width (img_width),.img_height(img_height),.valid_i (valid_gf),.img_data_i(img_data_gf),.valid_o (valid_sbl),.grad_mag (grad_mag),.grad_dx (grad_dx),.grad_dy (grad_dy));///非极大值计算non_maximum_suppression u_non_maximum_suppression (.clk (clk),.reset (reset),.img_width (img_width),.img_height(img_height),.valid_i (valid_sbl),.grad_mag (grad_mag),.grad_dx (grad_dx),.grad_dy (grad_dy),.valid_o (valid_nms),.img_data_o(img_data_nms));双阈值//根据输入的低阈值和高阈值来判断,如果这个像素点大于高阈值,则赋值为255;如果低于低阈值,则赋值为0;double_threshold u_double_threshold (.clk (clk),.reset (reset),.img_width (img_width),.img_height (img_height),.low_threshold (low_threshold),.high_threshold(high_threshold),.valid_i (valid_nms),.img_data_i (img_data_nms),.valid_o (valid_db),.img_data_o (img_data_db));assign valid_o = valid_db;assign img_data_o = {3{img_data_db}};endmodule
2 彩色图变灰度图代码
`timescale 1ns / 1ps
//彩色图像灰度化module image_rgb2gray (input clk,input reset,input valid_i,input [23:0] img_data_i,output valid_o,output [7:0] img_data_o
);//常量parameter MODE = 0; //0表示加权平均法,1表示平均法 //Y=0.299*R十0.587*G+0.114*Bparameter C0 = 9'd306; //0.299*1024;parameter C1 = 10'd601; //0.587*1024;parameter C2 = 7'd117; //0.114*1024;//参数声明wire [7:0] R, G, B;assign {R, G, B} = img_data_i;generateif (MODE) beginreg valid_d1;reg [9:0] RGB_avr;reg valid_d2;reg [16:0] RGB_avr_m;reg valid_d3;reg [7:0] RGB_new;//平均法//1/3 * 512 = 171always @(posedge clk) beginif (reset) beginvalid_d1 <= 'b0;RGB_avr <= 'b0;end else beginvalid_d1 <= valid_i;RGB_avr <= R + G + B;endend//最大值不可能超过255*3*171 = 17'd130815always @(posedge clk) beginRGB_avr_m <= RGB_avr * 8'd171;endalways @(posedge clk) beginif (reset) beginvalid_d2 <= 'b0;end else beginvalid_d2 <= valid_d1;endend//最大值不可能超过255always @(posedge clk) beginif (reset) beginvalid_d3 <= 'b0;RGB_new <= 'b0;end else beginvalid_d3 <= valid_d2;RGB_new <= RGB_avr_m[16:9];endendassign valid_o = valid_d3;assign img_data_o = {3{RGB_new}};end else begin//加权平均法reg valid_d1;reg [16:0] Y_R_m;reg [17:0] Y_G_m;reg [14:0] Y_B_m;reg valid_d2;reg [17:0] Y_s;//最大值,当RGB都等于255时,(C0 + C1 + C2)*255 = 1024*255;不会出现负数reg valid_d3;reg [7:0] Y;always @(posedge clk) beginY_R_m <= R * C0;Y_G_m <= G * C1;Y_B_m <= B * C2;endalways @(posedge clk) beginif (reset) beginvalid_d1 <= 0;end else beginvalid_d1 <= valid_i;endendalways @(posedge clk) beginif (reset) beginY_s <= 0;valid_d2 <= 0;end else beginif (valid_d1) beginY_s <= Y_R_m + Y_G_m + Y_B_m;endvalid_d2 <= valid_d1;endendalways @(posedge clk) beginif (reset) beginY <= 0;valid_d3 <= 0;end else beginif (valid_d2) beginY <= Y_s[17:10];endvalid_d3 <= valid_d2;endendassign valid_o = valid_d3;assign img_data_o = Y;endendgenerateendmodule
3 3行缓存代码
`timescale 1ns / 1ps
//FIFO实现3行图像缓存module image_line_buffer #(parameter W = 8
) (input wire clk,input wire reset,input wire [10:0] img_width,input wire [ 9:0] img_height,input wire valid_i,input wire [W-1:0] img_data_i,output reg valid_o,output reg [W-1:0] prev_line_data_o,output reg [W-1:0] cur_line_data_o,output reg [W-1:0] next_line_data_o
);//常量声明localparam N = 3; //窗口大小//变量声明genvar i;integer j;wire [0:0] valid[0:N-1];wire [W-1:0] data[0:N-1];reg [10:0] out_data_cnt;reg [9:0] out_line_cnt;reg ch_valid;reg [W-1:0] ch_data[0:N-1];assign valid[0] = valid_i;assign data[0] = img_data_i;//行缓存模块, 只需要缓存N-1个fifo即可generatefor (i = 1; i < N; i = i + 1) begin : lbline_buffer #(.W(W)) u_line_buffer (.clk (clk),.reset (reset),.img_width(img_width),.valid_i (valid[i-1]),.data_i (data[i-1]),.valid_o (valid[i]),.data_o (data[i]));endendgenerate//模式1,按照上一行、当前行、下一行输出//特殊情况,可根据需求设定,是复制还是给0//第1个行缓存,是整个画面的第1行时, 上一行数据不存在,复制第1个行缓存或者直接为0输出//第1个行缓存,是整个画面的最后1行时,下一行数据不存在,复制第1个行缓存输出always @(posedge clk) beginif (reset) beginfor (j = 0; j < 3; j = j + 1) ch_data[j] <= 0;end else if (valid[N-2]) beginch_data[1] <= data[1];if (out_line_cnt == 0) beginch_data[2] <= 0;ch_data[0] <= data[0];end else if (out_line_cnt == img_height - 1) beginch_data[2] <= data[2];ch_data[0] <= 0;end else beginch_data[2] <= data[2];ch_data[0] <= data[0];endendendalways @(posedge clk) beginif (reset) beginch_valid <= 0;out_data_cnt <= 0;out_line_cnt <= 0;end else beginch_valid <= valid[N-2];out_data_cnt <= valid[N-2] ? ((out_data_cnt == img_width - 1) ? 0 : out_data_cnt + 1) : out_data_cnt;out_line_cnt <= valid[N-2]&&(out_data_cnt == img_width - 1) ? ((out_line_cnt == img_height - 1) ? 0 : out_line_cnt + 1) : out_line_cnt;endend//单路输出always @(posedge clk) beginif (reset) beginvalid_o <= 0;prev_line_data_o <= 0;cur_line_data_o <= 0;next_line_data_o <= 0;end else beginvalid_o <= ch_valid;prev_line_data_o <= ch_data[2];cur_line_data_o <= ch_data[1];next_line_data_o <= ch_data[0];endendendmodule
4 1行缓存代码
`timescale 1ns / 1ps
//FIFO实现1行图像缓存module line_buffer #(parameter W = 8
) (input wire clk,input wire reset,input wire [10:0] img_width,input wire valid_i,input wire [W-1:0] data_i,output wire valid_o,output wire [W-1:0] data_o
);//变量声明reg [10:0] wr_data_cnt;wire rd_en;wire [11:0] fifo_data_count_w;//写入数据计数always @(posedge clk or posedge reset) beginif (reset) beginwr_data_cnt <= 0;end else beginwr_data_cnt <= valid_i && (wr_data_cnt < img_width) ? (wr_data_cnt + 1'b1) : wr_data_cnt;endend//assign rd_en = valid_i&&(wr_data_cnt == img_width) ? 1'b1 : 1'b0;//等价于assign rd_en = valid_i && (fifo_data_count_w == img_width) ? 1'b1 : 1'b0;assign valid_o = rd_en;generateif (W == 8) beginfifo_line_buffer_w8 u_fifo_line_buffer_w8 (.clk (clk), // input wire clk.srst (reset), // input wire srst.din (data_i), // input wire [7 : 0] din.wr_en (valid_i), // input wire wr_en.rd_en (rd_en), // input wire rd_en.dout (data_o), // output wire [7 : 0] dout.full (), // output wire full.empty (), // output wire empty.data_count(fifo_data_count_w) // output wire [11 : 0] data_count);end else beginfifo_line_buffer u_fifo_line_buffer (.clk (clk), // input wire clk.srst (reset), // input wire srst.din (data_i), // input wire [22 : 0] din.wr_en (valid_i), // input wire wr_en.rd_en (rd_en), // input wire rd_en.dout (data_o), // output wire [22 : 0] dout.full (), // output wire full.empty (), // output wire empty.data_count(fifo_data_count_w) // output wire [11 : 0] data_count);endendgenerateendmodule
5 高斯滤波代码
`timescale 1ns / 1ps
// 高斯滤波module image_gaussian_filter (input wire clk,input wire reset,input wire [10:0] img_width,input wire [ 9:0] img_height,input wire valid_i,input wire [7:0] img_data_i,output reg valid_o,output reg [7:0] img_data_o
);//常量声明localparam MODE = 1; //0表示彩色图像输出,1表示灰度图像输出//变量声明wire valid;wire [7:0] prev_line_data;wire [7:0] cur_line_data;wire [7:0] next_line_data;reg valid_d1;reg [7:0] prev_line_data_d1;reg [7:0] cur_line_data_d1;reg [7:0] next_line_data_d1;reg [7:0] prev_line_data_d2;reg [7:0] cur_line_data_d2;reg [7:0] next_line_data_d2;reg [7:0] x_cnt;reg valid_s;reg [7:0] prev_line_data_d2_s;reg [7:0] cur_line_data_d2_s;reg [7:0] next_line_data_d2_s;reg [7:0] prev_line_data_d1_s;reg [7:0] cur_line_data_d1_s;reg [7:0] next_line_data_d1_s;reg [7:0] prev_line_data_s;reg [7:0] cur_line_data_s;reg [7:0] next_line_data_s;wire [7:0] Y0, Y1, Y2;wire [7:0] Y3, Y4, Y5;wire [7:0] Y6, Y7, Y8;reg valid_s_d1;reg [9:0] Y_sum0;reg [10:0] Y_sum1;reg [9:0] Y_sum2;reg valid_s_d2;reg [14:0] Y_sum;wire [15:0] RGB_sum;wire [7:0] gray;image_line_buffer u_image_line_buffer (.clk (clk),.reset (reset),.img_width (img_width),.img_height (img_height),.valid_i (valid_i),.img_data_i (img_data_i),.valid_o (valid),.prev_line_data_o(prev_line_data),.cur_line_data_o (cur_line_data),.next_line_data_o(next_line_data));always @(posedge clk) beginif (reset) beginvalid_d1 <= 0;prev_line_data_d1 <= 0;cur_line_data_d1 <= 0;next_line_data_d1 <= 0;prev_line_data_d2 <= 0;cur_line_data_d2 <= 0;next_line_data_d2 <= 0;end else beginvalid_d1 <= valid;prev_line_data_d1 <= prev_line_data;cur_line_data_d1 <= cur_line_data;next_line_data_d1 <= next_line_data;prev_line_data_d2 <= prev_line_data_d1;cur_line_data_d2 <= cur_line_data_d1;next_line_data_d2 <= next_line_data_d1;endend//边界数据处理always @(posedge clk) beginif (reset) beginx_cnt <= 0;end else beginx_cnt <= valid_d1 ? ((x_cnt == img_width - 1) ? 0 : x_cnt + 1) : x_cnt;endendalways @(posedge clk) beginif (reset) beginvalid_s <= 0;prev_line_data_d2_s <= 0;cur_line_data_d2_s <= 0;next_line_data_d2_s <= 0;prev_line_data_d1_s <= 0;cur_line_data_d1_s <= 0;next_line_data_d1_s <= 0;prev_line_data_s <= 0;cur_line_data_s <= 0;next_line_data_s <= 0;end else beginvalid_s <= valid_d1;prev_line_data_d1_s <= prev_line_data_d1;cur_line_data_d1_s <= cur_line_data_d1;next_line_data_d1_s <= next_line_data_d1;if (x_cnt == 0) beginprev_line_data_d2_s <= prev_line_data_d1;cur_line_data_d2_s <= cur_line_data_d1;next_line_data_d2_s <= next_line_data_d1;prev_line_data_s <= prev_line_data;cur_line_data_s <= cur_line_data;next_line_data_s <= next_line_data;endif (x_cnt == img_width - 1) beginprev_line_data_d2_s <= prev_line_data_d2;cur_line_data_d2_s <= cur_line_data_d2;next_line_data_d2_s <= next_line_data_d2;prev_line_data_s <= prev_line_data_d1;cur_line_data_s <= cur_line_data_d1;next_line_data_s <= next_line_data_d1;end else beginprev_line_data_d2_s <= prev_line_data_d2;cur_line_data_d2_s <= cur_line_data_d2;next_line_data_d2_s <= next_line_data_d2;prev_line_data_s <= prev_line_data;cur_line_data_s <= cur_line_data;next_line_data_s <= next_line_data;endendendassign Y0 = prev_line_data_d2_s;assign Y1 = cur_line_data_d2_s;assign Y2 = next_line_data_d2_s;assign Y3 = prev_line_data_d1_s;assign Y4 = cur_line_data_d1_s;assign Y5 = next_line_data_d1_s;assign Y6 = prev_line_data_s;assign Y7 = cur_line_data_s;assign Y8 = next_line_data_s;//高斯滤波模版/************[1. 2. 1.][2. 4. 2.][1. 2. 1.]
*************/always @(posedge clk) beginif (reset) beginvalid_s_d1 <= 0;{Y_sum0, Y_sum1, Y_sum2} <= 0;end else if (valid_s) beginvalid_s_d1 <= 1;Y_sum0 <= Y0 + {Y1, 1'b0} + Y2;Y_sum1 <= {Y3, 1'b0} + {Y4, 2'b0} + {Y5, 1'b0};Y_sum2 <= Y6 + {Y7, 1'b0} + Y8;end else valid_s_d1 <= 0;end//彩色图像 直接求和//灰度图像 1/3,扩大4bit,即16/3约等于5 = 4 + 1always @(posedge clk) beginif (reset) beginvalid_s_d2 <= 0;Y_sum <= 0;end else if (valid_s_d1) beginvalid_s_d2 <= 1;Y_sum <= Y_sum0 + Y_sum1 + Y_sum2;end else valid_s_d2 <= 0;endalways @(posedge clk) beginif (reset) beginvalid_o <= 0;img_data_o <= 0;end else if (valid_s_d2) beginvalid_o <= 1;img_data_o <= Y_sum[11:4];end else beginvalid_o <= 0;endendendmodule
6 sobel边缘检测代码
`timescale 1ns / 1ps
//边缘检测一阶微分算子:Sobel算子module image_sobel_edge (input wire clk,input wire reset,input wire [10:0] img_width,input wire [ 9:0] img_height,input wire valid_i,input wire [7:0] img_data_i,output reg valid_o,output reg [7:0] grad_mag,output reg [10:0] grad_dx,output reg [10:0] grad_dy
);//常量声明localparam N = 16;//变量声明wire valid;wire [7:0] prev_line_data;wire [7:0] cur_line_data;wire [7:0] next_line_data;reg valid_d1;reg [7:0] prev_line_data_d1;reg [7:0] cur_line_data_d1;reg [7:0] next_line_data_d1;reg [7:0] prev_line_data_d2;reg [7:0] cur_line_data_d2;reg [7:0] next_line_data_d2;reg [10:0] x_cnt;reg valid_s;reg [7:0] prev_line_data_d2_s;reg [7:0] cur_line_data_d2_s;reg [7:0] next_line_data_d2_s;reg [7:0] prev_line_data_d1_s;reg [7:0] cur_line_data_d1_s;reg [7:0] next_line_data_d1_s;reg [7:0] prev_line_data_s;reg [7:0] cur_line_data_s;reg [7:0] next_line_data_s;wire [7:0] Y0;wire [7:0] Y1;wire [7:0] Y2;wire [7:0] Y3;wire [7:0] Y4;wire [7:0] Y5;wire [7:0] Y6;wire [7:0] Y7;wire [7:0] Y8;reg valid_s_d1;wire [9:0] Gx_Y0_a;wire [9:0] Gx_Y1_a;wire [9:0] Gy_Y0_a;wire [9:0] Gy_Y1_a;reg Gx_Y_sign;reg [9:0] Gx_Y;reg Gy_Y_sign;reg [9:0] Gy_Y;reg valid_s_d2;reg Gx_Y_sign_d1;reg [19:0] Gx_Y_square;reg Gy_Y_sign_d1;reg [19:0] Gy_Y_square;wire [20:0] Gx_Gy_sum;reg [N-1:0] Gx_Y_sign_shift;reg [10*N-1:0] Gx_Y_shift;reg [N-1:0] Gy_Y_sign_shift;reg [10*N-1:0] Gy_Y_shift;wire valid_sqr;wire [10:0] data_sqr;image_line_buffer u_image_line_buffer (.clk (clk),.reset (reset),.img_width (img_width),.img_height (img_height),.valid_i (valid_i),.img_data_i (img_data_i),.valid_o (valid),.prev_line_data_o(prev_line_data),.cur_line_data_o (cur_line_data),.next_line_data_o(next_line_data));always @(posedge clk) beginif (reset) beginvalid_d1 <= 0;prev_line_data_d1 <= 0;cur_line_data_d1 <= 0;next_line_data_d1 <= 0;prev_line_data_d2 <= 0;cur_line_data_d2 <= 0;next_line_data_d2 <= 0;end else beginvalid_d1 <= valid;prev_line_data_d1 <= prev_line_data;cur_line_data_d1 <= cur_line_data;next_line_data_d1 <= next_line_data;prev_line_data_d2 <= prev_line_data_d1;cur_line_data_d2 <= cur_line_data_d1;next_line_data_d2 <= next_line_data_d1;endend//边界数据处理always @(posedge clk) beginif (reset) beginx_cnt <= 0;end else beginx_cnt <= valid_d1 ? ((x_cnt == img_width - 1) ? 0 : x_cnt + 1) : x_cnt;endendalways @(posedge clk) beginif (reset) beginvalid_s <= 0;prev_line_data_d2_s <= 0;cur_line_data_d2_s <= 0;next_line_data_d2_s <= 0;prev_line_data_d1_s <= 0;cur_line_data_d1_s <= 0;next_line_data_d1_s <= 0;prev_line_data_s <= 0;cur_line_data_s <= 0;next_line_data_s <= 0;end else beginvalid_s <= valid_d1;prev_line_data_d1_s <= prev_line_data_d1;cur_line_data_d1_s <= cur_line_data_d1;next_line_data_d1_s <= next_line_data_d1;if (x_cnt == 0) beginprev_line_data_d2_s <= prev_line_data_d1;cur_line_data_d2_s <= cur_line_data_d1;next_line_data_d2_s <= next_line_data_d1;prev_line_data_s <= prev_line_data;cur_line_data_s <= cur_line_data;next_line_data_s <= next_line_data;endif (x_cnt == img_width - 1) beginprev_line_data_d2_s <= prev_line_data_d2;cur_line_data_d2_s <= cur_line_data_d2;next_line_data_d2_s <= next_line_data_d2;prev_line_data_s <= prev_line_data_d1;cur_line_data_s <= cur_line_data_d1;next_line_data_s <= next_line_data_d1;end else beginprev_line_data_d2_s <= prev_line_data_d2;cur_line_data_d2_s <= cur_line_data_d2;next_line_data_d2_s <= next_line_data_d2;prev_line_data_s <= prev_line_data;cur_line_data_s <= cur_line_data;next_line_data_s <= next_line_data;endendendassign Y0 = prev_line_data_d2_s;assign Y1 = cur_line_data_d2_s;assign Y2 = next_line_data_d2_s;assign Y3 = prev_line_data_d1_s;assign Y4 = cur_line_data_d1_s;assign Y5 = next_line_data_d1_s;assign Y6 = prev_line_data_s;assign Y7 = cur_line_data_s;assign Y8 = next_line_data_s;/Sobey算子/************[-1. 0. 1] [-2. 0. 2]
Gx= [-1. 0. 1][ 1. 2. 1][ 0. 0. 0]
Gy= [-1. -2. -1]
*************/assign Gx_Y0_a = Y0 + {Y3, 1'b0} + Y6;assign Gx_Y1_a = Y2 + {Y5, 1'b0} + Y8;assign Gy_Y0_a = Y0 + {Y1, 1'b0} + Y2;assign Gy_Y1_a = Y6 + {Y7, 1'b0} + Y8;always @(posedge clk) beginif (reset) beginvalid_s_d1 <= 0;{Gx_Y, Gy_Y} <= 0;{Gx_Y_sign, Gy_Y_sign} <= 0;end else if (valid_s) beginvalid_s_d1 <= 1;Gx_Y <= (Gx_Y0_a > Gx_Y1_a) ? Gx_Y0_a - Gx_Y1_a : Gx_Y1_a - Gx_Y0_a;Gx_Y_sign <= (Gx_Y0_a > Gx_Y1_a) ? 1 : 0;Gy_Y <= (Gy_Y0_a > Gy_Y1_a) ? Gy_Y0_a - Gy_Y1_a : Gy_Y1_a - Gy_Y0_a;Gy_Y_sign <= (Gy_Y0_a > Gy_Y1_a) ? 1 : 0;end else valid_s_d1 <= 0;end//求平方always @(posedge clk) beginif (reset) beginvalid_s_d2 <= 0;Gx_Y_square <= 0;Gy_Y_square <= 0;end else beginvalid_s_d2 <= valid_s_d1;Gx_Y_square <= Gx_Y * Gx_Y;Gy_Y_square <= Gy_Y * Gy_Y;endendassign Gx_Gy_sum = Gx_Y_square + Gy_Y_square;//平方根cordic_square_root u_cordic_square_root (.aclk (clk), // input wire aclk.s_axis_cartesian_tvalid(valid_s_d2), // input wire s_axis_cartesian_tvalid.s_axis_cartesian_tdata (Gx_Gy_sum), // input wire [23 : 0] s_axis_cartesian_tdata.m_axis_dout_tvalid (valid_sqr), // output wire m_axis_dout_tvalid.m_axis_dout_tdata (data_sqr) // output wire [15 : 0] m_axis_dout_tdata);always @(posedge clk) beginif (reset) beginGx_Y_sign_shift <= 0;Gx_Y_shift <= 0;Gy_Y_sign_shift <= 0;Gy_Y_shift <= 0;end else beginGx_Y_sign_shift <= {Gx_Y_sign_shift, Gx_Y_sign};Gx_Y_shift <= {Gx_Y_shift, Gx_Y};Gy_Y_sign_shift <= {Gy_Y_sign_shift, Gy_Y_sign};Gy_Y_shift <= {Gy_Y_shift, Gy_Y};endendalways @(posedge clk) beginif (reset) beginvalid_o <= 0;grad_mag <= 0;grad_dx <= 0;grad_dy <= 0;end else if (valid_sqr) beginvalid_o <= 1;grad_mag <= data_sqr;grad_dx <= {Gx_Y_sign_shift[N-1], Gx_Y_shift[N*10-1:(N-1)*10]};grad_dy <= {Gy_Y_sign_shift[N-1], Gy_Y_shift[N*10-1:(N-1)*10]};end else beginvalid_o <= 0;endendendmodule
7 非极大值抑制代码
`timescale 1ns / 1ps
// 非极大值抑制module non_maximum_suppression (input clk,input reset,input wire [10:0] img_width,input wire [ 9:0] img_height,input valid_i,input [7:0] grad_mag,input [10:0] grad_dx,input [10:0] grad_dy,output reg valid_o,output reg [7:0] img_data_o
);//常量localparam N = 24;//参数声明wire valid;wire [7:0] prev_line_data;wire [7:0] cur_line_data;wire [7:0] next_line_data;reg valid_d1;reg [7:0] prev_line_data_d1;reg [7:0] cur_line_data_d1;reg [7:0] next_line_data_d1;reg [7:0] prev_line_data_d2;reg [7:0] cur_line_data_d2;reg [7:0] next_line_data_d2;reg [10:0] x_cnt;reg valid_s;reg [7:0] prev_line_data_d2_s;reg [7:0] cur_line_data_d2_s;reg [7:0] next_line_data_d2_s;reg [7:0] prev_line_data_d1_s;reg [7:0] cur_line_data_d1_s;reg [7:0] next_line_data_d1_s;reg [7:0] prev_line_data_s;reg [7:0] cur_line_data_s;reg [7:0] next_line_data_s;wire [7:0] Y0, Y1, Y2;wire [7:0] Y3, Y4, Y5;wire [7:0] Y6, Y7, Y8;wire grad_valid;wire [21:0] grad_cur_line_data;reg valid_s_d1;reg grad_dx_sign;reg [9:0] grad_dx_abs;reg grad_dy_sign;reg [9:0] grad_dy_abs;reg [1:0] mode;reg [9:0] dividend, divisor;wire div_valid;wire [23:0] div_data;reg [2*N-1:0] mode_shift;wire mode_s;reg [72*N-1:0] Y_shift;wire [7:0] Y0_s, Y1_s, Y2_s;wire [7:0] Y3_s, Y4_s, Y5_s;wire [7:0] Y6_s, Y7_s, Y8_s;reg div_valid_d1;reg [7:0] grad1, grad2, grad3, grad4;reg [7:0] weight;reg [8:0] one_sub_weight;reg [7:0] Y4_s_d1;reg div_valid_d2;reg [15:0] grad1_m, grad2_m;reg [16:0] grad3_m, grad4_m;reg [7:0] Y4_s_d2;wire [16:0] t1, t2;/行视频数据缓存image_line_buffer u_image_line_buffer (.clk (clk),.reset (reset),.img_width (img_width),.img_height (img_height),.valid_i (valid_i),.img_data_i (grad_mag),.valid_o (valid),.prev_line_data_o(prev_line_data),.cur_line_data_o (cur_line_data),.next_line_data_o(next_line_data));always @(posedge clk) beginif (reset) beginvalid_d1 <= 0;prev_line_data_d1 <= 0;cur_line_data_d1 <= 0;next_line_data_d1 <= 0;prev_line_data_d2 <= 0;cur_line_data_d2 <= 0;next_line_data_d2 <= 0;end else beginvalid_d1 <= valid;prev_line_data_d1 <= prev_line_data;cur_line_data_d1 <= cur_line_data;next_line_data_d1 <= next_line_data;prev_line_data_d2 <= prev_line_data_d1;cur_line_data_d2 <= cur_line_data_d1;next_line_data_d2 <= next_line_data_d1;endend//边界数据处理always @(posedge clk) beginif (reset) beginx_cnt <= 0;end else beginx_cnt <= valid_d1 ? ((x_cnt == img_width - 1) ? 0 : x_cnt + 1) : x_cnt;endendalways @(posedge clk) beginif (reset) beginvalid_s <= 0;prev_line_data_d2_s <= 0;cur_line_data_d2_s <= 0;next_line_data_d2_s <= 0;prev_line_data_d1_s <= 0;cur_line_data_d1_s <= 0;next_line_data_d1_s <= 0;prev_line_data_s <= 0;cur_line_data_s <= 0;next_line_data_s <= 0;end else beginvalid_s <= valid_d1;prev_line_data_d1_s <= prev_line_data_d1;cur_line_data_d1_s <= cur_line_data_d1;next_line_data_d1_s <= next_line_data_d1;if (x_cnt == 0) beginprev_line_data_d2_s <= prev_line_data_d1;cur_line_data_d2_s <= cur_line_data_d1;next_line_data_d2_s <= next_line_data_d1;prev_line_data_s <= prev_line_data;cur_line_data_s <= cur_line_data;next_line_data_s <= next_line_data;endif (x_cnt == img_width - 1) beginprev_line_data_d2_s <= prev_line_data_d2;cur_line_data_d2_s <= cur_line_data_d2;next_line_data_d2_s <= next_line_data_d2;prev_line_data_s <= prev_line_data_d1;cur_line_data_s <= cur_line_data_d1;next_line_data_s <= next_line_data_d1;end else beginprev_line_data_d2_s <= prev_line_data_d2;cur_line_data_d2_s <= cur_line_data_d2;next_line_data_d2_s <= next_line_data_d2;prev_line_data_s <= prev_line_data;cur_line_data_s <= cur_line_data;next_line_data_s <= next_line_data;endendendassign Y0 = prev_line_data_d2_s;assign Y1 = cur_line_data_d2_s;assign Y2 = next_line_data_d2_s;assign Y3 = prev_line_data_d1_s;assign Y4 = cur_line_data_d1_s;assign Y5 = next_line_data_d1_s;assign Y6 = prev_line_data_s;assign Y7 = cur_line_data_s;assign Y8 = next_line_data_s;/grad_dx和grad_dy行数据缓存image_line_buffer #(.W(21)) u_image_grad_line_buffer (.clk (clk),.reset (reset),.img_width (img_width),.img_height (img_height),.valid_i (valid_i),.img_data_i ({grad_dx, grad_dy}),.valid_o (grad_valid),.prev_line_data_o(),.cur_line_data_o (grad_cur_line_data),.next_line_data_o());/非极大值限制计算//计算grad_dx,grad_dy绝对值always @(posedge clk) beginif (reset) begin{grad_dx_sign, grad_dx_abs} <= 0;{grad_dy_sign, grad_dy_abs} <= 0;end else begingrad_dx_sign <= grad_cur_line_data[21];grad_dx_abs <= grad_cur_line_data[20:11];grad_dy_sign <= grad_cur_line_data[10];grad_dy_abs <= grad_cur_line_data[9:0];endend//计算模式always @(posedge clk) beginif (reset) beginmode <= 0;{dividend, divisor} <= 0;end else beginif (grad_dx_abs > grad_dy_abs) beginmode <= (grad_dx_sign ^ grad_dy_sign) ? 0 : 1;dividend <= grad_dy_abs;divisor <= grad_dx_abs;end else beginmode <= (grad_dx_sign ^ grad_dy_sign) ? 2 : 3;dividend <= grad_dx_abs;divisor <= grad_dy_abs;endendend//除法计算div_gen_10x10 u_div_gen_10x10 (.aclk (clk), // input wire aclk.s_axis_divisor_tvalid (valid_s), // input wire s_axis_divisor_tvalid.s_axis_divisor_tdata ({6'b0, divisor}), // input wire [15 : 0] s_axis_divisor_tdata.s_axis_dividend_tvalid(valid_s), // input wire s_axis_dividend_tvalid.s_axis_dividend_tdata ({6'b0, dividend}), // input wire [15 : 0] s_axis_dividend_tdata.m_axis_dout_tvalid (div_valid), // output wire m_axis_dout_tvalid.m_axis_dout_tdata (div_data) // output wire [23 : 0] m_axis_dout_tdata);//同步延时always @(posedge clk) beginif (reset) beginmode_shift <= 0;Y_shift <= 0;end else beginmode_shift <= {mode_shift, mode};Y_shift <= {Y_shift, Y0, Y1, Y2, Y3, Y4, Y5, Y6, Y7, Y8};endendassign mode_s = mode_shift[2*N-1:2*(N-1)];assign {Y0_s, Y1_s, Y2_s, Y3_s, Y4_s, Y5_s, Y6_s, Y7_s, Y8_s} = Y_shift[72*N-1:72*(N-1)];//计算插值系数、插值数据always @(posedge clk) beginif (reset) begindiv_valid_d1 <= 0;weight <= 0;one_sub_weight <= 0;Y4_s_d1 <= 0;{grad1, grad2, grad3, grad4} <= 0;end else begindiv_valid_d1 <= div_valid;weight <= div_data[7:0];one_sub_weight <= 256 - div_data[7:0];Y4_s_d1 <= Y4_s;case (mode_s)0: begingrad1 <= Y7_s;grad2 <= Y1_s;grad3 <= Y8_s;grad4 <= Y0_s;end1: begingrad1 <= Y7_s;grad2 <= Y1_s;grad3 <= Y6_s;grad4 <= Y2_s;end2: begingrad1 <= Y5_s;grad2 <= Y3_s;grad3 <= Y8_s;grad4 <= Y0_s;end3: begingrad1 <= Y5_s;grad2 <= Y3_s;grad3 <= Y6_s;grad4 <= Y2_s;endendcaseendend//计算极值t1\t2always @(posedge clk) beginif (reset) begindiv_valid_d2 <= 0;Y4_s_d2 <= 0;{grad1_m, grad2_m, grad3_m, grad4_m} <= 0;end else begindiv_valid_d2 <= div_valid_d1;Y4_s_d2 <= Y4_s_d1;grad1_m <= grad1 * weight;grad2_m <= grad2 * weight;grad3_m <= grad3 * one_sub_weight;grad4_m <= grad4 * one_sub_weight;endendassign t1 = grad1_m + grad3_m;assign t2 = grad2_m + grad4_m;//超过极值后,赋值为0always @(posedge clk) beginif (reset) beginvalid_o <= 0;img_data_o <= 0;end else if (div_valid_d2) beginvalid_o <= 1;img_data_o <= ({1'b0, Y4_s_d2} > t1[16:8]) && ({1'b0, Y4_s_d2} > t2[16:8]) ? Y4_s_d2 : 0;end else beginvalid_o <= 0;endendendmodule
8 双阈值代码
`timescale 1ns / 1ps
//双阈值module double_threshold (input clk,input reset,input [10:0] img_width,input [ 9:0] img_height,input [ 7:0] low_threshold,input [ 7:0] high_threshold,input valid_i,input [7:0] img_data_i,output reg valid_o,output reg [7:0] img_data_o
);//常量声明localparam MODE = 1; //0表示彩色图像输出,1表示灰度图像输出//变量声明wire valid;wire [7:0] prev_line_data;wire [7:0] cur_line_data;wire [7:0] next_line_data;reg valid_d1;reg [7:0] prev_line_data_d1;reg [7:0] cur_line_data_d1;reg [7:0] next_line_data_d1;reg [7:0] prev_line_data_d2;reg [7:0] cur_line_data_d2;reg [7:0] next_line_data_d2;reg [7:0] x_cnt;reg valid_s;reg [7:0] prev_line_data_d2_s;reg [7:0] cur_line_data_d2_s;reg [7:0] next_line_data_d2_s;reg [7:0] prev_line_data_d1_s;reg [7:0] cur_line_data_d1_s;reg [7:0] next_line_data_d1_s;reg [7:0] prev_line_data_s;reg [7:0] cur_line_data_s;reg [7:0] next_line_data_s;wire [7:0] Y0, Y1, Y2;wire [7:0] Y3, Y4, Y5;wire [7:0] Y6, Y7, Y8;image_line_buffer u_image_line_buffer (.clk (clk),.reset (reset),.img_width (img_width),.img_height (img_height),.valid_i (valid_i),.img_data_i (img_data_i),.valid_o (valid),.prev_line_data_o(prev_line_data),.cur_line_data_o (cur_line_data),.next_line_data_o(next_line_data));always @(posedge clk) beginif (reset) beginvalid_d1 <= 0;prev_line_data_d1 <= 0;cur_line_data_d1 <= 0;next_line_data_d1 <= 0;prev_line_data_d2 <= 0;cur_line_data_d2 <= 0;next_line_data_d2 <= 0;end else beginvalid_d1 <= valid;prev_line_data_d1 <= prev_line_data;cur_line_data_d1 <= cur_line_data;next_line_data_d1 <= next_line_data;prev_line_data_d2 <= prev_line_data_d1;cur_line_data_d2 <= cur_line_data_d1;next_line_data_d2 <= next_line_data_d1;endend//边界数据处理always @(posedge clk) beginif (reset) beginx_cnt <= 0;end else beginx_cnt <= valid_d1 ? ((x_cnt == img_width - 1) ? 0 : x_cnt + 1) : x_cnt;endendalways @(posedge clk) beginif (reset) beginvalid_s <= 0;prev_line_data_d2_s <= 0;cur_line_data_d2_s <= 0;next_line_data_d2_s <= 0;prev_line_data_d1_s <= 0;cur_line_data_d1_s <= 0;next_line_data_d1_s <= 0;prev_line_data_s <= 0;cur_line_data_s <= 0;next_line_data_s <= 0;end else beginvalid_s <= valid_d1;prev_line_data_d1_s <= prev_line_data_d1;cur_line_data_d1_s <= cur_line_data_d1;next_line_data_d1_s <= next_line_data_d1;if (x_cnt == 0) beginprev_line_data_d2_s <= prev_line_data_d1;cur_line_data_d2_s <= cur_line_data_d1;next_line_data_d2_s <= next_line_data_d1;prev_line_data_s <= prev_line_data;cur_line_data_s <= cur_line_data;next_line_data_s <= next_line_data;endif (x_cnt == img_width - 1) beginprev_line_data_d2_s <= prev_line_data_d2;cur_line_data_d2_s <= cur_line_data_d2;next_line_data_d2_s <= next_line_data_d2;prev_line_data_s <= prev_line_data_d1;cur_line_data_s <= cur_line_data_d1;next_line_data_s <= next_line_data_d1;end else beginprev_line_data_d2_s <= prev_line_data_d2;cur_line_data_d2_s <= cur_line_data_d2;next_line_data_d2_s <= next_line_data_d2;prev_line_data_s <= prev_line_data;cur_line_data_s <= cur_line_data;next_line_data_s <= next_line_data;endendendassign Y0 = prev_line_data_d2_s;assign Y1 = cur_line_data_d2_s;assign Y2 = next_line_data_d2_s;assign Y3 = prev_line_data_d1_s;assign Y4 = cur_line_data_d1_s;assign Y5 = next_line_data_d1_s;assign Y6 = prev_line_data_s;assign Y7 = cur_line_data_s;assign Y8 = next_line_data_s;always @(posedge clk) beginif (reset) beginvalid_o <= 0;img_data_o <= 0;end else if (valid_s) beginvalid_o <= 1;if (Y4 < low_threshold) img_data_o <= 0;else if((Y0 > high_threshold)||(Y1 > high_threshold)||(Y2 > high_threshold)||(Y3 > high_threshold)||(Y4 > high_threshold)||(Y5 > high_threshold)||(Y6 > high_threshold)||(Y7 > high_threshold)||(Y8 > high_threshold))img_data_o <= 255;else img_data_o <= 0;end else beginvalid_o <= 0;endendendmodule
这篇关于FPGA 图像边缘检测(Canny算子)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!