如图所示,这是整个视频采集系统的原理框图。
上电初始,FPGA 需要通过 IIC 接口对 CMOS Sensor 进行寄存器初始化配置。这些初始化的基本参数,即初始化地址对应的初始化数据都存储在一个预先配置好的 FPGA 片内 ROM中。在初始化配置完成后,CMOS Sensor 就能够持续输出标准 RGB 的视频数据流,FPGA 通过对其同步信号,如时钟、行频和场频进行检测,从而从数据总线上实时的采集图像数据。
在 FPGA 内部,采集到的视频数据先通过一个 FIFO,将原本 25MHz 频率下同步的数据流转换到 50MHz 的频率下。接着将这个数据再送入写 DDR3 缓存的异步 FIFO 中,这个 FIFO 中的数据一旦达到一定数量,就会通过 AXI HP0 总线写入 DDR3 中。与此同时,AXI HP0 总线也会读取 DDR3 中缓存的图像数据,缓存到 FIFO 中,并最终送往 LCD 驱动模块进行显示。LCD驱动模块不断的发出读图像数据的请求,并驱动液晶显示器显示视频图像。
本实例除了前面提到对原始图像做 DDR3 缓存和显示,还会在原始图像缓存到 DDR3 之前,另外做图像的多行缓存和平滑处理运算,获得新的平滑后的图像流,这个图像流通过AXI HP1 总线写入到 DDR3 中。AXI HP1 总线也会根据 LCD 显示模块的请求,读取处理后的图像进行显示。最终在 VGA 液晶显示器上,可以看到左侧图像是原始的图像,右侧图像是经过锐化处理后的图像。
1、图像拉普拉斯锐化
1.1 基本概念
在图像增强中,平滑是为了消除图像中噪声的干扰,或者降低对比度。与之相反,有时为了强调图像的边缘和细节,需要对图像进行锐化,提高对比度。
拉普拉斯锐化图像是根据图像某个像素的周围像素到此像素的突变,也就是说它的依据是图像像素的变化程度。我们知道,一个函数的一阶微分描述了函数图像是朝哪里变化的,即增长或者降低;而二阶微分描述的则是图像变化的速度,急剧增长下降还是平缓的增长下降。那么据此我们可以猜测出依据二阶微分能够找到图像的色素的过渡程度,例如白色到黑色的过渡就是比较急剧的。
或者用官方点的话说:当邻域中心像素灰度低于它所在的领域内其它像素的平均灰度时,此中心像素的灰度应被进一步降低,当邻域中心像素灰度高于它所在的邻域内其它像素的平均灰度时,此中心像素的灰度应被进一步提高,以此实现图像的锐化处理。
1.2拉普拉斯(laplace)算子
最常用的无方向性的二阶差分算子,其模板有 3*3、5*5 和 7*7 等多种形式。
例如,以 33 算子为例,要实现图像的拉普拉斯锐化,1~8 像素是(x,y)点周围邻近的 8 个像素点。可以使用右侧的 2 种模板对(x,y)以及周边 4 或 8 个像素点进行运算,替代原来的(x,y)点。
当然了,根据中心点的权重程度,也可以使用如下 2 中模板来实现图像锐化。
1.3 Matlab 实现
本实例是基于第一种拉普拉斯算子对图像进行锐化处理。
基于第一种拉普拉斯锐化处理,我们的 Matlab 代码如下:
clear
clc
I1=imread('.\lena.jpg');
I=im2double(I1);
[m,n,c]=size(I);
A=zeros(m,n,c);
%for R
for i=2:m-1
for j=2:n-1
A(i,j,1)=I(i+1,j,1)+I(i-1,j,1)+I(i,j+1,1)+I(i,j-1,1)-4*I(i,j,1);
end
end
%for G
for i=2:m-1
for j=2:n-1
A(i,j,2)=I(i+1,j,2)+I(i-1,j,2)+I(i,j+1,2)+I(i,j-1,2)-4*I(i,j,2);
end
end
%for B
for i=2:m-1
for j=2:n-1
A(i,j,3)=I(i+1,j,3)+I(i-1,j,3)+I(i,j+1,3)+I(i,j-1,3)-4*I(i,j,3);
end
end
B=I-A;
%output
imwrite(B,'lena.tif','tif');
imshow('.\lena.jpg');title('origin image');figure
imshow('lena.tif');title('image after laplace transform')
滤波效果如下。
2、基于FPGA 的图像锐化处理
工程laplace_transform.v 模块实现了拉普拉斯锐化处理。该模块功能框图如下,使用 2 个 FIFO,分别缓存前后行,即进入图像处理的 3 组数据流分别是第 n-1 行、第 n 行和第 n+1 行的图像,控制输入数据流和 2 个FIFO 缓存的图像在同一个位置、寄存器对前后 2 个像素的图像值进行缓存,这样便可实现中心像素点以及前后列、上下行之间数据的同步处理了。
其代码和图像平滑处理基本相同,仅模板系数不同,这里不再详解,如有不懂请看OV5640 摄像头的图像平滑处理
laplace_transform.v
/*
对图像进行laplace transform锐化处理
第1行、最后1行、第1列、最后1列不做处理,使用原始图像像素值输出;
对其余图像像素点,取其像数值*5-左像数值-右像素值-上像素值-下像素值
*/
module laplace_transform(
input clk, //50MHz时钟
input rst_n, //复位信号,低电平有效
//Image Data flow from Image Sensor
input i_image_ddr3_wren,
input i_image_ddr3_line_end,
input i_image_ddr3_clr,
input[15:0] i_image_ddr3_wrdb,
//Image Data flow after laplace transform
output reg o_image_ddr3_wren,
output[15:0] o_image_ddr3_wrdb
);
parameter IMAGE_WIDTH = 10'd640;
parameter IMAGE_HIGHT = 10'd480;
//数据行计数器
reg[9:0] r_line_cnt;
always @(posedge clk or negedge rst_n)
if(!rst_n) r_line_cnt <= 10'd0;
else if(i_image_ddr3_clr) r_line_cnt <= 10'd0;
else if(i_image_ddr3_line_end) r_line_cnt <= r_line_cnt+1'b1;
else ;
//FIFO for cache 1 line image data
reg r_fifo1_rd_en;
wire[15:0] w_fifo1_dout;
wire[9:0] w_fifo1_data_count;
fifo_generator_3 uut1_fifo_generator_3 (
.clk(clk), // input wire clk
.srst(!rst_n || i_image_ddr3_clr), // input wire srst
.din(i_image_ddr3_wrdb), // input wire [15 : 0] din
.wr_en(i_image_ddr3_wren), // input wire wr_en
.rd_en(r_fifo1_rd_en), // input wire rd_en
.dout(w_fifo1_dout), // output wire [15 : 0] dout
.full(), // output wire full
.empty(), // output wire empty
.data_count(w_fifo1_data_count) // output wire [9 : 0] data_count
);
reg r_fifo2_wr_en;
reg r_fifo2_rd_en;
wire[15:0] w_fifo2_dout;
wire[9:0] w_fifo2_data_count;
fifo_generator_3 uut2_fifo_generator_3 (
.clk(clk), // input wire clk
.srst(!rst_n || i_image_ddr3_clr), // input wire srst
.din(w_fifo1_dout), // input wire [15 : 0] din
.wr_en(r_fifo2_wr_en), // input wire wr_en
.rd_en(r_fifo2_rd_en), // input wire rd_en
.dout(w_fifo2_dout), // output wire [15 : 0] dout
.full(), // output wire full
.empty(), // output wire empty
.data_count(w_fifo2_data_count) // output wire [9 : 0] data_count
);
//连续读出640个数据计数控制状态机
parameter RFIFO_RESET = 3'd0;
parameter RFIFO_IDLE = 3'd1;
parameter RFIFO_RDDB1 = 3'd2;
parameter RFIFO_RDDB2 = 3'd3;
parameter RFIFO_WAIT = 3'd4;
parameter RFIFO_RDDB3 = 3'd5;
reg[2:0] rfifo_state;
reg[9:0] dcnt; //读FIFO数据个数计数器
reg[9:0] laplace_num;
reg[3:0] dly_cnt;
always @(posedge clk or negedge rst_n)
if(!rst_n) rfifo_state <= RFIFO_RESET;
else if(i_image_ddr3_clr) rfifo_state <= RFIFO_RESET;
else begin
case(rfifo_state)
RFIFO_RESET: if(w_fifo1_data_count >= IMAGE_WIDTH) rfifo_state <= RFIFO_RDDB1;
else rfifo_state <= RFIFO_RESET;
RFIFO_RDDB1: if(dcnt >= (IMAGE_WIDTH-1)) rfifo_state <= RFIFO_IDLE;
else rfifo_state <= RFIFO_RDDB1;
RFIFO_IDLE: if(r_line_cnt >= IMAGE_HIGHT) rfifo_state <= RFIFO_WAIT;
else if(w_fifo2_data_count >= IMAGE_WIDTH) rfifo_state <= RFIFO_RDDB2;
else rfifo_state <= RFIFO_IDLE;
RFIFO_RDDB2: if(r_line_cnt >= IMAGE_HIGHT) rfifo_state <= RFIFO_WAIT;
else if(dcnt >= (IMAGE_WIDTH-1)) rfifo_state <= RFIFO_IDLE;
else rfifo_state <= RFIFO_RDDB2;
RFIFO_WAIT: if(dly_cnt == 4'hf) rfifo_state <= RFIFO_RDDB3;
else rfifo_state <= RFIFO_WAIT;
RFIFO_RDDB3: if(dcnt >= (IMAGE_WIDTH-1)) rfifo_state <= RFIFO_RESET;
else rfifo_state <= RFIFO_RDDB3;
default: rfifo_state <= RFIFO_IDLE;
endcase
end
always @(posedge clk or negedge rst_n)
if(!rst_n) dly_cnt <= 4'd0;
else if(rfifo_state == RFIFO_WAIT) dly_cnt <= dly_cnt+1'b1;
else dly_cnt <= 4'd0;
//读FIFO数据个数计数器
always @(posedge clk or negedge rst_n)
if(!rst_n) dcnt <= 10'd0;
else if((rfifo_state == RFIFO_IDLE) || (rfifo_state == RFIFO_RESET)) dcnt <= 10'd0;
else if(((rfifo_state == RFIFO_RDDB1) || (rfifo_state == RFIFO_RDDB2)) && i_image_ddr3_wren) dcnt <= dcnt+1'b1;
else if(rfifo_state == RFIFO_RDDB3) dcnt <= dcnt+1'b1;
else dcnt <= 10'd0;
//laplace transform数据计数器
always @(posedge clk or negedge rst_n)
if(!rst_n) laplace_num <= 10'd0;
else if(dcnt == 10'd4) laplace_num <= 10'd1;
else if(laplace_num != 10'd0) begin
if(laplace_num < IMAGE_WIDTH) laplace_num <= laplace_num+1'b1;
else laplace_num <= 10'd0;
end
else laplace_num <= 10'd0;
//读FIFO1使能信号产生逻辑
always @(posedge clk or negedge rst_n)
if(!rst_n) r_fifo1_rd_en <= 1'b0;
else if(((rfifo_state == RFIFO_RDDB1) || (rfifo_state == RFIFO_RDDB2)) && i_image_ddr3_wren) r_fifo1_rd_en <= 1'b1;
else if((rfifo_state == RFIFO_RDDB3) && (dcnt < IMAGE_WIDTH)) r_fifo1_rd_en <= 1'b1;
else r_fifo1_rd_en <= 1'b0;
//写FIFO2是能信号产生逻辑
always @(posedge clk or negedge rst_n)
if(!rst_n) r_fifo2_wr_en <= 1'b0;
else r_fifo2_wr_en <= r_fifo1_rd_en;
//读FIFO2使能信号产生逻辑
always @(posedge clk or negedge rst_n)
if(!rst_n) r_fifo2_rd_en <= 1'b0;
else if(((rfifo_state == RFIFO_RDDB2) || (rfifo_state == RFIFO_RDDB3)) && i_image_ddr3_wren) r_fifo2_rd_en <= 1'b1;
else r_fifo2_rd_en <= 1'b0;
//图像缓存3拍
reg[15:0] data_temp_line_1[2:0];
reg[15:0] data_temp_line_2[2:0];
reg[15:0] data_temp_line_3[3:0];
always @(posedge clk) begin
data_temp_line_1[0] <= w_fifo2_dout;
data_temp_line_1[1] <= data_temp_line_1[0];
data_temp_line_1[2] <= data_temp_line_1[1];
end
always @(posedge clk) begin
data_temp_line_2[0] <= w_fifo1_dout;
data_temp_line_2[1] <= data_temp_line_2[0];
data_temp_line_2[2] <= data_temp_line_2[1];
end
always @(posedge clk) begin
data_temp_line_3[0] <= i_image_ddr3_wrdb;
data_temp_line_3[1] <= data_temp_line_3[0];
data_temp_line_3[2] <= data_temp_line_3[1];
data_temp_line_3[3] <= data_temp_line_3[2];
end
//图像输出laplace transform运算
reg[9:0] sum_a_r,sum_b_r;
reg[9:0] sum_a_g,sum_b_g;
reg[9:0] sum_a_b,sum_b_b;
reg[15:0] laplace_result;
always @(posedge clk) begin
sum_a_r <= {3'b000,data_temp_line_2[1][15:11],2'b00} + {5'b0000,data_temp_line_2[1][15:11]};
sum_a_g <= {2'b00,data_temp_line_2[1][10:5],2'b00} + {4'b0000,data_temp_line_2[1][10:5]};
sum_a_b <= {3'b000,data_temp_line_2[1][4:0],2'b00} + {5'b0000,data_temp_line_2[1][4:0]};
end
always @(posedge clk) begin
sum_b_r <= {5'd0,data_temp_line_2[0][15:11]} + {5'd0,data_temp_line_2[2][15:11]} + {5'd0,data_temp_line_1[1][15:11]} + {5'd0,data_temp_line_3[3][15:11]};
sum_b_g <= {4'd0,data_temp_line_2[0][10:5]} + {4'd0,data_temp_line_2[2][10:5]} + {4'd0,data_temp_line_1[1][10:5]} + {4'd0,data_temp_line_3[3][10:5]};
sum_b_b <= {5'd0,data_temp_line_2[0][4:0]} + {5'd0,data_temp_line_2[2][4:0]} + {5'd0,data_temp_line_1[1][4:0]} + {5'd0,data_temp_line_3[3][4:0]};
end
wire[9:0] temp_r = sum_a_r-sum_b_r;
wire[9:0] temp_g = sum_a_g-sum_b_g;
wire[9:0] temp_b = sum_a_b-sum_b_b;
always @(posedge clk) begin
if((laplace_num == 10'd1) || (laplace_num == IMAGE_WIDTH)) laplace_result <= data_temp_line_2[2]; //第1列和最后1列使用原值
else begin
if(sum_a_r < sum_b_r) laplace_result[15:11] <= 5'd0;
else if(temp_r[9:5] != 5'd0) laplace_result[15:11] <= 5'b1_1111;
else laplace_result[15:11] = temp_r[4:0];
if(sum_a_g < sum_b_g) laplace_result[10:5] <= 6'd0;
else if(temp_g[9:6] != 4'd0) laplace_result[10:5] <= 6'b11_1111;
else laplace_result[10:5] = temp_g[5:0];
if(sum_a_b < sum_b_b) laplace_result[4:0] <= 5'd0;
else if(temp_b[9:5] != 5'd0) laplace_result[4:0] <= 5'b1_1111;
else laplace_result[4:0] = temp_b[4:0];
end
end
//图像输出有效信号产生
reg r_image_ddr3_wren;
reg[3:0] r_laplace_line_wren;
reg r_last_line_wren;
always @(posedge clk or negedge rst_n)
if(!rst_n) r_last_line_wren <= 1'b0;
else if((rfifo_state == RFIFO_RDDB3) && (dcnt < IMAGE_WIDTH)) r_last_line_wren <= 1'b1;
else r_last_line_wren <= 1'b0;
always @(posedge clk or negedge rst_n)
if(!rst_n) r_laplace_line_wren <= 4'd0;
else begin
r_laplace_line_wren[3:1] <= r_laplace_line_wren[2:0];
if((rfifo_state == RFIFO_RDDB2) && (r_line_cnt > 10'd1) && i_image_ddr3_wren) r_laplace_line_wren[0] <= 1'b1;
else r_laplace_line_wren[0] <= 1'b0;
end
always @(posedge clk or negedge rst_n)
if(!rst_n) r_image_ddr3_wren <= 1'b0;
else if(r_laplace_line_wren[3]) r_image_ddr3_wren <= 1'b1;
else if(r_last_line_wren) r_image_ddr3_wren <= 1'b1;
else r_image_ddr3_wren <= 1'b0;
always @(posedge clk or negedge rst_n)
if(!rst_n) o_image_ddr3_wren <= 1'b0;
else if((r_line_cnt == 10'd0) && i_image_ddr3_wren) o_image_ddr3_wren <= 1'b1;
else if(r_image_ddr3_wren) o_image_ddr3_wren <= 1'b1;
else o_image_ddr3_wren <= 1'b0;
//图像数据输出
reg[15:0] r_image_ddr3_wrdb;
always @(posedge clk or negedge rst_n)
if(!rst_n) r_image_ddr3_wrdb <= 16'd0;
else if(r_line_cnt == 10'd0) r_image_ddr3_wrdb <= i_image_ddr3_wrdb;
else if(r_image_ddr3_wren && (r_line_cnt >= IMAGE_HIGHT)) r_image_ddr3_wrdb <= w_fifo1_dout;
else ;
reg output_link;
always @(posedge clk or negedge rst_n)
if(!rst_n) output_link <= 1'b0;
else if(r_line_cnt == 10'd0) output_link <= 1'b1;
else if(r_image_ddr3_wren && (r_line_cnt >= IMAGE_HIGHT)) output_link <= 1'b1;
else output_link <= 1'b0;
assign o_image_ddr3_wrdb = output_link ? r_image_ddr3_wrdb:laplace_result;
endmodule
3、图像拉普拉斯边缘提取
3.1拉普拉斯(laplace)算子
最常用的无方向性的二阶差分算子,其模板有 3*3、5*5 和 7*7 等多种形式。
要实现图像的拉普拉斯边缘提取,以 33 算子为例,1~8 像素是(x,y)点周围邻近的 8个像素点。可以使用右侧的 2 种模板对(x,y)以及周边 8 个像素点进行运算,替代原来的(x,y)点。
3.2 Matlab 实现
本实例是基于第二种拉普拉斯算子对图像进行锐化处理。
基于第二种拉普拉斯边缘提取算子,我们的 Matlab 代码如下:
clear
clc
I1=imread('.\lena.jpg');
I=im2double(I1);
[m,n,c]=size(I);
A=zeros(m,n,c);
%for R
for i=2:m-1
for j=2:n-1
A(i,j,1)=I(i-1,j-1,1)+I(i+1,j-1,1)+I(i-1,j+1,1)+I(i+1,j+1,1)+I(i+1,j,1)+I(i-1,j,1)+I(i,j+1,1)+I(i,j-1,1)-8*I(i,j,1);
end
end
%for G
for i=2:m-1
for j=2:n-1
A(i,j,2)=I(i-1,j-1,2)+I(i+1,j-1,2)+I(i-1,j+1,2)+I(i+1,j+1,2)+I(i+1,j,2)+I(i-1,j,2)+I(i,j+1,2)+I(i,j-1,2)-8*I(i,j,2);
end
end
%for B
for i=2:m-1
for j=2:n-1
A(i,j,3)=I(i-1,j-1,3)+I(i+1,j-1,3)+I(i-1,j+1,3)+I(i+1,j+1,3)+I(i+1,j,3)+I(i-1,j,3)+I(i,j+1,3)+I(i,j-1,3)-8*I(i,j,3);
end
end
B=A;
%output
imwrite(B,'lena.tif','tif');
imshow('.\lena.jpg');title('origin image');figure
imshow('lena.tif');title('image after laplace transform')
滤波效果如下。
4、基于 FPGA 的的图像边缘提取处理
工程laplace_transform.v 模块实现了拉普拉斯锐化处理。该模块功能框图如下,使用 2 个 FIFO,分别缓存前后行,即进入图像处理的 3 组数据流分别是第 n-1 行、第 n 行和第 n+1 行的图像,控制输入数据流和 2 个FIFO 缓存的图像在同一个位置、寄存器对前后 2 个像素的图像值进行缓存,这样便可实现中心像素点以及前后列、上下行之间数据的同步处理了。
其代码和图像平滑处理基本相同,仅模板系数不同,这里不再详解,如有不懂请看OV5640 摄像头的图像平滑处理
laplace_transform.v
/*
对图像进行laplace transform锐化处理
第1行、最后1行、第1列、最后1列不做处理,使用原始图像像素值输出;
对其余图像像素点,取其像素点值*8-周边8个像素点的值之和,溢出处理后输出
*/
module laplace_transform(
input clk, //50MHz时钟
input rst_n, //复位信号,低电平有效
//Image Data flow from Image Sensor
input i_image_ddr3_wren,
input i_image_ddr3_line_end,
input i_image_ddr3_clr,
input[15:0] i_image_ddr3_wrdb,
//Image Data flow after laplace transform
output reg o_image_ddr3_wren,
output[15:0] o_image_ddr3_wrdb
);
parameter IMAGE_WIDTH = 10'd640;
parameter IMAGE_HIGHT = 10'd480;
//数据行计数器
reg[9:0] r_line_cnt;
always @(posedge clk or negedge rst_n)
if(!rst_n) r_line_cnt <= 10'd0;
else if(i_image_ddr3_clr) r_line_cnt <= 10'd0;
else if(i_image_ddr3_line_end) r_line_cnt <= r_line_cnt+1'b1;
else ;
//FIFO for cache 1 line image data
reg r_fifo1_rd_en;
wire[15:0] w_fifo1_dout;
wire[9:0] w_fifo1_data_count;
fifo_generator_3 uut1_fifo_generator_3 (
.clk(clk), // input wire clk
.srst(!rst_n || i_image_ddr3_clr), // input wire srst
.din(i_image_ddr3_wrdb), // input wire [15 : 0] din
.wr_en(i_image_ddr3_wren), // input wire wr_en
.rd_en(r_fifo1_rd_en), // input wire rd_en
.dout(w_fifo1_dout), // output wire [15 : 0] dout
.full(), // output wire full
.empty(), // output wire empty
.data_count(w_fifo1_data_count) // output wire [9 : 0] data_count
);
reg r_fifo2_wr_en;
reg r_fifo2_rd_en;
wire[15:0] w_fifo2_dout;
wire[9:0] w_fifo2_data_count;
fifo_generator_3 uut2_fifo_generator_3 (
.clk(clk), // input wire clk
.srst(!rst_n || i_image_ddr3_clr), // input wire srst
.din(w_fifo1_dout), // input wire [15 : 0] din
.wr_en(r_fifo2_wr_en), // input wire wr_en
.rd_en(r_fifo2_rd_en), // input wire rd_en
.dout(w_fifo2_dout), // output wire [15 : 0] dout
.full(), // output wire full
.empty(), // output wire empty
.data_count(w_fifo2_data_count) // output wire [9 : 0] data_count
);
//连续读出640个数据计数控制状态机
parameter RFIFO_RESET = 3'd0;
parameter RFIFO_IDLE = 3'd1;
parameter RFIFO_RDDB1 = 3'd2;
parameter RFIFO_RDDB2 = 3'd3;
parameter RFIFO_WAIT = 3'd4;
parameter RFIFO_RDDB3 = 3'd5;
reg[2:0] rfifo_state;
reg[9:0] dcnt; //读FIFO数据个数计数器
reg[9:0] laplace_num;
reg[3:0] dly_cnt;
always @(posedge clk or negedge rst_n)
if(!rst_n) rfifo_state <= RFIFO_RESET;
else if(i_image_ddr3_clr) rfifo_state <= RFIFO_RESET;
else begin
case(rfifo_state)
RFIFO_RESET: if(w_fifo1_data_count >= IMAGE_WIDTH) rfifo_state <= RFIFO_RDDB1;
else rfifo_state <= RFIFO_RESET;
RFIFO_RDDB1: if(dcnt >= (IMAGE_WIDTH-1)) rfifo_state <= RFIFO_IDLE;
else rfifo_state <= RFIFO_RDDB1;
RFIFO_IDLE: if(r_line_cnt >= IMAGE_HIGHT) rfifo_state <= RFIFO_WAIT;
else if(w_fifo2_data_count >= IMAGE_WIDTH) rfifo_state <= RFIFO_RDDB2;
else rfifo_state <= RFIFO_IDLE;
RFIFO_RDDB2: if(r_line_cnt >= IMAGE_HIGHT) rfifo_state <= RFIFO_WAIT;
else if(dcnt >= (IMAGE_WIDTH-1)) rfifo_state <= RFIFO_IDLE;
else rfifo_state <= RFIFO_RDDB2;
RFIFO_WAIT: if(dly_cnt == 4'hf) rfifo_state <= RFIFO_RDDB3;
else rfifo_state <= RFIFO_WAIT;
RFIFO_RDDB3: if(dcnt >= (IMAGE_WIDTH-1)) rfifo_state <= RFIFO_RESET;
else rfifo_state <= RFIFO_RDDB3;
default: rfifo_state <= RFIFO_IDLE;
endcase
end
always @(posedge clk or negedge rst_n)
if(!rst_n) dly_cnt <= 4'd0;
else if(rfifo_state == RFIFO_WAIT) dly_cnt <= dly_cnt+1'b1;
else dly_cnt <= 4'd0;
//读FIFO数据个数计数器
always @(posedge clk or negedge rst_n)
if(!rst_n) dcnt <= 10'd0;
else if((rfifo_state == RFIFO_IDLE) || (rfifo_state == RFIFO_RESET)) dcnt <= 10'd0;
else if(((rfifo_state == RFIFO_RDDB1) || (rfifo_state == RFIFO_RDDB2)) && i_image_ddr3_wren) dcnt <= dcnt+1'b1;
else if(rfifo_state == RFIFO_RDDB3) dcnt <= dcnt+1'b1;
else dcnt <= 10'd0;
//laplace transform数据计数器
always @(posedge clk or negedge rst_n)
if(!rst_n) laplace_num <= 10'd0;
else if(dcnt == 10'd4) laplace_num <= 10'd1;
else if(laplace_num != 10'd0) begin
if(laplace_num < IMAGE_WIDTH) laplace_num <= laplace_num+1'b1;
else laplace_num <= 10'd0;
end
else laplace_num <= 10'd0;
//读FIFO1使能信号产生逻辑
always @(posedge clk or negedge rst_n)
if(!rst_n) r_fifo1_rd_en <= 1'b0;
else if(((rfifo_state == RFIFO_RDDB1) || (rfifo_state == RFIFO_RDDB2)) && i_image_ddr3_wren) r_fifo1_rd_en <= 1'b1;
else if((rfifo_state == RFIFO_RDDB3) && (dcnt < IMAGE_WIDTH)) r_fifo1_rd_en <= 1'b1;
else r_fifo1_rd_en <= 1'b0;
//写FIFO2是能信号产生逻辑
always @(posedge clk or negedge rst_n)
if(!rst_n) r_fifo2_wr_en <= 1'b0;
else r_fifo2_wr_en <= r_fifo1_rd_en;
//读FIFO2使能信号产生逻辑
always @(posedge clk or negedge rst_n)
if(!rst_n) r_fifo2_rd_en <= 1'b0;
else if(((rfifo_state == RFIFO_RDDB2) || (rfifo_state == RFIFO_RDDB3)) && i_image_ddr3_wren) r_fifo2_rd_en <= 1'b1;
else r_fifo2_rd_en <= 1'b0;
//图像缓存3拍
reg[15:0] data_temp_line_1[2:0];
reg[15:0] data_temp_line_2[2:0];
reg[15:0] data_temp_line_3[4:0];
always @(posedge clk) begin
data_temp_line_1[0] <= w_fifo2_dout;
data_temp_line_1[1] <= data_temp_line_1[0];
data_temp_line_1[2] <= data_temp_line_1[1];
end
always @(posedge clk) begin
data_temp_line_2[0] <= w_fifo1_dout;
data_temp_line_2[1] <= data_temp_line_2[0];
data_temp_line_2[2] <= data_temp_line_2[1];
end
always @(posedge clk) begin
data_temp_line_3[0] <= i_image_ddr3_wrdb;
data_temp_line_3[1] <= data_temp_line_3[0];
data_temp_line_3[2] <= data_temp_line_3[1];
data_temp_line_3[3] <= data_temp_line_3[2];
data_temp_line_3[4] <= data_temp_line_3[3];
end
//图像输出laplace transform运算
reg[9:0] sum_a_r,sum_b_r1,sum_b_r2;
reg[9:0] sum_a_g,sum_b_g1,sum_b_g2;
reg[9:0] sum_a_b,sum_b_b1,sum_b_b2;
reg[15:0] laplace_result;
always @(posedge clk) begin
sum_a_r <= {2'b00,data_temp_line_2[1][15:11],3'b000};
sum_a_g <= {1'b0,data_temp_line_2[1][10:5],3'b000};
sum_a_b <= {2'b00,data_temp_line_2[1][4:0],3'b000};
end
always @(posedge clk) begin
sum_b_r1 <= {5'd0,data_temp_line_2[0][15:11]} + {5'd0,data_temp_line_2[2][15:11]} + {5'd0,data_temp_line_1[1][15:11]} + {5'd0,data_temp_line_3[3][15:11]};
sum_b_g1 <= {4'd0,data_temp_line_2[0][10:5]} + {4'd0,data_temp_line_2[2][10:5]} + {4'd0,data_temp_line_1[1][10:5]} + {4'd0,data_temp_line_3[3][10:5]};
sum_b_b1 <= {5'd0,data_temp_line_2[0][4:0]} + {5'd0,data_temp_line_2[2][4:0]} + {5'd0,data_temp_line_1[1][4:0]} + {5'd0,data_temp_line_3[3][4:0]};
sum_b_r2 <= {5'd0,data_temp_line_1[0][15:11]} + {5'd0,data_temp_line_1[2][15:11]} + {5'd0,data_temp_line_3[2][15:11]} + {5'd0,data_temp_line_3[4][15:11]};
sum_b_g2 <= {4'd0,data_temp_line_1[0][10:5]} + {4'd0,data_temp_line_1[2][10:5]} + {4'd0,data_temp_line_3[2][10:5]} + {4'd0,data_temp_line_3[4][10:5]};
sum_b_b2 <= {5'd0,data_temp_line_1[0][4:0]} + {5'd0,data_temp_line_1[2][4:0]} + {5'd0,data_temp_line_3[2][4:0]} + {5'd0,data_temp_line_3[4][4:0]};
end
wire[9:0] temp_r = sum_a_r-(sum_b_r1+sum_b_r2);
wire[9:0] temp_g = sum_a_g-(sum_b_g1+sum_b_g2);
wire[9:0] temp_b = sum_a_b-(sum_b_b1+sum_b_b2);
always @(posedge clk) begin
if((laplace_num == 10'd1) || (laplace_num == IMAGE_WIDTH)) laplace_result <= data_temp_line_2[2]; //第1列和最后1列使用原值
else begin
if(sum_a_r < (sum_b_r1+sum_b_r2)) laplace_result[15:11] <= 5'd0;
else if(temp_r[9:5] != 5'd0) laplace_result[15:11] <= 5'b1_1111;
else laplace_result[15:11] = temp_r[4:0];
if(sum_a_g < (sum_b_g1+sum_b_g2)) laplace_result[10:5] <= 6'd0;
else if(temp_g[9:6] != 4'd0) laplace_result[10:5] <= 6'b11_1111;
else laplace_result[10:5] = temp_g[5:0];
if(sum_a_b < (sum_b_b1+sum_b_b2)) laplace_result[4:0] <= 5'd0;
else if(temp_b[9:5] != 5'd0) laplace_result[4:0] <= 5'b1_1111;
else laplace_result[4:0] = temp_b[4:0];
end
end
//图像输出有效信号产生
reg r_image_ddr3_wren;
reg[3:0] r_laplace_line_wren;
reg r_last_line_wren;
always @(posedge clk or negedge rst_n)
if(!rst_n) r_last_line_wren <= 1'b0;
else if((rfifo_state == RFIFO_RDDB3) && (dcnt < IMAGE_WIDTH)) r_last_line_wren <= 1'b1;
else r_last_line_wren <= 1'b0;
always @(posedge clk or negedge rst_n)
if(!rst_n) r_laplace_line_wren <= 4'd0;
else begin
r_laplace_line_wren[3:1] <= r_laplace_line_wren[2:0];
if((rfifo_state == RFIFO_RDDB2) && (r_line_cnt > 10'd1) && i_image_ddr3_wren) r_laplace_line_wren[0] <= 1'b1;
else r_laplace_line_wren[0] <= 1'b0;
end
always @(posedge clk or negedge rst_n)
if(!rst_n) r_image_ddr3_wren <= 1'b0;
else if(r_laplace_line_wren[3]) r_image_ddr3_wren <= 1'b1;
else if(r_last_line_wren) r_image_ddr3_wren <= 1'b1;
else r_image_ddr3_wren <= 1'b0;
always @(posedge clk or negedge rst_n)
if(!rst_n) o_image_ddr3_wren <= 1'b0;
else if((r_line_cnt == 10'd0) && i_image_ddr3_wren) o_image_ddr3_wren <= 1'b1;
else if(r_image_ddr3_wren) o_image_ddr3_wren <= 1'b1;
else o_image_ddr3_wren <= 1'b0;
//图像数据输出
reg[15:0] r_image_ddr3_wrdb;
always @(posedge clk or negedge rst_n)
if(!rst_n) r_image_ddr3_wrdb <= 16'd0;
else if(r_line_cnt == 10'd0) r_image_ddr3_wrdb <= i_image_ddr3_wrdb;
else if(r_image_ddr3_wren && (r_line_cnt >= IMAGE_HIGHT)) r_image_ddr3_wrdb <= w_fifo1_dout;
else ;
reg output_link;
always @(posedge clk or negedge rst_n)
if(!rst_n) output_link <= 1'b0;
else if(r_line_cnt == 10'd0) output_link <= 1'b1;
else if(r_image_ddr3_wren && (r_line_cnt >= IMAGE_HIGHT)) output_link <= 1'b1;
else output_link <= 1'b0;
assign o_image_ddr3_wrdb = output_link ? r_image_ddr3_wrdb:laplace_result;
endmodule