【数字图像处理】边缘检测

边缘检测是一种图像处理技术,用于在图像中识别和提取物体边缘的信息,广泛应用于计算机视觉和图像分析领域。本文主要介绍数字图像边缘检测的基本原理,并记录在紫光同创 PGL22G FPGA 平台的布署与实现过程。

目录

1 边缘检测原理

2 FPGA 布署与实现

2.1 功能与指标定义

2.2 模块设计

2.3 上板调试


1 边缘检测原理

        边缘检测是一种数字图像处理技术,用于在图像中识别和提取物体边缘的信息,广泛应用于计算机视觉和图像分析领域。

        边缘检测的基本原理是利用图像中的亮度、颜色、纹理等差异,以及对象形状的不连续性,来检测图像中的边缘。常见的边缘检测算法包括 Prewitt、Sobel、Laplacian 等,这些算法可以生成一个边缘响应,图中每个像素点的值表示该位置周围边缘的强度。

        在边缘检测算法中,使用被称为算子的矩阵,例如 Prewitt 算子、Sobel 算子、Laplacian 算子等。算子在输入图像上移动时,重叠的区域进行卷积运算,得到输出图像上某个位置的响应。

Prewitt 算子

Prewitt_x = \begin{bmatrix} -1 & 0 & 1 \\ -1 & 0 & 1 \\ -1 & 0 & 1 \end{bmatrix}, Prewitt_y = \begin{bmatrix} -1 & -1 & -1 \\ 0 & 0 & 0 \\ 1 & 1 & 1 \end{bmatrix}

Sobel 算子

Sobel_x = \begin{bmatrix} -1 & 0 & 1 \\ -2 & 0 & 2 \\ -1 & 0 & 1 \end{bmatrix}, Sobel_y = \begin{bmatrix} -1 & -2 & -1 \\ 0 & 0 & 0 \\ 1 & 2 & 1 \end{bmatrix}

        Prewitt 边缘检测算法的优势在于它对噪声有一定的抑制作用,同时能够检测到图像中的水平和垂直边缘。然而,它对于其他方向的边缘检测效果较差。Sobel 检测算法对灰度渐变和噪声较多的边缘处理效果较好,但是对边缘的定位不够准确。

2 FPGA 布署与实现

2.1 功能与指标定义

        使用紫光同创 FPGA 平台实现边缘检测功能,FPGA 需要实现的功能与指标如下:

(1)与电脑的串口通信,用于接收上位机下发的图像数据,波特率为 256000 Bd/s;

(2)RGB 转灰度图处理,使用 3 个乘法器对接收到的图像进行灰度转换,用于后续的边缘检测;

(3)Prewitt 边缘检测,使用 FPGA 内部的 RAM 资源缓存 3 行图像数据,对 3 × 3 邻域内的数据进行 Prewitt 边缘检测;

(4)DDR3 读写控制,将处理前后的图像数据分别写入 DDR3 的不同区域,实现图像的拼接;

(5)HDMI 输出,输出一路 HDMI 信号源,用于将拼接后的图像显示在外接显示器上,分辨率为 1024×768。

2.2 模块设计

        边缘检测工程主要的设计模块层次与功能说明如下:

模块名称功能说明
top_uartuart_rx_slice串口接收驱动模块
uart_rx_parse串口数据解析模块,从上位机接收 8bit 原始图像,以及 Gamma 曲线数据
top_vidinvidin_pipelinepipeline 单元模块,缓存两行图像数据,并将数据提交到 ddr3 数据调度模块
vidin_pipeline_spipeline 单元简化模块,只缓存两行图像数据,无需产生与提交 ddr3 写命令
conv_rgb2grayRGB 转灰度图处理模块,使用乘法器进行灰度转换
conv_prewitt边缘检测模块,运用 Prewitt 算子对 3 × 3 领域内的数据进行处理
merge_outdvi_timing_genHDMI 视频时序产生模块
dvi_ddr_rd根据 HDMI 控制信号,提交读指令到 ddr3 数据调度模块
dvi_encoderHDMI 输出编码(8b10b 编码)与输出驱动模块

其中,conv_rgb2gray 模块实现灰度变换,conv_prewitt 模块实现边缘检测功能,conv_prewitt 实现水平边缘检测的思路为:

(1)对输入行数据进行打拍,得到 3 × 3 区域的数据;

(2)使用加法器电路,分别计算 3 × 3 区域内第 1 列、第 3 列的数据之和;

(3)使用比较器和减法器电路,计算第 1 列与第 3 列数据和的差。

对于垂直边缘检测,需要将列方向的数据求和,修改为行方向的数据求和。

conv_prewitt 模块代码如下:

`timescale 1 ns/ 1 ps

module conv_prewitt (
   input          reset,
   input          clock,
   input          load,
   input  [7:0]   ina,
   input  [7:0]   inb,
   input  [7:0]   inc,
   output [7:0]   edge_x,
   output [7:0]   edge_y
);

// internal signal declarations
reg               load_r1;
reg               load_r2;
reg       [23:0]  pipeline_data1;
reg       [23:0]  pipeline_data2;
reg       [23:0]  pipeline_data3;

reg       [15:0]  sum_of_col0;
reg       [15:0]  sum_of_col1;
reg       [15:0]  sum_of_col2;
reg       [15:0]  sum_of_row0;
reg       [15:0]  sum_of_row1;
reg       [15:0]  sum_of_row2;

reg       [15:0]  buf_edge_x;
reg       [15:0]  buf_edge_y;

// load 信号打两拍,用于边沿检测
always @(posedge reset or posedge clock) begin
   if (reset) begin
      load_r1 <= 1'b0;
      load_r2 <= 1'b0;
   end
   else begin
      load_r1 <= load;
      load_r2 <= load_r1;
   end
end

// 异步复位,同步复位
always @(posedge reset or posedge clock) begin
   if (reset) begin
      pipeline_data1 <= {3{8'h00}};
      pipeline_data2 <= {3{8'h00}};
      pipeline_data3 <= {3{8'h00}};
   end
   else if (~load) begin
      pipeline_data1 <= {3{8'h00}};
      pipeline_data2 <= {3{8'h00}};
      pipeline_data3 <= {3{8'h00}};
   end
   else begin
      pipeline_data1 <= {inc, inb, ina};
      pipeline_data2 <= pipeline_data1;
      pipeline_data3 <= pipeline_data2;
   end
end

// 行、列求和
always @(posedge reset or posedge clock) begin
   if (reset) begin
      sum_of_col0 <= 16'd0;
      sum_of_col1 <= 16'd0;
      sum_of_col2 <= 16'd0;
      sum_of_row0 <= 16'd0;
      sum_of_row1 <= 16'd0;
      sum_of_row2 <= 16'd0;
   end
   else begin
      sum_of_col0 <= pipeline_data1[0*8+:8] + pipeline_data1[1*8+:8] + pipeline_data1[2*8+:8];
      sum_of_col1 <= pipeline_data2[0*8+:8] + pipeline_data2[1*8+:8] + pipeline_data2[2*8+:8];
      sum_of_col2 <= pipeline_data3[0*8+:8] + pipeline_data3[1*8+:8] + pipeline_data3[2*8+:8];
      sum_of_row0 <= pipeline_data3[0*8+:8] + pipeline_data2[0*8+:8] + pipeline_data1[0*8+:8];
      sum_of_row1 <= pipeline_data3[1*8+:8] + pipeline_data2[1*8+:8] + pipeline_data1[1*8+:8];
      sum_of_row2 <= pipeline_data3[2*8+:8] + pipeline_data2[2*8+:8] + pipeline_data1[2*8+:8];
   end
end

always @(posedge reset or posedge clock) begin
   if (reset) begin
      buf_edge_x <= 16'd0;
      buf_edge_y <= 16'd0;
   end
   else begin
      if (sum_of_col2 >= sum_of_col0) 
         buf_edge_x <= sum_of_col2 - sum_of_col0;
      else 
         buf_edge_x <= sum_of_col0 - sum_of_col2;

      if (sum_of_row2 >= sum_of_row0) 
         buf_edge_y <= sum_of_row2 - sum_of_row0;
      else 
         buf_edge_y <= sum_of_row0 - sum_of_row2;
   end
end

assign edge_x = buf_edge_x[0+:8];
assign edge_y = buf_edge_y[0+:8];

endmodule

2.3 上板调试

        使用 PyQt5 和 OpenCV 库编写上位机程序,通过串口发送原始图像数据。连接 HDMI 线和串口线,选择与发送图像,就可以看到 FPGA 的处理效果了 ~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/209463.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

持续集成交付CICD:GitLabCI 运行前后端项目

目录 一、理论 1.spring项目自动构建 2.阿里云云效 Maven 3.Maven安装 4.Go安装 5.NPM安装 二、实验 1.GitLabCI 运行Maven项目 2.GitLabCI 运行Go项目 3.GitLabCI 运行NPM项目 三、问题 1.前端脚手架如何初始化项目 2.NPM下载如何指定 3.Go项目下载源如何指定 …

基于DigiThread的仿真模型调参功能

仿真模型调参是指通过调整模型内部的参数值&#xff0c;使仿真模型的输出更符合实际系统的行为或者预期结果的过程。 仿真过程中&#xff0c;往往需要频繁对模型参数进行调整&#xff0c;通过观察不同参数下系统整体的运行情况&#xff0c;实现系统的性能、可靠性和效率的优化…

UDP通信

UDP通信-快速入门 客户端程序 服务端程序 步骤 UDP通信-多发多收 客户端 服务端 步骤

Sentinel核心类解读:Node

基本介绍 Sentinel中的簇点链路是由一个个的Node组成的&#xff0c;Node是一个接口。Node中保存了对资源的实时数据的统计&#xff0c;Sentinel中的限流或者降级等功能就是通过Node中的数据进行判断的。 Sentinel中是这样描述Node的&#xff1a; Holds real-time statistics…

抑郁症中西医治疗对比?

抑郁症是一种常见的心理障碍&#xff0c;治疗方法包括中医和西医两种。下面就抑郁症中西医治疗进行对比&#xff1a; 治疗方法&#xff1a;中医治疗抑郁症强调整体观念和辨证论治&#xff0c;通过调理身体各部分的功能&#xff0c;达到治疗抑郁症的目的。中医治疗抑郁症多采用天…

YOLOv8创新魔改教程(一)如何进行模块创新

YOLOv8创新魔改教程&#xff08;一&#xff09;如何进行模块创新 YOLOv8创新魔改教程 本人研一&#xff0c;最近好多朋友问我要如何修改模型创新模块&#xff0c;就想着不如直接开个专栏歇一歇文章&#xff0c;也算是对自己学习的总结&#xff0c;本专栏以YOLOv8为例&#xf…

FH Admin Shiro反序列化漏洞复现

0x01 产品简介 FH Admin 是一款 java 快速开发平台。 0x02 漏洞概述 FH Admin CMS 存在 shiro 反序列化漏洞&#xff0c;该漏洞源于软件存在硬编码的 shiro-key&#xff0c;攻击者可利用该 key 生成恶意的序列化数据&#xff0c;在服务器上执行任意代码&#xff0c;执行系统命…

HT71778 实时音频信号跟踪同步升压转换器的特性

HT71778是一款高功率、全集成升压转换器&#xff0c;集成16mΩ功率开关管和18mΩ同步整流管&#xff0c;为便携式系统提供G效的小尺寸处理方案。 HT71778 实时音频信号跟踪同步升压转换器的特性&#xff1a; ・实时音频信号跟踪的电源供电 SN 短接地, VIN 2.7~4.5V, VOUT 5…

Leetcode—2661.找出叠涂元素【中等】

2023每日刷题&#xff08;四十六&#xff09; Leetcode—2661.找出叠涂元素 题意解读 题目意思就是&#xff0c;按照arr数组从左到右的顺序遍历各个arr[i]&#xff0c;涂抹这个值在矩阵中对应位置的网格&#xff0c;一旦你发现它所在的行或者列满员了&#xff0c;就返回这个i…

自定义Vue的DockPanel-Layout

创作来源 1、在vue项目中需要有停靠、浮动、面板布局等需求&#xff0c;如arcgis的界面布局 2、在npm中搜索了关于vue的docklayout组件&#xff0c;搜索后就一个组件imengyu/vue-dock-layout&#xff0c;截图如下&#xff0c;该组件没有停靠组件&#xff0c;没有浮动组件&…

Linux学习——模拟实现mybash小程序

目录 一&#xff0c;跟正宗的bash见个面 二&#xff0c;实现一个山寨的bash 1.提示符 2.输入命令与回显命令 3.解析命令 4.执行命令 5.执行逻辑 三&#xff0c;全部代码 一&#xff0c;跟正宗的bash见个面 在这篇文章中&#xff0c;我会写一个myshell小程序。这个小程序…

Linux中top命令输出日志分析?

以下是对输出的各部分的解释&#xff1a; 09:54:34&#xff1a;系统当前时间。up 161 days, 2:08&#xff1a;系统已经运行了161天2小时8分钟。5 users&#xff1a;有5个用户登录系统。load average: 0.13, 0.08, 0.05&#xff1a;系统的1分钟、5分钟、15分钟的平均负载。负载…

数据结构与算法之美学习笔记:29 | 堆的应用:如何快速获取到Top 10最热门的搜索关键词?

目录 前言堆的应用一&#xff1a;优先级队列堆的应用二&#xff1a;利用堆求 Top K堆的应用三&#xff1a;利用堆求中位数解答开篇内容小结 前言 本节课程思维导图&#xff1a; 搜索引擎的热门搜索排行榜功能你用过吗&#xff1f;搜索引擎每天会接收大量的用户搜索请求&#x…

Opencv制作电子签名(涉及知识点:像素过滤,图片通用resize函数,像素大于某个阈值则赋值为其它的像素值)

import cv2def resize_by_ratio(image, widthNone, heightNone, intercv2.INTER_AREA):img_new_size None(h, w) image.shape[:2] # 获得高度和宽度if width is None and height is None: # 如果输入的宽度和高度都为空return image # 直接返回原图if width is None:h_ratio …

手机上的记事本怎么打开?安卓手机通用的记事本APP

有不少上班族发现&#xff0c;自己想要在电脑上随手记录一些工作文字内容&#xff0c;直接使用电脑上的记事本工具来编辑文字是比较便捷的。但是如果想要在手机上记录文字内容&#xff0c;就找不到手机上的记事本了。那么手机上的记事本怎么打开&#xff1f;安卓手机通用的记事…

MySQL:找回root密码

一、情景描述 我们在日常学习中&#xff0c;经常会忘记自己的虚拟机中MySQL的root密码。 这个时候&#xff0c;我们要想办法重置root密码&#xff0c;从而&#xff0c;解决root登陆问题。 二、解决办法 1、修改my.cnf配置文件并重启MySQL 通过修改配置文件&#xff0c;来跳…

Symbol()和迭代器生成器

目录 1、Symbol&#xff08;&#xff09; 2、迭代器生成器 执行流程 模拟生成器函数 for of 遍历迭代选择器 yield * Generator函数应用 1、Symbol&#xff08;&#xff09; Symbol表示独一无二的值 const s1 Symbol(a)const s2 Symbol(a)console.log(s1 s2) // fa…

Elasticsearch 如何处理 Aggs 顺序中的大写字母和小写字母?

Elasticsearch 排序允许你根据特定条件对搜索结果进行排序。 然而&#xff0c;在排序时处理区分大小写时&#xff0c;Elasticsearch 将大写和小写字母视为不同的字符&#xff0c;分别对它们进行排序。 这是因为 ASCII 表顺序是从大写 A 到小写 z。 默认情况下&#xff0c;Elas…

MySQL之性能分析和系统调优

MySQL之性能分析和系统调优 性能分析 查看执行计划 EXPLAIN EXPLAIN作为MySQL的性能分析神器&#xff0c;可以用来分析SQL执行计划&#xff0c;需要理解分析结果可以帮助我们优化SQL explain select … from … [where ...]TABLE 表名 查询的每一行记录都对于着一张表 id 该…

【数据结构】最短路径(Dijskra算法)

一.引例 计算机网络传输的问题&#xff1a; 怎样找到一种最经济的方式&#xff0c;从一台计算机向网上所有其他计算机发送一条消息。 抽象为&#xff1a; 给定带权有向图G&#xff08;V&#xff0c;E&#xff09;和源点v&#xff0c;求从v到G中其余各顶点的最短路径。 即&…