FPGA图像处理之三行缓存
文章目录
- 一、前言
- 二、FPGA实现三行缓存的架构
- 三、Verilog代码实现
- 四、仿真验证
- 五、输入图像数据进行仿真验证
一、前言
在 FPGA 做图像处理时,行缓存是一个非常重要的一个步骤,因为图像输入还有输出都是一行一行进行的,即处理完一行后再处理下一行。行缓存可以存储当前行和前一行的数据以及多行的数据,使得在处理当前行时能够方便地访问周围像素。许多图像处理的算法都需要几行的图像数据进行处理,因此行缓存是非常重要的,本文实现三行缓存,多行缓存的思想也是一致的。
二、FPGA实现三行缓存的架构
由于图像数据一般都是从上到下从左到右一个一个输入进来,因此我们优先考虑使用FIFO,先进先出。按照一般想法,我们只需要三个FIFO,每个FIFO存储一行数据即可实现三行缓存,这里可以节省资源只使用两个FIFO实现,具体实现框框架如下:

开始时,图像数据的第0行写入到FIFO1中,图像数据的第1行写入到FIFO2中。

当第2行数据到来时写入到FIFO2中,同时输出写入的数据作为第二行;同时读出FIFO2中的数据写入到FIFO1中,并输出作为第一行,同时读出FIFO1中的数据输出作为第0行。

同理,当第三行数据来临时写入到FIFO2中,同时输出写入数据作为第二行,再同时读出FIFO2中的数据写入到FIFO1中并输出作为第一行,同时读出FIFO2中的数据输出作为第0行。后面的行以此类推。
三、Verilog代码实现
先看输入接口,输入为像素数据和有效信号,输出为三行数据以及有效信号。
input sys_clk ,input sys_rst ,input [23:0] i_img_data ,input i_img_data_valid ,output [23:0] o_img_data_1line ,output [23:0] o_img_data_2line ,output [23:0] o_img_data_3line ,output o_img_data_valid
再次例化两个FIFO,位宽就为一个像素位宽,深度为一行中最多的像素数量。
img_line_buffer_fifo u0_img_line_buffer_fifo (.clk (sys_clk ), // input wire clk.srst (sys_rst ), // input wire srst.din (fifo1_wr_data ), // input wire [23 : 0] din.wr_en(fifo1_wr_en ), // input wire wr_en.rd_en(rd_en ), // input wire rd_en.dout (fifo1_q ), // output wire [23 : 0] dout.full (), // output wire full.empty() // output wire empty
);img_line_buffer_fifo u1_img_line_buffer_fifo (.clk (sys_clk ), // input wire clk.srst (sys_rst ), // input wire srst.din (fifo2_wr_data ), // input wire [23 : 0] din.wr_en(fifo2_wr_en ), // input wire wr_en.rd_en(rd_en ), // input wire rd_en.dout (fifo2_q ), // output wire [23 : 0] dout.full (), // output wire full.empty() // output wire empty
);
然后根据架构图编写出剩下的代码,编写仿真代码。
四、仿真验证
仿真我们先设置图像宽度为50*50,这样仿真可以跑快一点,然后写入数据流为每次都是0-49循环。就像一幅图像的第0行数据是0-49,第1行的数据也是0-49,每一行的数据都是0-49。按照想法,我们每次输出的数据就是前三行的像素,也就是3行的 0-49数据,仿真代码如下:
`timescale 1ns / 1psmodule tb_img_3line_buffer();reg sys_clk ;
reg sys_rst ;
reg i_img_data_valid ;
reg [23:0] i_img_data ;
reg [12:0] cnt ;
wire [23:0] o_img_data_1line ;
wire [23:0] o_img_data_2line ;
wire [23:0] o_img_data_3line ;
wire o_img_data_valid ;initial beginsys_clk =0;sys_rst = 1;i_img_data_valid = 0;i_img_data = 'd0;#200;sys_rst = 0;
endalways #5 sys_clk = ~sys_clk;always @(posedge sys_clk) beginif(sys_rst == 1'b1)i_img_data_valid <= 1'b0;else if(cnt == 49)i_img_data_valid <= 1'b0;elsei_img_data_valid <= 1'b1;
endalways @(posedge sys_clk) beginif(sys_rst == 1'b1)cnt <= 'd0;else if(cnt == 49)cnt <= 'd0;else if(i_img_data_valid == 1'b1)cnt <= cnt + 1'b1;elsecnt <= cnt;
endalways @(posedge sys_clk) beginif(sys_rst == 1'b1)i_img_data <= 'd0;else if(i_img_data == 49)i_img_data <= 'd0;else if(i_img_data_valid == 1'b1)i_img_data <= i_img_data + 1'b1;elsei_img_data <= i_img_data;
endimg_3line_buffer#(.IMG_WIDTH ( 50 ),.IMG_HEIGHT ( 50 )
)u_img_3line_buffer(.sys_clk ( sys_clk ),.sys_rst ( sys_rst ),.i_img_data ( i_img_data ),.i_img_data_valid ( i_img_data_valid ),.o_img_data_1line ( o_img_data_1line ),.o_img_data_2line ( o_img_data_2line ),.o_img_data_3line ( o_img_data_3line ),.o_img_data_valid ( o_img_data_valid )
);endmodule
运行仿真

可以看到写入的每一行数据都是0-49,写入两行后,开始输出数据。

我们可以看到输出的三行数据都是0-49的数据。符合预期。我们修改一下仿真代码,写入2500个数据,对应50*50的图像大小,数据为0-2499,这样第0行的数据就是0-49,第1行的数据就是50-99,第2行的数据就是100-149,第3行的数据就是150-199。输出的数据就应该是(0,50,100),(1,51,101)以此类推,仿真代码如下:
`timescale 1ns / 1psmodule tb_img_3line_buffer();reg sys_clk ;
reg sys_rst ;
reg i_img_data_valid ;
reg [23:0] i_img_data ;
reg [12:0] cnt ;
wire [23:0] o_img_data_1line ;
wire [23:0] o_img_data_2line ;
wire [23:0] o_img_data_3line ;
wire o_img_data_valid ;initial beginsys_clk =0;sys_rst = 1;i_img_data_valid = 0;i_img_data = 'd0;#200;sys_rst = 0;
endalways #5 sys_clk = ~sys_clk;always @(posedge sys_clk) beginif(sys_rst == 1'b1)i_img_data_valid <= 1'b0;else if(cnt == 2499)i_img_data_valid <= 1'b0;elsei_img_data_valid <= 1'b1;
endalways @(posedge sys_clk) beginif(sys_rst == 1'b1)cnt <= 'd0;else if(cnt == 2499)cnt <= 'd0;else if(i_img_data_valid == 1'b1)cnt <= cnt + 1'b1;elsecnt <= cnt;
endalways @(posedge sys_clk) beginif(sys_rst == 1'b1)i_img_data <= 'd0;else if(i_img_data == 2499)i_img_data <= 'd0;else if(i_img_data_valid == 1'b1)i_img_data <= i_img_data + 1'b1;elsei_img_data <= i_img_data;
endimg_3line_buffer#(.IMG_WIDTH ( 50 ),.IMG_HEIGHT ( 50 )
)u_img_3line_buffer(.sys_clk ( sys_clk ),.sys_rst ( sys_rst ),.i_img_data ( i_img_data ),.i_img_data_valid ( i_img_data_valid ),.o_img_data_1line ( o_img_data_1line ),.o_img_data_2line ( o_img_data_2line ),.o_img_data_3line ( o_img_data_3line ),.o_img_data_valid ( o_img_data_valid )
);endmodule
运行仿真


验证完成和预期一致,后续一些图像处理算法需要用到这个行缓存。
五、输入图像数据进行仿真验证
现在我们在仿真中输入一张图片,然后通过三行缓存输出,每次只取出第一行的数据写入到新的图片中:

可以看出输出的图像和输入图像一模一样,文件大小也是一模一样,因此三行缓存是没问题的。
相关文章:
FPGA图像处理之三行缓存
文章目录 一、前言二、FPGA实现三行缓存的架构三、Verilog代码实现四、仿真验证五、输入图像数据进行仿真验证 一、前言 在 FPGA 做图像处理时,行缓存是一个非常重要的一个步骤,因为图像输入还有输出都是一行一行进行的,即处理完一行后再处理…...
10月15日,每日信息差
第一、《哈利・波特与魔法石》在中国内地总票房突破 3 亿元,包括 2002 年首映的 5600 万,2020 年重映的 1.923 亿,以及 2024 年重映的 5170 万。 第二、全国铁路实施新货物列车运行图,增开城际班列至 131 列,多式联运…...
4G、5G通信中,“网络侧“含义
在5G通信中,"网络侧"这个术语可以指代不同的网络元素,具体取决于上下文。通常,网络侧可以包括以下两个主要部分: 基站(gNB): 基站是无线接入网(RAN)的一部分&a…...
spring boot核心理解-各种starter
理解 Spring Boot 的 Starter 机制以及如何选择和使用各种 starter,是开发 Spring Boot 应用的重要一环。Spring Boot Starter 是一组方便的依赖组合,用于简化 Spring 项目中的依赖管理。它们可以帮助开发者快速引入所需的库和自动配置,从而加…...
解决海外社媒风控问题的工具——云手机
随着中国企业逐步进入海外市场,海外社交媒体的风控问题严重影响了企业的推广效果与账号运营。这种背景下,云手机作为一种新型技术解决方案,正日益成为企业应对海外社媒风控的重要工具。 由于海外社媒的严格监控,企业经常面临账号流…...
全能PDF工具集 | PDF Shaper Ultimate v14.6 便携版
软件简介 PDF Shaper是一款功能强大的PDF工具集,它提供了一系列用于处理PDF文档的工具。这款软件使用户能够轻松地转换、分割、合并、提取页面以及旋转和加密PDF文件。PDF Shaper的界面简洁直观,使得即使是新手用户也能快速上手。它支持广泛的功能&…...
Maven入门
Maven Maven Wrapper 版本一致性: Maven Wrapper 允许你在项目中指定一个特定的 Maven 版本。这意味着所有开发人员和 CI/CD 环境都将使用相同版本的 Maven,从而避免由于版本不一致导致的问题。 简化设置: 新开发者克隆项目时,…...
Chromium 中window.DOMParser接口说明c++
一、DOMParser DOMParser 可以将存储在字符串中的 XML 或 HTML 源代码解析为一个 DOM Document。 备注: XMLHttpRequest 支持从 URL 可寻址资源解析 XML 和 HTML,在其response 属性中返回Document。 你可以使用XMLSerializer 接口执行相反的操作 - 将…...
linux 安装gitlab
安装环境 CentOS 7.7 (centos6.10会报错)2g内存防火墙关闭 安装步骤: 1 安装gitlab # yum install -y git curl policycoreutils-python openssh-server # 安装依赖 # wget https://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/yum/el7/gitlab-ce-10.2.2-ce…...
java基础(5)继承与多态
目录 编辑 1.前言 2.正文 2.1继承 2.1.1继承概念 2.1.2继承语法 2.1.3子类访问父类 2.1.4super关键字 2.2多态 2.2.1多态概念 2.2.2多态条件 2.2.3重写 2.2.4向上转型与向下转型 2.2.5为什么要使用多态 3.小结 1.前言 哈喽大家好啊,今天继续来为大…...
Flink消费Kafka实时写入Doris
本文模拟实际生产环境,通过FileBeat采集日志信息到Kafka,再通过Flink消费Kafka实时写入Doris。 文章目录 Filebeat采集日志到KafkaFlink消费Kafka实时写入Doris总结 Filebeat采集日志到Kafka 常见的日志采集工具有以下几种:Flume、Logstash和…...
实现Web QQ音乐打开现有新标签页切换音乐
若没有打开播放音乐标签页,则打开新标签页播放所选音乐如果已打开新标签页,则直接切换所选音乐 pageA.vue <script setup lang"ts"> const tab2 ref<any>(null); const router useRouter();interface Track {id: number;name: …...
从底层结构开始学习FPGA(15)----时钟结构(通俗版)
目录 0、前言 1、IO Bank和Clock Region(时钟区域)是一个东西吗? 2、时钟输入管脚 3、时钟架构 3.1、全局时钟BUFG 3.2、水平时钟BUFH 3.3、IO时钟BUFIO 3.4、区域时钟BUFR/BUFMR 4、总结 《从底层结构开始学习FPGA》目录与传送门 0、前言 我思来想去,总觉…...
MacOS Sublime Text 解决中乱码
1. 安装Package Control 官方安装指南 手动安装 通过以此点击菜单 Sublime Text > Preferences > Browse Packages 打开Packages目录找到Packages的同级目录Installed Packages下载PackageControl.sublime-package并保存到Installed Packages中在菜单 Sublime Text &g…...
Python画笔案例-084 绘制 3D立方体
1、绘制 3D立方体 通过 python 的turtle 库绘制 3D立方体,如下图: 2、实现代码 绘制 3D立方体,以下为实现代码: import turtle import timeviewfactor = 150 xshift = 0 yshift = 0 zshift = 50...
“八股文”面试:助力、阻力还是空谈?
在当今的IT行业,面试程序员时提及“八股文”已成为一种普遍现象。所谓“八股文”,通常指的是一系列固定的、标准化的面试问题及其解答,这些问题往往涵盖了计算机科学和软件工程的基础知识,以及一些流行的技术框架和算法。然而&…...
如何实现弹出式窗口
文章目录 1 概念介绍2 使用方法3 示例代码我们在上一章回中介绍了Sliver综合示例相关的内容,本章回中将介绍PopupMenuButton组件.闲话休提,让我们一起Talk Flutter吧。 1 概念介绍 我们在本章回中介绍的PopupMenuButton组件位于AppBar右侧,通常显示三个圆点图标,点击该图标…...
Lua 函数
Lua 函数 Lua 是一种轻量级的编程语言,广泛用于游戏开发、脚本编写和其他应用程序中。在 Lua 中,函数是一等公民,这意味着它们可以被存储在变量中,作为参数传递给其他函数,以及作为其他函数的返回值。本文将详细介绍 …...
HTML_文本标签
概念: 1、用于包裹:词汇、短语等。 2、通常写在排版标签里面。 3、排版标签更宏观(大段的文字),文本标签更微观(词汇、短语)。 4、文本标签通常都是行内元素。 常用的文本标签 标签名 全称 标签语义em Emphasized 加重(文本)。要着重阅…...
基于SpringBoot+Vue+uniapp的诗词学习系统的详细设计和实现(源码+lw+部署文档+讲解等)
详细视频演示 请联系我获取更详细的演示视频 项目运行截图 技术框架 后端采用SpringBoot框架 Spring Boot 是一个用于快速开发基于 Spring 框架的应用程序的开源框架。它采用约定大于配置的理念,提供了一套默认的配置,让开发者可以更专注于业务逻辑而不…...
铭豹扩展坞 USB转网口 突然无法识别解决方法
当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...
MMaDA: Multimodal Large Diffusion Language Models
CODE : https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA,它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构…...
Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器
第一章 引言:语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域,文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量,支撑着搜索引擎、推荐系统、…...
ElasticSearch搜索引擎之倒排索引及其底层算法
文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...
tree 树组件大数据卡顿问题优化
问题背景 项目中有用到树组件用来做文件目录,但是由于这个树组件的节点越来越多,导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多,导致的浏览器卡顿,这里很明显就需要用到虚拟列表的技术&…...
【生成模型】视频生成论文调研
工作清单 上游应用方向:控制、速度、时长、高动态、多主体驱动 类型工作基础模型WAN / WAN-VACE / HunyuanVideo控制条件轨迹控制ATI~镜头控制ReCamMaster~多主体驱动Phantom~音频驱动Let Them Talk: Audio-Driven Multi-Person Conversational Video Generation速…...
return this;返回的是谁
一个审批系统的示例来演示责任链模式的实现。假设公司需要处理不同金额的采购申请,不同级别的经理有不同的审批权限: // 抽象处理者:审批者 abstract class Approver {protected Approver successor; // 下一个处理者// 设置下一个处理者pub…...
Linux系统部署KES
1、安装准备 1.版本说明V008R006C009B0014 V008:是version产品的大版本。 R006:是release产品特性版本。 C009:是通用版 B0014:是build开发过程中的构建版本2.硬件要求 #安全版和企业版 内存:1GB 以上 硬盘…...
如何应对敏捷转型中的团队阻力
应对敏捷转型中的团队阻力需要明确沟通敏捷转型目的、提升团队参与感、提供充分的培训与支持、逐步推进敏捷实践、建立清晰的奖励和反馈机制。其中,明确沟通敏捷转型目的尤为关键,团队成员只有清晰理解转型背后的原因和利益,才能降低对变化的…...
uniapp 小程序 学习(一)
利用Hbuilder 创建项目 运行到内置浏览器看效果 下载微信小程序 安装到Hbuilder 下载地址 :开发者工具默认安装 设置服务端口号 在Hbuilder中设置微信小程序 配置 找到运行设置,将微信开发者工具放入到Hbuilder中, 打开后出现 如下 bug 解…...
