项目需求

这个实验主要是实现了图像灰度的转换,将原来的RGB565通过串口发送到FPGA开发板,然后通过算法转换实现数据的处理。

方案思路

首先通过串口发送图片数据到FPGA开发板,写入RAM中,最后在读出数据后,在ram_control模块对数据进行,然后将计算后的结果显示大到VGA屏幕上的。下面是项目的实现RTL图。

注意点

  1. 首先是这里的串口模块,我为了是显示下效果更好,使用16位数据作为图片数据。将一个像素点经过两次发送,代码还是用的原来的代码,更详细思路见 串口发送图片VGA显示
  2. 第二个就是补位操作。开始的时候,进行算法计算时没有使用数据对RGB三个分量进行计算,结果显示的效果特别的暗(这里就不贴图了),补位的方式是使用相应的分量数据的低位对其低位进行补位。

R_data{doutb[15:11],doutb[13:11]}
G_data{doutb[10:5 ],doutb[6:5]}
B_data{doutb[4:0 ],doutb[2:0]}

  1. 流水线操作延时的处理方式。这里我将流水线处理的延时放在显示vga_driver模块进行处理,使用参数化,使得模块的复用性更好,具体在后文代码中展示。
  2. 小数操作与除法操作。这里基本思想是先扩大,在缩小,可以进行小数运算。除法运算就是使用移位操作。例如:a >>2就是将a缩小22倍。同理,乘法也是一样的。
  3. 运算过程中的数据溢出!!就是在使用中间变量进行数据存储的时候,一定要保证你用来放数据的寄存器可以存的下可能的最大数据,简单来说就是不能使得数据有溢出,

处理效果与MATLAB对比

这是使用MATLAB进行处理的效果

这是使用FGGA进行处理的效果。具体看还是很不错的

代码分享

这里只分享处理模块和VGA驱动模块,其他的代码往期有,或者很简单,使用的时候需要自己生成ramIP。
计算模块,这里使用流水线,可以为代码复用有很多好处

module ram_control(//system singnalsinput                    sclk            ,input                  s_rst_n         ,//communicate with  VGA_moduleinput                    vga_clk         ,input                  ram_rd_en       ,output          [8:0]      pixel_data      ,//communicate with uart_module input                   uart_flag       ,input      [15:0]      uart_data       );
localparam RD_ADDR_END = 150*150 - 1'b1       ;
localparam para_0114_8 = 9437              ;
localparam para_0587_8 = 38469             ;
localparam para_0299_8 = 19595             ;
//---------------------------计算模块---------------------------------------
// Gray= 0.114B+ 0.587G+ 0.299R
// 精度为256 ,
//这里将数据左移8位 0.114---- 29
//这里将数据左移8位 0.587---- 150
//这里将数据左移8位 0.299---- 77
//这里设置将数据先进行,第一步,乘法,第二步,求和,(然后使用位移符号,进行判断输出----组合逻辑)
wire    [15:0]      doutb               ;
// reg  [7:0]       data_line_2_a       ;
// always @ (posedge vga_clk)
// begin
//  data_line_2_a <= (({doutb[15:11],doutb[13:11]}*para_0299_8 + {doutb[10:5 ],doutb[6:5]}*para_0587_8 + {doutb[4:0  ],doutb[2:0]}*para_0114_8) >> 16);
// end
// assign pixel_data = (data_line_2_a >= 'd255) ? 8'd255 : data_line_2_a[7:0] ;reg   [32:0]      data_line_1a        ;//这里的数据长度一定要够!!!!
reg     [32:0]      data_line_1b        ;//这里的数据长度一定要够!!!!
reg     [32:0]      data_line_1c        ;//这里的数据长度一定要够!!!!
reg     [7:0]       data_line_2         ;
always @ (posedge vga_clk or negedge s_rst_n)
beginif(!s_rst_n)begindata_line_1a <= 'd0;data_line_1b <= 'd0;data_line_1c <= 'd0;endelse begindata_line_1a <= {doutb[15:11],doutb[13:11]}*para_0299_8;data_line_1b <= {doutb[10:5 ],doutb[6:5]}*para_0587_8  ;data_line_1c <= {doutb[4:0  ],doutb[2:0]}*para_0114_8  ;end
end// gray = (rom_q[23:16]*19595 + rom_q[15:8]*38469 + rom_q[7:0]*7472) >> 16
always @ (posedge vga_clk or negedge s_rst_n)
beginif(!s_rst_n)data_line_2 <= 'd0;else data_line_2 <= ((data_line_1a + data_line_1b + data_line_1c ) >> 16);
end assign pixel_data = (data_line_2 >= 'd255) ? 8'd255 : data_line_2[7:0] ;//-----------------------------地址控制模块-------------------------------------
reg     [14:0]      addwr   ;
reg     [14:0]      addrd   ;
always @ (posedge sclk or negedge s_rst_n)
beginif(!s_rst_n)addwr <= 'd0;else if(addwr == RD_ADDR_END && uart_flag)addwr <= 'd0;else if(uart_flag)addwr <= addwr + 1'b1;else addwr <= addwr;
end
always @ (posedge vga_clk or negedge s_rst_n)
beginif(!s_rst_n)addrd <= 'd0;else if(addrd == RD_ADDR_END && ram_rd_en)addrd <= 'd0;else if(ram_rd_en)addrd <= addrd + 1'b1;else addrd <= addrd;
end
ram_150_16 ram_contr (.clka(sclk), // input clka.wea(uart_flag), // input [0 : 0] wea.addra(addwr), // input [14 : 0] addra.dina(uart_data), // input [15 : 0] dina.clkb(vga_clk), // input clkb.addrb(addrd), // input [14 : 0] addrb.doutb(doutb) // output [15 : 0] doutb
);
endmodule

vga驱动模块

module vga_driver(input              vga_clk         ,
input               vga_rst_n       ,output                 vga_hs          ,
output              vga_vs          ,
output  reg [15:0]  vga_rgb         ,
//读数据使能
output  reg         ram_rd_en       ,
input       [15:0]  pixel_data      );
//---------------------------------常规---------------------------------
reg     [9:0]       cnt_h       ;
reg     [9:0]       cnt_v       ;
parameter Hor_Total_Time        = 800  ;       //行显示帧长parameter Hor_Sync               = 96   ;       //行同步脉冲
parameter Hor_Back_Porch        = 48   ;       //行显示后沿
parameter Hor_Addr_Time         = 640  ;       //行显示区域
parameter Hor_Front_Porch       = 16   ;       //行显示前沿parameter Ver_Total_Time         = 525  ;       //列显示帧长parameter Ver_Sync               = 2        ;       //列同步脉冲
parameter Ver_Back_Porch        = 33   ;       //列显示后沿
parameter Ver_Addr_Time         = 480  ;       //列显示区域
parameter Ver_Front_Porch       = 10   ;       //列显示前沿+列显示前门列parameter PIC_SIZES              = 150  ;       //图片尺寸大小//------------------------------------------------------------------
always@(posedge vga_clk or negedge vga_rst_n)
beginif(!vga_rst_n)cnt_h <= 'd0;else if(cnt_h == ( Hor_Total_Time - 1'b1) )cnt_h <= 'd0;else cnt_h <= cnt_h + 1'b1;
end
always@(posedge vga_clk or negedge vga_rst_n)
beginif(!vga_rst_n)cnt_v <= 'd0;else if(cnt_v == (Ver_Total_Time - 1'b1) && (cnt_h == Hor_Total_Time - 1'b1) )cnt_v <= 'd0;else if(cnt_h == (Hor_Total_Time - 1'b1))cnt_v <= cnt_v + 1'b1;
end assign vga_hs   =  (cnt_h < Hor_Sync)   ?   1'b1   :   1'b0; //从0开始计数,当到达96的时候,拉低
assign vga_vs   =  (cnt_v < Ver_Sync)   ?   1'b1   :   1'b0;
//这里使用参数化,对于要提前的时钟周期直接定义即可
localparam  TIME_DELAY          =          2       ;
//读数据使能,需要提4个时钟周期,读数据需要一个时钟周期,处理数据需要三个时钟周期
always@(posedge vga_clk or negedge vga_rst_n)
beginif(!vga_rst_n)ram_rd_en <= 1'b0;elseif (  cnt_v >      (Ver_Sync + Ver_Back_Porch  )              && cnt_v <=     (Ver_Sync + Ver_Back_Porch + PIC_SIZES  )     &&cnt_h >    (Hor_Sync + Hor_Back_Porch - TIME_DELAY + 1'b1 )                 && cnt_h <=     (Hor_Sync + Hor_Back_Porch + PIC_SIZES - TIME_DELAY + 1'b1 ) )ram_rd_en <= 1'b1;else ram_rd_en <= 1'b0;
endreg vga_en;
always@(*)
beginvga_en <= (cnt_h > (Hor_Sync + Hor_Back_Porch) && cnt_h <= (Hor_Sync + Hor_Back_Porch + Hor_Addr_Time) && cnt_v > (Ver_Sync + Ver_Back_Porch) && cnt_v <= (Ver_Sync + Ver_Back_Porch + Ver_Addr_Time));
end
always@(*)
beginif(vga_en)begin if(    cnt_v >      (Ver_Sync + Ver_Back_Porch ) && cnt_v <=   (Ver_Sync + Ver_Back_Porch + PIC_SIZES) &&cnt_h >  (Hor_Sync + Hor_Back_Porch ) && cnt_h <=   (Hor_Sync + Hor_Back_Porch + PIC_SIZES) )vga_rgb <= pixel_data;else if(cnt_v >= (Ver_Sync + Ver_Back_Porch  - 1'b1) && cnt_v < (Ver_Sync + Ver_Back_Porch  + 159 - 1'b1) )vga_rgb <= {5'h1f,11'h0};else if(cnt_v >= (Ver_Sync + Ver_Back_Porch  + 159 - 1'b1) && cnt_v < (Ver_Sync + Ver_Back_Porch  + 319 - 1'b1) )vga_rgb <= {5'h0,6'h3f,5'h0};else if(cnt_v >= (Ver_Sync + Ver_Back_Porch  + 319 - 1'b1) && cnt_v < (Ver_Sync + Ver_Back_Porch  + 480 - 1'b1) )vga_rgb <= {5'h0,6'h0,5'h1f};else vga_rgb <= 16'd0;end else vga_rgb <= 16'd0;
end
endmodule

反思与总结

这次做这个花的时间不是很多,主要时间花在了数据的处理运算,以及数据补位问题,还是够细心,考虑的还是不够。对于数据的处理,这里其实也不是很难,多多参考大佬的博文。学习!!感谢
FPGA浮点小数与定点小数的换算及应用
基于FPGA的彩色图转灰度图算法

FPGA 实现 RGB 图像转 Gray相关推荐

  1. 【FPGA教程案例48】图像案例8——基于FPGA的RGB图像转化为HSV图像的实现,通过MATLAB进行辅助验证

    FPGA教程目录 MATLAB教程目录 -------------------------------------------------------------------------------- ...

  2. 基于FPGA的RGB图像转 Ycbcr图像实现 gray图像

    Ycbcr图像 这里不解释过多,引荐一片论文.参考<基于FPGA的一种色空间转换算法的设计与实现_丁博文>,这篇论文里面讲的很清楚,还有其他的概念和算法的展示. 这里我使用Y分量实现显示的 ...

  3. python rgb2gray 将rgb图像转换为gray图像

    import numpy as np import cv2def bgr2gray(rgb):return np.dot(rgb, [0.114, 0.587, 0.299]).astype(np.u ...

  4. C语言运行时变成灰色,C语言实现RGB图像转换成灰(Gray)度图像

    以前实现RGB图像转换成灰度图像都是直接调用OpenCV的库函数RGB2GRAY(IplImage* src);最近老板让我们除了读入输出图像实时用OpenCV的函数,其余的最好都是自己写,所以我自己 ...

  5. matlab如何截取图像的中间部分_利用matlab提取并分割RGB图像中的某一个已知像素值的图像...

    已知一副RGB图像中的的像素值,利用matlab将其分割出来并以二进制图像形式显示: %extract.m clear all; I=imread('new_original.png'); figur ...

  6. 彩色RGB图像转为灰度图像

    将彩色RGB图像转为灰度图像,其中像素值的转换为 灰度值=0.2989 * R + 0.5870 * G + 0.1140 * B 原彩色RGB图像是三通道的,转换成单通道的灰度图像 自己写了一个Py ...

  7. python库skimage 将针对灰度图像的滤波器用于RGB图像

    有许多滤波器设计用于灰度图像但是不能用于彩色图像.为了简化创建函数,使其能够用于RGB图像,scikit-image图像处理库提供了adapt_rgb装饰器. 实际使用adapt_rgb装饰器,你必须 ...

  8. 彩色rgb图像拆分为rgb三个通道,并重新合并为彩色图像

    import numpy as np import imageio import matplotlib.pyplot as pltimg = imageio.imread(r'E:\Vaihingen ...

  9. 一、FPGA Cyclone Ⅳ OV5640图像实时采集系统设计

    一.FPGA Cyclone Ⅳ OV5640图像实时采集系统设计 1.系统框架 2.摄像头配置模块 3.图像数据拼接模块 4.SDRAM操作模块 5.乒乓缓存模块 6.VGA驱动模块 7.顶层模块 ...

最新文章

  1. 映入眼帘的JSON-fastjson常见用法
  2. python爬虫代码实例-Python爬虫爬取百度搜索内容代码实例
  3. 差分能量分析介绍(一)
  4. 使用Lambda表达式重构委托
  5. linux安全策略与实例pdf,实验一:Linux用户管理与安全策略.pdf
  6. linux lcd驱动调试 echo dev/fb0,LCD驱动程序 - osc_msmij2gf的个人空间 - OSCHINA - 中文开源技术交流社区...
  7. 设计模式(4)--AbstractFactory(抽象工厂模式)--创建型
  8. 原SUN网站:java.sun.com,developers.sun.com,bigadmin将合并到OTN
  9. ZNZD平台vue项目
  10. 项目管理(3):备战pmp
  11. linux每个版本发布时间,Ubuntu 21.04各版本的发布时间公布和计划功能介绍
  12. 手机modem开发(12)---MTK 平台如何PUSH modem 到手机中进行调试
  13. 轻量应用服务器支持带宽套餐升级至流量包套餐流程说明
  14. 亚马逊kindle设置_亚马逊的新款Kindle Fire平板电脑:极客评论
  15. android同花顺布局,同花顺首发 Android平板电脑炒股高清版
  16. 《代码大全》个人总结
  17. 大数据导论(二:大数据的架构)
  18. 当Linux配置zh_CN.UTF-8 ,中文还是显示乱码解决办法
  19. 申请license激活F5-LTM步骤
  20. 大一计算机系挂科,大一挂科和大三挂科,哪个后果更严重?实际差距不是一星半点...

热门文章

  1. Mysql添加用户错误:ERROR 1364 (HY000): Field ‘ssl_cipher‘ doesn‘t have a default value解决方法
  2. 版本化SQL Server数据库
  3. 如何在Windows上运行Redis?
  4. 将JS对象转换为JSON字符串
  5. 如果我已经开始重新设置基准,如何将两个提交合并为一个?
  6. html5自定义组件样式,Taro 自定义组件样式不生效及解决方案
  7. cmd imp导入dmp文件_exp/imp、expdp/impdp使用总结,这些你都清楚吗?
  8. boost 安装_Win10 + VS2019 编译安装 Boost
  9. vivox6android版本5.1,vivo X6 Plus的手机系统是什么?能升级安卓5.0吗?
  10. 重启iis与mysql服务器吗_每晚定时重启IIS和数据库服务可节省服务器资源