项目框架
本项目使用的开发板为zynq7020,框架为正点原子提供的hdim显示双目摄像头例程,
并在此基础上进行双目视觉处理,最终生成视差图和深度图;
所有双目视觉处理部分均在pl端采用Verilog实现
RGB转灰度图
vivado实现RGB转灰度还是很简单的,简单来说就是RGB通道的加权和
Gray = 0.2989*R+0.5870*G+0.1140*B
但是FPGA不擅长浮点数,所以要进行浮点转定点,虽然会丢失精度,但是会节省很多硬件资源,下面是浮点转定点后的代码`
always @(posedge clk or negedge rst_n) begin : proc_RGB
if(~rst_n) begin
R <= 15'b0;
G <= 15'b0;
B <= 15'b0;
end else
begin
R<= data_in[23:16]*8'd77; //打一拍
G<= data_in[15:8]*8'd150;
B<= data_in[7:0]*8'd29;
end
end
always @(posedge clk or negedge rst_n) begin : proc_gray
if(~rst_n) begin
gray <= 15'b0;
end else begin
gray <= R+G+B;//打2拍
end
end
然后取gray的高八位即为输出的灰度数据
打拍
由于彩色数据转灰度数据需要两个时钟周期,故输出要不输入往后打两拍
always @(posedge clk or negedge rst_n) begin : proc_data_out_vaild
if(~rst_n) begin
data_out_vaild <= 1'b0;
data_out_vsync <= 1'b0;
data_out_hsync <= 1'b0;
data_out_vaild_d0 <= 1'b0;
data_out_vsync_d0 <= 1'b0;
data_out_clken_d0 <= 1'b0;
end else begin
data_out_vsync_d0 <= data_in_vsync;//打一拍
data_out_clken_d0 <= data_in_hsync;//打一拍
data_out_vaild_d0 <= data_in_valid;//打一拍
data_out_vsync <= data_out_vsync_d0;//打2拍
data_out_hsync <= data_out_clken_d0;//打2拍
data_out_vaild <= data_out_vaild_d0;//打2拍
end
end
双目视觉处理
由于正点原子的例程是双目视频数据拼接到同一画面显示的,我使用的视频分辨率为800480,即每个摄像头的分辨率为400480,要进行后续双目视觉处理时需要左右目的数据同步输入,故需要对左目数据进行打拍处理,为实现左右目视频数据对齐左目需要打400拍,这里明显用寄存器打拍不现实,可以采用FIFO或者shitf_RAM进行打拍,我采用的是shift_RAM.下图为我的shift_RAM配置界面
shift_ram代码实现
c_shift_ram_0 your_instance_name (
.D(data_out_L_d), // input wire [7 : 0] D
.CLK(clk), // input wire CLK
.Q(data_out_L) // 400拍之后输出左图
);
在实现完左图打400拍后还需要一个计数器来计数从而实现左右目的同步输出
always @(posedge clk or negedge rst_n) begin : proc_x_pos
if(~rst_n)
begin
x_pos<= 11'd0;
end
else if(data_out_vaild&&(x_pos<IMG_HDISP-1'b1))
x_pos<= x_pos+1'b1;
else
x_pos<= 11'd0;
end
x_pos已输出有效信号拉高开始计数,在x_pos<400时输出左图,否则输出右图,由于左图使用shift_RAM打了400拍,故左右图实现了同步输出
assign data_out_R = x_pos<400 ? 8'd0 :gray[15:8];//输出右图
assign data_out_L_d = (x_pos<400&&data_out_vaild) ? gray[15:8]:8'd0 ;//输出左图
下面附上完整代码
`timescale 1ns/1ps
module rgb2gray #(
parameter [9:0] IMG_HDISP = 10'd800, //400*480
parameter [9:0] IMG_VDISP = 10'd480
)
( //时序 逻辑
input clk, // Clock
input rst_n , // Asynchronous reset active low
input [23:0] data_in,
input data_in_vsync ,
input data_in_hsync ,
input data_in_valid,//输入信号有效信号
output [7:0] data_out_R,
output [7:0] data_out_L,
output reg data_out_vsync ,
output reg data_out_hsync ,
output reg data_out_vaild//输出信号有效信号
);
reg [15:0] gray;
reg [9:0] x_pos;
wire [7:0] data_out_L_d;
wire [7:0] gray_8;
assign gray_8 = gray[15:8];
assign data_out_R = x_pos<400 ? 8'd0 :gray[15:8];//输出右图
assign data_out_L_d = (x_pos<400&&data_out_vaild) ? gray[15:8]:8'd0 ;//输出左图
c_shift_ram_0 your_instance_name (
.D(data_out_L_d), // input wire [7 : 0] D
.CLK(clk), // input wire CLK
.Q(data_out_L) // 400拍之后输出左图
);
//assign data_out = {gray[15:8],gray[15:8],gray[15:8]};
reg [15:0] R;
reg [15:0] G;
reg [15:0] B;
reg data_out_vaild_d0;
reg data_out_vsync_d0 ;
reg data_out_clken_d0 ;
always @(posedge clk or negedge rst_n) begin : proc_RGB
if(~rst_n) begin
R <= 15'b0;
G <= 15'b0;
B <= 15'b0;
end else
begin
R<= data_in[23:16]*8'd77; //打一拍
G<= data_in[15:8]*8'd150;
B<= data_in[7:0]*8'd29;
end
end
always @(posedge clk or negedge rst_n) begin : proc_gray
if(~rst_n) begin
gray <= 15'b0;
end else begin
gray <= R+G+B;//打2拍
end
end
always @(posedge clk or negedge rst_n) begin : proc_data_out_vaild
if(~rst_n) begin
data_out_vaild <= 1'b0;
data_out_vsync <= 1'b0;
data_out_hsync <= 1'b0;
data_out_vaild_d0 <= 1'b0;
data_out_vsync_d0 <= 1'b0;
data_out_clken_d0 <= 1'b0;
end else begin
data_out_vsync_d0 <= data_in_vsync;//打一拍
data_out_clken_d0 <= data_in_hsync;//打一拍
data_out_vaild_d0 <= data_in_valid;//打一拍
data_out_vsync <= data_out_vsync_d0;//打2拍
data_out_hsync <= data_out_clken_d0;//打2拍
data_out_vaild <= data_out_vaild_d0;//打2拍
end
end
always @(posedge clk or negedge rst_n) begin : proc_x_pos
if(~rst_n)
begin
x_pos<= 10'd0;
end
else if(data_out_vaild&&(x_pos<IMG_HDISP-1'b1))
x_pos<= x_pos+1'b1;
else
x_pos<= 10'd0;
end
endmodule