四、VGA项目:联合精简帧+双fifo+sobel算法 实现VGA显示

前言:该项目实际上是在很多基础的小练习上合成起来的,例如涉及到uart(rs232)的数据传输、双fifo流水线操作、VGA图像显示,本次内容在此基础上又增添了sobel算法,能实现图像的边沿监测并VGA显示。

文章目录

  • 1.项目描述
  • 2.sobel算法解析:
  • 3.模块结构示意图:
  • 4.sobel_ctrl模块设计
    • 4.1波形设计
    • 4.2代码
  • 5.VGA_shift模块设计
    • 5.1 显示效果示意图:
    • 5.2 简易波形示意图:
    • 5.3 代码
  • 6.uart_rx模块设计(直接用之前的设计 略)
  • 7.顶层设计
  • 8.最终的显示效果:

在这里插入图片描述

1.项目描述

通过串口助手把 200 行 x200 列数据传入 FPGA,对应三行三列的九个数进行 sobel算法,把边缘检测的结果(198x198的数据)通过 vga 来显示,用两种颜色来区分是否是边界点(边界用白色显示,其他用黑色)。

2.sobel算法解析:

在这里插入图片描述

  1. 把图像每三行三列的数据分别乘上算子中对应位置的值再相加。然后进行如下运算,得到相应方向(x 和 y)的 Dx 和 Dy。
    Dx=(a3-a1)+(b3-b1)*2+c3-c1;
    Dy=(a1-c1)+(a2-c2)*2+a3-c3;

  2. 对上面求得的 Dx 和 Dy 做平方和的平方根,再取近似值 Dx 和 Dy 的绝对值的和得到 Dxy:

在这里插入图片描述

  1. 如果 Dxy 的值大于一个阈值(这个阈值是多次尝试试出来的,本次项目中设置为5),表示该点为边界点,就让 VGA 显示一个白点,否则显示黑点。

  2. 把计算的结果通过 vga 显示,显示器会把是边界点的以白色像素显示,不是边界点的以黑色像素点显示,于是得到了一幅图像的轮廓

在这里插入图片描述

3.模块结构示意图:

在这里插入图片描述

其中:
uart_rx模块在:手写一个uart协议——rs232
sobel_ctrl模块的核心是双fifo的流水线操作參考(需在此基础上进行改动):双fifo流水线操作
VGA_shift模块參考(原移动框为200x200这里变成198x198,且添加了ram方便rgb图像的存储与读取):VGA接口驱动与图像显示动态移动

4.sobel_ctrl模块设计

4.1波形设计

在这里插入图片描述

4.2代码

module sobel_ctrl(input wire clk,input wire rst,input wire [7:0] rx_data,input wire pi_flag,output reg [7:0] rgb,output reg po_flag);
reg[9:0] cnt_col,cnt_row;
reg wr_en1_r,wr_en2_r;
wire wr_en1,wr_en2;reg [7:0] data_in1_r;
wire [7:0] data_in1;
wire [7:0] dout1,dout2;reg [7:0] dout1_t,dout1_tt,dout2_t,dout2_tt;
reg [7:0] rx_data_t,rx_data_tt;
reg rd_en_r;
wire rd_en;reg shift_flag;reg flag_d;reg [7:0] Dx,Dy;reg flag_abs,flag_dxy,flag_rgb;
reg [7:0] abs_dx,abs_dy;
reg [7:0] dxy;parameter COL_MUX=199;
parameter ROW_MUX=199;
parameter VALUR=5;  //不断调试得到一个合适的阈值// cnt_col
always @(posedge clk) begin if(rst==1'b1) begincnt_col <= 'd0;end else if (pi_flag==1'b1 && cnt_col==COL_MUX) begincnt_col<='d0;endelse if (pi_flag==1'b1) begincnt_col<=cnt_col+1'b1;end
end// cnt_row
always @(posedge clk) begin if(rst==1'b1) begincnt_row <= 'd0;endelse if (cnt_row==ROW_MUX && pi_flag==1'b1 && cnt_col==COL_MUX) begincnt_row<='d0;endelse if (pi_flag==1'b1 && cnt_col==COL_MUX) begincnt_row<=cnt_row+1'b1;end
end// wr_en1_r
assign wr_en1=wr_en1_r;
always @(posedge clk) begin if(rst==1'b1) beginwr_en1_r <= 'd0;endelse if (cnt_row=='d0) beginwr_en1_r<=pi_flag;endelse if (cnt_row>'d1 && cnt_row<ROW_MUX) beginwr_en1_r<=shift_flag;end
end// wr_en2_r
assign wr_en2=wr_en2_r;
always @(posedge clk) begin if(rst==1'b1) beginwr_en2_r <= 'd0;end else if (cnt_row>'d0 && cnt_row<ROW_MUX) beginwr_en2_r<=pi_flag;endelsewr_en2_r<='d0;
end// data_in1_r
assign data_in1=data_in1_r;
always @(posedge clk) begin if(rst==1'b1) begindata_in1_r<= 'd0;end else if (cnt_row=='d0) begindata_in1_r<=rx_data;endelse if (cnt_row>'d1 && cnt_row<ROW_MUX) begindata_in1_r<=dout2;end
end// rd_en_r
assign rd_en=rd_en_r;always @(posedge clk) begin if(rst==1'b1) beginrd_en_r<= 'd0;end else if (cnt_row>'d1) beginrd_en_r<=pi_flag;endelse rd_en_r<='d0;
end// shift_flag
always @(posedge clk) begin if(rst==1'b1) beginshift_flag <= 'd0;end elseshift_flag<=rd_en_r;
end// dout1_t,dout1_tt,dout2_t,dout2_tt,rx_data_t,rx_data_tt
always @(posedge clk) begin if (shift_flag==1'b1) begin{dout1_tt,dout1_t}={dout1,dout1_t};{dout2_tt,dout2_t}={dout2,dout2_t};{rx_data_tt,rx_data_t}={rx_data_t,rx_data};end
endalways @(posedge clk) begin if(rst==1'b1) beginflag_d <= 'd0;end else if (cnt_row>=2 && cnt_col>2) beginflag_d<=rd_en_r;end
endalways @(posedge clk) begin if(rst==1'b1) beginDx <= 'd0;Dy <= 'd0;end else if (flag_d==1'b1) beginDx<=(dout1_tt-dout1)+(dout2_tt-dout2)<<1+(rx_data_tt-rx_data);Dy<=(dout1_tt-rx_data_tt)+(dout1_t-rx_data_t)<<1+(dout1-rx_data);endendalways @(posedge clk) begin if (rst==1'b1) beginflag_abs<='d0;flag_dxy<='d0;flag_rgb<='d0;po_flag<='d0;endelse{po_flag,flag_rgb,flag_dxy,flag_abs}<={flag_rgb,flag_dxy,flag_abs,flag_d};
end// abs_dx
always @(posedge clk) begin if(rst==1'b1) beginabs_dx<='d0;end else if (flag_abs==1'b1 ) beginif (dx[7]==1'b1) beginabs_dx<=(~Dx)+1'b1;endelseabs_dx<=Dx;end
end// abs_dy
always @(posedge clk) begin if(rst==1'b1) beginabs_dy <= 'd0;end else if (flag_abs==1'b1) beginif (dy[7]==1'b1) beginabs_dy<=(~Dy)+1'b1;endelse abs_dy<=Dy;end
end// dxy
always @(posedge clk) begin if(rst==1'b1) begindxy<= 'd0;end else if (flag_dxy==1'b1) begindxy<=abs_dx+abs_dy;end
end// rgb
always @(posedge clk) begin if(rst==1'b1) beginrgb <= 'd0;end else if (flag_rgb==1'b1) beginif (dxy>VALUR) beginrgb<=8'hff;endelsergb<=8'h00;end
endsfifo_8X256 sfifo1_8X256 (.clk(clk),      // input wire clk.din(data_in1),      // input wire [7 : 0] din.wr_en(wr_en1),  // input wire wr_en.rd_en(rd_en),  // input wire rd_en.dout(dout1),    // output wire [7 : 0] dout.full(),    // output wire full.empty()  // output wire empty
);sfifo_8X256 sfifo2_8X256 (.clk(clk),      // input wire clk.din(rx_data),      // input wire [7 : 0] din.wr_en(wr_en2),  // input wire wr_en.rd_en(rd_en),  // input wire rd_en_r.dout(dout2),    // output wire [7 : 0] dout.full(),    // output wire full.empty()  // output wire empty
);
endmodule

5.VGA_shift模块设计

5.1 显示效果示意图:

在这里插入图片描述

5.2 简易波形示意图:

在这里插入图片描述

5.3 代码

module vga_shift(input wire sclk,//50mhzinput wire clk_25,input wire rst,input wire [7:0] rgb_in,input wire pi_flag,output reg hsync,output reg vsync,output reg [7:0] rgb);parameter HSYNC_END=95;
parameter CNT_H_END=799;parameter VSYNC_END=1;
parameter CNT_V_END=524;parameter RED=8'b11100000;
parameter GREEN=8'b00011100;
parameter BLUE=8'b00000011;
parameter WHITE=8'b11111111;parameter ADDR_MUX=16'd39203;
reg [9:0] cnt_h;
reg [9:0] cnt_v;reg [8:0] x;
reg [8:0] y;reg flag_x;
reg flag_y;reg [15:0] addra,addrb;
wire [7:0] doutb;// cnt_halways @(posedge clk_25) begin if(rst==1'b1) begincnt_h<= 'd0;end else if (cnt_h==CNT_H_END) begincnt_h<='d0;endelse cnt_h<=cnt_h+1'b1;end // hsyncalways @(posedge clk_25) begin if(rst==1'b1) beginhsync<= 'd1;endelse if (cnt_h==CNT_H_END) beginhsync<='d1;end else if (cnt_h==HSYNC_END) beginhsync<='d0;endend// cnt_v
always @(posedge clk_25) begin if(rst==1'b1) begincnt_v <= 'd0;end else if (cnt_v==CNT_V_END && cnt_h==CNT_H_END) begincnt_v<='d0;endelse if (cnt_h==CNT_H_END) begincnt_v<=cnt_v+1'b1;end
end// vsync
always @(posedge clk_25) beginif(rst==1'b1) beginvsync <= 'd1;end else if (cnt_v==VSYNC_END && cnt_h==CNT_H_END) beginvsync<='d0;endelse if (cnt_v==CNT_V_END && cnt_h==CNT_H_END) beginvsync<='d1;endend
// x
always @(posedge clk_25) begin if(rst==1'b1) beginx <= 'd0;end else if (cnt_h==CNT_H_END && cnt_v==CNT_V_END && flag_x=='d0) beginx<=x+1'b1;endelse if (cnt_h==CNT_H_END && cnt_v==CNT_V_END && flag_x=='d1) beginx<=x-1'b1;end
end// flag_x
always @(posedge clk_25) begin if(rst==1'b1) beginflag_x<= 'd0;end else if (cnt_h==CNT_H_END && cnt_v==CNT_V_END && x=='d441 && flag_x=='d0) beginflag_x<='d1;endelse if (cnt_h==CNT_H_END && cnt_v==CNT_V_END && x=='d1 && flag_x=='d1) beginflag_x<='d0;end
end//y
always @(posedge clk_25) begin if(rst==1'b1) beginy<= 'd0;end else if (cnt_h==CNT_H_END && cnt_v==CNT_V_END && flag_y=='d0) beginy<=y+1'b1;end else if (cnt_h==CNT_H_END && cnt_v==CNT_V_END && flag_y=='d1) beginy<=y-1'b1;end
end// flag_y
always @(posedge clk_25) begin if(rst==1'b1) beginflag_y <= 'd0;end else if (cnt_h==CNT_H_END && cnt_v==CNT_V_END && y=='d281 && flag_y<='d0) beginflag_y<='d1;endelse if (cnt_h==CNT_H_END && cnt_v==CNT_V_END && y=='d1 && flag_y<='d1) beginflag_y<='d0;end
end// rgb 
always @(posedge clk_25) begin if(rst=='b1) beginrgb<= 'd0;end//注意198x198像素时,白框范围需要改变else if (cnt_h>=144+x && cnt_h<=341+x && cnt_v>=35+y && cnt_v<=232+y) beginrgb<=doutb;endelse if (cnt_h>=144 && cnt_h<=783) beginif (cnt_v>=35 && cnt_v<=194) beginrgb<=RED;endelse if (cnt_v>=195 && cnt_v<=354) beginrgb<=GREEN;endelse if (cnt_v>=355 && cnt_v<=514) beginrgb<=BLUE;endend elsergb<='d0;end// addra  这里注意写ram的时钟为50mhz,读ram的时钟为25mhz(VGA的时钟)
always @(posedge sclk) begin if(rst) beginaddra<= 'd0;endelse if (pi_flag==1'b1 && addra==ADDR_MUX) beginaddra<='d0;endelse if (pi_flag==1'b1) beginaddra<=addra+1'b1;end end// addrb 注意ram读数据相对于读地址有一拍延迟,所以地址要早一拍给出
always @(posedge clk_25) begin if(rst==1'b1) beginaddrb <= 'd0;end else if (cnt_h>=144+x-1 && cnt_h<=341+x-1 && cnt_v>=35+y && cnt_v<=232+y && addrb==ADDR_MUX) beginaddrb<='d0;endelse if (cnt_h>=144+x-1 && cnt_h<=341+x-1 && cnt_v>=35+y && cnt_v<=232+y) beginaddrb<=addrb+1'b1;end
endasblk_mem_8x198x198 your_instance_name (.clka(sclk),    // input wire clka.wea(pi_flag),      // input wire [0 : 0] wea.addra(addra),  // input wire [15 : 0] addra.dina(rgb_in),    // input wire [7 : 0] dina.clkb(clk_25),    // input wire clkb.addrb(addrb),  // input wire [15 : 0] addrb.doutb(doutb)  // output wire [7 : 0] doutb
);endmodule

6.uart_rx模块设计(直接用之前的设计 略)

7.顶层设计

module top_sobel(input wire clk,//50mhzinput wire rst,input wire rx,output wire vsync,output wire hsync,output wire [7:0]rgb);wire clk_out25;
wire clk_out50;wire rx_data;
wire pi_flag_rx_to_sobel;
wire pi_flag_sobel_to_vga;wire [7:0] rgb_in;clk_wiz_gen25 instance_name(// Clock out ports.clk_out50(clk_out50),     // output clk_out50.clk_out25(clk_out25),     // output clk_out25// Clock in ports.clk_in50(clk));      // input clk_in50uart_rx inst_uart_rx (.clk     (clk_out50),.rst     (rst),.rx      (rx),.po_data (rx_data),.po_flag (pi_flag_rx_to_sobel));sobel_ctrl  inst_sobel_ctrl (.clk     (clk_out50),.rst     (rst),.rx_data (rx_data),.pi_flag (pi_flag_rx_to_sobel),.rgb     (rgb_in),.po_flag (pi_flag_sobel_to_vga));vga_shift inst_vga_shift (.sclk    (clk_out50),.clk_25  (clk_out25),.rst     (rst),.rgb_in  (rgb_in),.pi_flag (pi_flag_sobel_to_vga),.hsync   (hsync),.vsync   (vsync),.rgb     (rgb));endmodule

8.最终的显示效果:

上位机通过MATLAB处理,用友善助手下发原图像数据:

在这里插入图片描述
经过一系列图像处理后,最终在vga的显示效果:
在这里插入图片描述

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

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

相关文章

简单的DbUtils工具类【精细】

目录 单条通用增删改方法 1.创建maven项目&#xff0c;并加载依赖 2.创建数据库连接工具类(Dbutils类) 3.创建一个执行器(SqlExecutor类) 4.通用(增&#xff0c;删&#xff0c;改)方法 1.创建方法 2.创建userInfo实体类 3.创建测试类&#xff0c;测试增&#xff0c;删&#xf…

探索数据结构:树与二叉树

✨✨ 欢迎大家来到贝蒂大讲堂✨✨ &#x1f388;&#x1f388;养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; 所属专栏&#xff1a;数据结构与算法 贝蒂的主页&#xff1a;Betty’s blog 1. 树 1.1. 树的定义 树是一种非线性的数据结构&#xff0c;它是由n&a…

ORA-609频繁出现在alert.log,如何解决?

ORA-609就alertlog中比较常见的一个报错&#xff0c;虽然并没有太大的影响&#xff0c;但是频繁的出现在alert log也是很让人厌烦的事情&#xff0c;本文介绍如何排查解决ORA-609问题。 1.ORA-609官方定义 could not attach to incoming connection Cause Oracle process cou…

【SRC实战】前端脱敏信息泄露

挖个洞先 https://mp.weixin.qq.com/s/xnCQQCAneT21vYH8Q3OCpw “ 以下漏洞均为实验靶场&#xff0c;如有雷同&#xff0c;纯属巧合 ” 01 — 漏洞证明 一、前端脱敏&#xff0c;请求包泄露明文 “ 前端脱敏处理&#xff0c;请求包是否存在泄露&#xff1f; ” 1、获取验…

|Python新手小白中级教程|第二十八章:面向对象编程(类定义语法私有属性类的继承与多态)(4)

文章目录 前言一、类定义语法二、私有方法和私有属性1.私有属性2.私有方法 三、类“继承”1.初识继承2.使用super函数调用父类中构造的东西 四、类“多态”1.多态基础2.子类不同形态3.使用isinstance函数与多态结合判断类型 总结 前言 大家好&#xff0c;我是BoBo仔吖&#xf…

6818Linux内核开发移植

Linux内核开发移植 Linux内核版本变迁及其获得 Linux是最受欢迎的自由电脑操作系统内核&#xff0c; 是一个用C语言写成&#xff0c; 并且符合POSIX标准的类Unix操作系统 Linux是由芬兰黑客Linus Torvalds开发的&#xff0c; 目的是尝试在英特尔x86架构上提供自由免费的类Un…

Task Office for Mac v9.0激活版:任务管理新境界

还在为繁琐的任务管理而烦恼吗&#xff1f;Task Office for Mac为您带来全新的任务管理体验。简洁明了的界面设计&#xff0c;让您轻松上手&#xff1b;强大的任务管理和项目管理功能&#xff0c;让您轻松掌握任务进度&#xff1b;多用户协作功能&#xff0c;让团队协作更加高效…

Excel办公技巧之下拉菜单

在日常办工中&#xff0c;经常需在单元格中输入特定的值&#xff0c;此时我们可以使用下拉菜单解决&#xff0c;输入错误和错误值&#xff0c;可以一劳永逸的解决固定数据输入问题。 使用Excel下拉菜单时&#xff0c;它在数据输入和验证方面发挥着重要作用通过点击单元格的下拉…

商业数据分析--时间序列图及趋势分析

绘制时间序列图,并指出存在什么样的状态如上两图: 可见状态:从时间序列图可以看出,这些数据存在明显的季节性波动,每年的第4季度值都最高,而第2季度值最低。同时也存在一些下降的趋势。 通过引进虚拟变量,建立多元线性回归模型。答: 通过引入虚拟变量,我们可以建立如下的…

商场学习之微服务

前言 寒假前在新电脑上配置了java环境&#xff0c;maven仓库&#xff0c;node,js&#xff0c;navicat&#xff0c;MySQL&#xff0c;linux&#xff0c;vmware等环境&#xff0c;创建了6个mysql数据库&#xff0c;77张表。 如此多的表&#xff0c;字段&#xff0c;去手写基础…

Web入门——三栏布局页面

前置知识 内外边距 内边距(padding)&#xff1a; padding是元素边框与其内容之间的空间。也就是说&#xff0c;如果你给一个元素设置了内边距&#xff0c;这个空间会作为元素内容与元素边框之间的缓冲区域。设置内边距会使元素本身变大。例如padding:10px就创建了10像素的空间…

Qt之QMqtt 发送图片数据

简述 MQTT(消息队列遥测传输)是ISO标准下基于发布/订阅范式的消息协议;它工作在TCP/IP协议族上,是为硬件性能低下的远程设备以及网络状况糟糕的情况下而设计的发布/订阅型消息协议,为此,它需要一个消息中间件; MQTT是一个基于客户端-服务器的消息发布/订阅传输协议;MQT…

Docker in Docker(DinD)原理与实战

&#x1f407;明明跟你说过&#xff1a;个人主页 &#x1f3c5;个人专栏&#xff1a;《Docker幻想曲&#xff1a;从零开始&#xff0c;征服容器宇宙》 &#x1f3c5; &#x1f516;行路有良友&#xff0c;便是天堂&#x1f516; 目录 一、引言 1、Docker简介 2、Docker …

使用 AI Assistant for Observability 和组织的运行手册增强 SRE 故障排除

作者&#xff1a;Almudena Sanz Oliv, Katrin Freihofner, Tom Grabowski 通过本指南&#xff0c;你的 SRE 团队可以实现增强的警报修复和事件管理。 可观测性 AI 助手可帮助用户使用自然语言界面探索和分析可观测性数据&#xff0c;利用自动函数调用来请求、分析和可视化数据…

windows系统安装Ubuntu子系统

安装前先在 控制面板 中打开 程序与功能选项 &#xff0c;点击 启用或关闭Windows功能&#xff1a; 勾选 适用于 Linux的Windows子系统 和 虚拟机平台 、 Hyper-v 。 重启电脑后再 Microsoft Store Windows应用商店 中下载合适的Ubuntu版本。 运行Ubuntu程序&#xff0c;如出现…

【实战】算法思路总结

面试过程中&#xff0c;总是被拷打&#xff0c;信心都要没了。但是也慢慢摸索出一些思路&#xff0c;希望对大家有帮助。 &#xff08;需要多用一下ACM模式&#xff0c;力扣模式提供好了模板&#xff0c;自己在IDEA里面写的话&#xff0c;还是会有些陌生&#xff09; 0、基本…

Unity Editor 找物体助手

找啊找朋友~ &#x1f371;功能介绍&#x1f959;使用方法 &#x1f371;功能介绍 &#x1f4a1;输入相关字符串&#xff0c;它会帮你找到名称中带有该字符串的所有物体&#xff0c;还会找包含该字符串的Text、TextMeshProUGUI。 &#x1f959;使用方法 &#x1f4a1;导入插…

小学拼音弄一下

import re from xpinyin import Pinyindef remove_middle_characters(text):# 仅保留汉字chinese_chars re.findall(r[\u4e00-\u9fff], text)cleaned_text .join(chinese_chars)# 如果字符数为偶数&#xff0c;则在中间添加空格if len(cleaned_text) % 2 0:middle_index le…

【北京迅为】《iTOP-3588从零搭建ubuntu环境手册》-第5章 安装SSH

RK3588是一款低功耗、高性能的处理器&#xff0c;适用于基于arm的PC和Edge计算设备、个人移动互联网设备等数字多媒体应用&#xff0c;RK3588支持8K视频编解码&#xff0c;内置GPU可以完全兼容OpenGLES 1.1、2.0和3.2。RK3588引入了新一代完全基于硬件的最大4800万像素ISP&…

从0开始学python(七)

目录 前言 1 break、continue和pass函数 1.1 break 1.2 continue 1.3 pass 2、序列的索引及切片操作 2.1字符串的索引和切片 2.1.1 字符串索引 2.1.2 字符串切片 总结 前言 上一篇文章我们介绍了python中的循环结构&#xff0c;包括for和while的使用。本章接着往下讲。…