EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
今天给大侠带来基于 FPGA 的图像边缘检测设计,话不多说,上货。
& K+ P/ |. T% X; R3 X9 ~
设计流程如下:mif文件的制作→ 调用 ip 核生成rom以及仿真注意问题→ 灰度处理→ 均值滤波:重点是3*3 像素阵列的生成→ sobel边缘检测→ 图片的显示→ 结果展示 。 # k( \5 j0 F, U/ f5 A
4 d* J' z2 M. G, d/ K3 u1 ~5 j
一、mif文件的制作7 W: R! F4 |; o( O8 v. c j
6 K9 _% E* t3 x' X
- T4 h1 }$ Y4 z 受资源限制,将图片像素定为 160 * 120,将图片数据制成 mif 文件,对 rom ip 核进行初始化。mif文件的制作方法网上有好多办法,因此就不再叙述了,重点说mif文件的格式。& O$ l- D( r( h% K- S
# s. e4 a/ W: X5 I. q& w, j% T1 J$ e# o- \* {: C
mif文件的格式为:
, I2 s' ]3 f% ~8 w" z% c
( ?; W/ @0 Y+ w/ ]WIDTH=16 ; //数据位宽
$ j9 o6 A4 k' YDEPTH=19200 ; // rom 深度即图片像素点的个数
, M: W# @2 R7 k2 q0 j% F$ aADDRESS_RADIX=UNS ; //地址数据格式: V4 ~7 e+ N) G5 ~% Z9 s$ Y- Y
DATA_RADIX=BIN ; //数据格式% \. K; a5 P8 O" V* Q( G; }
CONTENT8 T- E i; S) J8 W$ x- k
BEGIN
. F! Y; p! d+ h h5 a0:1010110011010000 ; // 地址 :数据 ;注意格式要和上面定义的保持统一
$ n. E. q$ i3 o/ N1 E1:1010110011010000 ;* r' p) r$ ]5 n: i [8 y5 E* H
2:1010010010110000 ;2 L/ l* l" y0 v; Y3 b
......
& Q/ {% E" W7 t# m1 x19198:1110011011111001 ;
" X8 C1 V! o7 v19199:1110011011011000 ;
, D# N: s2 j& `( N7 @3 I- O) z* tEND;0 N+ o6 D4 a2 H# `
6 f! V0 r( X# V8 c
% W# {( B3 v2 ^
二、ip 核生成 rom 及仿真时需要注意的问题 ip 核生成 rom 1、Tools -> MegaWizard Plug-In Manager - y/ n% O* B% ]3 \- j% I
\. c% @. g/ [; e( ?
% X1 O3 v" e" _$ c* N A" i
2、Create a new custom megafuction variation
) G, W8 A: Q# k' ?: J, j3 x1 R
9 G' e. \/ P- `7 V" q! o; s. C* j( P; U. P
3、Memory Compier -> ROM -> Verilog HDL -> 自定义名称 " |$ Q: u; }% D. Z& I$ V: N
' h6 J, e& s+ H7 ~$ f; b$ t/ @9 f( v# X3 q! B: f P
: i I0 S* ?1 [- C6 x% B
/ m8 R9 |, v4 _
+ w. h' z: ~2 i+ {- `
9 X0 m) b# q4 p0 h( L0 g" T4 Z' y
0 Y# |4 C: q! z4 ^. m% I
! V( S+ G) w5 e- {; M# O
7 [7 e0 a. w- }' A. |2 r E1 b9 L& l* q, f4 l' P9 k! ~8 t0 m' R g
仿真注意问题:% C* c' ^. p) v# E3 K
" [' T1 M- [4 O6 h
1、仿真时要注意是否有 altera_mf 库文件,否则会报错。' A( P* O0 D. Y- X) ~+ \
Module 'altsyncram' is not define- s8 a& C; ?/ O3 B0 V2 V% c/ Y7 @" f
解决方案:4 _7 B) h/ @* l4 ]
(1).下载 altera_mf 库文件;8 i$ K( w8 Y! Q& O9 `; T" z( Y
- p4 P Z* o& j5 u
(2). 仿真时将 altera_mf.v 与其他文件一起加入到 project 中。
7 K: l% N8 d* l" f- k
! S0 a( h/ r9 q9 r' k
0 F) C% ~- x: @7 N, a2、要将 .mif 文件放在仿真工程目录下,即与 .mpf 文件在一起,否则将不会有数据输出。& `% J; \4 R1 X$ f1 m/ e( P3 {& _
; J7 K5 @% n- o+ j三、灰度处理4 S+ b+ b! l- P% m1 m
任何颜色都由红、绿、蓝三原色组成,假如原来某点的颜色为( R,G,B )那么,我们可以通过下面几种方法,将其转换为灰度:# m* E# P$ F% I! J" H
; f+ E% e b5 ~( ?+ [0 j
将计算出来的Gray值同时赋值给 RGB 三个通道即RGB为(Gray,Gray,Gray),此时显示的就是灰度图。通过观察调色板就能看明了。 通过观察可知,当RGB三个通道的值相同时即为灰色,Gray的值越大,颜色越接近白色,反之越接近黑色(这是我自己的理解,不严谨错误之处请大神指正)。这是在线调色板网址,可以进去自己研究一下。
% [) g9 _0 R* T( a% M( N; c" g# y: \6 X7 P7 G( A
站长工具颜色代码查询、RGB颜色值: ; m: b/ g" D& @6 ^
1 {; @4 `. {! N6 h5 u
http://tool.chinaz.com/tools/selectcolor.aspx $ h* ]% ]( w2 W* e9 A
7 j) ^' B g; U
: |# u0 _" ?: c# Z6 A: l0 K9 W" K8 O 此次采用是浮点算法来实现灰度图的,我的图片数据是RGB565 格式 ,难点: 如何进行浮点运算。思路:先将数据放大,然后再缩小。; S; j2 l0 z- N+ b
4 y4 C! m8 b7 k( ^% @
( L% Q$ L, m7 I7 E例如:
3 |$ ]( k6 W/ O1 s
$ @5 z( P8 v% S: ~% I8 c5 @: y# b( e' E. M4 V4 |. K
Gray=0.299R+0.587G+0.114B转化为 Gray=(77R+150G+29B)>>8 即可,这里有一个技巧,若 a 为 16 位即 a [15:0],那么 a>>8 与 a [15:8]是一样的。0 r* M% T w- k+ j u" i. O
/ [% A- T4 m) V) d% u
. u+ e) q0 c1 v8 m核心代码如下:
* s$ R& _. I. m. H4 f9 L7 R$ f
+ ^1 S. o/ b( w. }* }always @(posedge clk or negedge rst_n)begin
. o; f$ e: A& { ~; {1 _( a- L; v3 O3 o& k3 M
( b! C6 `* m( g% n' ^- W, l
if(rst_n==1'b0)begin
; f1 _! _9 S; O( b( v# Y red_r1 <= 0 ;
9 z2 ]4 H6 s" D( Q( V( u0 i( _ green_r1 <= 0 ; 6 p+ w% o5 a8 z& o3 E4 w! R t
blue_r1 <= 0 ;
: u% Q1 H% e+ E' W: C% G* N/ u end
: V2 l% F, `: Q) e" s. K else begin
7 x5 |. U9 s% W red_r1 <= red * 77 ; //放大后的值
. J% l* h3 h' ]# {, _ green_r1 <= green * 150; 9 w K+ e3 m5 y: T1 }9 Z3 G
blue_r1 <= blue * 29 ;
# E; Y+ O$ e; l( ]8 |% k! E end5 o2 w! C: ~9 e
end
& U2 W0 j) U2 h5 [/ a# Z" W V6 @; U
( z% a1 Y- G- a" w) k. C9 p
8 I7 D# N- j% Jalways @(posedge clk or negedge rst_n)begin , c" O0 L' k6 u: l* D
if(rst_n==1'b0)begin
( c6 S3 p& b( B2 d* j2 { Gray <= 0; // 三个数之和 0 v0 {) l" [+ I- d r$ o
end ' y W: ^3 t& ^" \; b1 ~; J( k8 F! H
else begin - g) X' a5 o0 d
Gray <= red_r1 + green_r1 + blue_r1;) ?" e. `. {- @0 t5 h5 p
end" X0 M* m' ], Y! q" P5 t
end
, ?5 h/ v( P; B4 f6 M3 [# L+ k p1 A, [6 Y$ l( G/ ]" J7 a/ l/ C$ G
, K+ a ~" ^6 c( O0 `0 l/ Z' M
always @(posedge clk or negedge rst_n)begin 9 i( D( }8 f9 [4 b- {
if(rst_n==1'b0)begin
( X( c: T: ^7 @; A2 o) K post_data_in <= 0; //输出的灰度数据
4 M0 d0 A# Q) |3 }/ n end 4 l! f( \; d: @6 y# d6 @
else begin 8 q9 a7 P9 K+ ]
post_data_in <= { Gray[13:9], Gray[13:8], Gray[13:9] };//将Gray值赋值给RGB三个通道
" V! |/ e. x3 R/ \# L end% E9 D/ T/ D, z0 | W. h- O
end
- ]! K2 Z9 y8 E9 X
* m# N$ S9 H) U. c. q9 h& b) S; U7 j4 ^9 x. l& q4 l: I. i
# U) k+ g) O7 ^! o% r% R' J1 G
; K( ~. {0 `, s4 ^% O& E
6 d( j' ?7 w+ E. p四、均值滤波5 P/ O# f3 A0 P; j4 V* N. @
均值滤波的原理做图像处理, “把每个像素都用周围的8个像素来做均值操作 ”, 比如:
' [ A" x: m; @3 a% E8 l( O9 u; Y8 G
( ~% M& {4 d- a( \6 I7 |
! X( P7 G" h' x6 D. e+ b( h( q4 f# M# [ B3 t. y
. E& F* @! u" N& f( j
图通常是最能说明问题的东西, 非常明显的, 这个3*3区域像素的颜色值分别是5,3,6,2,1,9,8,4,7那么中间的1这个像素的过滤后的值就是这些值的平均值, 也就是前面的计算方法:(5+3+6+2+1+9+8+4+7)/9=5
5 e# x5 N! ?! G5 q T. D1 j O: \! s9 }
+ r: t, E4 ], R- i- [! U
一目了然。那么这个均值滤波有什么用处呢?主要还是平滑图像的用处, 有的图像的锐度很高,用这样的均值算法,可以把锐度降低。使得图像看上去更加自然,下面就有几幅图我们可以看出一些端倪:原图: 8 D3 b7 y: L3 X: Z9 S$ a7 Z
6 j: @9 Q$ [$ v3 C. A9 W
2 J* H* q c1 J" b* }, ]
2 Q7 q: w+ n, ]1 a
# D; J1 `8 c$ H6 _5 a, i
平滑处理后:) c, C! x/ `* \7 f
/ p$ Z6 F$ f7 a* c8 ^
z, k& I0 Q" e) n8 G% F1 C" c, T# @- D% C5 @& ]
- p7 J6 ?0 m1 ]& {7 B1 |: j
7 C, T/ a* c2 P( H& i/ T
; e0 n& c& h# K7 g9 |) B. {) g这里还是可以明显的感觉到不同的, 没有好坏之分,就是第二幅图片看上去更为平滑。继续我们的问题, 那这里均值平滑是否具有去除噪声的功能呢?我们搞来了椒盐噪声(就是随机的白点,黑点)来试试手: : L3 J/ D! e: C; B' C6 {6 j8 k
噪声图(5%):
* W6 n. o# \/ y2 |+ J; {* y2 {! S: l! I- S8 }
- O9 D2 U) W5 x& h) u
2 p7 J6 K1 _2 i0 o
/ B; M, ` h& s9 [1 k, d平滑处理之后:$ t% w1 l* O) G4 Z
; v* F0 T& @# y" a/ Q( L9 Y, c5 ]/ p2 \* N" X
9 V* P* |; p; Q/ I! t
: [, N6 { E h1 M5 ^6 a$ {& F
首先这里的噪声还是比较小的, 只有5%,从均值的效果来看的话, 我可以说几乎没有用,其实直观的想也可以判断, 因为这里的处理并没有剔除这些噪声点, 而只是微弱地降低了噪声,所以效果可以想见的。 最后的时候还是贴上一段处理的代码:+ C' e' D. @+ Q7 _
& E& z9 r6 d* w2 s$ r3 ?8 R8 m/ R
void meanFilter (unsigned char* corrupted, unsigned char* smooth, int width, int height)2 B* T B6 W6 @7 ]5 r
{2 m* Q8 I6 L# L. V7 ^9 r- T- n
7 ^ @. y% S2 p+ k) a, |7 V
mEMCpy ( smooth, corrupted, width*height*sizeof(unsigned char) );
1 }3 a$ l( Q8 S0 d4 z _1 B/ D( W" D9 U2 d+ L; l, ~$ @6 }
6 ~# Z1 w; Z1 K3 Y0 a3 P4 ?& t7 i2 Y0 W
for (int j=1;j<height-1;j++) : u( X5 E5 L: B r+ w
{ : k# E' x+ q* @8 G" ?4 @: U
for (int i=1;i<width-1;i++) 3 R7 Z7 y! i7 l+ S* e! e
{
* H9 z! w2 z- |: ^# _ smooth [ j*width+i ] = ( corrupted [ (j-1)*width+(i-1) ] + corrupted [ (j-1)*width+i] + corrupted [ (j-1)*width+(i+1) ] +% i0 x- M, w; J5 j9 @
, [$ t6 R9 [, ~0 b9 O corrupted [ j*width+(i-1) ] + corrupted [ j*width+i] + corrupted [ j*width+(i+1) ] +% Q- \1 v; G- {7 S
corrupted [ (j+1)*width+(i-1) ] + corrupted [ (j+1)*width+i] + corrupted [ (j+1)*width+(i+1) ] ) / 9; 4 R3 m3 ~* |0 m Q! M
1 D& m: u* @! |# [1 O- K5 B; [. d2 K8 m
}
; y* I+ y: o- o( j }
% m) G2 {; S ]# ]2 l. g- j3 B }
6 }" M U3 i* b8 D% z5 I" ?. c5 `" q; q* X
简单的从1...width-1来处理, 所以第一个和最后一个像素就简单的抛掉了, 如果只是简单的看看效果还是没有问题的。 6 ^( O0 O& c. B9 |: D |7 A4 Q
如何生成 3*3 的像素阵列。可以利用 ip 核生成移位寄存器 ,方法与 ip 核生成 rom 一样,详情见 ip 核 生成 rom 操作 。
4 K4 h1 n0 k5 r+ ~% m2 J! a- G! |+ t! K7 z: J7 G
5 c+ ?4 e C1 ?5 L$ h
- p9 y0 V4 W1 U5 H. [. L" g- K8 P4 A1 N
8 `9 [/ e9 I2 G/ v i9 U, |" L; H2 m
仿真波形如下 row_1 , row_2 , row_3 是指图像的第一、二、三行的数据,Per_href 是行有效信号(受VGA时序的启发,从 rom 中读取数据时设计了行有效和场有效的控制信号,事半功倍,有了利于仿真查错和数据的控制)。从 3 开始就出现了3*3 的像素阵列,这时候就可以求取周围 8 个像素点的平均值,进行均值滤波。
2 n. }8 U/ B- @. d( h, `& g- a1 w. D' q: T3 U( J, I9 v
4 j" w0 x: E, V0 z. z# D' C% ~
- m* ~' g# B6 |, D" `; F
% J6 f3 c4 x+ c
) T a# e6 y- q W7 k+ t* i 下面这个图表示的是FPGA 如何将矩阵数据处理成并行的像素点,可以结合下面的代码好好理解,这也是精华所在。
: _; r, K+ Q( U/ `$ E5 q) c% M2 K- }2 D+ @/ q* I6 T- {8 J2 _
( m c" E, {+ w1 K8 U; Q! a/ V1 P" _
正方形红框框起来的是第一个完整的 3*3 矩阵,长方形红框框起来的是并行的像素点,在此基础上就可以求得平均值,进行均值滤波。
. C0 m3 N# L# K
4 \* C- i4 K/ Y$ B- [7 P
# Y: v# I; s, A, g( d9 q. X从下图也能看到 3*3 矩阵从左往右滑动。) e1 v, j! J }
1 b" r/ w# c ?5 c$ @
7 d6 d. @. ?$ W+ e第一个3*3 阵列。
3 ]' y9 |4 {) z0 i0 {/ T
* w L3 v1 \( f' n
% T: F: ^6 r6 x0 1 2 -- > p11 p12 p13
$ T/ X/ s+ t9 e3 4 5 -- > p21 p22 p23
+ ?' m9 z8 c7 k y9 b6 7 8 -- > p31 p32 p33' V% {4 Z& N9 o: m
: i8 L6 D ?+ @: J" v
& l& a' m( N, c
. p3 F& M6 H: x3 H% O; M
核心代码如下:+ h# S2 k8 q/ O+ ?) A- b
7 j2 U9 Q+ k$ w. f- ?' |
6 G8 J% }! P7 E3 X0 ~
" E% b9 o& D8 h- m
& s7 Y% p- @' m$ Freg [5:0]p_11,p_12,p_13; // 3 * 3 卷积核中的像素点
, W9 P* V7 T* X7 `' Z( G7 ]( J5 Wreg [5:0]p_21,p_22,p_23;
7 j+ A9 }, K& U, O# Ureg [5:0]p_31,p_32,p_33;
0 ` C5 ^5 C. r* G# s+ U% Y* Wreg [8:0]mean_value_add1,mean_value_add2,mean_value_add3;//每一行之和6 J6 g! p3 [8 u7 |9 i
5 G* L# N0 k4 ?: f% r+ T4 T3 q, @9 y: q X8 u
0 I9 ?( |: n0 Ualways @(posedge clk or negedge rst_n)begin
/ x. M: M$ W3 s& n7 ? 0 \4 W- k! H" o$ V" b
if(rst_n==1'b0)begin
* L6 `( {' E1 B* G. {% g Z {p_11,p_12,p_13} <= {5'b0,5'b0,5'b0} ;
3 R5 u9 C* N2 n ]9 }% y {p_21,p_22,p_23} <= {15'b0,15'b0,15'b0}; : k' q, X1 c G9 u4 ~" m$ x' P
{p_31,p_32,p_33} <= {15'b0,15'b0,15'b0}; $ i5 T2 A, b/ A6 b+ i# b
2 p. G5 c; h3 y Y$ O. C
4 L1 ?- X* N8 \( d, c, e" S, N% ]* J# d# N" Z$ u9 s4 C! P
end
5 ^+ ]! l, _ d" e+ X" {/ h else begin
( G& W) @; L |0 C if(per_href_ff0==1&&flag_do==1)begin, g3 ~# ^ i C5 B0 U/ I+ |
{p_11,p_12,p_13}<={p_12,p_13,row_1};; v$ R' D5 ]3 F: x. M7 _( l
{p_21,p_22,p_23}<={p_22,p_23,row_2};
% ~! S4 d8 u- P5 I1 J4 k+ t {p_31,p_32,p_33}<={p_32,p_33,row_3};0 h% o% N( O9 h/ V0 W
* a5 R( a2 G3 o4 b# O4 m& u end2 z# m! {6 R' S4 E- J) W6 w+ A! f
else begin
7 l( G, i. V7 j! T V {p_11,p_12,p_13}<={5'b0,5'b0,5'b0};
0 J8 G4 l" X0 r {p_21,p_22,p_23}<={5'b0,5'b0,5'b0}
- ], j" |/ H4 b" m- s {p_31,p_32,p_33}<={5'b0,5'b0,5'b0} 6 _' n' b/ D# e! x5 U
- ~0 [7 k( u; w5 A1 B, @9 c/ c9 N P: U9 Z8 B3 ^7 v' T3 _
end* X- Q4 H! p- I% w
( {8 L& B" Y7 N& \+ T: ?: N end
$ h8 ]1 s" N% J- I/ I i
5 i/ N* O' M0 `# V0 J2 v4 Z. [ R0 @ ]) k
end
( p. V- s4 P1 P# i5 ?* W
! i( l% I b" ^* F c4 X, c# Z$ K
" H9 z1 H) E ?/ Z3 ]+ u5 W* p& B# ? F0 p* e3 W
7 y% u$ M0 X; V" u! l8 ~always @(posedge clk or negedge rst_n)begin! t0 y+ @4 k5 I+ t0 N9 p
if(rst_n==1'b0)begin! u C$ j4 ^* S9 V! t @/ `
mean_value_add1<=0;
, B, Z, X( h; m# K; K6 } mean_value_add2<=0;# h9 c2 G+ M9 g+ \. E0 k; d& m
mean_value_add3<=0;
( T. j) a) D5 W% C; m. x" h0 \: y2 t# v7 D
5 I+ w4 v5 o6 i& [1 o( g% Q I+ _
end% j4 T- q6 _9 H, C+ k3 k- k
else if(per_href_ff1)begin5 A/ W$ t* ?" u2 D+ r7 i
mean_value_add1<=p_11+p_12+p_13;
- }! r* h, v) R7 }. F mean_value_add2<=p_21+ 0 +p_23;
; v7 w* e5 v6 V, M$ u2 A) I/ n0 | mean_value_add3<=p_31+p_32+p_33;
) B- s6 c' V5 \5 n% r end
9 k& J, o) H3 S! C6 }7 Jend, P" N9 c- H- a* _+ t& A3 p
& X1 |& L5 l8 i
4 F4 i2 Q) o& q0 N1 b
* c4 R. q8 m M" F) a F6 X3 Nwire [8:0]mean_value;//8位数之和
2 h. a. V6 t- Z1 Rwire [5:0]fin_y_data; //平均数,除以8,相当于左移三位。
* G! P4 M5 }: R1 M
# A0 p/ j; ?5 F
2 i! ?) k" K4 b$ [8 R9 R/ C. T) R8 h9 g
assign mean_value=mean_value_add1+mean_value_add2+mean_value_add3;
H# w& P, V, a4 {/ L eassign fin_y_data=mean_value[8:3];
$ G, _* a1 V8 Q! v+ H6 R7 e. d
五、sobel 边缘检测
- ?5 o$ [ G2 y b9 X1 I# |# s7 R- E" W
边缘检测的原理
/ t$ X; p' M! Y2 F: B+ i5 M7 e" X6 T# c3 V0 t# O) x
. u) J( q2 Y+ k0 [7 g5 G, E
该算子包含两组 3x3 的矩阵,分别为横向及纵向,将之与图像作平面卷积,即可分别得出横向及纵向的亮度差分近似值。A代表原始图像的 3*3 像素阵列,Gx及Gy分别代表经横向及纵向边缘检测的图像,其公式如下:
) l! h# S8 W1 J' N1 e* O7 o1 {" C* e) V, `" U I1 |
# y0 }- m" g% E4 P, I; v$ F; \; W
^7 X7 u C. y) {; Z) @6 [* P! {图像的每一个像素的横向及纵向梯度近似值可用以下的公式结合,来计算梯度的大小。
/ I, S' f& ?, [/ r$ V& Q2 t1 ]
# J) F, o: R @5 d, o# n/ p! D: Y; a1 Z* _" Y" c* e8 [ u
如果梯度G大于某一阀值则认为该点(x,y)为边缘点。
# P7 e4 K- t! ]; T1 n
/ g5 W- H x1 X m% ^5 w& ^
1 W, j+ r. W. _' H用的是边缘检测算法。
& y9 n8 c6 {$ W, H- {" _+ G0 j5 v) {7 K8 f- M5 v, a" O3 V0 L4 V* ~$ y
/ i( v3 d# e# X! s2 m9 e
难点:9 H G) F8 U8 E: f8 y- J
1 T R; n1 R0 [' F! T; P; d S! ?8 D2 T( m* ~+ l" P/ O
(1)掌握了 3*3 像素阵列,Gx 与 Gy 就很好计算了。
- Y1 A$ C0 d0 H! \. L/ F a8 ?5 p9 ^5 i, P. k5 \( E0 s
2 |# `' D) l8 R: X
注意问题:为了避免计算过程中出现负值,所以将正负值分开单独计算,具体见代码)1 J5 ?3 X2 Y& C5 s: W: P3 q
- M. L6 t5 {: S% a
; N, v5 X e {* i9 ?
(2)G的计算需要开平方,如何进行开平方运算Quartus ii 提供了开平方 ip 核,因此我们直接调用就好了 。
* ]8 R6 A2 }' @+ L; r8 ^: U% ~! j6 }% S- ?9 U, M" F# Z% ]* q! R/ L* s: g
) [% H8 l S; K2 ~, B d; \7 q
k8 A9 U- F5 ]: Z* u& M. R
代码如下:
( b" i4 J5 e. z I: { H; k. D/ [6 \ W) `, h5 n
) y4 G% m6 O6 V" c7 H7 ?; N5 E( w i
reg [8:0] p_x_data ,p_y_data ; // x 和 y 的正值之和, G( s/ |1 C0 C. }8 T5 M$ k
reg [8:0] n_x_data ,n_y_data ; // x 和 y 的负值之和
+ t/ _5 H$ L( }- I% o- _3 j' Xreg [8:0] gx_data ,gy_data ; //最终结果9 H9 H5 U9 W# t
- F) _% s4 D; e: F, Halways @(posedge clk or negedge rst_n)begin2 ]* a" [4 g" Z! [7 |" O {
! j) l3 I6 U1 C2 v
+ H: l3 \5 H& D5 Q$ D$ {
if(rst_n==1'b0)begin e# W+ m W( Z4 O
p_x_data <=0;
& D* q6 u( j/ y% d( J" }6 t/ r n_x_data <=0;
/ f2 f( C/ t3 ^3 \$ P- n) ~) t- [ gx_data <=0;
& N* @, w2 m. P6 D8 L, ]9 [' K# j
7 {4 i& ?/ b2 o# d0 J# ] end2 l8 k F8 B G! {: f/ ?
0 t4 D2 B' e+ Z" `. |/ r7 S7 [
; d, R% O# I5 { Y( D else if(per_href_ff1==1) begin
# ^' B& Y! C# j0 J6 N" F
9 h6 N; B) M! |1 q8 f7 y n4 P, H y' X
p_x_data <= p_13 + (p_23<<1) + p_33 ;
5 h8 F( J! x3 X0 a3 A n_x_data <= p_11 + (p_12<<1 )+ p_13 ;
: F" t- M& T0 c- k7 @ gx_data <= (p_x_data >=n_x_data)? p_x_data - n_x_data : n_x_data - p_x_data ;5 j4 H& f- D, H4 [$ A- A+ p
g# g" U, _; R8 C3 ?1 b* C8 _* ?/ s. X, e& H1 s1 o3 n
end' G5 c$ |3 p: l1 _/ W! j
& n* x0 W& ^4 w/ ~; [, W) b
v1 r8 L( c+ V4 k& a2 ~) x& | else begin
+ q: S0 J- s p- Q2 |) _. ? p_x_data<=0;
9 j# G# o) [# J% Y4 h n_x_data<=0;$ O; m! |8 i, Y( m
gx_data <=0;
' z' }2 T& a5 E/ I; P) [. s end
* C% L- r1 A! }2 rend) w, _; B/ T& T9 U4 O$ ]( }$ V
J T n$ {. {3 j9 y& W
always @(posedge clk or negedge rst_n)begin5 v' e6 T+ u* z3 }& H3 v" E4 {
if(rst_n==1'b0)begin
' x3 ` ?: J# N; j+ R; o3 E8 { p_y_data <=0;
6 I+ c+ M! O, F& I! r; `) t n_y_data <=0;
# y R A# Z6 X. `2 y: U# B gy_data <=0;
, ^$ r0 w; ]" f
& S& p+ w& c. n8 h, v8 Y1 s' ^4 {2 v3 d7 V8 {
end
0 M$ q! J# Q$ X6 f. K. C8 Q/ R* m 8 X7 a: }7 P k
else if(per_href_ff1==1) begin
4 }' \6 V+ j& D6 o- H p_y_data <= p_11 + (p_12<<1) + p_13 ;6 l: ~6 P& Q7 O0 V: h3 W
n_y_data <= p_31 + (p_32<<1) + p_33 ;
/ P( h" T# v9 C- }+ s" J& G gy_data <= (p_y_data >=n_y_data)? p_y_data - n_y_data : n_y_data - p_y_data ;
0 k/ l3 r8 @* |
* b# k& G( Y- E% ]
1 p6 G. W' Z/ d0 a. ?1 W3 n) G end
' f; B& J }6 t& F# ]0 q
# ^# s9 T4 h: ^! W% x, S4 K5 s; e: a2 D
else begin5 n5 J: j6 M" R8 T) m
p_y_data <=0;/ [7 q7 [' L& B0 z0 L
n_y_data <=0;
' Q V7 f# @. \' O gy_data <=0;# _! a" |# g; \8 D4 x
end
7 R3 b' k) i H) Z. c$ _end2 ^& B( A5 a( y4 d2 R: v5 b* C" b
& z5 S% G% ^, q2 g//求平方和,调用ip核开平方/ N* \: |; T- P* H) P% l
reg [16:0] gxy; // Gx 与 Gy 的平方和 l4 W# F; g0 @$ I* C
always @(posedge clk or negedge rst_n)begin
" K5 }. H3 z5 }: ?7 o2 m if(rst_n==1'b0)begin
* b. X' ^( U# ~+ W! x) S gxy<=0;
% i, }+ n: Q" J7 M! j+ n, Y1 X' Q* `/ Y* y end7 a* d Y7 |5 P% K
else begin: ]7 |' ~+ E- u& t. B9 l
gxy<= gy_data* gy_data + gx_data* gx_data ;
8 k' _5 B# c: E9 X% s6 T end0 [5 t. k8 ~! w4 m) t% i6 ^( l
end
& N4 |$ @1 ^1 S' a9 P3 _# C2 P8 ~& w- q: p% X6 w. B7 a% w
wire [8:0] squart_out ;8 {! O3 l9 l* H% S
altsquart u1_altsquart ( //例化开平方的ip核
$ w( @) O. L" m+ `3 A5 K .radical (gxy),2 j0 a' t6 \& D
.q (squart_out), //输出的结果' i! s6 n2 m* e$ c. R
.remainder()
% f! C4 R; N% d1 `. i );# u E8 |$ y _' V+ ^2 M. [
* s# }8 D$ a- f/ `& [6 V' c
) Z+ e7 C4 I! m; F+ h# @# N
7 `! a- _" @0 S! d3 T0 g/ \//与阈值进行比较) o6 Y: T* `3 g8 Y
0 R& ^* i$ n; p# q. L4 t: ]$ [/ l* A5 U% g C
reg [15:0] post_y_data_r;; ?% U1 z4 ^3 I; s: k2 r
always @(posedge clk or negedge rst_n)begin- z. J, l* Q' t2 @
if(rst_n==1'b0)begin
; u0 {3 i3 Q/ t7 a0 m/ ]8 } post_y_data_r<=16'h00;
; L* s1 W& K2 \. q end( @6 @. [- A6 {, X
else if(squart_out>=threshold)
; o. o4 l7 e* [+ t# @! V post_y_data_r<=16'h00 ;& E/ U% k: X3 D0 H
else0 e# z8 v6 I8 u$ f9 M [
post_y_data_r<=16'hffff ;! c, k4 U& \7 i
- {7 F3 D3 Z9 [+ V, t! T$ |
end) g4 Z0 z7 o B( K" _3 G" O
k4 T% t2 T: a$ E
六、图片的显示
9 m0 U \7 r/ }5 k; l& x; _/ q% N
) J# O; |5 u2 D3 k/ b/ r
本来是想用 VGA 来显示图片的,由于条件的限制没能实现,最终只能将处理完的数据输出保存在 .txt 文件中,然后借助网页进行显示。: ?) q1 d* B' E9 N
% l0 s* |) O4 [9 v/ D
& u- a' N1 T/ y# @7 a4 e. j难点:
1 F2 C/ i3 Y4 @4 L) g" W) ^- D2 o' k8 o& m1 U2 b) ^9 y
* p+ r2 j2 n ?(1) 如何将数据流输出保存到 .txt 文件中。
/ `: R* G- F; t) m6 v% z* N0 d F2 C5 K' m# b
! ?" e; c: N* V
(2) 网页的使用及注意事项。在testbench里加入下面所示代码即可将图片数据保存到 .txt 文本。
8 W6 m# O" J. f# E; s4 b. v
5 J) t* }1 a/ T; K# u' y, f9 M5 {# @; Q" q" O$ ~# t7 K
代码如下:
, B0 q4 @+ w9 M+ P$ H% z8 ~) w
9 f0 u9 N: d9 H6 ^ integer w_file; initial w_file = $fopen("data_out_3.txt"); //保存数据的文件名 2 K) z# {* Y; V1 J; B, Y. D
always @(posedge clk or negedge rst_n) begin if(flag_write==1&&post_href==1)//根据自己的需求定义 $fdisplay(w_file,"%b",post_y_data);
, |: q$ p8 s; g/ E# \3 P end
1 ?" s* J! @7 i6 W4 k3 ]( x) N6 a; w" G Z& w
网页的界面如下,将参数设置好以后就可以显示图片。 0 Z2 R U: ]$ a5 p
下载链接:
+ {2 h7 S! {1 ~ q3 c% y+ ]/ R# Y提取码:e87j
3 B1 n1 d$ s6 U: `- n* c$ m2 n; X' \
! w/ r5 _$ n+ d/ k2 ~" y
5 |% E) w n( v0 B" K
注意:由于此网站是量身定做的,所以只能显示数据格式为RGB565的16位二进制的数才能正确显示,注意不能有分号,正确格式示例如下,必须严格遵守。 6 j9 ~; b5 A2 x6 c
0 Q6 ?! c0 A) U3 f% y6 J七、结果展示' Q' c* P. {' s
% Z+ n8 p* i& e/ r' I' B, }5 `
+ Z0 c2 x& F, ?0 ]
" t, G1 _+ w& o" U& r+ a7 X0 q; n' J* i7 j' a
: T! ?* q1 u0 `! [5 ]$ U" v
小结:均值滤波处理后的图片有明显的黑边,产生这一现象的原因就是生成 3*3 像素矩阵和取像素值时数据有损失造成的,但是这也是可以优化的,后续我会继续努力不断完善。本次只是简单对一幅图像进行边缘检测,我的后续目标是实现图片的实时处理,这又需要学习很多东西了,SDRAM、摄像头驱动等等等,越学习越发现自己知道的实在是太少了,永远在路上,学无止境。希望我的分享能够帮助一些和我一样热爱 FPGA 图像处理的朋友。
# O; b& K7 z4 p) ~6 G0 V: ]- THE END - . c7 q; K# j) I) W5 }
! l7 w8 |6 r- h$ s- ~ |