Verilog实现图像处理的行缓存Line Buffer

news2025/3/2 1:11:47

在图像处理中,难免会遇到对图像进行卷积或者模板的局部处理,例如ISP中的一些算法,很大部分都需要一个窗口,在实时视频处理中,可以利用行缓存Line buffer可以暂存几行数据,然后同时输出每行中的对应列的像素。

下面以一个三行缓存进行解释

 DVP像素流从Shif_in输入,像素不流不断在行缓存中移动,行缓存的最后一个像素使用line_out来保存,通过这种方式,lin_out输出部分就是每行对应列中的像素,在算法模块中,对line_out寄存三拍,就可以得到3x3的窗口大小。

暂存区的设计可以使用一个双口同步RAM来实现:

module simple_dp_ram
#(
	parameter DW = 8,
	parameter AW = 4,
	parameter SZ = 2**AW
)
(
	input           clk,
	input           wen,
	input  [AW-1:0] waddr,
	input  [DW-1:0] wdata,
	input           ren,
	input  [AW-1:0] raddr,
	output [DW-1:0] rdata
);
	reg [DW-1:0] mem [SZ-1:0];
	always @ (posedge clk) begin
		if (wen) begin
			mem[waddr] <= wdata;
		end
	end
	reg [DW-1:0] q;
	always @ (posedge clk) begin
		if (ren) begin
			q <= mem[raddr];
		end
	end
    
	// always @(posedge clk) begin
	// 	// 先执行读操作
	// 	if (ren) begin
	// 		q <= mem[raddr];
	// 	end

	// 	// 后执行写操作
	// 	if (wen) begin
	// 		mem[waddr] <= wdata;
	// 	end
	// end

	assign rdata = q;
endmodule

这里涉及到一个问题,当读地址和写地址相同时,会导致冲突吗?

我这里找到的解释是,具体行为会依赖于底层的实现,在同一个时钟周期同时读写同一个地址在FPGA中通常是读优先的,即会先读取该地址的旧值,然后向该地址写如新值。(有大佬了解的可以帮忙解释以下:))。

行缓存LineBuffer源码如下所示:

///基于卷积或者模板的算法需要使用该模块
module shift_register
#(
	parameter BITS = 8,         
	parameter WIDTH = 480,    //行缓存宽度
	parameter LINES = 3       //行缓存行数
)
(
	input                clock,    
	input                clken, 
	input  [BITS-1:0]    shiftin,        //输入数据流
	output [BITS-1:0]    shiftout,       //当前行最后一个像素的数据输出。
	output [BITS*LINES-1:0] tapsx        //行缓存的输出:包含每行最后一个像素的输出,拼接成一个长向量
);

	localparam RAM_SZ = WIDTH - 1;   //每行的实际大小
	localparam RAM_AW = clogb2(RAM_SZ);  //计算地址宽度


    ///地址指针逻辑
	reg [RAM_AW-1:0] pos_r;   //pos_r:记录当前写入的位置。
    ///(RAM_SZ[RAM_AW-1:0] - 1'b1)实际上就是WIDTH - 2
    //行缓存的最后一个像素使用line_out来保存,RAM实际上只保存了WDITH-1个像素(pos在0~WIDTH-2之间)
	wire [RAM_AW-1:0] pos = pos_r < RAM_SZ ? pos_r : (RAM_SZ[RAM_AW-1:0] - 1'b1);  ///当 pos_r 超过范围时限制其值,用于确保地址有效
	always @ (posedge clock) begin
		if (clken) begin     
			if (pos_r < RAM_SZ - 1)  
				pos_r <= pos_r + 1'b1;   //地址指针 pos_r 循环递增,直到到达最大地址后重置为 0
			else
				pos_r <= 0;
		end
	end

	reg [BITS-1:0] in_r;  
	always @ (posedge clock) begin
		if (clken) begin
			in_r <= shiftin;      //寄存输入数据 shiftin,用于提供给第 0 行的 RAM 写入。
		end
	end

	wire [BITS-1:0] line_out[LINES-1:0];    //记录每行的最后一个像素

    ///生成菊花链行缓存结构,在第二行开始才将上一行末尾连接到下一行的输入中,第一行输入in_r,每一行的最后一个像素寄存在line_out中
	generate          
		genvar i;
		for (i = 0; i < LINES; i = i + 1) begin : gen_ram_inst
            //在当前周期,line_out[i] 先从 pos 地址中读取之前存储的数据。随后将 (i > 0 ? line_out[i-1] : in_r) 写入 pos 地址。
			simple_dp_ram #(BITS, RAM_AW, RAM_SZ) u_ram(clock, clken, pos, (i > 0 ? line_out[i-1] : in_r), clken, pos, line_out[i]);
		end
	endgenerate


	assign shiftout = line_out[LINES-1];     //移位输出
	generate
		genvar j;
		for (j = 0; j < LINES; j = j + 1) begin : gen_taps_assign
			assign tapsx[(BITS*j)+:BITS] = line_out[j];
		end
	endgenerate


    //计算需要位宽
	function integer clogb2;    
	input integer depth;
	begin
		for (clogb2 = 0; depth > 0; clogb2 = clogb2 + 1)
			depth = depth >> 1;
	end
	endfunction
endmodule

这里使用了一个clogb2函数来获取配置的WIDTH需要的位宽。在代码中涉及了同一时钟周期对双口RAM中同一地址的读写问题,既然项目最后能跑起来,应该就是读优先的。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

String【Redis对象篇】

&#x1f3c6; 作者简介&#xff1a;席万里 ⚡ 个人网站&#xff1a;https://dahua.bloggo.chat/ ✍️ 一名后端开发小趴菜&#xff0c;同时略懂Vue与React前端技术&#xff0c;也了解一点微信小程序开发。 &#x1f37b; 对计算机充满兴趣&#xff0c;愿意并且希望学习更多的技…

Microsemi Libero SoC免费许可证申请指南(Microchip官网2024最新方法)

点击如下链接&#xff1a; https://www.microchip.com/en-us/products/fpgas-and-plds/fpga-and-soc-design-tools/fpga/licensing 点击右侧&#xff0c;请求免费的License 如果提示登录&#xff0c;请先登录Microchip账号。 点击Request Free License。 选项一年免费的Li…

动态规划子序列问题系列一>最长递增子序列的个数

题目&#xff1a; 解析&#xff1a; 这里求最长递增子序列的长度&#xff0c;请看这篇博客&#xff1a;动态规划子序列问题系列一&#xff1e;最长递增子序列-CSDN博客 这里主要运用&#xff1a;一个小贪心状态转移方程的分析方法完成该题 代码&#xff1a; public int fi…

每天40分玩转Django:Django视图和URL

Django视图和URL 一、课程概述 学习项目具体内容预计用时视图基础函数视图、类视图、视图装饰器90分钟URL配置URL模式、路由系统、命名URL60分钟请求处理请求对象、响应对象、中间件90分钟 二、视图基础 2.1 函数视图 # blog/views.py from django.shortcuts import render…

token失效重新存储发起请求

import axios from axios import { MessageBox, Message } from element-ui import store from /store import Router from /router import { getCookie, setToken, setCookie } from ./auth// 因为后端环境区分v1 v2 剔除测试盛传的环境配置&#xff0c;并添加统一前缀 const …

悬赏任务源码(悬赏发布web+APP+小程序)开发附源码

悬赏任务源码是指一个软件或网站的源代码&#xff0c;用于实现悬赏任务的功能。悬赏任务是指发布方提供一定的奖励&#xff0c;希望能够找到解决特定问题或完成特定任务的人。悬赏任务源码通常包括任务发布、任务接受、任务完成和奖励发放等功能的实现。搭建悬赏任务源码是一个…

【一本通】虫洞

【一本通】虫洞 C语言代码C代码JAVA代码 &#x1f490;The Begin&#x1f490;点点关注&#xff0c;收藏不迷路&#x1f490; John在他的农场中闲逛时发现了许多虫洞。虫洞可以看作一条十分奇特的有向边&#xff0c;并可以使你返回到过去的一个时刻&#xff08;相对你进入虫洞之…

Linux之条件变量,信号量,生产者消费者模型

Linux之条件变量&#xff0c;信号量&#xff0c;生产消费者模型&#xff0c;日志以及线程池 一.条件变量1.1条件变量的概念1.2条件变量的接口 二.信号量2.1信号量的重新认识2.2信号量的接口 三.生产者消费者模型3.1生产者消费者模型的概念3.2基于阻塞队列的生产者消费者模型3.3…

如何写出优秀的单元测试?

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 写出优秀的单元测试需要考虑以下几个方面&#xff1a; 1. 测试用例设计 测试用例应该覆盖被测试代码的不同场景和边界情况&#xff0c;以尽可能发现潜在的问题。…

【竞技宝】LOL:JDG官宣yagao离队

北京时间2024年12月13日,在英雄联盟S14全球总决赛结束之后,各大赛区都已经进入了休赛期,目前休赛期也快进入尾声,LPL大部分队伍都开始陆续官宣转会期的动向,其中JDG就在近期正式官宣中单选手yagao离队,而后者大概率将直接选择退役。 近日,JDG战队在官方微博上连续发布阵容变动消…

2024美赛数学建模C题:网球比赛中的动量,用马尔可夫链求解!详细分析

文末获取历年美赛数学建模论文&#xff0c;交流思路模型 接下来讲解马尔可夫链在2024年C题中的运用 1. 马尔科夫链的基本原理 马尔科夫链是描述随机过程的一种数学模型&#xff0c;其核心特征是无记忆性。 简单来说&#xff0c;系统在某一时刻的状态只取决于当前状态&#x…

图形学笔记 - 5. 光线追踪 - RayTracing

Whitted-Style Ray tracing 为什么要光线追踪 光栅化不能很好地处理全局效果 软阴影尤其是当光线反射不止一次的时候 栅格化速度很快&#xff0c;但质量相对较低 光线追踪是准确的&#xff0c;但速度很慢 光栅化&#xff1a;实时&#xff0c;光线追踪&#xff1a;离线~10K …

Nginx之配置防盗链(Configuring Anti-hotlinking in Nginx)

运维小白入门——Nginx配置防盗 什么是防盗链&#xff1a; 防盗链技术主要用于防止未经授权的第三方或域名访问网站的静态资源。例如&#xff0c;一个网站可能拥有独特的图片素材&#xff0c;为了防止其他网站通过直接链接图片URL的方式访问这些图片&#xff0c;网站管理员会采…

51c大模型~合集89

我自己的原文哦~ https://blog.51cto.com/whaosoft/12815167 #OpenAI很会营销 而号称超强AI营销的灵感岛实测成效如何&#xff1f; OpenAI 是懂营销的&#xff0c;连续 12 天发布&#xff0c;每天一个新花样&#xff0c;如今刚过一半&#xff0c;热度依旧不减。 毫无疑问&…

深度学习的unfold操作

unfold&#xff08;展开&#xff09;是深度学习框架中常见的数据操作。与我们熟悉的卷积类似&#xff0c;unfold也是使用一个特定大小的窗口和步长自左至右、自上至下滑动&#xff0c;不同的是&#xff0c;卷积是滑动后与核求乘积&#xff08;所以取名为卷积&#xff09;&#…

Jetpack Compose赋能:以速破局,高效打造非凡应用

Android Compose 是谷歌推出的一种现代化 UI 框架&#xff0c;基于 Kotlin 编程语言&#xff0c;旨在简化和加速 Android 应用开发。它以声明式编程为核心&#xff0c;与传统的 View 系统相比&#xff0c;Compose 提供了更直观、更简洁的开发体验。以下是对 Android Compose 的…

Dual-Write Problem 双写问题(微服务)

原文链接https://www.confluent.io/blog/dual-write-problem/ 双写问题发生于当两个外部系统必须以原子的方式更新时。 问题 说有人到银行存了一笔钱&#xff0c;触发 DepositFunds 命令&#xff0c;DepositFunds 命令被发送到Account microservice。 Account microservice需…

桥接模式的理解和实践

桥接模式&#xff08;Bridge Pattern&#xff09;&#xff0c;又称桥梁模式&#xff0c;是一种结构型设计模式。它的核心思想是将抽象部分与实现部分分离&#xff0c;使它们可以独立地进行变化&#xff0c;从而提高系统的灵活性和可扩展性。本文将详细介绍桥接模式的概念、原理…

kubeadm安装K8s集群之高可用组件keepalived+nginx及kubeadm部署

系列文章目录 1.kubeadm安装K8s集群之基础环境配置 2.kubeadm安装K8s集群之高可用组件keepalivednginx及kubeadm部署 3.kubeadm安装K8s集群之master节点加入 4.kubeadm安装K8s集群之worker1节点加入 kubeadm安装K8s集群之高可用组件keepalivednginx及kubeadm部署 1.安装kubeadm…

Avalonia实战实例三:实现可输入框的ComboBox控件

文章目录 一、Avalonia中的ComboBox控件二、更改Template&#xff0c;并添加水印 接着上篇关闭按钮实现登录界面 实现一个可输入&#xff0c;可下拉的用户名输入框 一、Avalonia中的ComboBox控件 Avalonia中Fluent主题里ComboBox实现&#xff1a; <ControlTheme x:Key&q…