边缘检测是图像处理和计算机视觉中的基本问题,边缘检测的目的是标识数字图像中亮
度变化明显的点。图像属性中的显著变化通常反映了属性的重要事件和变化。 这些包括(i)
深度上的不连续、(ii)表面方向不连续、(iii)物质属性变化和(iv)场景照明变化。 边缘
检测是图像处理和计算机视觉中,尤其是特征提取中的一个研究领域。
边缘检测算子
一阶: Roberts Cross 算子, Prewitt 算子, Sobel 算子, Kirsch 算子,罗盘算子;
二阶: Marr-Hildreth,在梯度方向的二阶导数过零点, Canny 算子, Laplacian 算子。 今
天我们要讲的是基于 Sobel 算子的边缘检测的 FPGA 算法的实现。
Sobel 算法是像素图像边缘检测中最重要的算子之一,在机器学习、数字媒体、计算机
视觉等信息科技领域起着举足轻重的作用。在技术上,它是一个离散的一阶差分算子,用来
计算图像亮度函数的一阶梯度之近似值。在图像的任何一点使用此算子,将会产生该点对应
的梯度矢量或是其法矢量
Sobel 边缘检测算法比较简,实际应用中效率比 canny 边缘检测效率要高,但是边缘不
如 Canny 检测的准确,但是很多实际应用的场合, sobel 边缘却是首选,尤其是对效率要求
较高,而对细纹理不太关心的时候。
Sobel 边缘检测通常带有方向性,可以只检测竖直边缘或垂直边缘或都检测。
实现步骤:
1. Gx = P ★Sobelx – 原始图像与 Sobel 算子 X 方向卷积;
2. Gy = P★Sobely – 原始图像与 Sobel 算子 Y 方向卷积;
3. G = 两个分量的平方和的算数平方根
4. 阈值比较形成边缘查找后的二值图像。
实现代码如下:
/*
Filename : Sobel.v
Compiler : Quartus II 13.0
Description : implement Sobel Edge Detector
Release :
*/
module sobel (
input iCLK,
input iRST_N,
input [7:0] iTHRESHOLD,
input iDVAL,
input [9:0] iDATA,
output reg oDVAL,
output reg [9:0] oDATA
);
// mask x
parameter X1 = 8'hff, X2 = 8'h00, X3 = 8'h01;
parameter X4 = 8'hfe, X5 = 8'h00, X6 = 8'h02;
parameter X7 = 8'hff, X8 = 8'h00, X9 = 8'h01;
// mask y
parameter Y1 = 8'h01, Y2 = 8'h02, Y3 = 8'h01;
parameter Y4 = 8'h00, Y5 = 8'h00, Y6 = 8'h00;
parameter Y7 = 8'hff, Y8 = 8'hfe, Y9 = 8'hff;
wire [7:0] Line0;
wire [7:0] Line1;
wire [7:0] Line2;
wire [17:0] Mac_x0;
wire [17:0] Mac_x1;
wire [17:0] Mac_x2;
wire [17:0] Mac_y0;
wire [17:0] Mac_y1;
wire [17:0] Mac_y2;
wire [19:0] Pa_x;
wire [19:0] Pa_y;
wire [15:0] Abs_mag;
LineBuffer LineBuffer_inst (
.clken(iDVAL),
.clock(iCLK),
.shiftin(iDATA[9:2]),
.taps0x(Line0),
.taps1x(Line1),
.taps2x(Line2)
);
// X
MAC_3 x0 (
.aclr3(!iRST_N),
.clock0(iCLK),
.dataa_0(Line0),
.datab_0(X9),
.datab_1(X8),
.datab_2(X7),
.result(Mac_x0)
);
MAC_3 x1 (
.aclr3(!iRST_N),
.clock0(iCLK),
.dataa_0(Line1),
.datab_0(X6),
.datab_1(X5),
.datab_2(X4),
.result(Mac_x1)
);
MAC_3 x2 (
.aclr3(!iRST_N),
.clock0(iCLK),
.dataa_0(Line2),
.datab_0(X3),
.datab_1(X2),
.datab_2(X1),
.result(Mac_x2)
);
// Y
MAC_3 y0 (
.aclr3(!iRST_N),
.clock0(iCLK),
.dataa_0(Line0),
.datab_0(Y9),
.datab_1(Y8),
.datab_2(Y7),
.result(Mac_y0)
);
MAC_3 y1 (
.aclr3(!iRST_N),
.clock0(iCLK),
.dataa_0(Line1),
.datab_0(Y6),
.datab_1(Y5),
.datab_2(Y4),
.result(Mac_y1)
);
MAC_3 y2 (
.aclr3(!iRST_N),
.clock0(iCLK),
.dataa_0(Line2),
.datab_0(Y3),
.datab_1(Y2),
.datab_2(Y1),
.result(Mac_y2)
);
PA_3 pa0 (
.clock(iCLK),
.data0x(Mac_x0),
.data1x(Mac_x1),
.data2x(Mac_x2),
.result(Pa_x)
);
PA_3 pa1 (
.clock(iCLK),
.data0x(Mac_y0),
.data1x(Mac_y1),
.data2x(Mac_y2),
.result(Pa_y)
);
SQRT sqrt0 (
.clk(iCLK),
.radical(Pa_x * Pa_x + Pa_y * Pa_y),
.q(Abs_mag)
);
always@(posedge iCLK, negedge iRST_N) begin
if (!iRST_N)
oDVAL <= 0;
else begin
oDVAL <= iDVAL;
if (iDVAL)
oDATA <= (Abs_mag > iTHRESHOLD) ? 0 : 1023;
else
oDATA <= 0;
end
end
endmodule
IP设置: