简介
二值图像的像素可分为两类:目标像素和背景像素,通常目标像素用1表示,背景像素用0表示。形态学滤波最基本的操作是腐蚀和膨胀。下面这张图展示了腐蚀膨胀的处理结果,不过图中目标像素是黑色,背景像素是白色。 腐蚀是一种消除边界点,使边界向内部收缩的过程。可以用来消除小且无意义的物体。 比如3x3腐蚀,即用一个3x3窗口对图像进行卷积,当窗口内全部为1则输出1,其他情况输出0,等同于与运算这样卷积一遍下来,目标的尺寸就变小了。 膨胀和腐蚀相反,当窗口内有任意像素为1时,输出1,全为0时才输出0,等同于或运算。
电路图
由于腐蚀和膨胀具有互补性,所以可以用一个电路实现两种功能,用一个控制信号选择腐蚀或膨胀。 异或门具有选择反相性,所以当控制型号为0时,对电路没有影响,电路功能为腐蚀 当控制型号为1时,输入被反相后进入电路,进行与操作后反相输出,等同于或运算,逻辑代数公式为X + Y = (X’Y’)’ 在FPGA中进行腐蚀膨胀运算,和之前一样,要用到3x3卷积模板,在之前的博客已经介绍过,因为是对二值图像进行卷积,3x3卷积模板的位宽要改为1,请自行修改
verilog代码
按照上面的电路图,很容易就能写出腐蚀膨胀的verilog代码:
// 腐蚀膨胀,输入为经过sobel的边缘图
module erosion_dilation(
input clk,
input rst_n,
input sel, // 0选择腐蚀,1选择膨胀
input iValid,
input [7:0] iData,
output oValid,
output [7:0] oData
);
// 信号声明
wire filter_11, filter_12, filter_13;
wire filter_21, filter_22, filter_23;
wire filter_31, filter_32, filter_33;
// 输入8bit转1bit
wire iData_1bit = &iData;
// filter模块中的shift-ram ip核的tap间隔要与图片宽度一致
filter_3x3_1bit inst_filter_3x3_1bit(
.clk (clk),
.rst_n (rst_n),
.iValid (iValid),
.iData (iData_1bit ^ sel),
.oValid (oValid),
.oData_11 (filter_11), .oData_12 (filter_12), .oData_13 (filter_13),
.oData_21 (filter_21), .oData_22 (filter_22), .oData_23 (filter_23),
.oData_31 (filter_31), .oData_32 (filter_32), .oData_33 (filter_33)
);
// 第一行与
wire and_1 = filter_11 & filter_12 & filter_13;
// 第二行与
wire and_2 = filter_21 & filter_22 & filter_23;
// 第三行与
wire and_3 = filter_31 & filter_32 & filter_33;
// 与运算结果
wire and_all = and_1 & and_2 & and_3;
// 输出1bit转8bit
assign oData = (and_all ^ sel) ? 8'hff : 8'h00;
endmodule
Testbench
// 只能使用bmp灰度图片,,最好用边缘检测后的图片,如果更换图片了,记得修改shift-ram行缓存大小
`timescale 1ps/1ps
module bmp_tb;
reg clk = 1'b1;
always #10 clk = ~clk; // 时钟周期为20
reg rst_n = 1'b0;
// 输入图片数组
reg [7:0] bmpData[0:1000000];
integer bmpFile; // 图片文件id
integer outFile; // 输出图片文件id
integer bfSize; // 文件大小
integer bfOffbits; // 像素起始位置
integer code; // 读取图片返回的错误码
integer width; // 图片宽度
integer height; // 图片高度
integer i;
integer j;
reg iValid = 0;
reg [7:0] gray = 0;
wire oValid;
wire [7:0] oData;
initial begin
// 使用绝对路径较好
bmpFile = $fopen("image/tiger_sobel.bmp", "rb"); // 打开输入图片
outFile = $fopen("image/tiger_sobel_erosion.bmp", "wb+"); // 打开输出图片
code = $fread(bmpData, bmpFile); // 读取输入图片数据到数组内
bfOffbits = {bmpData[13], bmpData[12], bmpData[11], bmpData[10]}; // 图片像素数据偏移
width = {bmpData[21], bmpData[20], bmpData[19], bmpData[18]};
height = {bmpData[25], bmpData[24], bmpData[23], bmpData[22]};
// 向输出图片写入文件头信息
for(i = 0; i |