Sobel算子实现(公式)

sobel的由来是求导公式即:

        f'(x) = lim(h→0)[f(x+h)-f(x-h)]/2h,

        通过高等数学的知识易得,这个公式可以通过求微分来取得数值变化的大小。

        而要对图像使用的情况下由于求极限也只能趋于1,则取近似为f'(x) = [f(x+1)-f(x-1)]/2,通常sobel核的范围是3x3,而其中的中间需要加权一倍。

        整体呈现:(来自百度百科)

 verilog实现方法:

    always@(posedge Sys_clk or negedge Rst_n) begin
        if(!Rst_n) begin
            kernel_1  <= 'd0;            
            kernel_2  <= 'd0;
            kernel_3  <= 'd0;            
        end else if(flag_kernel) begin
            kernel_1  <= { kernel_1 , data_receive }; 
            kernel_2  <= { kernel_2 , RD_DATA_OUT_2};
            kernel_3  <= { kernel_3 , RD_DATA_OUT_1}; 
        end
    end
    always@(posedge Sys_clk or negedge Rst_n) begin
        if(!Rst_n) begin
            dx <= 'd0;
            dy <= 'd0;
        end else if(flag_Conv == 1'b1) begin
            dx <=   (kernel_1[15:8] - data_receive) 
                 + ((kernel_2[15:8] - RD_DATA_OUT_2)<<1)
                 +  (kernel_3[15:8] - RD_DATA_OUT_1);
            dy <=   (RD_DATA_OUT_1 - data_receive) 
                 + ((kernel_3[ 7:0] - kernel_1[7:0])<<1)
                 +  (kernel_3[15:8] - kernel_1[15:8]);
        end else begin
            dx <= dx;
            dy <= dy;
        end
    end

整体图像处理思路:

        1.接收图像数据,准备两个FIFO,存储两行图像数据。

        2.利用输入的第三行数据与前两行数据做sobel计算,获得sobel像素。

        3.把sobel像素存进RAM里,等待VGA时序合适的时候调取。

        具体操作:首先第一个FIFO存下第一行数据,第二个FIFO存下第二行数据:

    always@(posedge Sys_clk or negedge Rst_n) begin
        if(!Rst_n) begin
            WR_EN_IN_1 <= 1'b0;
        end else if(row_cnt == 'd0 
                 && rx_done) begin
            WR_EN_IN_1 <= 1'b1; 
        end else begin
            WR_EN_IN_1 <= RP2_WR_EN_IN_1;
        end
    end
    always@(posedge Sys_clk or negedge Rst_n) begin
        if(!Rst_n) begin
            RP1_WR_EN_IN_1 <= 1'b0;
        end else if(row_cnt >= 'd2 
                 && rx_done 
                 && row_cnt <= image_y -2'd2) begin
            RP1_WR_EN_IN_1 <= 1'b1;
        end else begin
            RP1_WR_EN_IN_1 <= 1'b0;
        end
    end
    always @(posedge Sys_clk) begin
        RP2_WR_EN_IN_1 <= RP1_WR_EN_IN_1;
    end
    //WR_EN_IN_2
    always@(posedge Sys_clk or negedge Rst_n) begin
        if(!Rst_n) begin
            WR_EN_IN_2 <= 1'b0;
        end else if(row_cnt >= 'd1 
                 && rx_done 
                 && row_cnt <= image_y -2'd2) begin
            WR_EN_IN_2 <= 1'b1; 
        end else begin
            WR_EN_IN_2 <= 1'b0;
        end
    end

        其中,FIFO1存入的是第0行输入数据,以及row_cnt >1以后FIFO2读出的数据,所以row_cnt >1以后FIFO1的写信号将有所延迟。(也可以用FIFO1的读信号延迟一拍得到)

        FIFO2存入的是第一行以后的输入数据,并且不断读出给FIFO1写入,这样就持续存有两行数据了。

        数据输入:

    //WR_DATA_IN_1
    always@(posedge Sys_clk or negedge Rst_n) begin
        if(!Rst_n) begin
            WR_DATA_IN_1 <= 'd0;
        end else if(row_cnt == 'd0) begin
            WR_DATA_IN_1 <= data_receive;
        end else begin
            WR_DATA_IN_1 <= RD_DATA_OUT_2;
        end
    end
    //WR_DATA_IN_2
    always@(posedge Sys_clk or negedge Rst_n) begin
        if(!Rst_n) begin
            WR_DATA_IN_2 <= 'd0;
        end else if (row_cnt >= 'd1 
                  && row_cnt <= image_y -2'd2) begin
            WR_DATA_IN_2 <= data_receive;
        end
    end

读使能:

//RD
    always@(posedge Sys_clk or negedge Rst_n) begin
        if(!Rst_n) begin
            RD_EN_IN_1 <= 1'b0;
        end else if(row_cnt >= 'd2 
                 && rx_done 
                 && row_cnt <= image_y -1'b1) begin
            RD_EN_IN_1 <= 1'b1;  
        end else begin
           RD_EN_IN_1 <= 1'b0;
        end
    end
    always@(posedge Sys_clk or negedge Rst_n) begin
        if(!Rst_n) begin
            RD_EN_IN_2 <= 1'b0;
        end else if(row_cnt >= 'd2 
                 && rx_done 
                 && row_cnt <= image_y -1'b1) begin
            RD_EN_IN_2 <= 1'b1;  
        end else begin
           RD_EN_IN_2 <= 1'b0;
        end
    end
/--------------------对比-------------------------------/
    always@(posedge Sys_clk or negedge Rst_n) begin
        if(!Rst_n) begin
            RP1_WR_EN_IN_1 <= 1'b0;
        end else if(row_cnt >= 'd2 
                 && rx_done 
                 && row_cnt <= image_y -2'd2) begin
            RP1_WR_EN_IN_1 <= 1'b1;
        end else begin
            RP1_WR_EN_IN_1 <= 1'b0;
        end
    end
    always @(posedge Sys_clk) begin
        RP2_WR_EN_IN_1 <= RP1_WR_EN_IN_1;
    end

对比可知:

        row_cnt >1以后FIFO1的写信号将有所延迟。(也可以用FIFO1的读信号延迟一拍得到)

SOBEL计算:

        1.实现SOBEL算子
    always@(posedge Sys_clk) begin
        if(flag_kernel) begin
            { data_receive_d ,data_receive_dd  } = { data_receive ,data_receive_d   };
            { RD_DATA_OUT_1_d,RD_DATA_OUT_1_dd } = { RD_DATA_OUT_1,RD_DATA_OUT_1_d  };
            { RD_DATA_OUT_2_d,RD_DATA_OUT_2_dd } = { RD_DATA_OUT_2,RD_DATA_OUT_2_d  };
        end
    end
    //dx dy
    always@(posedge Sys_clk or negedge Rst_n) begin
        if(!Rst_n) begin
            dx <= 'd0;
            dy <= 'd0;
        end else if(flag_Conv == 1'b1) begin
            dx <=   (data_receive_dd  - data_receive ) 
                 + ((RD_DATA_OUT_2_dd - RD_DATA_OUT_2)<<1)
                 +  (RD_DATA_OUT_1_d  - RD_DATA_OUT_1);
            dy <=   (RD_DATA_OUT_1    - data_receive  ) 
                 + ((RD_DATA_OUT_1_d  - data_receive_d)<<1)
                 +  (RD_DATA_OUT_1_dd - data_receive_dd);
        end else begin
            dx <= dx;
            dy <= dy;
        end
    end
        2.利用补码求绝对值:

                最高位为1:负数,则按位取反得到绝对值。

                最高位为0:正数,直接使用。

    always@(posedge Sys_clk or negedge Rst_n) begin
        if(!Rst_n) begin
            abs_dx <= 'd0;
        end else if(flag_abs == 1'b1 && dx[7] == 1'b1) begin
            abs_dx <= ~(dx) + 1'b1;
        end else if(flag_abs == 1'b1 && dx[7] == 1'b0) begin
            abs_dx <= dx;
        end
    end
    always@(posedge Sys_clk or negedge Rst_n) begin
        if(!Rst_n) begin
            abs_dy <= 'd0;
        end else if(flag_abs == 1'b1 && dy[7] == 1'b1) begin
            abs_dy <= ~(dy) + 1'b1;
        end else if(flag_abs == 1'b1 && dy[7] == 1'b0) begin
            abs_dy <= dy;
        end
    end
        3.绝对值求和。
    always@(posedge Sys_clk or negedge Rst_n) begin
        if(!Rst_n) begin
            dxy_sum <= 'd0;
        end else if(flag_dxy == 1'b1) begin
            dxy_sum <= abs_dy + abs_dx;
        end
    end
        4.设置阈值并判断
    always@(posedge Sys_clk or negedge Rst_n) begin
        if(!Rst_n) begin
            tx_data <= 'd0;
        end else if(flag_gate == 1'b1 && dxy_sum >  gate) begin
            tx_data <= black;
        end else if(flag_gate == 1'b1 && dxy_sum <= gate) begin
            tx_data <= white;
        end else begin
            tx_data <= tx_data;
        end
    end

[1]威三学院FPGA教程

[2]小梅哥AC620V2教程

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值