项目框架
本项目使用的开发板为zynq7020,框架为正点原子提供的hdim显示双目摄像头例程,
并在此基础上进行双目视觉处理,最终生成视差图和深度图; 所有双目视觉处理部分均在pl端采用Verilog实现
视差缓存
在左右图像的census计算完成之后会获得左目的5*5的windows窗口
input [24:0] data_in_L,//WIndows input [24:0] data_in_R,//WIndows
在获取到窗口后需要定义一个最大视差范围,这里我选择的是64,并且以左目相机为基准计算代价空间,这就需要对右目数据进行缓存,共需要缓存64个Windows,我这里直接选择用寄存器缓存
//============= 缓存 视差范围内的census向量 以便并行处理========================
integer i;
reg [24:0] census_array_L [0:`MAX_DISP-1];
reg [24:0] census_array_R [0:`MAX_DISP-1];
always@(posedge clk,negedge rst_n)begin
if(~rst_n)begin
for (i=0;i<`MAX_DISP;i=i+1)begin
census_array_L[i]<=0;
census_array_R[i]<=0;
end
end
else if(data_in_L_valid)begin
census_array_R[0]<=data_in_R; //第一拍
census_array_L[0]<=data_in_L;
for (i=1;i<`MAX_DISP;i=i+1)begin
census_array_R[i]<=census_array_R[i-1];//右图保存64个census用于和左图计算汉明距离
end
end
end
异或运算得到汉明距离
再进行完右目数据缓存之后在进行异或计算,FPGA可以实现左目当前数据和右目缓存的64个数据同时进行异或运算,代码如下:
//============== 并行异或运算 MAX_DISP=> 1 ======================
wire [24:0] now_census_L ;
reg [24:0] hamming_distance_vec[0:`MAX_DISP-1];
assign now_census_L = census_array_L[0];//左图为主为census_array_L[0];右图为主为census_array_L[`MAX_DISP-1]
always@(posedge clk,negedge rst_n)begin
if(~rst_n)begin
for (i=0;i<`MAX_DISP;i=i+1)begin
hamming_distance_vec[i]<=0;
end
end
else begin
for (i=0;i<`MAX_DISP;i=i+1)begin
//现在左边像素点的cesusu与右边的像素点的(64-census~census)64个像素点进行异或运算
hamming_distance_vec[i]<=now_census_L ^ census_array_R[i];// hamming_distance_vec[i]==5*5 //第二拍 汉明距离的计算从右向左
end
end
end
在进行完异或运算之后便会等到一个64个数据的 hamming_distance_vec[]数组,每个数据为24位,将数组每个数据的24位逐个累加便得到了汉明距离数组,其代码如下
integer disp_index,add_index;
always@(posedge clk)begin
//===== add0 ====== //第三拍
for(disp_index=0;disp_index<`MAX_DISP;disp_index=disp_index+1)begin//视差方向
for(add_index=0;add_index<12;add_index=add_index+1)begin //组内加法
add0[disp_index][add_index]<=hamming_distance_vec[disp_index][add_index*2]+hamming_distance_vec[disp_index][add_index*2+1];
end
add0[disp_index][12] <= hamming_distance_vec[disp_index][24];
end
//===== add1 ====== //第四拍
for(disp_index=0;disp_index<`MAX_DISP;disp_index=disp_index+1)begin//视差方向
for(add_index=0;add_index<6;add_index=add_index+1)begin //组内加法
add1[disp_index][add_index]<=add0[disp_index][add_index*2]+add0[disp_index][add_index*2+1];
end
add1[disp_index][6] <= add0[disp_index][12];
end
//===== add2 ====== //第五拍
for(disp_index=0;disp_index<`MAX_DISP;disp_index=disp_index+1)begin//视差方向
for(add_index=0;add_index<3;add_index=add_index+1)begin //组内加法
add2[disp_index][add_index]<=add1[disp_index][add_index*2]+add1[disp_index][add_index*2+1];
end
add2[disp_index][3] <= add1[disp_index][6];
end
//===== add3 ====== //第六拍
for(disp_index=0;disp_index<`MAX_DISP;disp_index=disp_index+1)begin//视差方向
for(add_index=0;add_index<2;add_index=add_index+1)begin //组内加法
add3[disp_index][add_index]<=add2[disp_index][add_index*2]+add2[disp_index][add_index*2+1];
end
end
//===== add4 ====== //第七拍
for(disp_index=0;disp_index<`MAX_DISP;disp_index=disp_index+1)begin//视差方向
add4[disp_index]<=add3[disp_index][0]+add3[disp_index][1];
end
end
视差计算
在得到汉明距离后只需在所表示汉明距离的数组中找出最小值所在的数组下标索引便可以得出初步视差图,具体效果如下
这是根据左右目图像算出的 初步视差图,后续还需要进行SGM聚合,SGM聚合之后的效果为:
可以看到效果有明显的改善.