基于FPGA的双目视觉教程_3.census计算

项目框架

本项目使用的开发板为zynq7020,框架为正点原子提供的hdim显示双目摄像头例程,
并在此基础上进行双目视觉处理,最终生成视差图和深度图;
所有双目视觉处理部分均在pl端采用Verilog实现

在这里插入图片描述

Census原理

参考文章 https://blog.csdn.net/MyStylee/article/details/78491271

在视图中选取任一点,以该点为中心划出一个例如3 × 3 的矩形,矩形中除中心点之外的每一点都与中心点进行比较,灰度值小于中心点记为1,灰度大于中心点的则记为0,以所得长度为 8 的只有 0 和 1 的序列作为该中心点的 census 序列,即中心像素的灰度值被census 序列替换。经过census变换后的图像使用汉明距离计算相似度,所谓图像匹配就是在匹配图像中找出与参考像素点相似度最高的点,而汉明距正是匹配图像像素与参考像素相似度的度量。具体而言,对于欲求取视差的左右视图,要比较两个视图中两点的相似度,可将此两点的census值逐位进行异或运算,然后计算结果为1 的个数,记为此两点之间的汉明值,汉明值是两点间相似度的一种体现,汉明值愈小,两点相似度愈大实现算法时先异或再统计1的个数即可,汉明距越小即相似度越高。
在这里插入图片描述

FPGA实现Census

fpga要实现census首先需要缓存多行数据才能组成矩阵,本项目中采用双端口RAM来进行左右图灰度数据的缓存

//==================================左图缓存部分===================================

//======================= 缓存部分 ==================
    reg [9 : 0] addra;
    reg [9 : 0] addrb;
    wire [9:0] addra_plus2 = addra + 2 ;
     //=========== 地址
    always@(posedge clk,negedge rst_n)begin
        if(~rst_n)begin
            addra<=0;
            addrb<=0;
        end
        else if(data_in_valid)begin
            //========== a ==========
            if(addra == IMG_HDISP-1'b1)
                addra<=0;
            else
                addra<=addra+1'd1;
            //========= b ===========
            if(addra_plus2 > IMG_HDISP-1'b1)
                addrb <= addra_plus2 - IMG_HDISP;
            else
                addrb <= addra_plus2;
        end
    end
    
    //=========== 数据 ==============
    wire [7:0] linebuffer_in[0:4];
    wire [7:0] linebuffer_out[0:4];
    
    assign linebuffer_in[0] = data_in_L;
    genvar k ;
    generate 
        for (k=1;k<5;k=k+1)begin
            assign linebuffer_in[k] = linebuffer_out[k-1];
        end
    endgenerate
    
    generate 
         for (k=0;k<5;k=k+1)begin
            blk_mem_gen_0 your_instance_name (
              .clka(clk),    // input wire clka
              .wea(data_in_valid),      // input wire [0 : 0] wea
              .addra(addra),  // input wire [9 : 0] addra
              .dina(linebuffer_in[k]),    // input wire [7 : 0] dina
              .clkb(clk),    // input wire clkb
              .addrb(addrb),  // input wire [9 : 0] addrb
              .doutb(linebuffer_out[k])  // output wire [7 : 0] doutb
            );
        end
    endgenerate

上图已左目数据的缓存为例,采用了 5个RAM来生成5*5的窗口来进行census计算,右图同理
由于双端口RAM的乒乓存储操作,输出的地址要比输入的地址+2,如果理解不了可以看下面的波形图
在这里插入图片描述
只有输出地址比输入地址多2才能实现数据对齐,数据对齐之后就要取出窗口了

    //=============== 取出窗口====================================
    reg [7:0] window [4:0][4:0];
    integer i,j;
    always@(posedge clk,negedge rst_n)begin
        if(~rst_n)begin
            for(i=0;i<5;i=i+1)begin
                for(j=0;j<5;j=j+1)begin
                     window[i][j]<=0;
                end
            end
        end
        else begin
            for(i=0;i<5;i=i+1)begin
                window[i][0]<=linebuffer_in[i];//需要一个时钟周期
                for(j=1;j<5;j=j+1)begin
                     window[i][j]<=window[i][j-1];
                end
            end
        end
    end

窗口的取出是以流水线的形式实现的,故只需要一个时钟周期 ,取出5*5的窗口之后就需要进行census计算了

    //====================== Census 计算 ==========================
    wire [7:0] center;
    reg [24:0] census_vec ;
    assign center = window[2][2];
    genvar x,y;
    generate
        for(y=0;y<5;y=y+1)begin
            for(x=0;x<5;x=x+1)begin
                always@(posedge clk)begin
                    if(window[y][x] > center )
                        census_vec[y*5+x] <= 1'b1;需要一个时钟周期
                    else
                        census_vec[y*5+x] <= 1'b0;
                end
            end 
        end
    endgenerate
    assign data_out_L = census_vec;

census计算也很简单,上面原理已经介绍过了,计算出的census为25位,也就是说原先8bit的灰度数据被25为的census所代替

输出打拍

由于需要缓存5行数据才能真正输出有效的数据,这个输出打拍来说,需要打的拍太多了,所有只需要考虑核心计算部分,即取出窗口和census计算即可,这样的话输出相对于输入会有5行的偏移,但是左右图都有偏移,而且偏移是相同的故不影响后续汉明距离的计算

//=======输出打拍====//
reg data_out_vaild_d0;
reg data_out_vsync_d0;
reg data_out_clken_d0;
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;
    end else begin
        //只考虑取出windows和Census 计算 ,故只需要打两拍
          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;//打两拍
      data_out_hsync <= data_out_clken_d0;//打两拍
      data_out_vaild <= data_out_vaild_d0;//打两拍  
    end
end
  • 7
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

嵌入式学习~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值