直方图统计的FPGA实现

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了直方图统计的FPGA实现相关的知识,希望对你有一定的参考价值。

直方图统计是图像处理算法中最基本和常见的算法之一,主要原理就是将图像中各个灰度级的像素个数进行计算并统计,这在一些对灰度特性进行统计的算法中比较常见。虽然直方图统计在MATLAB或软件中耗时也很少,但是现在随着FPGA的普及,更加快速的实现一些图像处理算法成为了主流。 
FPGA实现图像处理算法现在有几种主流的方式:1、HDL纯逻辑代码编写;2、基于System generator的模块搭建;3、Xilinx公司vivado套件中的HLS软件进行C/C++代码的转换。 
而本文主要采用第一种方法,即采用Verilog代码形式直接实现直方图统计算法。


  • 方法1:倍频操作
  • 方法2:相邻数据判断

倍频操作

直方图统计给人的第一反应就是按照软件中方法,设置256个寄存器,然后对每个像素大小进行判断后再对对应的寄存器进行+1,而在FPGA中可以充分利用内部RAM的完成这一操作。而在这边我们选用的是伪双端口RAM。 
在伪双端口RAM中,需要主要的是有两个设置选项: 
技术分享 
1、Primitives Output Register 
这一设置主要是在RAM的输出端口添加一个寄存器,对输出的数据进行打一拍缓存操作。如果勾选上这个,在高频时钟情况下,可以有效的保证输出信号满足建立和保持时间。而RAM本身默认读出数据延时为一拍,则RAM读出数据的总延时为2个时钟单位。 
2、Operating Mode 
主要包括了No Change , Write First和Read First,顾名思义,主要指的读出数据的先后顺序。在No Change模式下,写操作不改变输出端数据,在Write First模式下,如果对同一地址进行读写,则先写后读,在Read First模式下,如果对同一地址进行读写,则先读后写。

倍频方式的代码如下:(本例程中未勾选Primitives Output Register,且Operating Mode设置为Write First)

module his_count(
input rst_n,
input clk_150M,      //  150M
input LVAL,      //data的伴随使能信号
input [7:0]data  // 输入2K的图像,连续数据流
    );

reg LVAL_temp1,LVAL_temp2;    
reg [7:0]data_temp1,data_temp2;

reg [20:0]addra; 
reg [7:0]dina;
reg ena,wea;

reg [20:0]addrb;
reg enb;
reg [8:0]count=9‘d0;
wire [7:0]doutb;
wire clk_300M;
clk_wiz_1 clk_pll_inst
(
   // Clock in ports
   .clk_in1(clk_150M),      // 150M
   .clk_out1(clk_300M),     // 300M
   .reset(), // input reset
   .locked());      // output locked

//RAM的读出延时设为1
blk_mem_gen_1 L1 (
  .clka(clk_300M),    
  .ena(ena),      
  .wea(wea),   
  .addra(addra),  
  .dina(dina),    
  .clkb(clk_300M),    
  .rstb(),  
  .enb(enb),      
  .addrb(addrb), 
  .doutb(doutb)  
); 
 always @(posedge clk_150M or negedge rst_n)
 begin
    if(!rst_n) begin
        {LVAL_temp2,LVAL_temp1}<=2‘d0;
        {data_temp2,data_temp1}<=16‘d0;
    end else begin
        {LVAL_temp2,LVAL_temp1}<={LVAL_temp1,LVAL};
        {data_temp2,data_temp1}<={data_temp1,data};
    end
 end

 // 读模块
 always @(posedge clk_150M or negedge rst_n)
 begin
    if(!rst_n) begin
        enb<=0;
        addrb<=21‘d0;
    end else begin
        enb<=LVAL;
        addrb<={14‘d0,data};
    end
 end

 //写模块
 always @(posedge clk_300M or negedge rst_n)
 begin
    if(!rst_n) begin
        ena<=0;
        wea<=0;
        addra<=21‘d0;
        dina<=8‘d0;
    end else begin
        ena<=LVAL_temp2;
        wea<=LVAL_temp2;
        addra<={14‘d0,data_temp2};
        dina<=doutb+1;
    end
 end

相邻数判断

相邻数判断主要通过判断前一个像素与之是否相同来改变RAM写入的数据。因为RAM的读出至少有一个延时,所以假如相邻的数遇到相同的情况,前一个数写入的数值无法被后一个数所读出,因此会遇到漏计数的情况。如果采用相邻数判断的方式,则可以避免倍频带来的时序问题。 
在本情况下,Operating Mode设置为Write First。且未勾选Primitives Output Register。 
代码如下:

module his_count(
input rst_n,
input clk_150M,      //  150M
input LVAL,      //data的伴随使能信号
input [7:0]data  // 输入2K的图像,连续数据流
    );

reg LVAL_temp2,LVAL_temp1;    
reg [7:0]data_temp2,data_temp1;

reg [20:0]addra; 
reg [7:0]dina;
reg ena,wea;

reg [20:0]addrb;
reg enb;
wire [7:0]doutb;
//RAM的读出延时设为1
blk_mem_gen_1 L1 (
  .clka(clk_150M),    
  .ena(ena),      
  .wea(wea),   
  .addra(addra),  
  .dina(dina),    
  .clkb(clk_150M),    
  .rstb(),  
  .enb(enb),      
  .addrb(addrb), 
  .doutb(doutb)  
); 
 always @(posedge clk_150M or negedge rst_n)
 begin
    if(!rst_n) begin
        {LVAL_temp2,LVAL_temp1}<=2‘d0;
        {data_temp2,data_temp1}<=16‘d0;
    end else begin
        {LVAL_temp2,LVAL_temp1}<={LVAL_temp1,LVAL};
        {data_temp2,data_temp1}<={data_temp1,data};
    end
 end

 // 读模块
 always @(posedge clk_150M or negedge rst_n)
 begin
    if(!rst_n) begin
        enb<=0;
        addrb<=21‘d0;
    end else begin
        enb<=LVAL;
        addrb<={14‘d0,data};
    end
 end

 //写模块
 always @(posedge clk_150M or negedge rst_n)
 begin
    if(!rst_n) begin
        ena<=0;
        wea<=0;
        addra<=21‘d0;
        dina<=8‘d0;
    end else if(data_temp2 == data_temp1)begin
        ena<=LVAL_temp2;
        wea<=LVAL_temp2;
        addra<={14‘d0,data_temp2};
        dina<=doutb+2;
    end else begin
        ena<=LVAL_temp2;
        wea<=LVAL_temp2;
        addra<={14‘d0,data_temp2};
        dina<=doutb+1;      
    end
 end
 

以上是关于直方图统计的FPGA实现的主要内容,如果未能解决你的问题,请参考以下文章

OpenCV学习笔记13-图像直方图的介绍及代码实现

基于FPGA的图像增强系统的verilog开发(3000+字)

统计随机数出现个数与直方图显示的C实现

ElasticSearch6.x版本聚合统计在Kibana上的实操和在SpringBoot上的实操

图像处理系列——直方图统计算法

直方图均衡化局部直方图均衡化直方图统计算法在图像处理效果上的对比