本文主要内容是实现图像的边缘检测功能


目录

  1. mif文件的制作
  2. 调用 ip 核生成rom以及在 questasim 仿真注意问题
  3. 灰度处理
  4. 均值滤波:重点是3*3 像素阵列的生成
  5. sobel边缘检测
  6. 图片的显示
  7. 结果展示

mif文件的制作

受资源限制,将图片像素定为 160 * 120,将图片数据制成 mif 文件,对 rom ip 核进行初始化。mif文件的制作方法网上有好多办法,因此就不再叙述了,重点说mif文件的格式。

1、mif文件的格式为:

 WIDTH= ;    //数据位宽
DEPTH= ; // rom 深度即图片像素点的个数
ADDRESS_RADIX=UNS ; //地址数据格式
DATA_RADIX=BIN ; //数据格式
CONTENT
BEGIN
: ; // 地址 :数据 ;注意格式要和上面定义的保持统一
: ;
: ;
......
: ;
: ;
END;

调用ip 核生成 rom 以及在 questasim 仿真注意问题

这部分内容已经在上篇博文中详细描述过,详情请见http://www.cnblogs.com/aslmer/p/5780107.html


灰度处理

任何颜色都由红、绿、蓝三原色组成,假如原来某点的颜色为( R,G,B )那么,我们可以通过下面几种方法,将其转换为灰度:
  • 浮点算法:Gray=0.299R+0.587G+0.114B
  • 平均值法:Gray=(R+G+B)/3;
  • 仅取单色(如绿色):Gray=G;
将计算出来的Gray值同时赋值给 RGB 三个通道即RGB为(Gray,Gray,Gray),此时显示的就是灰度图。通过观察调色板就能看明了。 通过观察可知,当RGB三个通道的值相同时即为灰色,Gray的值越大,颜色越接近白色,反之越接近黑色(这是我自己的理解,不严谨错误之处请大神指正)。
这是在线调色板网址,可以进去自己研究一下。http://tool.chinaz.com/tools/selectcolor.aspx

--------------------------------------------------------------------------------------------------------------------

此次我采用是浮点算法来实现灰度图的,我的图片数据是RGB565 格式 ,

难点: 如何进行浮点运算。

思路:先将数据放大,然后再缩小。

例如:
Gray=0.299R+0.587G+0.114B转化为 Gray=(77R+150G+29B)>>8 即可,这里有一个技巧,若 a 为 16 位即 a [15:0],那么 a>>8 与 a [15:8]是一样的。
核心代码如下:
always  @(posedge clk or negedge rst_n)begin
if(rst_n=='b0)begin
red_r1 <= 0 ;
green_r1 <= 0 ;
blue_r1 <= 0 ;
end
else begin
red_r1 <= red * 77 ; //放大后的值
green_r1 <= green * ;
blue_r1 <= blue * 29 ;
end
end always @(posedge clk or negedge rst_n)begin
if(rst_n=='b0)begin
Gray <= ; // 三个数之和
end
else begin
Gray <= red_r1 + green_r1 + blue_r1;
end
end always @(posedge clk or negedge rst_n)begin
if(rst_n=='b0)begin
post_data_in <= ; //输出的灰度数据
end
else begin
post_data_in <= { Gray[:], Gray[:], Gray[:] };//将Gray值赋值给RGB三个通道
end
end
 

均值滤波

均值滤波的原理

http://blog.csdn.net/hhygcy/article/details/4325304 (此处引用 hhygcy 的文章)

难点:如何生成 3*3 的像素阵列。

我们可以利用 ip 核生成移位寄存器 ,方法与 ip 核 生成 rom 一样,详情见目录 2 因此不再赘述 。

仿真波形如下 row_1 , row_2 , row_3 是指图像的第一、二、三行的数据,Per_href 是行有效信号(受VGA时序的启发,从 rom 中读取数据时设计了行有效和场有效的控制信号,事半功倍,有了利于仿真查错和数据的控制)。从 3 开始就出现了3*3 的像素阵列,这时候就可以求取周围 8 个像素点的平均值,进行均值滤波。

下面这个图是我自己画的 FPGA 如何将矩阵数据处理成并行的像素点,可以结合下面的代码好好理解,这也是精华所在。

正方形红框框起来的是第一个完整的 3*3 矩阵,长方形红框框起来的是并行的像素点,在此基础上就可以求得平均值,进行均值滤波。

从下图也能看到 3*3 矩阵从左往右滑动。

第一个3*3 阵列。

0  1  2   -- >  p11 p12 p13

3  4  5   -- >  p21 p22 p23

6  7  8   -- >  p31 p32 p33

核心代码如下:

reg [:]p_11,p_12,p_13;  // 3 * 3 卷积核中的像素点
reg [:]p_21,p_22,p_23;
reg [:]p_31,p_32,p_33;
reg [:]mean_value_add1,mean_value_add2,mean_value_add3;//每一行之和 always @(posedge clk or negedge rst_n)begin
if(rst_n=='b0)begin
{p_11,p_12,p_13} <= {'b0,5'b0,'b0} ;
{p_21,p_22,p_23} <= {'b0,15'b0,'b0};
{p_31,p_32,p_33} <= {'b0,15'b0,'b0};
end
else begin
if(per_href_ff0==&&flag_do==)begin
{p_11,p_12,p_13}<={p_12,p_13,row_1};
{p_21,p_22,p_23}<={p_22,p_23,row_2};
{p_31,p_32,p_33}<={p_32,p_33,row_3};
end
else begin
{p_11,p_12,p_13}<={'b0,5'b0,'b0};
{p_21,p_22,p_23}<={'b0,5'b0,'b0}
{p_31,p_32,p_33}<={'b0,5'b0,'b0}
end
end
end always @(posedge clk or negedge rst_n)begin
if(rst_n=='b0)begin
mean_value_add1<=;
mean_value_add2<=;
mean_value_add3<=;
end
else if(per_href_ff1)begin
mean_value_add1<=p_11+p_12+p_13;
mean_value_add2<=p_21+ +p_23;
mean_value_add3<=p_31+p_32+p_33;
end
end wire [:]mean_value;//8位数之和
wire [:]fin_y_data; //平均数,除以8,相当于左移三位。 assign mean_value=mean_value_add1+mean_value_add2+mean_value_add3;
assign fin_y_data=mean_value[:];

sobel 边缘检测

边缘检测的原理

该算子包含两组 3x3 的矩阵,分别为横向及纵向,将之与图像作平面卷积,即可分别得出横向及纵向的亮度差分近似值。A代表原始图像的 3*3 像素阵列,Gx及Gy分别代表经横向及纵向边缘检测的图像,其公式如下:

图像的每一个像素的横向及纵向梯度近似值可用以下的公式结合,来计算梯度的大小。

如果梯度G大于某一阀值则认为该点(x,y)为边缘点。

-------------------------------------------------------------------------------------------------------------------

用的是 边缘检测算法。

难点:(1)掌握了 3*3 像素阵列,Gx 与 Gy 就很好计算了 (注意问题:为了避免计算过程中出现负值,所以将正负值分开单独计算,具体见代码)

(2)G的计算需要开平方,如何进行开平方运算

Quartus 提供了开平方 ip 核,因此我们直接调用就好了 。

代码:

reg [:] p_x_data ,p_y_data ;  // x 和 y 的正值之和
reg [:] n_x_data ,n_y_data ; // x 和 y 的负值之和
reg [:] gx_data ,gy_data ; //最终结果 always @(posedge clk or negedge rst_n)begin
if(rst_n=='b0)begin
p_x_data <=;
n_x_data <=;
gx_data <=;
end
else if(per_href_ff1==) begin
p_x_data <= p_13 + (p_23<<) + p_33 ;
n_x_data <= p_11 + (p_12<< )+ p_13 ;
gx_data <= (p_x_data >=n_x_data)? p_x_data - n_x_data : n_x_data - p_x_data ;
end
else begin
p_x_data<=;
n_x_data<=;
gx_data <=;
end
end always @(posedge clk or negedge rst_n)begin
if(rst_n=='b0)begin
p_y_data <=;
n_y_data <=;
gy_data <=;
end
else if(per_href_ff1==) begin
p_y_data <= p_11 + (p_12<<) + p_13 ;
n_y_data <= p_31 + (p_32<<) + p_33 ;
gy_data <= (p_y_data >=n_y_data)? p_y_data - n_y_data : n_y_data - p_y_data ;
end
else begin
p_y_data <=;
n_y_data <=;
gy_data <=;
end
end //求平方和,调用ip核开平方
reg [:] gxy; // Gx 与 Gy 的平方和
always @(posedge clk or negedge rst_n)begin
if(rst_n=='b0)begin
gxy<=;
end
else begin
gxy<= gy_data* gy_data + gx_data* gx_data ;
end
end wire [:] squart_out ;
altsquart u1_altsquart ( //例化开平方的ip核
.radical (gxy),
.q (squart_out), //输出的结果
.remainder()
); //与阈值进行比较
reg [:] post_y_data_r;
always @(posedge clk or negedge rst_n)begin
if(rst_n=='b0)begin
post_y_data_r<='h00;
end
else if(squart_out>=threshold)
post_y_data_r<='h00 ;
else
post_y_data_r<='hffff ; end

图片的显示

本来是想用 VGA 来显示图片的,由于条件的限制没能实现,最终只能将处理完的数据输出保存在 .txt 文件中,然后借助好友写的网页进行显示。

难点:(1) 如何将数据流输出保存到 .txt 文件中。

(2) 网页的使用及注意事项

在testbench里加入下面所示代码即可将图片数据保存到 .txt 文本

代码如下:

     integer w_file;
initial
w_file = $fopen("data_out_3.txt"); //保存数据的文件名 always @(posedge clk or negedge rst_n)
begin
if(flag_write==&&post_href==)//根据自己的需求定义
$fdisplay(w_file,"%b",post_y_data);
end

------------------------------------------------------------------------------------------------

网页的界面如下,将参数设置好以后就可以显示图片。

下载链接 http://files.cnblogs.com/files/aslmer/aggregrate.zip

注意:由于此网站是量身定做的,所以只能显示数据格式为RGB565的16位二进制的数才能正确显示,注意不能有分号,正确格式示例如下,必须严格遵守


结果展示

1 原图

2 灰度图

3 均值滤波

4 边缘检测 阈值为5

5  阈值为 10

6  阈值为 16

小结:均值滤波处理后的图片有明显的黑边,产生这一现象的原因就是生成 3*3 像素矩阵和取像素值时数据有损失造成的,但是这也是可以优化的,后续我会继续努力不断完善。本次只是简单对一幅图像进行边缘检测,我的后续目标是实现图片的实时处理,这又需要学习很多东西了,SDRAM、摄像头驱动等等等,越学习越发现自己知道的实在是太少了,永远在路上,学无止境。希望我的分享能够帮助一些和我一样热爱 FPGA 图像处理的朋友。

每天进步一点点,开心就好

aslmer

转载请注明出处 http://www.cnblogs.com/aslmer/p/5779079.html

基于 FPGA 的图像边缘检测的更多相关文章

  1. 基于FPGA的Sobel边缘检测的实现

    前面我们实现了使用PC端上位机串口发送图像数据到VGA显示,通过MATLAB处理的图像数据直接是灰度图像,后面我们在此基础上修改,从而实现,基于FPGA的动态图片的Sobel边缘检测.中值滤波.Can ...

  2. 【转】基于FPGA的Sobel边缘检测的实现

    前面我们实现了使用PC端上位机串口发送图像数据到VGA显示,通过MATLAB处理的图像数据直接是灰度图像,后面我们在此基础上修改,从而实现,基于FPGA的动态图片的Sobel边缘检测.中值滤波.Can ...

  3. 基于FPGA的图像开发平台 其他摄像头附件说明(OV5642 OV9655)

    基于FPGA的图像开发平台 其他摄像头附件说明 FPGA_VIP_V101 编者 奇迹再现 个人博客 http://www.cnblogs.com/ccjt/ 联系邮箱 Shenyae86@163.c ...

  4. 基于FPGA的图像镜像

    图像镜像,一种较为常见的图像处理操作,分为水平镜像.垂直镜像.对角镜像.水平镜像即处理后的图像与原图像关于垂直线对称,垂直镜像为处理后的图像与 原图像关于水平线对称,对角镜像则关于对角线对称. 关于低 ...

  5. 基于FPGA的腐蚀膨胀算法实现

    本篇文章我要写的是基于的腐蚀膨胀算法实现,腐蚀膨胀是形态学图像处理的基础,,腐蚀在二值图像的基础上做"收缩"或"细化"操作,膨胀在二值图像的基础上做" ...

  6. 基于FPGA的图像去噪

    目录 结构图 其中FPGA 控制模块为核心,通过它实现视频图像数据的获取.缓存.处理和控制各模块间通讯[1].由CCD 相机对目标成像,高速图像数据由camera link 实时传输[2],经信号转换 ...

  7. 基于FPGA的线阵CCD图像测量系统研究——笔记

    本文是对基于FPGA的线阵CCD图像测量系统研究(作者:高尚)的阅读笔记 第一章绪论 1. 读读看 读了前面的摘要依然没有看懂作者要做什么.接着往下读....终于看到了一个字眼“基于机器视觉的图像测量 ...

  8. 基于FPGA的Uart接收图像数据至VGA显示

    系统框图 前面我们设计了基于FPGA的静态图片显示,接下来我们来做做基于FPGA的动态图片显示,本实验内容为:由PC端上位机软件通过串口发送一幅图像数据至FPGA,FPGA内部将图像数据存储,最后扫描 ...

  9. 基于FPGA的线阵CCD实时图像采集系统

    基于FPGA的线阵CCD实时图像采集系统 2015年微型机与应用第13期 作者:章金敏,张 菁,陈梦苇2016/2/8 20:52:00 关键词: 实时采集 电荷耦合器件 现场可编程逻辑器件 信号处理 ...

随机推荐

  1. Linux Shell流程例子

    #!/bin/bash read -p "input a dight:"echo $REPLY DATE=`date`echo "DATE is ${DATE}" ...

  2. UOJ#7 NOI2014 购票 点分治+凸包二分 斜率优化DP

    [NOI2014]购票 链接:http://uoj.ac/problem/7 因为太麻烦了,而且暴露了我很多学习不扎实的问题,所以记录一下具体做法. 主要算法:点分治+凸包优化斜率DP. 因为$q_i ...

  3. 2015 ACM/ICPC Asia Regional Changchun Online Pro 1008 Elven Postman (BIT,dfs)

    Elven Postman Time Limit: 1500/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)T ...

  4. UVA12897 - Decoding Baby Boos

    没必要每次都真的修改一遍字母值,用一个标记表示字母最后的值,最后一遍的时候再进行修改 #include<cstdio> #include<cstring> +; char st ...

  5. C11 C语言文件的读写

    目录 文件的打开和关闭 字符流读写文件 文件的打开和关闭 fopen( ) fopen( ) 函数来创建一个新的文件或者打开一个已有的文件,这个调用会初始化类型 FILE 的一个对象,类型 FILE ...

  6. vim 自动补全 颜色设置

    vim 自动补全 颜色设置 hi Pmenu ctermfg=black ctermbg=gray guibg=# hi PmenuSel ctermfg= ctermbg= guibg=# guif ...

  7. java基础—方法重载(overload)

    一.方法的重载 方法名一样,但参数不一样,这就是重载(overload). 所谓的参数不一样,主要有两点:第一是参数的个数不一样,第二是参数的类型不一样.只要这两方面有其中的一方面不一样就可以构成方法 ...

  8. Luogu P1666 前缀单词

    校内资格赛题目,差点高一就要\(\tt{AFO}\)了 30分思路 对30%的数据,满足$1≤n≤10 $ 所以我们可以子集枚举,实际得分40pts #include<iostream> ...

  9. VueX源码分析(1)

    VueX源码分析(1) 文件架构如下 /module /plugins helpers.js index.esm.js index.js store.js util.js util.js 先从最简单的 ...

  10. 一句话懂什么是JS闭包

    无论何时声明新函数并将其赋值给变量,都要存储函数定义和闭包.闭包包含在函数创建时作用域中的所有变量,它类似于背包.函数定义附带一个小背包,它的包中存储了函数定义创建时作用域中的所有变量. 我将永远记住 ...