王 刚,朱明清,石 磊
(黑龙江省科学院智能制造研究所,黑龙江 哈尔滨 150090)
随着科学技术的发展,激光测量方法广泛应用非接触测量[1]、物体表面缺陷检测[2],目标跟踪[3]等领域,应用光学激光测量方法原理时,向目标物体投射激光需要精确提取数字图像中激光光斑信息,为获取目标物体的关键步骤,那么作为激光光斑中心定位[4-6]在光学测量系统中占有重要的地位,当激光光斑点通过CCD或CMOS图像传感器采集时,受到环境中各种干扰及其采集后出现多点坐标,在实际使用背景时,如激光三角法[7]、激光准直仪、共焦显微测量法、激光参数测定等光学测量中,需要准确提取激光光斑中心图像坐标。
本文就是针对于激光三角法中,向被测物体投射激光源后,通过COMS采集激光光斑图像,通过FPGA硬件系统设计,提取出激光光斑中心坐标;为了验证所选用的算法正确性,首先通过计算机软件验证,将得到的结果与FPGA 仿真结果对比,数据相同的情况,将应用FPGA 硬件实现提取光斑坐标,实现激光光斑位置的算法移植到硬件中,利用FPGA的并行运算能力,使得测量速度得到提高,实时的应用在实际生产中。
为了完成本文的研究内容,即通过FPGA 实现激光光斑中心定位的研究设计;激光光斑中心是将激光照射到物体表面,通过图像传感器采集图像信息,再通过算法处理实现其算法完成中心坐标的提取,由于FPGA 是一种硬件描述语言实现的逻辑,要完成上述过程直接在FPGA中去算法验证实现会变得更加复杂;对于FPGA无论在运行还是仿真过程中看到的就是一组数据或是一组时序波形,不能像二维图片直观的表达所要得到的信息,而且在越复杂的算法中越难直观得到结果,出现问题也不利于问题的分析,综上所述,文章中采用软件通过opencv 实现激光中心定位的算法验证,而在实现过程中采用的函数语言能够方便转化成verilog HDL语言的形式去实现,最后能够通过FPGA硬件描述语言实现。
系统设计方案图如图1,首先计算机通过采集系统采集到激光光斑的图像,并保存到计算机中,其次来通过opencv 算法验证,最后还得将图像数据转化成图像灰度数据存储于文本文件中,便于在modelsim中读取灰度数据;FPGA的仿真采用modelsim软件完成,但是此软件不能直接读取图像数据,只能读取二进制或是十六进制的数据,为了完成此功能,可以采用c++语言将图像转化成灰度数据,再通过软件直接读取数据。
图1 系统设计方案图
通过灰度图像提取中心的方法有质心法[8]、灰度重心法[9],区别在于一个是对二值图像的运算,一个是对灰度图像直接处理的方法。
1) 质心法
用于对二值图像[10]的中心提取处理方法,可理解为灰度重心法的特例;质心法就是通过图像阈值区分背景,是待测信息的一阶矩来获取质心的方法,横坐标为二值化的图像将值为‘1’的所有i的数值相加,再除以值为‘1’的总和数,纵坐标为二值化的图像将值为‘1’的所有j 的数值相加,再除以值为‘1’的总和数,其公式如下:
其中:g(i,j)为f(i,j)的二值图像值,
M为图像的行数,
N为图像的列数。
2) 灰度重心法
灰度重心法不需要对图像二值化处理,它将光斑区域内每一像素的灰度值当作该点的“质量”,横坐标为图像坐标中所有u值乘以对应灰度值累加,再除所有灰度值的总和数,纵坐标为图像坐标中所有v值乘以对应灰度值累加,再除所有灰度值的总和数,其求光斑的公式为:
其中:f(u,v)为图像的灰度值,
M为图像的行数,
N为图像的列数。
在实际拍摄获取激光光斑图像时,由于是主动投射激光源的方式,背景信息与激光光斑信息具有明显的差异,且有用信息都集中在最大灰度数据部分,通过对一般图像处理数据的过程,首先将采集到的数据进行滤波处理,在进行算法运算;但是在FPGA中实现任何一种算法都是对硬件逻辑的负担,增加硬件描述语言的难度,同时占用大量的逻辑单元,影响整体的测量速度,减弱FPGA并行运行的能力,而通过质心法与灰度重心法相比较,质心法运算使得硬件运算简单,占用寄存器的空间也相对较小,且硬件在读取数据的过程中就可将图像二值化,充分利用了FPGA流水线运行,达到更高质量的使用。
根据上面分析,激光光斑都集中在灰度最大值部分,可以直接运用质心法计算激光光斑中心坐标,如图2所示,软件系统的流程图,首先程序进入主函数,接着读取原始灰度图像,通过P参数法求取灰度图像的阈值,并输出二值图像;根据二值图像带入质心法公式,求取横、纵中心坐标;最后要将原始灰度图像输出txt文件,为modelsim仿真做准备。
图2 Visual软件流程图
对于open cv是专门用于处理图像的函数库,但是设计函数时要能够方便于硬件描述语言的转化,根据这个思想首先设计P参数法求取阈值,得到二值图像的函数,接着运用质心法求横纵中心坐标的函数,最后输出灰度图像的txt文件函数。
1) P 参数法获得二值图像函数为void gray2ot(Mat&inputImg,Mat&outputImg);运用P 参数法求P 值时,verilog HDL语言没有对浮点数处理的方法,需要设计浮点数处理,再硬件对寄存器的位宽也有指定,为防止溢出,减少硬件空间占用,将所有像素点数缩小处理,总像素点数为1310720移动四位数据缩小处理,这样使得P参数得到为整数,避免小数的出现,在运算中实在允许的误差范围内。
2) 质心法求取中心坐标函数为void sumMat(Mat&inputImg,double x,double y);求取中心坐标主要将公式中的参量转化成程序来运算,得到要运算的值,在c 语言中主要就是为for循环遍历图像。
3) 将灰度图像输出txt 文件函数为int WriteData(string fileName,cv::Mat&matData);在设计此函数时输出的图像灰度数据为十六进制数字,并且每个数据为一行,modelsim 读取txt 文本数据时,只支持这样的文件格式,如果按照数组形式输出,数据是不能读到相应的寄存器中。
根据以上P参数法获得二值图像函数的设计,分别通过调整摄像头的镜头,使得进光不同,得到图3的图像与图4的图像,分别在程序中读取图3激光光斑背景为黑色背景与图4激光光斑背景为灰度背景,得到阈值都是128,如图5P 参数法阈值,两幅灰度图像得到二值图像为图6激光光斑二值图。
图3 激光光斑背景为黑色背景
图4 激光光斑背景为灰度背景
图5 P参数法阈值
图6 激光光斑二值图
将上一步得到的二值图像通过质心法求取中心坐标函数运算得到图7质心法中心坐标,对应横坐标公式中所有激光光斑点数坐标i的和为177705,纵坐标公式中所有激光光斑点数坐标j 的和为1.4464*10^6,总的激光光斑点数为1326,最后得到的横纵坐标为(134,1090)。
图7 质心法中心坐标
对于顶层模块的设计思路是通过考虑实际CCD 或CMOS采集数据过程,实际图像采集是利用时钟、行和场信号共同完成数据的采集,在行、场信号有效周期内,每一个时钟读取一个像素的数据,那么根据这样的方法,只要在利用modelsim仿真时,仿真文件能够根据时钟读取图像中每一个像素数据即可,仿真文件需要从测试文件中读取到数据,实际测试文件中的数据是事先存到寄存器中的,可以采用读取RAM的方式完成,给出地址信号,利用时钟信号产生地址,每一个地址对应一个数据,保证数据的初始过程,利用时序电路设计时还需设计复位信号,最后根据激光光斑中心定位算法从模块输出图像坐标下的横、纵坐标,设计的端口如下。
module CentralDistant(input clk,
input nrst,
input [7:0]data,
output [20:0]addr,
output [9:0]xdata,
output [10:0]ydata
);
……
endmodule
根据以上端口模块的信号设计后,还需要考虑位宽,而在上面已经定义出来,对于时钟、复位信号是1位;数据是读取0~255的灰度数据,那么对应的数据位宽是8位;读取原始图像的大小是1024*1280大小的图像,进而得出总的数据个数为1310720,对应的二进制数应为21 位,故地址位数为21位;根据图像的大小即可得到横、纵坐标的位宽分别为10位和11位。
根据上一节对待测模块端口的设计,将对应的输入信号变成reg类型,输出信号变成wire类型;同时定义时间尺度,时延单位为1ns,时延精度为1ps;同时调用待测模块CentralDistant,测试模块端口如下。
'timescale 1ns/100ps
module tester;
reg clk;
reg nrst;
wire [7:0]data;
wire [20:0]addr;
wire [9:0]xdata;
wire [10:0]ydata;
CentralDistant u(clk,nrst,addr,data,xdata,ydata);
endmodule
通过modulesim 仿真过程为软件波形图仿真,没有实际的硬件,modulesim 中有系统函数指令$readmemh读取文本文件数据,那么通过Visual Studio 读取激光光斑的图像,利用函数转换成十六进制数文本文件。对于读取的数据存储到寄存中,寄存器的位宽为数据宽度,寄存器的数据深度为地址总数,即可定义位21位,读取过程在初始化过程中完成即可,保证测试程序执行时,寄存器中已经存在图像灰度数据,硬件描述部分代码如下。
parameter wordsize=7;
parameter arraysize=1310719;
Reg[wordsize:0]admin_cq_entry_table[0:arraysize];
integer i;
initial begin
$readmemh("data.txt",admin_cq_entry_table);
for(i=1230042;i< 1230052;i=1+i)
$display("admin_cq_entry_table[%d]=%h",i,admin_cq_entry_table[i]);
end
测试模块的作用就是产生对应的输入信号,及其提供需要的灰度数据,上一步已经将所需要的数据读取到寄存admin_cq_entry_table 中,接下来控制对应于端口设计的时钟、复位信号,将数据按照地址给到数据端口即可,硬件描述语言部分代码如下。
always repeat(1000)#2 clk=~clk;//
initial
begin
clk=0;
nrst=0;
#3 nrst=1;
#3 nrst=0;
#3 nrst=1;
end
assign data=admin_cq_entry_table[addr];
硬件描述语言并行运行的特点,图像灰度数据是每个像素依次传输,根据传输过程中就可以进行处理,但是硬件执行也有先后顺序,所以将Verilog HDL 语言描述分成五步,第一步为初始化寄存器,主要是以初始化作为灰度直方图寄存器的数据,与C 语言for 循环不同,硬件采用时序电路设计,做循环的本质就是在执行时钟周期,利用多个时钟周期完成对直方图寄存器初始化;第二步做灰度直方图中灰度统计,计算出各个灰度级上灰度个数,为下一步P 参数法求阈值做好统计;第三步为P 参数法求阈值,通过从高位累计灰度直方图寄存器的值,到达设定的P 值后,结束运算,得到阈值;第四步为图像二值化,并计算大于阈值的数据个数,及其横、纵坐标的值,为下一步计算做后数据准备;第五步为计算横、纵坐标值,并复位相应寄存器,并使硬件能够返回第一步。
对于图像灰度数据在程序代码中,都按照二维数组的方式去进行运算,而在测试文件中读取的到的图像数据为一个8位的1310720个寄存器,那么需要按照行场的方式转换,将横坐标乘以列数1280,再加上纵坐标即可得到对应的数据地址;同时在硬件描述语言中,利用时序电路的特点,在有效的周期内,按照每个时钟周期产生行场的变化,主要部分Verilog HDL语言如下。
assign addr=xcoordinate*11'd1280+ycoordinate;
if(xcoordinate>=10'd1023 || flag)
begin
xcoordinate<=10'd 0;
ycoordinate<=11'd 0;
end
else if(ycoordinate>=11'd1279)
begin
xcoordinate<=xcoordinate+1'b 1;
ycoordinate<=11'd 0;
end
else
ycoordinate<=ycoordinate+1'b 1;
图8modelsim仿真图所示,按照上面所述xdata、ydata为求取的横纵坐标,其运算的结果为(134,1090),与软件中运算取得整数结果相同;在仿真中,sumx 寄存器值为177705,sumy寄存器值为1446395,sum寄存器值为1326,而在软件中计算得值依次为:177705,1.4464*10^6,1326,两种方式验证数据相同,其他运算的数据两者也都完全一致,即设计的并行运算提取光斑中心坐标的方法能够在硬件上使用。
图8 modelsim仿真图
综上所述,FPGA 中是能够实现激光光斑中心坐标的提取,但是其中还是存在着浮点数的问题,接下来研究浮点数的方式可以通过两种方法,一是扩大寄存器的位宽,使其能够达到最大数据,在除法运算时要继续扩大位宽保证小数点后面的位数;二是在FPGA 中做32 位浮点数的运算,完成整数与浮点数之间的转化,在浮点数下计算;只要能够保证运算精度的情况,在实际使用中,那种方式都可以,主要还要参考FPGA 的运算速度与使用面积,只要增加功能,必然影响FPGA 的性能,需要综合去考虑。