VGA项目:联合精简帧+双fifo+sobel算法 实现VGA显示(未完)

2024-05-06 13:44

本文主要是介绍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图像的存储与读取):

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的显示效果:
在这里插入图片描述

这篇关于VGA项目:联合精简帧+双fifo+sobel算法 实现VGA显示(未完)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/964516

相关文章

不懂推荐算法也能设计推荐系统

本文以商业化应用推荐为例,告诉我们不懂推荐算法的产品,也能从产品侧出发, 设计出一款不错的推荐系统。 相信很多新手产品,看到算法二字,多是懵圈的。 什么排序算法、最短路径等都是相对传统的算法(注:传统是指科班出身的产品都会接触过)。但对于推荐算法,多数产品对着网上搜到的资源,都会无从下手。特别当某些推荐算法 和 “AI”扯上关系后,更是加大了理解的难度。 但,不了解推荐算法,就无法做推荐系

这15个Vue指令,让你的项目开发爽到爆

1. V-Hotkey 仓库地址: github.com/Dafrok/v-ho… Demo: 戳这里 https://dafrok.github.io/v-hotkey 安装: npm install --save v-hotkey 这个指令可以给组件绑定一个或多个快捷键。你想要通过按下 Escape 键后隐藏某个组件,按住 Control 和回车键再显示它吗?小菜一碟: <template

如何用Docker运行Django项目

本章教程,介绍如何用Docker创建一个Django,并运行能够访问。 一、拉取镜像 这里我们使用python3.11版本的docker镜像 docker pull python:3.11 二、运行容器 这里我们将容器内部的8080端口,映射到宿主机的80端口上。 docker run -itd --name python311 -p

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

康拓展开(hash算法中会用到)

康拓展开是一个全排列到一个自然数的双射(也就是某个全排列与某个自然数一一对应) 公式: X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[1]*0! 其中,a[i]为整数,并且0<=a[i]<i,1<=i<=n。(a[i]在不同应用中的含义不同); 典型应用: 计算当前排列在所有由小到大全排列中的顺序,也就是说求当前排列是第

第10章 中断和动态时钟显示

第10章 中断和动态时钟显示 从本章开始,按照书籍的划分,第10章开始就进入保护模式(Protected Mode)部分了,感觉从这里开始难度突然就增加了。 书中介绍了为什么有中断(Interrupt)的设计,中断的几种方式:外部硬件中断、内部中断和软中断。通过中断做了一个会走的时钟和屏幕上输入字符的程序。 我自己理解中断的一些作用: 为了更好的利用处理器的性能。协同快速和慢速设备一起工作

csu 1446 Problem J Modified LCS (扩展欧几里得算法的简单应用)

这是一道扩展欧几里得算法的简单应用题,这题是在湖南多校训练赛中队友ac的一道题,在比赛之后请教了队友,然后自己把它a掉 这也是自己独自做扩展欧几里得算法的题目 题意:把题意转变下就变成了:求d1*x - d2*y = f2 - f1的解,很明显用exgcd来解 下面介绍一下exgcd的一些知识点:求ax + by = c的解 一、首先求ax + by = gcd(a,b)的解 这个

综合安防管理平台LntonAIServer视频监控汇聚抖动检测算法优势

LntonAIServer视频质量诊断功能中的抖动检测是一个专门针对视频稳定性进行分析的功能。抖动通常是指视频帧之间的不必要运动,这种运动可能是由于摄像机的移动、传输中的错误或编解码问题导致的。抖动检测对于确保视频内容的平滑性和观看体验至关重要。 优势 1. 提高图像质量 - 清晰度提升:减少抖动,提高图像的清晰度和细节表现力,使得监控画面更加真实可信。 - 细节增强:在低光条件下,抖

【数据结构】——原来排序算法搞懂这些就行,轻松拿捏

前言:快速排序的实现最重要的是找基准值,下面让我们来了解如何实现找基准值 基准值的注释:在快排的过程中,每一次我们要取一个元素作为枢纽值,以这个数字来将序列划分为两部分。 在此我们采用三数取中法,也就是取左端、中间、右端三个数,然后进行排序,将中间数作为枢纽值。 快速排序实现主框架: //快速排序 void QuickSort(int* arr, int left, int rig

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象