OV5640 摄像头的图像拉普拉斯锐化处理和边缘提取

这篇具有很好参考价值的文章主要介绍了OV5640 摄像头的图像拉普拉斯锐化处理和边缘提取。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

如图所示,这是整个视频采集系统的原理框图。

OV5640 摄像头的图像拉普拉斯锐化处理和边缘提取,fpga开发

        上电初始,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 等多种形式。
        例如,以 3
3 算子为例,要实现图像的拉普拉斯锐化,1~8 像素是(x,y)点周围邻近的 8 个像素点。可以使用右侧的 2 种模板对(x,y)以及周边 4 或 8 个像素点进行运算,替代原来的(x,y)点。

OV5640 摄像头的图像拉普拉斯锐化处理和边缘提取,fpga开发

当然了,根据中心点的权重程度,也可以使用如下 2 中模板来实现图像锐化。

OV5640 摄像头的图像拉普拉斯锐化处理和边缘提取,fpga开发

1.3 Matlab 实现
        本实例是基于第一种拉普拉斯算子对图像进行锐化处理。
        基于第一种拉普拉斯锐化处理,我们的 Matlab 代码如下:

OV5640 摄像头的图像拉普拉斯锐化处理和边缘提取,fpga开发

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')

滤波效果如下。

OV5640 摄像头的图像拉普拉斯锐化处理和边缘提取,fpga开发

2、基于FPGA 的图像锐化处理
        工程laplace_transform.v 模块实现了拉普拉斯锐化处理。该模块功能框图如下,使用 2 个 FIFO,分别缓存前后行,即进入图像处理的 3 组数据流分别是第 n-1 行、第 n 行和第 n+1 行的图像,控制输入数据流和 2 个FIFO 缓存的图像在同一个位置、寄存器对前后 2 个像素的图像值进行缓存,这样便可实现中心像素点以及前后列、上下行之间数据的同步处理了。

OV5640 摄像头的图像拉普拉斯锐化处理和边缘提取,fpga开发

        其代码和图像平滑处理基本相同,仅模板系数不同,这里不再详解,如有不懂请看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 等多种形式。
        要实现图像的拉普拉斯边缘提取,以 3
3 算子为例,1~8 像素是(x,y)点周围邻近的 8个像素点。可以使用右侧的 2 种模板对(x,y)以及周边 8 个像素点进行运算,替代原来的(x,y)点。

OV5640 摄像头的图像拉普拉斯锐化处理和边缘提取,fpga开发

3.2 Matlab 实现
        本实例是基于第二种拉普拉斯算子对图像进行锐化处理。
        基于第二种拉普拉斯边缘提取算子,我们的 Matlab 代码如下:

OV5640 摄像头的图像拉普拉斯锐化处理和边缘提取,fpga开发

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')

滤波效果如下。

OV5640 摄像头的图像拉普拉斯锐化处理和边缘提取,fpga开发

4、基于 FPGA 的的图像边缘提取处理

OV5640 摄像头的图像拉普拉斯锐化处理和边缘提取,fpga开发

        工程laplace_transform.v 模块实现了拉普拉斯锐化处理。该模块功能框图如下,使用 2 个 FIFO,分别缓存前后行,即进入图像处理的 3 组数据流分别是第 n-1 行、第 n 行和第 n+1 行的图像,控制输入数据流和 2 个FIFO 缓存的图像在同一个位置、寄存器对前后 2 个像素的图像值进行缓存,这样便可实现中心像素点以及前后列、上下行之间数据的同步处理了。

OV5640 摄像头的图像拉普拉斯锐化处理和边缘提取,fpga开发

   其代码和图像平滑处理基本相同,仅模板系数不同,这里不再详解,如有不懂请看OV5640 摄像头的图像平滑处理

 laplace_transform.v文章来源地址https://www.toymoban.com/news/detail-790553.html

/*
对图像进行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

到了这里,关于OV5640 摄像头的图像拉普拉斯锐化处理和边缘提取的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • AX7A200教程(9): ov5640摄像头输出显示720p视频

    ov5640摄像头视频通过ddr3缓存后,最后使用hdmi接口进行输出显示 2.1,像头硬件管脚 如下图所示,一共18个管脚 2.2,摄像头电源初始化时序 因这个ov5640摄像头是买的老摄像头,所以需要对Reset和PWDN的电源上电进行控制,控制时序如下图所示。 2.3,电源初始化程序 其中cmos_pwd

    2024年01月23日
    浏览(59)
  • 基于zynq7100的OV5640摄像头照相机实验,提供工程源码和技术支持

    设计框图如下: 采用Xilinx官方推荐的VDMA架构实现图像缓存和显示,除OV5640摄像头采集和HDMI输出外,其他ip均采用Xilinx官方IP实现。 这里说明一下: OV5640摄像头图像数据经VDMA三帧缓存后有2路输出 1路输出HDMI显示器显示; 1路通过FATFS文件系统写入sd卡中存放,存放的数据格式

    2024年02月03日
    浏览(40)
  • FPGA GTP全网最细讲解 aurora 8b/10b协议OV5640摄像头视频传输 提供2套工程源码和技术支持

    没玩过GT资源都不好意思说自己玩儿过FPGA,这是CSDN某大佬说过的一句话,鄙人深信不疑。。。 GT资源是Xilinx系列FPGA的重要卖点,也是做高速接口的基础,不管是PCIE、SATA、MAC等,都需要用到GT资源来做数据高速串化和解串处理,Xilinx不同的FPGA系列拥有不同的GT资源类型,低端

    2024年02月09日
    浏览(52)
  • 基于拉普拉斯金字塔的图像融合

    仅为笔记,供自己使用。 读入两幅大小相同的图像 img1 img2; 构建 img1 img2的 高斯金字塔,层数根据需要设定(本实验为7层); 根据高斯金字塔和拉普拉斯金字塔的关系,推出拉普拉斯金字塔的Li(也为7层,第一层大小和原图相同); 在 两组拉普拉斯图层 的每一层进行图像

    2024年02月11日
    浏览(47)
  • 图像处理之LoG算子(高斯拉普拉斯)

    LoG算子是由拉普拉斯算子改进而来。拉普拉斯算子是二阶导数算子,是一个标量,具有线性、位移不变性,其传函在频域空间的原点为0。所有经过拉普拉斯算子滤波的图像具有零平均灰度。但是该算子的缺点是对噪声具有敏感性,因此在实际应用中,一般先要对图像进行平滑

    2024年02月16日
    浏览(48)
  • Opencv 图像金字塔----高斯和拉普拉斯

    原文:图像金字塔----高斯和拉普拉斯 图像金字塔 是图像中多尺度表达的一种,最初用于机器视觉和图像压缩,最主要用于图像的分割、融合。 高斯金字塔是由底部的最大分辨率图像逐次向下采样得到的一系列图像。最下面的图像分辨率最高,越往上图像分辨率越低。 高斯

    2024年02月09日
    浏览(46)
  • 学习笔记:Opencv实现拉普拉斯图像锐化算法

    2023.8.19 为了在暑假内实现深度学习的进阶学习,Copy大神的代码,记录学习日常 图像锐化的百科: 图像锐化算法-sharpen_lemonHe_的博客-CSDN博客 在环境配置中要配置opencv: pip install opencv-contrib-python Code and lena.png:注意你是否在data下由lena.png   附上lena.png  效果所示(解读):

    2024年02月12日
    浏览(48)
  • 使用 OpenCV 进行图像模糊度检测(拉普拉斯方差方法)

    工作中遇到,简单整理 人脸识别中,对于模糊程度较高的图像数据,识别率低,错误率高。 虽然使用 AdaFace 模型,对 低质量人脸 表现尤为突出。 但是还是需要对 模糊程度高的图像进行丢弃处理 当前通过 阈值分类 ,符合要求的进行特性提取 实际应用中,可以维护一个 质

    2024年02月15日
    浏览(77)
  • stm32(SCCB)+ov7670摄像头输出图像程序

    一、简介:   OV7670一般模块指低成本数字输出CMOS摄像头,其摄像头包含30w像素的CMOS图像感光芯片,3.6mm焦距的镜头和镜头座,板载CMOS芯片所需要的各种不同电源(电源要求详见芯片的数据文件),板子同时引出控制管脚和数据管脚,方便操作和使用。 二、管脚定义 3V3---

    2024年02月13日
    浏览(47)
  • opencv基础46-图像金字塔02-拉普拉斯金字塔

    前面我们介绍了高斯金字塔,高斯金字塔是通过对一幅图像一系列的向下采样所产生的。有时,我们希望通过对金字塔中的小图像进行向上采样以获取完整的大尺寸高分辨率图像,这时就需要用到拉普拉斯金字塔 前面我们已经介绍过,一幅图像在经过向下采样后,再对其进行

    2024年02月13日
    浏览(45)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包