基于Sobel算法的边沿检测设计与实现
基于Sobel算法的边沿检测设计与实现
- 1. 边缘检测
- 2. 实战演练
- 2.1. matlab进行灰度图像生成
- 2.2. sobel_ctrl控制模块
- 2.3. vga显示模块
- 2.4. 顶层模块实例化
- 2.5. 仿真与下板测试
1. 边缘检测
边缘检测,针对的是灰度图像,顾名思义,检测图像的边缘,是针对图像像素点的一种计算,目的是标识数据图像中灰度变化明显的点,图像的边缘检测,在保留了图像的重要结构信息的同时,剔除了可以认为不相关的信息,大幅度减少了数据量,便于图像的传输和处理
边缘检测的实现方式:基于查找的方式、零穿越
Sobel算法属于基于查找的方式,两个sobel算子是固定的
先转灰度图像,之后的边缘显示看VGA输出
2. 实战演练
将图像用软件转成灰度图像,然后将灰度图像的高三位取出进行保存,通过串口将图像数据传给FPGA,随后FPGA通过Sobel算法检测图像轮廓,然后将处理后的图片通过VGA显示640*480@60,图像大小为100 * 100
时钟生成模块调用IP核,rx、tx模块实现过,vga显示和控制模块也实现过,需要实现的就是sobel算法模块,已经顶层模块的编写
2.1. matlab进行灰度图像生成
clc; %清理命令行窗口
clear all; %清理工作区
image = imread('logo.png'); %使用imread函数读取图片数据
figure; %创建一个窗口
imshow(image); %窗口显示图片
R = image(:,:,1); %提取图片中的红色层生成灰度图像
figure;
imshow(R); %窗口显示灰色图像
[ROW,COL] = size(R); %灰色图像大小参数
data = zeros(1,ROW*COL); %定义一个初值为0的数组,存储转换后的图片数据
for r = 1:ROWfor c = 1 : COLdata((r-1)*COL+c) = bitshift(R(r,c),-5); %红色层数据右移5位end
end
fid = fopen('logo.txt','w+'); %打开或新建一个txt文件
for i = 1:ROW*COL;fprintf(fid,'%02x ',data(i)); %写入图片数据
end
fclose(fid);
2.2. sobel_ctrl控制模块
这里用到的算法就是sobel算法,其中两个sobel算子是固定的参数,图像数据是通过串口发送给fpga的
图像数据是以数据流的方式传送的,在图片数据流中就要提取三行三列的数据参与运算,数据提取的方式就可以参考之前的FIFO求和,用FIFO进行数据的缓存和提取
module sobel_ctrl (input wire sys_clk ,input wire sys_rst_n ,input wire pi_flag ,input wire [ 7: 0] pi_data ,output reg po_flag ,output reg [ 7: 0] po_data
);// 100行100列的数据矩阵parameter CNT_COL_MAX = 8'd100;parameter CNT_ROW_MAX = 8'd100;// 阈值参数parameter THR = 8'b000_011_00;// 颜色参数RGB332格式parameter BLACK = 8'b000_000_00;parameter WHITE = 8'b111_111_11;reg [ 7: 0] cnt_col ;reg [ 7: 0] cnt_row ;reg wr_en_1 ;reg [ 7: 0] wr_data_1 ;reg wr_en_2 ;reg [ 7: 0] wr_data_2 ;reg rd_en ;wire [ 7: 0] dout_1 ;wire [ 7: 0] dout_2 ;reg dout_flag ;reg [ 7: 0] cnt_rd ;reg [ 7: 0] dout_1_reg ;reg [ 7: 0] dout_2_reg ;reg [ 7: 0] pi_data_reg ;reg rd_en_reg ;reg rd_en_reg1 ;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 gx_gy_flag ;reg [ 8: 0] gx ; // 最高位为符号位reg [ 8: 0] gy ;reg gxy_flag ;reg [ 7: 0] gxy ;reg com_flag ;// cnt_col:列计数器always @ (posedge sys_clk or negedge sys_rst_n)if (sys_rst_n == 1'b0)cnt_col <= 8'd0;else if ((cnt_col == CNT_COL_MAX - 1'b1) && (pi_flag == 1'b1))cnt_col <= 8'b0;else if (pi_flag == 1'b1)cnt_col <= cnt_col + 1'b1;// cnt_row:行计数器always @ (posedge sys_clk or negedge sys_rst_n)if (sys_rst_n == 1'b0)cnt_row <= 8'd0;else if ((cnt_row == CNT_ROW_MAX - 1'b1) && (cnt_col == CNT_COL_MAX - 1'b1) && (pi_flag == 1'b1))cnt_row <= 8'd0;else if ((cnt_col == CNT_COL_MAX - 1'b1) && (pi_flag == 1'b1))cnt_row <= cnt_row + 1'b1;// wr_en_1:FIFO_1写使能always @ (posedge sys_clk or negedge sys_rst_n)if (sys_rst_n == 1'b0)wr_en_1 <= 1'b0;else if ((cnt_row == 8'd0) && (pi_flag == 1'b1))wr_en_1 <= 1'b1;elsewr_en_1 <= dout_flag;// wr_data_1:FIFO_1写数据always @ (posedge sys_clk or negedge sys_rst_n)if (sys_rst_n == 1'b0)wr_data_1 <= 8'd0;else if ((cnt_row == 8'd0) && (pi_flag == 1'b1))wr_data_1 <= pi_data;else if (dout_flag == 1'b1)wr_data_1 <= dout_2;// wr_en_2:FIFO_2写使能always @ (posedge sys_clk or negedge sys_rst_n)if (sys_rst_n == 1'b0)wr_en_2 <= 1'b0;else if ((cnt_row >= 8'd1) && (cnt_row <= CNT_ROW_MAX - 2) && (pi_flag == 1'b1)) // 第1、2、3行写入FIFO_2wr_en_2 <= 1'b1;elsewr_en_2 <= 1'b0;// wr_data_2:FIFO_2写数据always @ (posedge sys_clk or negedge sys_rst_n)if (sys_rst_n == 1'b0)wr_data_2 <= 8'd0;else if ((cnt_row >= 8'd1) && (cnt_row <= CNT_ROW_MAX - 2) && (pi_flag == 1'b1))wr_data_2 <= pi_data;elsewr_data_2 <= wr_data_2;// rd_en:读使能always @ (posedge sys_clk or negedge sys_rst_n)if (sys_rst_n == 1'b0)rd_en <= 1'b0;else if ((cnt_row >= 8'd2) && (cnt_row <= CNT_ROW_MAX - 1'b1) && (pi_flag == 1'b1))rd_en <= 1'b1;elserd_en <= 1'b0;// dout_flag:FIFO读出标志信号,用于产生FIFO_1写使能信号always @ (posedge sys_clk or negedge sys_rst_n)if (sys_rst_n == 1'b0)dout_flag <= 1'b0;else if ((wr_en_2 == 1'b1) && (rd_en == 1'b1))dout_flag <= 1'b1;elsedout_flag <= 1'b0;// cnt_rd:读数据计数器always @ (posedge sys_clk or negedge sys_rst_n)if (sys_rst_n == 1'b0)cnt_rd <= 8'd0;else if ((cnt_rd == CNT_COL_MAX - 1'b1) && (rd_en == 1'b1)) // 一行数据读出cnt_rd <= 8'd0;else if (rd_en == 1'b1)cnt_rd <= cnt_rd + 1'b1;// dout_1_reg:always @ (posedge sys_clk or negedge sys_rst_n)if (sys_rst_n == 1'b0)dout_1_reg <= 8'd0;else if (rd_en_reg == 1'b1)dout_1_reg <= dout_1;// dout_2_reg:always @ (posedge sys_clk or negedge sys_rst_n)if (sys_rst_n == 1'b0)dout_2_reg <= 8'd0;else if (rd_en_reg == 1'b1)dout_2_reg <= dout_2;// pi_data_reg:always @ (posedge sys_clk or negedge sys_rst_n)if (sys_rst_n == 1'b0)pi_data_reg <= 8'd0;else if (rd_en_reg == 1'b1)pi_data_reg <= pi_data;// rd_en_reg:always @ (posedge sys_clk or negedge sys_rst_n)if (sys_rst_n == 1'b0)rd_en_reg <= 1'b0;else if (rd_en == 1'b1)rd_en_reg <= 1'b1;elserd_en_reg <= 1'b0;// rd_en_reg1:a、b、c赋值标志信号always @ (posedge sys_clk or negedge sys_rst_n)if (sys_rst_n == 1'b0)rd_en_reg1 <= 1'b0;else if (rd_en_reg == 1'b1)rd_en_reg1 <= 1'b1;elserd_en_reg1 <= 1'b0;// a1、a2、a3、b1、b2、b3、c1、c2、c3always @ (posedge sys_clk or negedge sys_rst_n)if (sys_rst_n == 1'b0)begina1 <= 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;endelse if (rd_en_reg1 == 1'b1)begina1 <= a2;a2 <= a3;a3 <= dout_1_reg;b1 <= b2;b2 <= b3;b3 <= dout_1_reg;c1 <= c2;c2 <= c3;c3 <= pi_data_reg;end// 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_reg1 == 1'b1) && ((cnt_rd >= 8'd3) || (cnt_rd == 8'd0)))gx_gy_flag <= 1'b1;elsegx_gy_flag <= 1'b0;// gx:Gx = (a3-a1) + (b3-b1)*2 + (c3-c1)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); // 左移1位,扩大二倍elsegx <= gx;// gy:Gy = (a1-c1) + (a2-c2)*2 + (a3-c3)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); // 左移1位,扩大二倍elsegy <= gy;// 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;elsegxy_flag <= 1'b0;// gxy:Gxy = √[(Gx)^2+(Gy)^2] ≈ (|Gx| + |Gy|)always @ (posedge sys_clk or negedge sys_rst_n)if (sys_rst_n == 1'b0)gxy <= 8'd0;else if ((gx[8] == 1'b1) && (gy[8] == 1'b1) && (gxy_flag == 1'b1)) // gx为负,gy为负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)) // gx为负,gy为正gxy <= (~gx[7:0] + 1'b1) + (gy[7:0]);else if ((gx[8] == 1'b0) && (gy[8] == 1'b1) && (gxy_flag == 1'b1)) // gx为正,gy为负gxy <= (gx[7:0]) + (~gy[7:0] + 1'b1);else if ((gx[8] == 1'b0) && (gy[8] == 1'b0) && (gxy_flag == 1'b1)) // gx为正,gy为正gxy <= (gx[7:0]) + (gy[7:0]);// com_flag:阈值比较信号always @ (posedge sys_clk or negedge sys_rst_n)if (sys_rst_n == 1'b0)com_flag <= 1'b0;else if (gxy_flag == 1'b1)com_flag <= 1'b1;elsecom_flag <= 1'b0;// po_data:always @ (posedge sys_clk or negedge sys_rst_n)if (sys_rst_n == 1'b0)po_data <= 8'd0;else if ((com_flag == 1'b1) && (gxy > THR))po_data <= BLACK;else if (com_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;elsepo_flag <= com_flag;fifo fifo_1 (.clk (sys_clk ), // input wire clk.rst (~sys_rst_n ), // input wire rst.din (wr_data_1 ), // input wire [7 : 0] din.wr_en (wr_en_1 ), // input wire wr_en.rd_en (rd_en ), // input wire rd_en.dout (dout_1 ), // output wire [7 : 0] dout.full ( ), // output wire full.empty ( ) // output wire empty);fifo fifo_2 (.clk (sys_clk ), // input wire clk.rst (~sys_rst_n ), // input wire rst.din (wr_data_2 ), // input wire [7 : 0] din.wr_en (wr_en_2 ), // input wire wr_en.rd_en (rd_en ), // input wire rd_en.dout (dout_2 ), // output wire [7 : 0] dout.full ( ), // output wire full.empty ( ) // output wire empty);endmodule
2.3. vga显示模块
实例化之前实现过的vga_ctrl模块和vga_pic模块
vga_pic模块需要重新确定图片显示的区域:
100x100大小的图像,经过sobel算法之后的大小为【98x98】
列求和实验:n×m大小 ——> p×q大小 p = n-(x-1) q = m
eg. 5x5大小的矩阵,经过列求和会变成3x5的新矩阵
sobel算法是三行三列进行求和,
进行三行的列求和会少两行,进行三行的行求和会少两列
parameter H_PIC = 10'd98,V_PIC = 10'd98;parameter PIC_SIZE= 14'd9604; // 98x98=9604
module vga (input wire sys_clk , // 50MHzinput wire vga_clk , // 25MHzinput wire sys_rst_n ,input wire [ 7: 0] pi_data ,input wire pi_flag ,output wire [11: 0] rgb ,output wire hsync ,output wire vsync
);wire [ 9: 0] pix_x ;wire [ 9: 0] pix_y ;wire [ 7: 0] pix_data;wire [ 7: 0] rgb_332 ; // 332vga_ctrl vga_ctrl_inst (.vga_clk (vga_clk ), // 25MHz.sys_rst_n (sys_rst_n ),.pix_data (pix_data ),.pix_x (pix_x ),.pix_y (pix_y ),.hsync (hsync ),.vsync (vsync ),.rgb (rgb_332 ));vga_pic vga_pic_inst (.rx_clk (sys_clk ), // 50MHz.vga_clk (vga_clk ), // 25MHz.sys_rst_n (sys_rst_n ),.pix_x (pix_x ),.pix_y (pix_y ),.pi_data (pi_data ),.pi_flag (pi_flag ),.pix_data (pix_data ));assign rgb = {2'b0, rgb_332[7:6], 1'b0, rgb_332[5:3], 1'b0, rgb_332[2:0]};endmodule
2.4. 顶层模块实例化
module sobel (input wire sys_clk ,input wire sys_rst_n ,input wire rx ,output wire hsync ,output wire vsync ,output wire [11: 0] rgb ,output wire tx
);parameter CLK_FREQ = 'd50_000_000; wire clk_25M ; // vgawire clk_50M ; // uartwire locked ;wire [ 7: 0] rx_data ;wire rx_flag ;wire [ 7: 0] po_data ;wire po_flag ;wire rst_n = sys_rst_n && locked;clk_gen instance_name(// Clock out ports.clk_out1 (clk_25M ), // output clk_out1.clk_out2 (clk_50M ), // output clk_out2// Status and control signals.reset (~sys_rst_n ), // input reset.locked (locked ), // output locked// Clock in ports.clk_in1 (sys_clk ) // input clk_in1); uart_rx#(.UART_BPS ('d9600 ),.CLK_FREQ (CLK_FREQ ))uart_rx_inst(.sys_clk (clk_50M ),.sys_rst_n (rst_n ),.rx (rx ),.po_data (rx_data ),.po_flag (rx_flag ));uart_tx#(.UART_BPS ('d9600 ),.CLK_FREQ (CLK_FREQ ))uart_tx_inst(.sys_clk (clk_50M ),.sys_rst_n (rst_n ),.pi_data (po_data ),.pi_flag (po_flag ),.tx (tx ));vga vga_inst (.sys_clk (clk_50M ),.vga_clk (clk_25M ),.sys_rst_n (rst_n ),.pi_data (po_data ),.pi_flag (po_flag ),.rgb (rgb ),.hsync (hsync ),.vsync (vsync ));sobel_ctrl sobel_ctrl_inst (.sys_clk (clk_50M ),.sys_rst_n (rst_n ),.pi_flag (rx_flag ),.pi_data (rx_data ),.po_flag (po_flag ),.po_data (po_data ));endmodule
2.5. 仿真与下板测试
tb模块的代码复用之前串口发送数据到FPGA然后由VGA显示的工程代码,只需要修改添加输出信号tx和读文件地址
`timescale 1ns / 1nsmodule sobel_tb ();reg sys_clk ;reg sys_rst_n ;reg rx ;wire hsync ;wire vsync ;wire [11: 0] rgb ;wire tx ;initial beginsys_clk <= 1'b0;sys_rst_n <= 1'b0;#20sys_rst_n <= 1'b1;endalways #5 sys_clk = ~sys_clk;reg [ 7: 0] data_mem[9999: 0]; // 存储器,用来产生模拟图片数据initial begin
// $readmemh ("C:/Users/123/Desktop/Vivado_test/VGA_uart_pic/matlab/mine/bird_RGB332.txt", data_mem);$readmemh ("C:/Users/123/Desktop/Vivado_test/Sobel/matlab/logo.txt", data_mem);endinitial beginrx = 1'b1;#200rx_byte (); end// 17mssobel sobel_inst (.sys_clk (sys_clk ),.sys_rst_n (sys_rst_n ),.rx (rx ),.hsync (hsync ),.vsync (vsync ),.rgb (rgb ),.tx (tx ));// defparam vga_uart_pic_inst.uart_rx_inst.BAUD_CNT_MAX = 52;
// parameter可用作在顶层模块中例化底层模块时传递参数的接口,
// localparam的作用域仅仅限于当前module,不能作为参数传递的接口
// 为了仿真简单,可以去uart_tx把BAUD_CNT_MAX改成52// 或者重定义defparam sobel_inst.CLK_FREQ = 'd50_000_0;task rx_byte ();integer j;beginfor (j = 0; j < 10000; j = j + 1)rx_bit(data_mem[j]);endendtasktask rx_bit;input [ 7: 0] data ;integer i;beginfor (i = 0; i < 10; i = i + 1) begincase (i)0: rx <= 1'b0;1: rx <= data[0];2: rx <= data[1];3: rx <= data[2];4: rx <= data[3];5: rx <= data[4];6: rx <= data[5];7: rx <= data[6];8: rx <= data[7];9: rx <= 1'b1;default: rx <= 1'b1;endcase
// #(5208 * 20)#(52 * 20)
// #(5 * 20);endendendtaskendmodule
下板成功
基于Sobel算法的边沿检测设计与实现相关推荐
- 基于sobel算法的边缘检测设计与实现
基于sobel算法的边缘检测设计与实现 边缘是图像的基本特征.边缘检测针对的是灰度图像,目的是标识数字图像中灰度变化明显的点. 边缘检测的方法大致可以分为两类:基于查找的一类,通过寻找图像一阶导数中最 ...
- 【FPGA】基于OV5640的 图像边沿检测
目录 一 项目结构 1.1 设计思路 1.2 设计流程 二 接口设计 2.1 摄像头配置模块 2.2 IIC_master 模块 之后就进行数据采集 2.3 采集数据模块 2.4 灰度转化 2.5 ...
- sobel算子原理_「学术论文」基于Sobel算法图像边缘检测的FPGA实现
摘要: 针对嵌入式软件无法满足数字图像实时处理速度问题,提出用硬件加速器的思想,通过FPGA实现Sobel边缘检测算法.通过乒乓操作.并行处理数据和流水线设计,大大提高算法的处理速度.采用模块的硬件设 ...
- matlab ds18b20 单片机,基于51单片机ds18b20温度检测————设计报告.doc
基于51单片机ds18b20温度检测----设计报告 课程名称: 微机原理课程设计 题 目: 温度检测课程设计 摘要 随着时代的进步和发展,单片机技术已经普及到我们生活,工作,科研,各个领域,已经成为 ...
- 基于Adaboost算法的车牌检测在OpenCV上的研究与实现
目录结构 E:\Adaboost\ ---------positive\ //正样本文件夹 ---------pimages\ //正样本图片所在文件夹 --- ...
- 【MFC基础入门】基于Adaboost算法的车牌检测在OpenCV上的研究与实现
目录结构 E:\Adaboost\---------positive\ //正样本文件夹---------pimages\ //正样本图片所在文件夹---------pos.dat //正样本集描述文 ...
- YOLOv7如何提高目标检测的速度和精度,基于优化算法提高目标检测速度
目录 一.学习率调度 二.权重衰减和正则化 三.梯度累积和分布式训练 1.梯度累积 2.分布式训练 四.自适应梯度裁剪 大家好,我是哪吒. 上一篇介绍了YOLOv7如何提高目标检测的速度和精度,基于模 ...
- 基于51单片机的火灾检测设计(仿真+程序+原理图+论文报告)
本设计: 基于51单片机的火灾检测设计(仿真+程序+原理图+论文报告) Proteus仿真版本:proteus7.8 原理图:Altium Designer 程序编译器:keil 4 编程语言:C语言 ...
- 基于DCT算法的图像模糊检测
文章目录 基于DCT算法的图像模糊检测 1.离散余弦变换DCT 2.基于离散余弦变换DCT来估计图像模糊度的图像质量评价算法 总结 基于DCT算法的图像模糊检测 转载: https://yinguob ...
最新文章
- 一个web左侧菜单例子
- 移动数据平台mParticle获1750万美元B轮融资,帮助企业快速获取客户数据
- haproxy 作为反向代理被攻击
- php发送验证码短信,php发送短信验证码
- React条件渲染列表渲染
- matlab 赋空值,未对输出参数赋值 求大神帮忙解惑
- 怎么查看python文件的代码_python实现代码查看列举目录下的文件
- Redis学习---(15)Redis 脚本
- python软件如何下载-python软件怎么样?实际的操作方法来了
- 企业大数据分析平台如何构建
- [云计算]交换机二层端口access、trunk、hybird的理解
- Hibernate中的merge方法
- 幼儿园调查过程怎么写_关于幼儿园的调查报告格式及范文
- Windows兼容性设置图文教程,Windows兼容模式怎么设置?
- RBF技术实现“双花漏洞”研究
- 华为设备接口视图_华为交换机的三种视图
- Character.UnicodeBlock中cjk的说明
- velocity 模板语法
- Ubuntu软件安装与更改镜像源(超详细)
- ExBPA工具的使用方法