【Verilog&vivado】彩色图像转灰度的硬件实现

一、算法简述[2]
转灰度的算法还是比较简单的,最后的结果就是加权和:

Gray = 0.2989*R+0.5870*G+0.1140*B

这就是MATLAB中rgb2gray函数的算法原理;

本示例输入的是8bits的三通道彩色图像数据,输出的也是8bits的数据,为了不涉及到小数,我们将数据整体左移16位即乘以65536,然后在右移16bit进行还原。根据matlab中的算法原理进行设计:

gray <= 19589 * red + 38469 * green + 7471 * blue;
Gray = gray >> 16;

二、代码示例:

//addr module
module addr#(
	parameter ADDRWIDTH = 18
	
)
(
	input 	              		 CLK,
	input 						 RSTn,
	input                        start,
	input                        Done_one,
	output [ ADDRWIDTH - 1 : 0 ] ADDR,
	output                       Done_full
);

reg [ ADDRWIDTH - 1 : 0 ] addr;
reg isDone;

always @ ( posedge CLK  )
begin
	if (!RSTn)
		begin
			addr <= 0;
			isDone <= 0;
			#100 addr <= 1;
		end
//	else 
//		begin
//			addr <= 1;
//		end
end		
always @ ( posedge CLK or negedge RSTn )
begin		
		if (addr == 19'd262144)
		begin
			addr <= 0;
			isDone <= 1;
		end
		else if (Done_one)
		begin
			addr <= addr + 1;
			isDone <= 0;
		end
end		

assign ADDR = addr;
assign Done_full = isDone;
endmodule
//rgb2gray module
module rgb2gray#(
	parameter DATAWIDTH = 8
)
(
	input 					     CLK,
	input 						 RSTn,
	input                        start,
	input  [ DATAWIDTH - 1 : 0 ] DATA_R,
	input  [ DATAWIDTH - 1 : 0 ] DATA_G,
	input  [ DATAWIDTH - 1 : 0 ] DATA_B,
	output [ DATAWIDTH - 1 : 0 ] gray_picture,
	output                       Done_one
);

reg [ DATAWIDTH - 1 : 0 ] data_r;
reg [ DATAWIDTH - 1 : 0 ] data_g;
reg [ DATAWIDTH - 1 : 0 ] data_b;
reg [ 23 : 0 ] gray;
reg get_gray;
reg [2:0] k;
reg isDone;


always @ ( posedge CLK or negedge RSTn )
begin
	if (!RSTn)
	begin
		data_b <= 0;
		data_g <= 0;
		data_r <= 0;
		get_gray <= 0;
	end
	else if (start)
	begin
		data_b <= DATA_B;
		data_g <= DATA_G;
		data_r <= DATA_R;
		get_gray <= 1;
	end
end
always @ ( posedge CLK or negedge RSTn )
begin
	if (!RSTn)
	begin
		gray <= 0;
		isDone <= 0;
		k <= 0;
	end
	else if (get_gray)
		case ( k ) 
        0: 
            begin
                gray <= 19589 * data_r + 38469 * data_g + 7471 * data_b;
                k <= k + 1'b1; 
            end
        1: 
            begin 
                isDone <= 1'b1; 
                k <= k + 1'b1; 
                end
        2: 
            begin 
                isDone <= 1'b0; 
                k <= 3'd0; 
            end
    endcase
	
end

assign gray_picture = ( gray >> 16 );
assign Done_one = isDone;
endmodule
//top module
module top#(
	parameter DATAWIDTH = 8,
	parameter ADDRWIDTH = 18
)
(
	input 						CLK,
	input 						RSTn,
	input 						start,
	output [ DATAWIDTH - 1 :0 ] Gray,
	output					    Done_full,
	output                      Done_one
);

wire [ ADDRWIDTH - 1 :0 ] addri;
wire [ DATAWIDTH - 1 :0 ] r;
wire [ DATAWIDTH - 1 :0 ] g;
wire [ DATAWIDTH - 1 :0 ] b;
wire                      Done_one_w;

addr addr (.CLK(CLK),
           .start(start),
           .Done_one(Done_one_w),
		   .RSTn(RSTn),
		   .ADDR(addri),
		   .Done_full(Done_full));
picture_512x512_r R (.clka(CLK),
				   .addra(addri),
				   .douta(r));
picture_512x512_g G (.clka(CLK),
				   .addra(addri),
				   .douta(g));
picture_512x512_b B (.clka(CLK),
				   .addra(addri),
				   .douta(b));
				   
rgb2gray rgb2gray (.CLK(CLK),
				   .RSTn(RSTn),
				   .start(start),
				   .DATA_R(r),
				   .DATA_G(g),
				   .DATA_B(b),
				   .gray_picture(Gray),
				   .Done_one(Done_one_w));
				   
assign Done_one = Done_one_w;
endmodule
//test
module tb();
	reg CLK;
	reg RSTn;
	reg start;
	wire [7:0] Gray;
	wire Done_full;
	wire Done_one;	
reg [18:0] counter;	
integer fout;
initial 
begin
	CLK = 0;
	forever #10 CLK = ~CLK;
end

initial 
begin
	RSTn = 0;
	start = 0;
	counter = 0;
	fout = $fopen ("rgb2gray_512x512_v.txt");
	#100 RSTn = 1;
	start = 1;
	counter = 1;
end

always @ ( posedge CLK )
  if ( Done_one ) 
  begin
     $fwrite (fout,"%d",Gray,"\n");
  end
  
always @ ( posedge CLK )
  if ( Done_one ) 
    begin
       counter <= counter + 1;
    end
 always @ ( posedge CLK )
  if ( counter == 19'd262145 ) 
    begin
       start <= 0;
       $stop;
    end
top top (.CLK(CLK),
         .RSTn(RSTn),
		 .start(start),
		 .Gray(Gray),
		 .Done_full(Done_full),
		 .Done_one(Done_one));
endmodule

调用IP核:
本示例调用了IP,调IP事儿真多,主要是license,综合out of date等的一些问题,还不如写一个ROM。具体做法:https://blog.csdn.net/weixin_42183170/article/details/88853224
最后的project:
在这里插入图片描述
工程下载:https://download.csdn.net/download/weixin_42183170/11862204
仿真结果:
在这里插入图片描述
在这里插入图片描述
生成一个rgb2gray_512x512_v.txt的文件,load进matlab比对。
三、matlab比较:

clc
clear all
%生成的数据是一行行进行读取的
[file1,path1] = uigetfile({'*.jpg';'*.png'},'选择图片');
img = imread([path1,file1]);
I_gray = rgb2gray(img);%灰度处理
[m, n] = size(I_gray);%获取尺寸
subplot(2, 3, 4), imshow(I_gray), title('img-rgb2gray-matlab')
subplot(2, 3, 2), imshow(img), title('img-RGB')

rgb2gray_v_load = load('.\rgb2gray_512x512_v.txt'); % verilog 产生的rgb2gray数据
rgb2gray_v = reshape(rgb2gray_v_load, n, m);%262144*1的数组转为512*512的数组
rgb2gray_v = uint8(rgb2gray_v');%转为8bit
subplot(2, 3, 6), imshow(rgb2gray_v), title('img-rgb2gray-verilog');

diff = I_gray - rgb2gray_v%每个像素的误差
a = mean(diff);
b=mean(a)%总误差

matlab结果:
在这里插入图片描述
总误差:
在这里插入图片描述
可以看出结果相差无几,总像素误差在0.5左右。
总结:
时序好烦,一直都没法把握住时序,出现各种各样的问题,数据流出的地址都会被时序更改。
加油!
越是憧憬,越要风雨兼程!

reference:
[1] https://www.cnblogs.com/happyamyhope/p/5725741.html
[2] https://www.cnblogs.com/diewcs/archive/2010/10/03/1841744.html等大佬的博客。

  • 8
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值