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算子)
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 va…...

2024.3.28学习笔记
今日学习韩顺平java0200_韩顺平Java_对象机制练习_哔哩哔哩_bilibili 今日学习p286-p294 继承 继承可以解决代码复用,让我们的编程更加靠近人类思维,当多个类存在相同的属性和方法时,可以从这些类中抽象出父类,在父类中定义这些…...

33.HarmonyOS App(JAVA)鸿蒙系统app数据库增删改查
33.HarmonyOS App(JAVA)鸿蒙系统app数据库增删改查 关系数据库 关系对象数据库(ORM) 应用偏好数据库 分布式数据库 关系型数据库(Relational Database,RDB)是一种基于关系模型来管理数据的数据库。HarmonyOS关系型…...

寄主机显示器被快递搞坏了怎么办?怎么破?
大家好,我是平泽裕也。 最近,我在社区里看到很多关于开学后弟弟寄来的电脑显示器被快递损坏的帖子。 看到它真的让我感到难过。 如果有人的数码产品被快递损坏了,我会伤心很久。 那么今天就跟大家聊聊寄快递的一些小技巧。 作为一名曾经的…...

python爬虫-bs4
python爬虫-bs4 目录 python爬虫-bs4说明安装导入 基础用法解析对象获取文本Tag对象获取HTML中的标签内容find参数获取标签属性获取所有标签获取标签名嵌套获取子节点和父节点 说明 BeautifulSoup 是一个HTML/XML的解析器,主要的功能也是如何解析和提取 HTML/XML 数…...

SpringBoot学习之ElasticSearch下载安装和启动(Mac版)(三十一)
本篇是接上一篇Windows版本,需要Windows版本的请看上一篇,这里我们继续把Elasticsearch简称为ES,以下都是这样。 一、下载 登录Elasticsearch官网,地址是:Download Elasticsearch | Elastic 进入以后,网页会自动识别系统给你提示Mac版本的下载链接按钮 二、安装 下载…...

OC对象 - Block解决循环引用
文章目录 OC对象 - Block解决循环引用前言1. 循环引用示例1.1 分析 2. 解决思路3. ARC下3.1 __weak3.2 __unsafe_unretained3.3 __block 4. MRC下4.1 __unsafe_unretain....4.1 __block 5. 总结5.1 ARC下5.2 MRC下 OC对象 - Block解决循环引用 前言 本章将会通过一个循环引用…...

Java设计模式之装饰器模式
装饰器模式是一种结构型设计模式,它允许动态地将责任附加到对象上。装饰器模式是通过创建一个包装对象,也就是装饰器,来包裹真实对象,从而实现对真实对象的功能增强。装饰器模式可以在不修改原有对象的情况下,动态地添…...

Java基础知识总结(25)
代理模式 什么是代理模式? 代理模式是指,为其他对象提供一种代理以控制这个对象的访问。一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户和目标对象之间起到中介的作用。换句话说,代理模式,是在不修…...

Vue3 实现基于token 用户登录
前后端分离情况下,实现的大致思路 1 第一次登录的时候,前端调用后端的登录接口,发送用户名与密码 2 后端收到请求,验证用户名和密码,验证成功 给前端返回一个token 3 前段拿到token 将token 存储进localStorage 和…...

在word中显示Euclid Math One公式的问题及解决(latex公式,无需插件)
问题:想要在word中显示形如latex中的花体字母 网上大多解决办法是安装Euclid Math One。安装后发现单独的符号插入可行,但是公式中选择该字体时依然显示默认字体。 解决办法:插入公式后,勾选左上角的latex 在公式块中键入latex代码…...

江协科技STM32:按键控制LED光敏传感器控制蜂鸣器
按键控制LED LED模块 左上角PA0用上拉输入模式,如果此时引脚悬空,PA0就是高电平,这种方式下,按下按键,引脚为低电平,松下按键,引脚为高电平 右上角PA0,把上拉电阻想象成弹簧 当按键…...

最佳矢量绘图设计软件Sketch for Mac v99.5 最新中文激活版
Sketch for Mac是一款功能强大的矢量绘图软件,它提供了简单易用的界面和丰富的工具,让用户能够轻松创建精美的设计作品。 软件下载:Sketch for Mac v99.5 最新中文激活版 Sketch具有直观的布局和智能的工具,使得设计师能够快速实现…...

【IntelliJ IDEA】运行测试报错解决方案(附图)
IntelliJ IDEA 版本 2023.3.4 (Ultimate Edition) 测试报错信息 命令行过长。 通过 JAR 清单或通过类路径文件缩短命令行,然后重新运行 解决方案 修改运行配置,里面如果没有缩短命令行,需要再修改选项里面勾选缩短命令行让其显示&#x…...

【Kotlin】List、Set、Map简介
1 List Java 的 List、Set、Map 介绍见 → Java容器及其常用方法汇总。 1.1 创建 List 1.1.1 emptyList var list emptyList<String>() // 创建空List 1.1.2 List 构造函数 var list1 List(3) { "abc" } // [abc, abc, abc] var list2 ArrayList<In…...

OpenCV 形态学处理函数
四、形态学处理(膨胀,腐蚀,开闭运算)_getstructuringelement()函数作用-CSDN博客 数字图像处理(c opencv):形态学图像处理-morphologyEx函数实现腐蚀膨胀、开闭运算、击中-击不中变换、形态学梯度、顶帽黑帽变换 - 知乎…...

互联网摸鱼日报(2024-03-27)
互联网摸鱼日报(2024-03-27) 36氪新闻 谈“肉”色变,预制菜“顶流”要完? 欧美监管机构出重拳,苹果和谷歌都要被拆分了吗? 为什么产品经理的薪资待遇,这么高? AI PC:一场浩荡的革命 二氧化…...

2014年认证杯SPSSPRO杯数学建模B题(第二阶段)位图的处理算法全过程文档及程序
2014年认证杯SPSSPRO杯数学建模 B题 位图的处理算法 原题再现: 图形(或图像)在计算机里主要有两种存储和表示方法。矢量图是使用点、直线或多边形等基于数学方程的几何对象来描述图形,位图则使用像素来描述图像。一般来说&#…...

C++基本语法
C是如何工作的 文章目录 C是如何工作的1、新建Hello World工程1.1使用Visual Studio新建项目1.2 HelloWorld1.2.1 命名空间1.2.2 输出输出 1.3 注释1.4 函数1.4.1 使用有返回的函数1.4.2 自定义函数 1、新建Hello World工程 1.1使用Visual Studio新建项目 按照下面的图片&…...

Node Sass does not yet support your current environment
项目运行时报错:Node Sass does not yet support your current environment 原因是node版本过高。 解决办法: 使用nvm管理node版本,(如何安装nvm?请点击跳转) 具体步骤如下: 1.查看当前node…...

长陆工业自动控制系统邀您到场参观2024第13届生物发酵产品与技术装备展
参展企业介绍 珠海市长陆工业自动控制系统股份有限公司于2004年在素有“百岛之市,浪漫之城”的珠江口西岸核心城市—珠海成立。长陆工业是流程工业智能制造自动化、信息化综合解决方案的提供者。产品遍及冶金、化工、建材、食品、石油、橡塑、能源、环保、物流、粮…...

数据仓库——维度表更新
维度表的更新 维度表修改规律: 绝大部分维度表都是不变的很多维度虽然会变化,但是变化的很缓慢源记录产品键不会改变产品描述及其他属性的改变都很缓慢在源OLTP 系统中,新的值会覆盖旧的值在数据仓库中,覆盖维度表的属性并不总是适当的做法…...

Web3创作整理 - 2024-02-23 ~ 2024-03-25
Web3 创作整理 - 2024-02-23 ~ 2024-03-25 整理下3月份的文章,方便大家阅读 分类文章地址🫑ETH什么是Dapp🎼ETH什么是以太坊🎵ETH如何才能拥有ETH🎶ETHBTC网络 vs ETH网络🎙️ETHETH网络中的区块链…...

CSS(一)---【CSS简介、导入方式、八种选择器、优先级】
零.前言 本系列适用于零基础小白,亦或是初级前端工程师提升使用。 知识点较为详细,如果追求非常详细,请移步官方网站或搬运网站。 1.CSS简介 CSS全称:“Cascading Style Sheets”,中文名:“层叠样式表”…...

智慧公厕解决方案打造更加智能的卫生空间
一、智慧公厕方案概述 智慧公厕方案旨在解决现有公厕存在的诸多问题,包括民众用厕困难、环境卫生状况不佳、管理效率低下等方面。针对民众的需求和管理方面的挑战,智慧公厕提供了一套综合解决方案,包括智能导航、环境监测、资源管理等功能&a…...

美团0316春招笔试题
下面是美团2024-03-16笔试真题,进行了VP,由于未参与评测,故不保证正确性,仅供参考。 第一题 小美点外卖 求和然后减去满减和红包即可。 #include <bits/stdc.h> using namespace std; using LL long long ; int n, t, x,…...

typescript 实现RabbitMQ死信队列和延迟队列 订单10分钟未付归还库存
Manjaro安装RabbitMQ 安装 sudo pacman -S rabbitmq rabbitmqadmin启动管理模块 sudo rabbitmq-plugins enable rabbitmq_managementsudo rabbitmq-server管理界面 http://127.0.0.1:15672/ 默认用户名和密码都是guest。 要使用 rabbitmqctl 命令添加用户并分配权限…...

怎样才能把重建大师的空三导进去CC?
导出空三文件xml两者都是通用的,cc和photoscan都可以兼容。 重建大师是一款专为超大规模实景三维数据生产而设计的集群并行处理软件,输入倾斜照片,激光点云,POS信息及像控点,输出高精度彩色网格模型,可一键…...

命令模式(请求与具体实现解耦)
目录 前言 UML plantuml 类图 实战代码 模板 Command Invoker Receiver Client 前言 命令模式解耦了命令请求者(Invoker)和命令执行者(receiver),使得 Invoker 不再直接引用 receiver,而是依赖于…...

开发一款MMOARPG难度到底有多大
开发一款MMOARPG难度到底有多大 MMORPG游戏开发到底有多难,我们按照过去开发的标准,就比如开发一款传奇,那时候哪会用什么别人的引擎,都是自研,从基础图形API开始。我们不考虑美术和策划,就单指程序&#x…...