基于FPGA灰度图像的laplacian算子的实现
千里之行,始于足下
1 背景知识
Laplacian 算子是n维欧几里德空间中的一个二阶微分算子,定义为梯度grad的散度div。可使用运算模板来运算这定理定律。
如果f是二阶可微的实函数,则f的拉普拉斯算子定义为:
(1) f的拉普拉斯算子也是笛卡儿坐标系中的所有非混合二阶偏导数求和:
(2) 作为一个二阶微分算子,拉普拉斯算子把C函数映射到C函数,对于k ≥ 2。表达式(1)(或(2))定义了一个算子Δ : C(R) → C(R),或更一般地,定义了一个算子Δ : C(Ω) → C(Ω),对于任何开集Ω。
对于阶跃状边缘,导数在边缘点出现零交叉,即边缘点两旁二阶导数取异号。据此,对数字图像{f(i,j)}的每个像素,取它关于x轴方向和y轴方向的二阶差分之和,表示为:
运算模板:
函数的拉普拉斯算子也是该函数的黑塞矩阵的迹,可以证明,它具有各向同性,即与坐标轴方向无关,坐标轴旋转后梯度结果不变。如果邻域系统是4 邻域,Laplacian 算子的模板为:
0 | 1 | 0 |
---|---|---|
1 | -4 | 1 |
0 | 1 | 0 |
如果邻域系统是8 邻域,Laplacian 算子的模板为:
1 | 1 | 1 |
---|---|---|
1 | -8 | 1 |
1 | 1 | 1 |
前面提过,Laplacian 算子对噪声比较敏感,所以图像一般先经过平滑处理,因为平滑处理也是用模板进行的,所以,通常的分割算法都是把Laplacian 算子和平滑算子结合起来生成一个新的模板。
2 matlab 实现
clc
clear all
img=imread('lena.jpg');
figure,imshow(img);
title('lena');
AW=edge(rgb2gray(img),'sobel');%将真彩图像转为灰度图,再用edge函数调用sobel prewitt,laplacian算子
figure,imshow(AW);
title('lena sobel');
BW=edge(rgb2gray(img),'prewitt');
figure,imshow(BW);
title('lena prewitt');
CW=edge(rgb2gray(img),'log');
figure,imshow(CW);
title('lena laplacian');
DW=edge(rgb2gray(img),'canny');
figure,imshow(DW);
title('lena canny');
实现结果:
3 FPGA实现
图1 FPGA基于串口传图实现laplacian算子边缘检测架构
来实现边缘检测算法。
/*
Module name: laplace.v
Description: laplace
0 -1 0
-1 5 -1
0 -1 0
Data: 2017/03/05
Engineer: lipu
e-mail: 137194782@qq.com
微信公众号: FPGA开源工作室
*/
`timescale 1ns/1ps
`define D_WIDTH 8
module laplace(
input clk, //pixel clk
input rst_n,
input hs_in,
input vs_in,
input [`D_WIDTH-1:0] data_in,
input data_in_en,
output hs_out,
output vs_out,
output [`D_WIDTH-1:0] data_out,
output data_out_en
);
// mask 1
//-------------------------------------------//
// 0 -1 0
// -1 5 -1
// 0 -1 0
//-------------------------------------------//
parameter X1 = 4'h0, X2 = 4'hf, X3 = 4'h0;
parameter X4 = 4'hf, X5 = 4'h5, X6 = 4'hf;
parameter X7 = 4'h0, X8 = 4'hf, X9 = 4'h0;
// mask 2
//-------------------------------------------//
// 0 1 0
// 1 -4 1
// 0 1 0
//-------------------------------------------//
//parameter X1 = 4'h0, X2 = 4'h1, X3 = 4'h0;
//parameter X4 = 4'h1, X5 = 4'hc, X6 = 4'h1;
//parameter X7 = 4'h0, X8 = 4'h1, X9 = 4'h0;
// mask 3
//-------------------------------------------//
// 0 -1 0
// -1 4 -1
// 0 -1 0
//-------------------------------------------//
//parameter X1 = 4'h0, X2 = 4'hf, X3 = 4'h0;
//parameter X4 = 4'hf, X5 = 4'h4, X6 = 4'hf;
//parameter X7 = 4'h0, X8 = 4'hf, X9 = 4'h0;
wire [`D_WIDTH-1:0] line0;
wire [`D_WIDTH-1:0] line1;
wire [`D_WIDTH-1:0] line2;
wire [13:0] Mac_x0;
wire [13:0] Mac_x1;
wire [13:0] Mac_x2;
wire [15:0] Pa_x;
reg data_out_en0;
reg data_out_en1;
reg data_out_en2;
reg hs_r0;
reg hs_r1;
reg hs_r2;
reg vs_r0;
reg vs_r1;
reg vs_r2;
line3x3 line3x3_inst(
.clken(data_in_en),
.clock(clk),
.shiftin(data_in),
.shiftout(),
.taps0x(line0),
.taps1x(line1),
.taps2x(line2)
);
// X
MAC_3 x0 (
.aclr3(!rst_n),
.clock0(clk),
.dataa_0(line0),
.datab_0(X9),
.datab_1(X8),
.datab_2(X7),
.result(Mac_x0)
);
MAC_3 x1 (
.aclr3(!rst_n),
.clock0(clk),
.dataa_0(line1),
.datab_0(X6),
.datab_1(X5),
.datab_2(X4),
.result(Mac_x1)
);
MAC_3 x2 (
.aclr3(!rst_n),
.clock0(clk),
.dataa_0(line2),
.datab_0(X3),
.datab_1(X2),
.datab_2(X1),
.result(Mac_x2)
);
PA_3 pa0 (
.clock(clk),
.data0x(Mac_x0),
.data1x(Mac_x1),
.data2x(Mac_x2),
.result(Pa_x)
);
assign data_out = Pa_x[10:3];
endmodule
实验结果:
lena
Mask1
Mask2
推荐阅读: