FPGA实现边缘检测Sobel算法

简介: 笔记

一. Sobel算法


首先先在这里,介绍一下Sobel算法的原理,以及实现过程,由于Sobel算法并不复杂,可以说是相对简单的,就不作过多的介绍.

100.png


二. dx,dy的求法


dx方向的核值如下,核值与图像上3*3的区域对应相乘然后相加,

1.png

dy同dx求法一样

2.png


最后判断对应图像3*3区域的中心点是否为边缘点


当然核值的1,2是可以修改的,例如3,10


上面就简单的介绍了一下Sobel算法的原理以及实现步骤,接下来就在FPGA中实现它吧。


三. 目标图片的准备


我们先将图片写入rom中,然后将数据从rom中读出进行处理。

先借助python和opencv将图片转为灰度图,然后生成mif文件,代码如下

import numpy as np
import matplotlib.pyplot as plt
import os
import shutil
import cv2
headfile = '''
DEPTH = 10000;
WIDTH = 8;
ADDRESS_RADIX = HEX;
DATA_RADIX = HEX;
CONTENT
BEGIN
'''
img = cv2.imread("13.png")     #读取图片
img = cv2.resize(img,(100,100))  #将图片resize到100*1001的大小
img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)    #将图片转为灰度图
mif = open('image.mif', 'w')
mif.writelines(headfile)
i = 0
for m in range(0,100):
    for n in range(0,100):
        mif.writelines(str(hex(i)[2:]))
        mif.writelines(' : ')
        mif.writelines(str(hex(img[m][n]))[2:])# + str(hex(img[n][m][1]))[2:] + str(hex(img[n][m][0]))[2:])
        mif.writelines(';')
        mif.writelines('\n')
        i += 1
mif.write('END;')

经过上面的代码,就可以生成mif文件了,然后在软件中调用单端rom的ip,并且选择mif就可以了,位宽8,深度10000。


根据我们的dx,dy的核值,可以看出,每一次操作需要三行图像数据,
以及每一行图像数据的三个连续的值。
所以我们需要两个ram来存储两行数据,另外一行为当前读取的数据,
不需要事先存储,连续的三个值可以用延时


四. 两行图像数据的存储


先事先声明一下如下数据


reg[7:0]  data_line_11,data_line_12,data_line_13;  #第一行数据的3个值
reg[7:0]  data_line_21,data_line_22,data_line_23;  #第二行数据的3个值
reg[7:0]  data_line_31,data_line_32,data_line_33;  #第三行数据的3个值


采用双端ram,进行存储数据,由于图像的宽度为100,所以深度为128即可。

实例出来代码如下


RAM RAM_V1(
  .clock(clk_9M),    //时钟
  .data(ram1_data_in),  //写入的数据
  .rdaddress(ram1_raddr), //读出的地址
  .wraddress(ram1_waddr), //写入的地址
  .wren(1'b1),      //读写使能
  .q(ram1_data_out)); //读出的数据
RAM RAM_V2(
  .clock(clk_9M),
  .data(ram2_data_in),
  .rdaddress(ram2_raddr),
  .wraddress(ram2_waddr),
  .wren(1'b1),
  .q(ram2_data_out));


为了使最边缘的图像数据建立起3*3的区域,这里将图像的最框添加了0像素值,所以现在处理的图像数据大小为102 * 102了。


假定一二行数据以及存储进去了,现在读取的是第三行。


当第三行读取到第三个数据时,是不是可以将第二行的数据的第一个更新为
 第三行读取到第一个数据,将第一行的数据的第一个更新为第二行数据的第一个
 同样当第三行数据读到第四,五,六...个数据时,依次更新第一行第二行的第二,
 三,四...个数据


假定第一行,第二行没有数据,当为显示到图像的第一行时,将第一行的数据写入0,然后按照1的方式更新第二行数据。


//图像显示的区域 cur_x >= 'd101 && cur_x <='d200 && 
//    cur_y >= 'd50 && cur_y < 'd150
//第一行 写
always@(posedge clk_9M or negedge rst)
begin
  if(rst == 1'b0)
  ram1_waddr <= 'd0;
  else if(cur_x >= 'd100 && cur_x <= 'd201 && cur_y >= 'd49)
  ram1_waddr <= ram1_waddr + 1'b1;
  else
  ram1_waddr <= 'd0;
end
always@(posedge clk_9M or negedge rst)
begin
  if(rst == 1'b0)
  ram1_data_in <= 'd0;
  else if(cur_x >= 'd100 && cur_x <= 'd201 && cur_y >= 'd49)
  if(cur_y == 'd49)
    ram1_data_in <= 'd0;
  else
    ram1_data_in <= data_line_21;
end
//第二行 写
always@(posedge clk_9M or negedge rst)
begin
  if(rst == 1'b0)
  ram2_waddr <= 'd0;
  else if(cur_x >= 'd100 && cur_x <= 'd201 && cur_y >= 'd49)
  ram2_waddr <= ram2_waddr + 1'b1;
  else
  ram2_waddr <= 'd0;
end
always@(posedge clk_9M or negedge rst)
begin
  if(rst == 1'b0)
  ram2_data_in <= 'd0;
  else if(cur_x >= 'd100 && cur_x <= 'd201 && cur_y >= 'd49)
  ram2_data_in <= data_line_31;
end


五. 三行数据的读取


这个较为简单了,直接从对应的rom和ram中读出即可

下面代码是第二行和第三行的,第一行就不拿出来了,都一模一样的。


always@(posedge clk_9M or negedge rst)
begin
  if(rst == 1'b0)
  begin
    data_line_21 = 'd0;
    data_line_22 = 'd0;
    data_line_23 = 'd0;
  end
  //这里读取的cur_x的值对比于显示的值需要注意一下
  else if(cur_x >= 'd98 && cur_x <= 'd199 && cur_y >= 'd50) 
  begin
    data_line_21 <= data_line_22;
    data_line_22 <= data_line_23;
    data_line_23 <= ram2_data_out;  
  end
  else
  begin
    data_line_21 <= data_line_22;
    data_line_22 <= data_line_23;
    data_line_23 <= 'd0;  
  end
end
always@(posedge clk_9M or negedge rst)
begin
  if(rst == 1'b0)
  begin
    data_line_31 <= 'd0;
    data_line_32 <= 'd0;
    data_line_33 <= 'd0;
  end
  else if(cur_x >= 'd98 && cur_x <= 'd199 && cur_y >= 'd49 && cur_y < 149)
  begin
    data_line_33 <= img;
    data_line_32 <= data_line_33;
    data_line_31 <= data_line_32;
  end
  else
  begin
    data_line_31 <= data_line_32;
    data_line_32 <= data_line_33;
    data_line_33 <= 'd0;
  end
end


六. 进行Sobel运算


这里需要注意一下dx和dy的值可能会有1000多,所以说其位宽不在是8了而是10.


分别计算负的和正的,然后判断大小,最近用大的减去小的。最后与阈值进行判断来赋值。 阈值的大小不是0-255了,而是0-1520(肯能不太准确),我下面的是1035.


reg[10:0] Sobel_px ,Sobel_nx;
reg[10:0] Sobel_py ,Sobel_ny;
wire[10:0]  Sobel_x;
wire[10:0]  Sobel_y;
wire[7:0] Sobel_data;
assign Sobel_x = (Sobel_px > Sobel_nx) ? (Sobel_px - Sobel_nx) : (Sobel_nx - Sobel_px);
assign Sobel_y = (Sobel_py > Sobel_ny) ? (Sobel_py - Sobel_ny) : (Sobel_ny - Sobel_py);
assign Sobel_data = (Sobel_x + Sobel_y > 'd1035) ? 'd0 : 'd255;
always@(posedge clk_9M or negedge rst)
begin
  if(rst == 1'b0)
  begin
    Sobel_px <= 'd0;
    Sobel_nx <= 'd0;
  end
  else if(cur_x >= 'd100 && cur_x <= 'd199 && cur_y >= 'd50)
  begin
    Sobel_nx <= data_line_11 + data_line_21 + data_line_21 + data_line_31;
    Sobel_px <= data_line_13 + data_line_23 + data_line_23 + data_line_33;
  end
  else
  begin
  Sobel_nx <= 'd0;
  Sobel_px <= 'd0;
  end
end
always@(posedge clk_9M or negedge rst)
begin
  if(rst == 1'b0)
  begin
    Sobel_py <= 'd0;
    Sobel_ny <= 'd0;
  end
  else if(cur_x >= 'd100 && cur_x <= 'd199 && cur_y >= 'd50)
  begin
    Sobel_py <= data_line_11 + data_line_12 + data_line_12 + data_line_13;
    Sobel_ny <= data_line_31 + data_line_32 + data_line_32+ data_line_33;
  end
  else
  begin
    Sobel_ny <= 'd0;
    Sobel_py <= 'd0;
  end
end

最后给出在FPGA上的原图和效果图,效果不错,完整项目下载链接


3.pngimage.jpeg

欢迎关注公众号 FPGA之旅

公众号:FPGA之旅

目录
相关文章
|
7月前
|
存储 算法 生物认证
基于Zhang-Suen算法的图像细化处理FPGA实现,包含testbench和matlab验证程序
本项目基于Zhang-Suen算法实现图像细化处理,支持FPGA与MATLAB双平台验证。通过对比,FPGA细化效果与MATLAB一致,可有效减少图像数据量,便于后续识别与矢量化处理。算法适用于字符识别、指纹识别等领域,配套完整仿真代码及操作说明。
|
9月前
|
存储 算法 数据安全/隐私保护
基于FPGA的图像退化算法verilog实现,分别实现横向和纵向运动模糊,包括tb和MATLAB辅助验证
本项目基于FPGA实现图像运动模糊算法,包含横向与纵向模糊处理流程。使用Vivado 2019.2与MATLAB 2022A,通过一维卷积模拟点扩散函数,完成图像退化处理,并可在MATLAB中预览效果。
|
算法 数据安全/隐私保护 计算机视觉
基于FPGA的图像双线性插值算法verilog实现,包括tb测试文件和MATLAB辅助验证
本项目展示了256×256图像通过双线性插值放大至512×512的效果,无水印展示。使用Matlab 2022a和Vivado 2019.2开发,提供完整代码及详细中文注释、操作视频。核心程序实现图像缩放,并在Matlab中验证效果。双线性插值算法通过FPGA高效实现图像缩放,确保质量。
|
算法 数据安全/隐私保护 异构计算
基于LSB最低有效位的音频水印嵌入提取算法FPGA实现,包含testbench和MATLAB对比
本项目展示了一种基于FPGA的音频水印算法,采用LSB(最低有效位)技术实现版权保护与数据追踪功能。使用Vivado2019.2和Matlab2022a开发,完整代码含中文注释及操作视频。算法通过修改音频采样点的最低有效位嵌入水印,人耳难以察觉变化。然而,面对滤波或压缩等攻击时,水印提取可能受影响。该项目运行效果无水印干扰,适合实时应用场景,核心逻辑简单高效,时间复杂度低。
|
监控 算法 数据安全/隐私保护
基于三帧差算法的运动目标检测系统FPGA实现,包含testbench和MATLAB辅助验证程序
本项目展示了基于FPGA与MATLAB实现的三帧差算法运动目标检测。使用Vivado 2019.2和MATLAB 2022a开发环境,通过对比连续三帧图像的像素值变化,有效识别运动区域。项目包括完整无水印的运行效果预览、详细中文注释的代码及操作步骤视频,适合学习和研究。
|
算法 数据安全/隐私保护 异构计算
基于FPGA的变步长LMS自适应滤波器verilog实现,包括testbench
### 自适应滤波器仿真与实现简介 本项目基于Vivado2022a实现了变步长LMS自适应滤波器的FPGA设计。通过动态调整步长因子,该滤波器在收敛速度和稳态误差之间取得良好平衡,适用于信道均衡、噪声消除等信号处理应用。Verilog代码展示了关键模块如延迟单元和LMS更新逻辑。仿真结果验证了算法的有效性,具体操作可参考配套视频。
541 74
|
12月前
|
机器学习/深度学习 算法 数据安全/隐私保护
基于FPGA的SNN脉冲神经网络之LIF神经元verilog实现,包含testbench
本项目展示了 LIF(Leaky Integrate-and-Fire)神经元算法的实现与应用,含无水印运行效果预览。基于 Vivado2019.2 开发,完整代码配有中文注释及操作视频。LIF 模型模拟生物神经元特性,通过积分输入信号并判断膜电位是否达阈值产生脉冲,相较于 Hodgkin-Huxley 模型更简化,适合大规模神经网络模拟。核心程序片段示例,助您快速上手。
|
算法 数据安全/隐私保护 异构计算
基于FPGA的16QAM调制+软解调系统,包含testbench,高斯信道模块,误码率统计模块,可以设置不同SNR
本项目基于FPGA实现了16QAM基带通信系统,包括调制、信道仿真、解调及误码率统计模块。通过Vivado2019.2仿真,设置不同SNR(如8dB、12dB),验证了软解调相较于传统16QAM系统的优越性,误码率显著降低。系统采用Verilog语言编写,详细介绍了16QAM软解调的原理及实现步骤,适用于高性能数据传输场景。
678 69
|
算法 数据安全/隐私保护 异构计算
基于FPGA的2ASK+帧同步系统verilog开发,包含testbench,高斯信道,误码统计,可设置SNR
本内容展示了基于Vivado2019.2的算法仿真效果,包括设置不同信噪比(SNR=8db和20db)下的结果及整体波形。同时,详细介绍了2ASK调制解调技术的原理与实现,即通过改变载波振幅传输二进制信号,并提供数学公式支持。此外,还涉及帧同步理论,用于确定数据帧起始位置。最后,给出了Verilog核心程序代码,实现了2ASK解调与帧同步功能,结合DDS模块生成载波信号,完成信号处理流程。
263 0
|
编解码 算法 数据安全/隐私保护
基于FPGA的信号DM编解码实现,包含testbench和matlab对比仿真
本项目展示了DM编解码算法的实现与测试结果。FPGA测试结果显示为T1,Matlab仿真结果为T2。使用软件版本为Matlab 2022a和Vivado 2019.2。核心程序包含详细中文注释和操作视频。DM编解码通过比较信号样本差值进行编码,适用于音频等低频信号处理。硬件结构包括编码器(采样器、减法器、比较器)和解码器(解码器、积分器)。

热门文章

最新文章

下一篇
开通oss服务