基于fpga的sobel边缘检测

这篇具有很好参考价值的文章主要介绍了基于fpga的sobel边缘检测。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

基于fpga的sobel边缘检测,部分的代码参考的是野火正点原子的代码和视频。通过matlab将图片转成txt文件,并编写verilog代码将处理好的数据再转成txt文件,同时通过matlab将txt文件再读取成图片。

文章目录

  • 前言
  • 一、verilog代码
    • 1.sobel_edge代码
    • 2.tb文件(读写txt文件)
  • 注意

前言

一、sobel边缘检测的原理(源自野火)

Sobel算法的核心就是Sobel算子,该算子包含两组3x3的矩阵

基于fpga的sobel边缘检测              基于fpga的sobel边缘检测

对于图像而言,取三行三列的图像数据,将图像数据与对应的算子相乘再相加,得到x方向的GX和y方向的Gy,平方后相加,提取算数平方根,得到Gxy,近似值为GX和Gy绝对值之和,将得到的Gxy与设定的阈值相比较,如果大于阈值则显示黑点,否则显示白点。

基于fpga的sobel边缘检测

Sobel算法在边缘检测中分4步:

  1. 通过GX和Gy的计算公式,结合FIFO求和算法求取数值。
  2. 求得GX和Gy绝对值。
  3. 求出Gxy。
  4. 将求得的值与设定的阈值相比,大于则为黑色,小于为白。

 在经过Sobel运算后,输出的图片相比于输入时的图片会缺少2行2列数据,因为在求GX和Gy时需要使用FIFO求和算法,该算法只有在第2行或第二列数据输入时才开始执行,第0、1行或者第0、1列不会进行求和运算,没有数据输出,所以会缺少2行2列。

求和计算的要点:

完成3行数据的SUM求和,需要调用两个FIFO ip核,当数据开始输入时,将数据的第0行存储到FIFO1中,第一行的数据存入FIFO2中,当数据的第二行的第0个数据输入的同时,读取写入FIFO1中的第0行第0个数据和写入FIFO2中的第一行第一个数据,将三者求和并输出。完成求和的同时,将读取的FIFO2的第一行第0个数据写入FIFO1中,覆盖掉第0行的第0个数据,相当于将第一行数据重新写入FIFO1中,将第二行数据写入FIFO2中, 当第三行数据开始传入时,将1.2.3行进行求和,并继续此步骤。

基于fpga的sobel边缘检测

二、verilog代码

1.sobel_edge代码

代码如下(示例):

module  sobel_edge
(
    input   wire            sys_clk     ,   
    input   wire            sys_rst_n   ,   
    input   wire    [7:0]   pi_data     ,   //输入信号
    input   wire            pi_flag     ,   

    output  reg     [7:0]   po_data     ,   //输出信号
    output  reg             po_flag        
);

//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//
//parameter define
parameter   LENGTH_P    =   10'd436         ,   //图片长度
            WIDE_P      =   10'd293         ;   //图片宽度
parameter   THRESHOLD   =   8'b000_011_00   ;   //比较阈值
parameter   BLACK       =   8'b0000_0000    ,   //黑色
            WHITE       =   8'b1111_1111    ;   //白色

//wire  define
wire    [7:0]   data_out1   ;   //fifo1数据输出
wire    [7:0]   data_out2   ;   //fifo2数据输出

//reg   define
reg     [7:0]   cnt_h       ;   //行计数
reg     [7:0]   cnt_v       ;   //场计数
reg     [7:0]   pi_data_dly ;   //pi_data数据寄存
reg             wr_en1      ;   //fifo1写使能
reg             wr_en2      ;   //fifo2写使能
reg     [7:0]   data_in1    ;   //fifo1写数据
reg     [7:0]   data_in2    ;   //fifo2写数据
reg             rd_en       ;   //fifo1,fifo2共用读使能
reg     [7:0]   data_out1_dly   ;   //fifo1数据输出寄存
reg     [7:0]   data_out2_dly   ;   //fifo2数据输出寄存
reg             dout_flag   ;   //使能信号
reg             rd_en_dly1  ;   //输出数据标志信号,延后rd_en一拍
reg             rd_en_dly2  ;   //a,b,c赋值标志信号
reg             gx_gy_flag  ;   //gx,gy计算标志信号
reg             gxy_flag    ;   //gxy计算标志信号
reg             compare_flag;   //阈值比较标志信号
reg     [7:0]   cnt_rd      ;   //读出数据计数器
reg     [7:0]   a1          ;
reg     [7:0]   a2          ;
reg     [7:0]   a3          ;
reg     [7:0]   b1          ;
reg     [7:0]   b2          ;
reg     [7:0]   b3          ;
reg     [7:0]   c1          ;
reg     [7:0]   c2          ;
reg     [7:0]   c3          ;   //图像数据
reg     [8:0]   gx          ;
reg     [8:0]   gy          ;   //gx,gy
reg     [7:0]   gxy         ;   //gxy

//********************************************************************//
//***************************** Main Code ****************************//
//********************************************************************//
//cnt_h:行数据个数计数器
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_h   <=  8'd0;
    else    if((cnt_h == (LENGTH_P - 1'b1)) && (pi_flag == 1'b1))
        cnt_h   <=  8'd0;
    else    if(pi_flag == 1'b1)
        cnt_h   <=  cnt_h + 1'b1;

//cnt_v:场计数器
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_v   <=  8'd0;
    else    if((cnt_v == (WIDE_P - 1'b1)) && (pi_flag == 1'b1)
            && (cnt_h == (LENGTH_P - 1'b1)))
        cnt_v   <=  8'd0;
    else    if((cnt_h == (LENGTH_P - 1'b1)) && (pi_flag == 1'b1))
        cnt_v   <=  cnt_v + 1'b1;

//cnt_rd:fifo数据读出个数计数,用来判断何时对gx,gy进行运算
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_rd   <=  8'd0;
    else    if((cnt_rd == (LENGTH_P - 1'b1)) && (rd_en == 1'b1))
        cnt_rd   <=  8'd0;
    else    if(rd_en == 1'b1)
        cnt_rd   <=  cnt_rd + 1'b1;

//wr_en1:fifo1写使能,高电平有效
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        wr_en1  <=  1'b0;
    else    if((cnt_v == 8'd0) && (pi_flag == 1'b1))
        wr_en1  <=  1'b1;      //第0行写入fifo1
    else
        wr_en1  <=  dout_flag;  //2-198行写入fifo1

//wr_en2,fifo2的写使能,高电平有效
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        wr_en2  <=  1'b0;
    else    if((cnt_v >= 8'd1)&&(cnt_v <= ((WIDE_P - 1'b1) - 1'b1))
            && (pi_flag == 1'b1))
        wr_en2  <=  1'b1;      //2-199行写入fifo2
    else
        wr_en2  <=  1'b0;

//data_in1:fifo1的数据写入
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        data_in1    <=  8'b0;
    else    if((pi_flag == 1'b1) && (cnt_v == 8'b0))
        data_in1    <=  pi_data;
    else    if(dout_flag == 1'b1)
        data_in1    <=  data_out2;
    else
        data_in1    <=  data_in1;

//data_in2:fifo2的数据写入
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        data_in2    <=  8'b0;
    else    if((pi_flag == 1'b1) && (cnt_v >= 8'd1)
            && (cnt_v <= ((WIDE_P - 1'b1) - 1'b1)))
        data_in2    <=  pi_data;
    else
        data_in2    <=  data_in2;

//rd_en:fifo1和fifo2的共用读使能,高电平有效
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        rd_en   <=  1'b0;
    else    if((pi_flag == 1'b1) && (cnt_v >= 8'd2)
            && (cnt_v <= (WIDE_P - 1'b1)))
        rd_en   <=  1'b1;  
    else
        rd_en   <=  1'b0;


//dout_flag:控制fifo1写使能wr_en1
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        dout_flag   <=  1'b0;
    else    if((wr_en2 == 1'b1) && (rd_en == 1'b1))
        dout_flag   <=  1'b1;
    else
        dout_flag   <=  1'b0;

//rd_en_dly1:输出数据标志信号
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        rd_en_dly1  <=  1'b0;
    else    if(rd_en == 1'b1)
        rd_en_dly1  <=  1'b1;
    else
        rd_en_dly1  <=  1'b0;

//data_out1_dly:data_out1数据寄存
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        data_out1_dly   <=  8'b0;
    else    if(rd_en_dly1 == 1'b1)
        data_out1_dly   <=  data_out1;

//data_out2_dly:data_out2数据寄存
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        data_out2_dly   <=  8'b0;
    else    if(rd_en_dly1 == 1'b1)
        data_out2_dly   <=  data_out2;

//pi_data_dly:输入数据pi_data寄存
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        pi_data_dly <=  8'b0;
    else    if(rd_en_dly1 == 1'b1)
        pi_data_dly <=  pi_data;

//rd_en_dly2:a,b,c赋值标志信号
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        rd_en_dly2  <=  1'b0;
    else    if(rd_en_dly1 == 1'b1)
        rd_en_dly2  <=  1'b1;
    else
        rd_en_dly2  <=  1'b0;

//gx_gy_flag:gx,gy计算标志信号
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        gx_gy_flag  <=  1'b0;
    else    if((rd_en_dly2 == 1'b1) && ((cnt_rd >= 8'd3) || (cnt_rd == 8'd0)))
        gx_gy_flag  <=  1'b1;
    else
        gx_gy_flag  <=  1'b0;

//gxy_flag:gxy计算标准信号
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        gxy_flag    <=  1'b0;
    else    if(gx_gy_flag == 1'b1)
        gxy_flag    <=  1'b1;
    else
        gxy_flag    <=  1'b0;

//compare_flag,阈值比较标志信号
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        compare_flag    <=  1'b0;
    else    if(gxy_flag == 1'b1)
        compare_flag    <=  1'b1;
    else
        compare_flag    <=  1'b0;

//a,b,c赋值
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
    begin
        a1  <=  8'd0;
        a2  <=  8'd0;
        a3  <=  8'd0;
        b1  <=  8'd0;
        b2  <=  8'd0;
        b3  <=  8'd0;
        c1  <=  8'd0;
        c2  <=  8'd0;
        c3  <=  8'd0;
    end
    else    if(rd_en_dly2==1)
    begin
        a1  <=  data_out1_dly;
        b1  <=  data_out2_dly;
        c1  <=  pi_data_dly;
        a2  <=  a1;
        b2  <=  b1;
        c2  <=  c1;
        a3  <=  a2;
        b3  <=  b2;
        c3  <=  c2;
    end

//gx:计算gx
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        gx  <=  9'd0;
    else    if(gx_gy_flag == 1'b1)
        gx  <=  a3 - a1 + ((b3 - b1) << 1) + c3 - c1;
    else
        gx  <=  gx;

//gy:计算gy
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        gy  <=  9'd0;
    else    if(gx_gy_flag == 1'b1)
        gy  <=  a1 - c1 + ((a2 - c2) << 1) + a3 - c3;
    else
        gy  <=  gy;

//gxy:gxy计算
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        gxy <=  0;
    else    if((gx[8] == 1'b1) && (gy[8] == 1'b1) && (gxy_flag == 1'b1))
        gxy <=  (~gx[7:0] + 1'b1) + (~gy[7:0] + 1'b1);
    else    if((gx[8] == 1'b1) && (gy[8] == 1'b0) && (gxy_flag == 1'b1))
        gxy <=  (~gx[7:0] + 1'b1) + (gy[7:0]);
    else    if((gx[8] == 1'b0) && (gy[8] == 1'b1) && (gxy_flag == 1'b1))
        gxy <=  (gx[7:0]) + (~gy[7:0] + 1'b1);
    else    if((gx[8] == 1'b0) && (gy[8] == 1'b0) && (gxy_flag == 1'b1))
        gxy <=  (gx[7:0]) + (gy[7:0]);

//po_data:通过gxy与阈值比较,赋值po_data
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        po_data <=  8'b0;
    else    if((gxy >= THRESHOLD) && (compare_flag == 1'b1))
        po_data <=  BLACK;
    else    if(compare_flag == 1'b1)
        po_data <=  WHITE;

//po_flag:输出标志位
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        po_flag <=  1'b0;
    else    if(compare_flag == 1'b1)
        po_flag <=  1'b1;
    else
        po_flag <=  1'b0;
          
          
//inst
fifo    fifo_inst_1 (
    .clock ( sys_clk ),
    .data ( data_in1 ),
    .rdreq ( rd_en ),
    .wrreq ( wr_en1 ),
    .q ( data_out1 )
    );
    
fifo    fifo_inst_2 (
    .clock ( sys_clk ),
    .data ( data_in2 ),
    .rdreq ( rd_en ),
    .wrreq ( wr_en2 ),
    .q ( data_out2 )
    );
    
endmodule 

2.tb文件(读写txt文件)

代码如下(示例):

`timescale 1ns/1ps
module  sobel_edge_tb;

    reg                 sys_clk;
    reg                    sys_rst_n;

    reg     [7:0]             pi_data;
    reg                 pi_flag;

    wire [7:0]             po_data;
    wire                po_flag;

    reg     [7:0]            sobel_mem[127747:0];
    reg     [18:0]            addr;
    
    integer                fid;
    initial                 fid=$fopen("sobel_out.txt");

    always @ (posedge sys_clk,negedge sys_rst_n)
    begin
        if(po_flag==1'b1)
            $fdisplay(fid,"%d",po_data);
    end

    initial    sys_clk=0;
    always #10 sys_clk=~sys_clk;
    initial $readmemh("sobel.txt",sobel_mem);

initial begin
        sys_rst_n=0;
        pi_data=0;
        pi_flag=0;
        addr=0;
        #105;
        sys_rst_n=1;

    repeat (127748) begin
        @(posedge sys_clk);
        #2;
        pi_data=sobel_mem[addr];
        pi_flag=1;
        #5;
        addr=addr+1;
    end
    
        @(posedge sys_clk);
        #2;
        pi_data=0;
        pi_flag=0;
    
        #200;
        $fclose(fid);
        $stop;
end

//inst
sobel_edge   sobel_edge_inst(
    .  sys_clk              (sys_clk),
    .  sys_rst_n            (sys_rst_n),
    
    .  pi_data              (pi_data),                
    .  pi_flag              (pi_flag),                
    
    .  po_data              (po_data),                
    .  po_flag              (po_flag)                 
);

endmodule 

注意的问题

实际上txt文件在转成图像的时候,会有很多的夹杂的噪声,有能力的最好还是外接一个显示器。文章来源地址https://www.toymoban.com/news/detail-479133.html

到了这里,关于基于fpga的sobel边缘检测的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 基于ZYNQ的OV5640摄像头的sobel算子边缘检测

    最近鸽了挺久的,因为最近要做课设,再加上被这个工程的调试给难到了。 在做该工程的时候,有一个良好的项目管理习惯会让开发的时候不会让人那么的高血压。 特别要注意的是,异步FIFO的读写时钟的速率匹配问题,这个问题卡了我好久。 Sobel 算法是像素图像边缘检测中

    2024年01月20日
    浏览(30)
  • 基于FPGA的图像sobel边缘提取算法开发,包括tb测试文件以及matlab验证代码

    目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 vivado2019.2 matlab2022a         图像边缘检测大幅度地减少了数据量,并且剔除了可以认为不相关的信息,保留了图像重要的结构属性。有许多方法用于边缘检测,它们的绝大部

    2024年02月10日
    浏览(35)
  • 图像边缘检测--(Sobel、Laplacian、Canny)

    1、图像中各种形状的检测是计算机视觉领域中非常常见的技术之一,特别是图像中直线的检测,圆的检测,图像边缘的检测等,下面将介绍如何快速检测图像边缘。 2、边缘是不同区域的分界线,是周围(局部)像素有显著变化的像素的集合,有幅值与方向两个属性。这个不

    2024年02月07日
    浏览(37)
  • Python Opencv实践 - Sobel边缘检测

         

    2024年02月10日
    浏览(33)
  • 《opencv实用探索·十一》opencv之Prewitt算子边缘检测,Roberts算子边缘检测和Sobel算子边缘检测

    1、前言 边缘检测: 图像边缘检测是指在图像中寻找灰度、颜色、纹理等变化比较剧烈的区域,它们可能代表着物体之间的边界或物体内部的特征。边缘检测是图像处理中的一项基本操作,可以用于人脸识别、物体识别、图像分割等多个领域。 边缘检测实质上是计算当前点和

    2024年02月22日
    浏览(42)
  • ZYNQ图像处理(7)——sobel边缘检测

    所谓边缘是指其周围像素灰度急剧变化的那些象素的集合,它是图像最基本的特征。边缘存在于目标、背景和区域之间,所以,它是图像分割所依赖的最重要的依据。由于边缘是位置的标志,对灰度的变化不敏感,,因此,边缘也是图像匹配的重要的特征。边缘检测和区域划分

    2024年02月05日
    浏览(47)
  • 【OpenCv • c++】基础边缘检测算子 —— Sobel

    🚀 个人简介:CSDN「 博客新星 」TOP 10 , C/C++ 领域新星创作者 💟 作    者: 锡兰_CC ❣️ 📝 专    栏: 【OpenCV • c++】计算机视觉 🌈 若有帮助,还请 关注➕点赞➕收藏 ,不行的话我再努努力💪💪💪

    2024年02月03日
    浏览(38)
  • OpenCV—Sobel边缘检测的python代码实现

    目录 一、前言 二、主要参数 三、代码实现及效果展示 在 计算机视觉 和 图像处理 中,边缘通常包含了有关对象轮廓和结构的重要信息。OpenCV 是一个流行的计算机视觉库,它提供了许多用于边缘检测的工具,其中之一就是Sobel算子。 什么是Sobel算子? Sobel算子是一种基于卷

    2024年02月03日
    浏览(33)
  • OpenCV(7):边缘检测之Sobel算子,Scharr算子,Laplacian算子和Canny算子边缘检测

    Sobel算子、Scharr算子、Laplacian算子和Canny算子都是常用的图像边缘检测算法。它们可以用来识别图像中物体之间的边界,从而对物体进行定位、跟踪、分割、识别等处理。 Sobel算子和Scharr算子都是基于卷积运算实现的边缘检测算法。Sobel算子使用两个3×3的矩阵对原始图像进行卷

    2024年02月05日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包