FPGA图像处理系列:图像缩放


实现了一个Avalon-ST总线的简单图像缩放模块,将640*480的图像输入,变成320*240大小的图像输出。主要思想是,得到图像的行列计数值,根据要缩放的比例,在相应的行列值使能valid信号,比如我要将640*480图像缩小成320*240,那么只需控制将其隔行、隔列使能valid就行了。其实就是一个降采样。代码直接贴出
  1. </pre><pre name="code" class="cpp">module ST_RESIZE(  
  2.     // global clock & reset  
  3.         input           clk,  
  4.         input               reset_n,  
  5.   
  6.     // stream sink  
  7.         input   [23:0]      sink_data,  
  8.         input               sink_valid,  
  9.         output          sink_ready,  
  10.         input           sink_sop,  
  11.         input           sink_eop,  
  12.       
  13.     // stream source  
  14.         output [23:0]     source_data,  
  15.        output            source_valid,  
  16.        input             source_ready,  
  17.        output            source_sop,  
  18.        output            source_eop  
  19.   
  20. );  
  21.   
  22. localparam CTRL_PKT_NUM     = 3;  
  23.   
  24. assign sink_ready   =  source_ready;    
  25. assign source_sop   =  sink_sop;  
  26. assign source_eop   =  sink_eop;  
  27. //assign source_valid =  sink_valid;  
  28. //assign source_data  =  sink_data;  
  29.   
  30. parameter WIDTH = 640;  
  31. parameter HEIGHT = 480;  
  32. parameter w_LOG_WIDTH = 320;  
  33. parameter w_LOG_HEIGHT = 240;  
  34. reg state;  
  35. localparam STATE_CTRL = 0;  
  36. localparam STATE_DATA = 1;  
  37. always@(posedge clk)begin  
  38. if(~reset_n)  
  39.     state <= STATE_CTRL;  
  40. else if( process_en && sink_sop&& sink_data == 24'd15)  
  41.     state <= STATE_CTRL;  
  42. else if( process_en && sink_sop&& sink_data == 24'd0)  
  43.     state <= STATE_DATA;  
  44. end  
  45.   
  46. reg [10:0]  h_count;  
  47. reg [10:0]  v_count;  
  48. wire process_en;  
  49. assign process_en = source_ready & sink_valid;    
  50. always@(posedge clk)begin  
  51. if(~reset_n)  
  52.     h_count <= 11'b0;  
  53. else if( process_en && sink_sop && sink_data == 24'd0)  
  54.     h_count <= 11'b0;  
  55. else if( process_en && h_count< WIDTH-1 && state == STATE_DATA)  
  56.     h_count <= h_count + 1'b1;  
  57. else if( process_en &&  h_count== WIDTH-1 && state == STATE_DATA)  
  58.     h_count <= 11'b0;  
  59. end  
  60.   
  61. always@(posedge clk)begin  
  62. if(~reset_n)  
  63.     v_count <= 11'b0;  
  64. else if( process_en && sink_sop&& sink_data == 24'd0)  
  65.     v_count <= 11'b0;  
  66. else if( process_en && h_count == WIDTH-1 && state == STATE_DATA)  
  67.     v_count <= v_count + 1'b1;  
  68. end  
  69.   
  70.   
  71.   
  72. assign source_valid =(sink_valid & sink_sop & sink_data == 24'd15) |   
  73.                     (sink_valid & state == STATE_CTRL )|  
  74.                     (sink_valid & sink_sop & sink_data == 24'd00) |   
  75.                     ( sink_valid & state == STATE_DATA & h_count[0]==0 & v_count[0]==0) |  
  76.                     ( sink_valid & sink_eop )  
  77.                     ;  
  78. //assign source_data =  sink_data;  
  79.   
  80. always @(*) begin  
  81.   case (state )  
  82.     STATE_CTRL :   
  83.     if(source_ready & sink_valid)begin  
  84.         if(dot_cnt==0)source_data = { 4'b0,  w_LOG_WIDTH[ 7: 4], 4'b0,  w_LOG_WIDTH[11: 8], 4'b0,  w_LOG_WIDTH[15:12] };  
  85.         if(dot_cnt==1)source_data = { 4'b0,  w_LOG_HEIGHT[11: 8], 4'b0, w_LOG_HEIGHT[15:12], 4'b0,  w_LOG_WIDTH[ 3: 0] };  
  86.         if(dot_cnt==2)source_data = { 4'b0,            4'b0, 4'b0, w_LOG_HEIGHT[ 3: 0], 4'b0, w_LOG_HEIGHT[ 7: 4] };  
  87.     end  
  88.     STATE_DATA : source_data = sink_data;  
  89.     default : source_data = sink_data;  
  90.   endcase  
  91. end  
  92.   
  93. reg [11:0] dot_cnt;  
  94. always @(posedge clk) begin  
  95.   if (!reset_n) begin  
  96.      dot_cnt <= 0;  
  97.   end  
  98.   else begin  
  99.     if (dout_ready & source_ready)begin  
  100.         if ((pkt_state == STATE_CTRL) )begin // control packet  
  101.             if ( dot_cnt < (CTRL_PKT_NUM-1) )  
  102.                dot_cnt <= dot_cnt + 11'd1;  
  103.             else  
  104.                dot_cnt <= 0;  
  105.       end  
  106.   end  
  107. end  
  108. endmodule  
</pre><pre name="code" class="cpp">module ST_RESIZE(
	// global clock & reset
		input          	clk,
		input	            reset_n,

	// stream sink
		input	[23:0]		sink_data,
		input	      		sink_valid,
		output         	sink_ready,
		input          	sink_sop,
		input          	sink_eop,
	
	// stream source
		output [23:0]     source_data,
	   output            source_valid,
	   input             source_ready,
	   output            source_sop,
	   output            source_eop

);

localparam CTRL_PKT_NUM     = 3;

assign sink_ready   =  source_ready;  
assign source_sop   =  sink_sop;
assign source_eop   =  sink_eop;
//assign source_valid =  sink_valid;
//assign source_data  =  sink_data;

parameter WIDTH = 640;
parameter HEIGHT = 480;
parameter w_LOG_WIDTH = 320;
parameter w_LOG_HEIGHT = 240;
reg state;
localparam STATE_CTRL = 0;
localparam STATE_DATA = 1;
always@(posedge clk)begin
if(~reset_n)
    state <= STATE_CTRL;
else if( process_en && sink_sop&& sink_data == 24'd15)
    state <= STATE_CTRL;
else if( process_en && sink_sop&& sink_data == 24'd0)
    state <= STATE_DATA;
end

reg [10:0]  h_count;
reg [10:0]  v_count;
wire process_en;
assign process_en = source_ready & sink_valid;  
always@(posedge clk)begin
if(~reset_n)
    h_count <= 11'b0;
else if( process_en && sink_sop && sink_data == 24'd0)
    h_count <= 11'b0;
else if( process_en && h_count< WIDTH-1 && state == STATE_DATA)
    h_count <= h_count + 1'b1;
else if( process_en &&  h_count== WIDTH-1 && state == STATE_DATA)
    h_count <= 11'b0;
end

always@(posedge clk)begin
if(~reset_n)
    v_count <= 11'b0;
else if( process_en && sink_sop&& sink_data == 24'd0)
    v_count <= 11'b0;
else if( process_en && h_count == WIDTH-1 && state == STATE_DATA)
    v_count <= v_count + 1'b1;
end



assign source_valid =(sink_valid & sink_sop & sink_data == 24'd15) | 
					(sink_valid & state == STATE_CTRL )|
					(sink_valid & sink_sop & sink_data == 24'd00) | 
					( sink_valid & state == STATE_DATA & h_count[0]==0 & v_count[0]==0) |
					( sink_valid & sink_eop )
					;
//assign source_data =  sink_data;

always @(*) begin
  case (state )
    STATE_CTRL : 
	if(source_ready & sink_valid)begin
		if(dot_cnt==0)source_data = { 4'b0,  w_LOG_WIDTH[ 7: 4], 4'b0,  w_LOG_WIDTH[11: 8], 4'b0,  w_LOG_WIDTH[15:12] };
		if(dot_cnt==1)source_data = { 4'b0,  w_LOG_HEIGHT[11: 8], 4'b0, w_LOG_HEIGHT[15:12], 4'b0,  w_LOG_WIDTH[ 3: 0] };
		if(dot_cnt==2)source_data = { 4'b0,            4'b0, 4'b0, w_LOG_HEIGHT[ 3: 0], 4'b0, w_LOG_HEIGHT[ 7: 4] };
	end
    STATE_DATA : source_data = sink_data;
    default : source_data = sink_data;
  endcase
end

reg [11:0] dot_cnt;
always @(posedge clk) begin
  if (!reset_n) begin
     dot_cnt <= 0;
  end
  else begin
    if (dout_ready & source_ready)begin
		if ((pkt_state == STATE_CTRL) )begin // control packet
			if ( dot_cnt < (CTRL_PKT_NUM-1) )
			   dot_cnt <= dot_cnt + 11'd1;
			else
			   dot_cnt <= 0;
      end
  end
end
endmodule


另外,假如对于一幅图像(1920*1080),我想把它缩小到任意的大小,比如320*240大小:

对于水平的320像素,因为1920/320=6,因此只需设置一个列循环计数值,范围0-5,在等于5的时候,输出像素valid为1;

对于竖直方向的240,因为1080除以240不是整数,而是9/2。也就是说,需要每隔4.5行,就应该输出一个valid。为了使其整数化,可以等同为每隔9行输出两个valid。因此可以设置一个行循环计数值,范围0-8,在等于3或者等于8的时候,输出valid为1。代码如下:

  1. module ST_RESIZE(  
  2.     // global clock & reset  
  3.         input           clk,  
  4.         input               reset_n,  
  5.   
  6.     // stream sink  
  7.         input   [15:0]      sink_data,  
  8.         input               sink_valid,  
  9.         output          sink_ready,  
  10.         input           sink_sop,  
  11.         input           sink_eop,  
  12.       
  13.     // stream source  
  14.         output [15:0]     source_data,  
  15.        output            source_valid,  
  16.        input             source_ready,  
  17.        output            source_sop,  
  18.        output            source_eop  
  19.   
  20. );  
  21.   
  22. assign sink_ready   =  source_ready;    
  23. assign source_sop   =  sink_sop;  
  24. assign source_eop   =  sink_eop;  
  25.   
  26. parameter WIDTH = 1920;  
  27. parameter HEIGHT = 1080;  
  28.   
  29. reg state;  
  30. localparam STATE_CTRL = 0;  
  31. localparam STATE_DATA = 1;  
  32. always@(posedge clk)begin  
  33. if(~reset_n)  
  34.     state <= STATE_CTRL;  
  35. else if( process_en && sink_sop&& sink_data == 16'd15)  
  36.     state <= STATE_CTRL;  
  37. else if( process_en && sink_sop&& sink_data == 16'd0)  
  38.     state <= STATE_DATA;  
  39. end  
  40.   
  41. reg [10:0]  h_count;  
  42. reg [10:0]  v_count;  
  43. wire process_en;  
  44. assign process_en = source_ready & sink_valid;    
  45.   
  46. reg [3:0] h_step_count;  
  47. reg [3:0] v_step_count;  
  48. always@(posedge clk)begin  
  49. if(~reset_n)begin  
  50.     h_count <= 11'b0;  
  51.     h_step_count <= 4'b0;  
  52.     end  
  53. else if( process_en && sink_sop && sink_data == 16'd0)begin  
  54.     h_count <= 11'b0;  
  55.     h_step_count <= 4'b0;  
  56.     end  
  57. else if( process_en && h_count< WIDTH-1 && state == STATE_DATA)begin  
  58.     h_count <= h_count + 1'b1;  
  59.     if(h_step_count >= 4'd5)  
  60.         h_step_count <= 4'b0;  
  61.     else  
  62.         h_step_count <= h_step_count+1;  
  63.     end  
  64. else if( process_en &&  h_count== WIDTH-1 && state == STATE_DATA)begin  
  65.     h_count <= 11'b0;  
  66.     h_step_count <= 4'b0;  
  67.     end  
  68. end  
  69.   
  70. always@(posedge clk)begin  
  71. if(~reset_n)begin  
  72.     v_count <= 11'b0;  
  73.     v_step_count <= 4'b0;  
  74.     end  
  75. else if( process_en && sink_sop&& sink_data == 16'd0)begin  
  76.     v_count <= 11'b0;  
  77.     v_step_count <= 4'b0;      
  78.     end  
  79. else if( process_en && h_count == WIDTH-1 && state == STATE_DATA)begin  
  80.     v_count <= v_count + 1'b1;  
  81.     if(v_step_count >= 4'd8)  
  82.         v_step_count <= 4'b0;  
  83.     else  
  84.         v_step_count <= v_step_count+1;  
  85.     end  
  86. end  
  87.   
  88.   
  89. assign source_valid =(sink_valid & sink_sop & sink_data == 16'd15) | //  
  90.                     (sink_valid & state == STATE_CTRL )|  
  91.                     (sink_valid & sink_sop & sink_data == 16'd00) |   
  92.                     ( sink_valid & state == STATE_DATA & h_step_count==4'd5 &( v_step_count==4'd3 | v_step_count==4'd8)) |  
  93.                     ( sink_valid & sink_eop )  
  94.                     ;                     
  95.                       
  96.                       
  97. assign source_data =  sink_data;  
  98. endmodule 
  • 9
    点赞
  • 47
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
你可以使用纯Verilog代码实现FPGA上的图像缩放。下面是一个简单的示例,展示了如何使用双线性插值算法进行图像缩放: ```verilog module image_scale ( input wire clk, input wire rst, input wire [7:0] in_width, input wire [7:0] in_height, input wire [7:0] out_width, input wire [7:0] out_height, input wire [15:0] in_image [0:1023][0:767], output wire [15:0] out_image [0:511][0:383] ); // 计算水平和垂直比例因子 reg [15:0] scale_x; reg [15:0] scale_y; always @(in_width, out_width) begin scale_x = (in_width << 16) / (out_width + 1); end always @(in_height, out_height) begin scale_y = (in_height << 16) / (out_height + 1); end // 缩放图像 always @(posedge clk or posedge rst) begin if (rst) begin // 复位状态 // ... end else begin // 缩放计算 // ... end end endmodule ``` 在上面的示例中,`in_width`和`in_height`表示输入图像的宽度和高度,`out_width`和`out_height`表示期望的输出图像的宽度和高度。`in_image`是一个二维数组,用于存储输入图像的像素值。`out_image`也是一个二维数组,用于存储输出图像的像素值。 你需要在`always @(posedge clk or posedge rst)`块中实现图像缩放的逻辑。你可以使用双线性插值算法来计算输出图像的每个像素值。具体的实现方法超出了本文的范围,但你可以参考相关资料来了解如何在Verilog中实现双线性插值算法。 请注意,上述代码仅提供了一个基本的框架,你需要根据实际需求进行适当的修改和完善。同时,你还需要根据你使用的开发板和FPGA器件进行相应的时钟和复位处理。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值