一、算法简述[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等大佬的博客。