我是靠谱客的博主 活泼鼠标,最近开发中收集的这篇文章主要介绍基于FPGA的中值滤波设计————(1)图片数据TXT读写,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

        书接上回http://t.csdn.cn/Q1zZThttp://t.csdn.cn/Q1zZT       其中讲述的是matlab将彩色图像数据读写到TXT当中。

        这部分主要是关于FPGA设计的内容,为了方便理解所以单独成为一个系列。在本文这一章主要讲解FPGA对图像数据读写。在后面会陆续讲解中值滤波,小伙伴们别急,一口是吃不成大佬的。

一、明确图像存储在txt当中的格式        

        首先我们来复习一下,前面我们不是说到,利用matlab将彩色图像数据以16进制写入到txt当中,且写入的形式如下:

         这里的0x11是图层1的第一个数,往下0x02依次为图层1的第二个数;

        0x2a是图层2的第一个数,往下0x2b依次为图层2的第二个数;

         0x2f是图层3的第一个数,往下0x20依次为图层3的第二个数;

        TXT中数的深度就是图层的大小row*col,数的宽度就是三个像素,每个像素点8bit,总共24bit,例如这里的第一个数112a2f,就是24bit的位宽

二、FPGA读写txt文件

        接下来我们就利用verilog将txt文件里的数据读到FPGA当中,FPGA当中数据处理完后,再将数据写入txt当中。整体的数据流程框图如下:

  主要是通过激励文件的里的函数调用来读写图像数据,然后将数据输入到mid_top(中值滤波顶层模块)进行处理。

1)读txt数据

        为了方便讲解,我就先将我自己的tb(test benches,测试激励)文件读写拆分,直接上代码

`timescale 1ns/1ps
parameter picture_size = 71200 ;
integer fp_r;
reg rst_n;
reg clk;
reg [23:0] data_in;
reg [31:0] count;

initial
begin

    fp_r=$fopen("*/*/*.txt","r");//以读的方式打开*.txt文件
    rst_n=1'b0;
    clk=1'b0;
    #20
    rst_n=1'b1;
    #63000
    $stop;
end
initial
    forever
         #5 clk=!clk;

always@(posedge clk)
begin
     if(!rst_n)
        begin
            data_in<=24'd0;
            count<=0;
        end
     else if(count<=picture_size)
            begin
                $fscanf(fp_r,"%hn",data_in);//每次读一行
                count<=count+1'b1;
            end
    else
        begin
            $fclose(fp_r)'//关闭已打开的文件
        end
       
end

        先仔细的讲解一下,后面遇到相同的就不做解释了,首先

`timescale 1ns/1ps

        代表的是对仿真时间规定,这里就是单位ns精度ps,比如后面initial部分里面的#20、#5等代表的就是20ns和5ns。

        然后是常量定义:

parameter picture_size = 71200 ;

        这里的picture_size大小可以根据大家自己的图层大小定义,比如我的图层大小就是356*200=71200;定义这个常量就是为了把txt里面的所有图像数据通过计数的方式一个一个读出来。

        接下来就是五个寄存器:

integer fp_r;
reg rst_n;
reg clk;
reg [23:0] data_in;
reg [31:0] count;

        位宽分别为32、1、1、24、32,没错是五个,integer形式的定义也是寄存器只不过是整型的有符号,规定为32位且这个位宽不可更改,而reg定义的是无符号的寄存器,位宽可设置,不设置时默认位1bit。

        然后是运用$fopen函数打开想要读的文件夹:

initial
begin

    fp_r=$fopen("*/*/*.txt","r");//以读的方式打开*.txt文件
    rst_n=1'b0;
    clk=1'b0;
    #20
    rst_n=1'b1;
    #63000
    $stop;
end

        在这里的("*/*/*.txt")大家可以根据自己的TXT文件所在目录和文件名进行更改,且注意斜杠“”“/”和文件目录的斜杠“”是不一样的。利用$fopen函数把文件以读的方式打开,存储在了fp_r当中。然后定义了复位rst_n、时钟clk的初始值0,#20ns 过后复位rst_n变为1启动程序,再过#63000ns停止激励仿真程序,63000的停止时间也可以修改。

        接着就是时钟脉冲的翻转设置:

initial
    forever
         #5 clk=!clk;

        时钟脉冲初始值在上面设置了是0,然后每隔5ns翻转一次,在0和1之间有周期性的变换,就形成了时钟脉冲。

        最后是利用$fscanf函数通过时钟驱动寄存器输出TXT每一行的24bit数据:

always@(posedge clk)
begin
     if(!rst_n)
        begin
            data_in<=24'd0;
            count<=0;
        end
     else if(count<=picture_size)
            begin
                $fscanf(fp_r,"%hn",data_in);//每次读一行
                count<=count+1'b1;
            end
    else
        begin
            $fclose(fp_r)'//关闭已打开的文件
        end
       
end

        当计数器count计数到picture_size常量也就是图层大小时候通过$fclose关闭打开的txt文件。这里需要注意的是,读的时候是以"%hn"也就是16进制的方式读数据,一个时钟读一行,因为我们写进去的是16进制形式,记住写入TXT是什么数据形式(是h还是d等),读的时候也需要更改相应的形式。

        总结一下,上面的一系列代码实现的功能,主要就是将*.txt的图像数据通过一个一个clk时钟周期读入到data_in当中存储和输出data_in就可以通过实例化输出到mid_top当中做中值滤波处理

2)将处理后的数据写入txt

         这部分的写代码就和读数据的代码高度相似了,直接上代码:

`timescale 1ns/1ps
parameter picture_size = 71200 ;
integer fp_w;
reg rst_n;
reg clk;
reg [31:0] count_out;

wire [23:0] data_out;
wire flag;

initial
begin

    fp_w=$fopen("*/*/*.txt","w");//以写的方式打开*.txt文件
    rst_n=1'b0;
    clk=1'b0;
    #20
    rst_n=1'b1;
    #63000
    $stop;
end
initial
    forever
         #5 clk=!clk;

always@(posedge clk)
begin
     if(!rst_n)
        begin
            count_out<=0;
        end
     else if((count_out<=picture_size-1)&flag)
            begin
                $fwrite(fp_w,"%hn",data_out);//每次写一行
                count_out<=count_out+1'b1;
            end
    else if(count_out==picture_size)
        begin
            $fclose(fp_w)'//关闭已打开的文件
        end
       
end

        讲一下跟读数据不同的地方,第一处就是加入了两个wire型的数据:

wire [23:0] data_out;
wire flag;

        这两个信号就来自mid_top模块,data_out代表是图像处理后的像素数据,flag代表data_out数据的有效性,通俗的说就是告诉别的模块,我这个模块(mid_top)像素中值滤波滤完成了一个像素,你把这个像素拿去做其他处理吧。

        然后第二处就是以写"w"的方式打开一个*.txt,并将它放入fp_w里,如果指定的目录里没有这个txt,它会新建一个。

        最后不同的地方就是always功能块里面的:

always@(posedge clk)
begin
     if(!rst_n)
        begin
            count_out<=0;
        end
     else if((count_out<=picuture_size-1)&flag)
            begin
                $fwrite(fp_w,"%hn",data_out);//每次写一行
                count_out<=count_out+1'b1;
            end
    else if(count_out==picture_size)
        begin
            $fclose(fp_w)'//关闭已打开的文件
        end
       
end

        意思其实也很简单,当falg信号有效就是为1的时候且count_out计数小于图层大小时,开始利用$fwrite函数将data_out数据一个一个的写入txt当中,当写完了所有像素也就是count_out=picture_size之后,就关闭打开的文件,停止写。

3)仿真测试

来看看实际的仿真结果:

         主要看data_in数据读出是没有问题的跟之前数据存入txt(看本文的第一张图)是一样的,证明我们的操作没有问题,很成功。

        在我的仿真激励中数据的写入TXT需要把仿真往后运行:

        先不分析数据处理的正确性,只看写数据这个操作,我们可以大致看一下数据写出是没问题的,写出生成的TXT如下:

 对了这里的TXT我都是用MATLAB打开看的,所以前面有12345678这些前缀。

三、总结

        基本上将前面的读写方式学会后,图像数据写入就可以通过data_in接到自己想要的模块去使用,想要知道处理后的结果就可以将data_out接出来交给matlab等软件去验证和分析效果。如果需要同时读写,只需要将我上面的代码稍加修改,去掉重复的部分就可以了。

        其实还有其他的方式能将数据输入到FPGA当中,我这里再提及一下这个方案,就是通过之前我有讲到的利用MATLAB生成.mif文件或者.coe文件,然后调用FPGA的rom核,再通过rom读出这些数据,也是可以这样操作的,操作没有什么难度,这里就不深入的探究了。

        每天一点新知识,打工人奥利给!

最后

以上就是活泼鼠标为你收集整理的基于FPGA的中值滤波设计————(1)图片数据TXT读写的全部内容,希望文章能够帮你解决基于FPGA的中值滤波设计————(1)图片数据TXT读写所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(47)

评论列表共有 0 条评论

立即
投稿
返回
顶部