************************************************************************************************
************************************************************************************************ * 例程:detect_indent_fft.hdev * . 说明:这个程序展示了如何利用快速傅里叶变换(FFT)对塑料制品的表面进行目标(缺陷)的检测,大致分为三步: * . 首先,我们用高斯滤波器构造一个合适的滤波器(将原图通过高斯滤波器滤波); * . 然后,将原图和构造的滤波器进行快速傅里叶变换; * . 最后,利用形态学算子将缺陷表示在滤波后的图片上(在缺陷上画圈)。 * 注:代码中绿色部分为个人理解和注释,其余为例程中原有代码 * 算法讲解:在实际的表面缺陷检测系统中,针对的检测表面很多是具有一定纹理的比如:布匹、皮革、塑料等,
* 针对这一类表面的检测就不能单纯依靠帧差或者背景差来完成,因为背景的纹理不可能和当前图像的
* 纹理完全相同。因此,本例程的算法通过将图像变换到频域进行处理,提取缺陷分量后反变换到时域,
* 获得缺陷的具体位置。 * 高斯滤波器:在本算法中,在一开始就构造了两个高斯滤波器,高斯滤波器是一种线性平滑滤波器,适用于消除高斯噪声。
* 滤波器的实质是对信号进行滤波,滤除不需要的部分,得到想要的部分。一个低通的滤波器可以滤除高频信号,
* 对于图像来说,噪声和边缘往往集中在高频分量,因此低通能够降噪,但是也能造成图像的模糊。 * 本文关键:本文的关键就是使用两个低通滤波器,进行相减后构造了一个带阻滤波器来提取缺陷分量。这就需要保证在实际
* 的待检测表面中缺陷所处的频率范围要和背景以及噪声有明显的差异,并且带阻的频率选择要合适。通过带阻滤
* 波后获得的频率成分对背景中的纹理要有明显的抑制,并且突出缺陷成分,进行傅里叶反变换后重构的图像就是
* 缺陷图像,经过简单的分割就能很容易得到缺陷了。 ***********************************************************************************************
*********************************************************************************************** ** Initialization(初始化) ********* dev_update_off(): 这一句包含如下三个算子:
* dev_updata_pc(‘off’) 关闭更新程序计数器
* dev_updata_var(‘off’) 关闭更新变量窗口
* dev_updata_window(‘off’) 关闭更新图像窗口(即通过命令来显示想要在图像窗口显示的图片)
dev_update_off() ********* dev_close_window(): 关闭活动的图像窗口
dev_close_window() * 参数说明:为读入图片命名(Image)
* 文件名(’plastics/plastics_01’)
read_image(Image,'plastics/plastics_01') * 参数说明:之前读入或生成的图片(Image)
* 图片的宽(Width)
* 图片的高(Height)
get_image_size(Image,Width,Height) //获取图片的长宽; * 打开一个新的图像窗口
* 参数说明:起始坐标(,)
* 大小(Width,Height)
* 背景颜色(’Black’)
* 窗口句柄(WindowHandle)
dev_open_window(, , Width, Height, 'black', WindowHandle) *设置不依赖操作系统的字体
*参数说明:窗口句柄(WindowHandle)
* 字体大小()
* 字体类型(’mono’)
* 是否黑体(’ture’)
* 是否倾斜(’false’)
set_display_font(WindowHandle, , 'mono', 'true', 'false') *定义区域填充模式
*参数说明:填充模式(’Margin'或者'Fill’)
dev_set_draw ('margin') *设置输出区域轮廓线的线宽
*可以修改参数来看最后缺陷区域标示的区别
dev_set_line_width() *设置一种或者多种输出颜色
dev_set_color('red') *Optimize the fft speed for the specific image size(根据指定图像大小进行fft速度最优化)
*参数说明:图片大小(Width,Height)
* 优化模式(’standard’)
optimize_rft_speed(Width,Height,'standard') //对指定大小的图片的fft速度进行优化 *Construct a suitable filter by combining two Gaussian filters(结合两个高斯滤波器构造一*个合适的滤波器)
Sigma1 := 20.0
Sigma2 := 3.0 //定义两个常量 * 如何知道缺陷的频率范围->选用适合的滤波器
* 、
* 、
* 、 *在频域生成两个高斯滤波器
*参数说明: 生成的高斯滤波器(GaussFilter)
* 空域中高斯在主方向上的标准差[Sigma1 >= ]
* 空域中高斯在正交于主方向的方向上的标准差[Sigma2 >= ]
* 滤波器主方向的角度[0.0]
* 滤波器的规范['n', 'none' ]
* 直流项在频域的位置['dc_center', 'dc_edge', 'rft' ]
* 图片的大小(Width,Height)
*高斯函数 高斯-平滑滤波器 无论在空间域还是在频率域都是十分有效的低通滤波器 高斯函数具有五个十分重要的性质,它们是:
* ()二维高斯函数具有旋转对称性 ,即滤波器在各个方向上的平滑程度是相同的.一般来说,一幅图像的边缘方向是事先不知道的,
* 因此,在滤波前是无法确定一个方向上比另一方向上需要更多的平滑.旋转对称性意味着高斯平滑滤波器在后续边缘检测 中不会偏向任一方向.
* ()高斯函数是单值函数.这表明,高斯滤波器用像素邻域 的加权均值来代替该点的像素值,而每一邻域像素点权值是随该点与中心点的距离单调增减的.
* 这一性质是很重要的,因为边缘是一种图像局部特征,如果平滑运算对离算子 中心很远的像素点仍然有很大作用,则平滑运算会使图像失真.
* ()高斯函数的付立叶变换频谱 是单瓣的.正如下面所示,这一性质是高斯函数付立叶变换等于高斯函数本身这一事实的直接推论.
* 图像常被不希望的高频信号 所污染(噪声和细纹理 ).而所希望的图像特征(如边缘),既含有低频分量,又含有高频分量.
* 高斯函数付立叶变换的单瓣意味着平滑图像不会被不需要的高频信号所污染,同时保留了大部分所需信号.
* ()高斯滤波器宽度(决定着平滑程度)是由参数σ表征的,而且σ和平滑程度的关系是非常简单的.σ越大,高斯滤波器的频带 就越宽,
* 平滑程度就越好.通过调节平滑程度参数σ,可在图像特征过分模糊(过平滑)与平滑图像中由于噪声和细纹理所引起的过多的不希望突变量(欠平滑)之间取得折衷.
* ()由于高斯函数的可分离性,大高斯滤波器可以得以有效地实现.二维高斯函数卷积 可以分两步来进行,
* 首先将图像与一维 高斯函数进行卷积,然后将卷积结果与方向垂直的相同一维高斯函数卷积.因此,二维高斯滤波的计算量随滤波模板宽度成线性 增长而不是成平方增长. * 调节Sigma1和Sigma2,其中:
* 、调节Sigma1:
* 、调节Sigma1:
* 、调节Sigma1与调节Sigma2关系:
gen_gauss_filter(GaussFilter1,Sigma1,Sigma1,0.0,'none','rft',Width,Height)
gen_gauss_filter(GaussFilter2,Sigma2,Sigma2,0.0,'none','rft',Width,Height) *两图片相减(灰度)
*sub_image(ImageMinuend, ImageSubtrahend : ImageSub : Mult, Add : )
*g' := (g1 - g2) * Mult + Add
*以上为函数原型以及运算公式
sub_image(GaussFilter1,GaussFilter2,Filter,,) *Process the images iteratively(对图像进行迭代运算)
NumImages := for Index := to NumImages by *Read an image and convert it to gray values
read_image(Image,'plastics/plastics_'+Index$'') *将原图转化为灰度图,第一个参数为原图
rgb1_to_gray(Image,Image) *Perform the convolution in the frequency domain
*对计算一幅图片实部进行快速傅里叶变换
*参数说明:输入的图片(Image)
* 傅里叶变换后输出的图片(ImageFFT)
* 变换方向(’to_freq'或'from_freq’)
* 变换因子的规范(’none’)
* 输出图片的数据类型(’complex’)
* 图片的宽(Width)
rft_generic(Image,ImageFFT,'to_freq','none','complex',Width) *参数说明:输入的图片(ImageFFT)
* 频域滤波器(Filter)
* 运算后输出的结果
*对图片用一个滤波器在频域进行卷积运算
convol_fft(ImageFFT,Filter,ImageConvol) *对滤波后的图片进行傅里叶反变换
rft_generic(ImageConvol,ImageFiltered,'from_freq','n','real',Width) *Process the filtered image
*参数说明:输入的图片(ImageFiltered)
* 输出的灰度范围图(ImageResult)
* 矩形掩膜大小(,)
gray_range_rect(ImageFiltered,ImageResult,,)//用一个矩形掩膜计算像素点的灰度范围 *判断区域内灰度值的最大和最小值
* ???? min_max_gray
*参数说明:
* 待分析图片区域(ImageResult)
* 图片(ImageResult)
* 被去除的直方图两边像素点所
* 占总像素数的百分比()
* 得到的最小值最大值及灰度值范围(Min,Max,Range)
min_max_gray(ImageResult,ImageResult,,Min,Max,Range) *利用全局阈值对图像进行分割
*参数说明:输入的图片(ImageResult)
* 分割后得到的区域(RegionDynThresh)
* 阈值(max([5.55,Max*0.8]),)
* 公式:MinGray <= g <= MaxGray
threshold(ImageResult,RegionDynThresh,max([5.55,Max*0.8]),) *计算区域内的连通部分
*参数说明:输入的图片(RegionDynThresh)
* 得到的连通区域(ConnectedRegions)
connection(RegionDynThresh,ConnectedRegions) *根据指定的形态特征选择区域
*参数说明:输入的图片(ConnectedRegions)
* 满足条件的区域(SelectedRegions)
* 将要计算的形态特征(’area’)
* 独立特征间的连接关系(’and’)
* 特征的最小限制()
* 特征的最大限制()
select_shape(ConnectedRegions,SelectedRegions,'area','and',,) *返回包含所有区域的集合
*参数说明:包含所有区域的待计算区域的图片(tedRegions)
* 所有输入区域合(RegionUnion)
union1(SelectedRegions,RegionUnion) *用一个圆圈来封闭一个区域
*参数说明:将要被封闭的区域(RegionUnion)
* 被封闭的区域(RegionClosing)
* 圆圈的半径()
closing_circle(RegionUnion,RegionClosing,) connection(RegionClosing,ConnectedRegions1) select_shape(ConnectedRegions1,SelectedRegions1,'area','and',,) * 计算区域的面积以及中心位置
*参数说明:待计算的区域(SelectedRegions1)
* 区域的面积(Area)
* 区域中心的行(Row)
* 区域中心的列(Column)
area_center(SelectedRegions1,Area,Row,Column) *Display the results
dev_display(Image) //显示原图
Number := |Area| //将区域面积赋给Number用于后面检查是否存在缺陷
if(Number) *构造一个与设定的圆弧或圆相一致的边界
*参数说明:生成的边界(ContCircle)
* 圆弧或圆的中心坐标(Row,Cloumn)
* 圆弧或圆的半径(gen_tuple_const(Number,))
* 圆弧或圆的起始角度(gen_tuple_const(Number,))
* 圆弧或圆的结束角度(gen_tuple_const(Number,rad()))
* 不明白是什么意思
* 相邻两点间的距离()
gen_circle_contour_xld(ContCircle,Row,Column,gen_tuple_const(Number,),gen_tuple_const(Number,), gen_tuple_const(Number,rad()),'positive',) ResultMessage := ['Not OK',Number + 'defect(s) found'] Color := ['red','black'] dev_display(ContCircle) else ResultMessage := 'OK' Color := 'forest green' endif disp_message(WindowHandle,ResultMessage,'window',,,Color,'true') if(Index#NumImages) disp_continue_message(WindowHandle,'black','true') stop() endif endfor
- ************************************************************************************************
- ************************************************************************************************
- * 例程:detect_indent_fft.hdev
- * 1. 说明:这个程序展示了如何利用快速傅里叶变换(FFT)对塑料制品的表面进行目标(缺陷)的检测,大致分为三步:
- * 2. 首先,我们用高斯滤波器构造一个合适的滤波器(将原图通过高斯滤波器滤波);
- * 3. 然后,将原图和构造的滤波器进行快速傅里叶变换;
- * 4. 最后,利用形态学算子将缺陷表示在滤波后的图片上(在缺陷上画圈)。
- * 注:代码中绿色部分为个人理解和注释,其余为例程中原有代码
- * 算法讲解:在实际的表面缺陷检测系统中,针对的检测表面很多是具有一定纹理的比如:布匹、皮革、塑料等,
- * 针对这一类表面的检测就不能单纯依靠帧差或者背景差来完成,因为背景的纹理不可能和当前图像的
- * 纹理完全相同。因此,本例程的算法通过将图像变换到频域进行处理,提取缺陷分量后反变换到时域,
- * 获得缺陷的具体位置。
- * 高斯滤波器:在本算法中,在一开始就构造了两个高斯滤波器,高斯滤波器是一种线性平滑滤波器,适用于消除高斯噪声。
- * 滤波器的实质是对信号进行滤波,滤除不需要的部分,得到想要的部分。一个低通的滤波器可以滤除高频信号,
- * 对于图像来说,噪声和边缘往往集中在高频分量,因此低通能够降噪,但是也能造成图像的模糊。
- * 本文关键:本文的关键就是使用两个低通滤波器,进行相减后构造了一个带阻滤波器来提取缺陷分量。这就需要保证在实际
- * 的待检测表面中缺陷所处的频率范围要和背景以及噪声有明显的差异,并且带阻的频率选择要合适。通过带阻滤
- * 波后获得的频率成分对背景中的纹理要有明显的抑制,并且突出缺陷成分,进行傅里叶反变换后重构的图像就是
- * 缺陷图像,经过简单的分割就能很容易得到缺陷了。
- ***********************************************************************************************
- ***********************************************************************************************
- ** Initialization(初始化)
- ********* dev_update_off(): 这一句包含如下三个算子:
- * dev_updata_pc(‘off’) 关闭更新程序计数器
- * dev_updata_var(‘off’) 关闭更新变量窗口
- * dev_updata_window(‘off’) 关闭更新图像窗口(即通过命令来显示想要在图像窗口显示的图片)
- dev_update_off()
- ********* dev_close_window(): 关闭活动的图像窗口
- dev_close_window()
- * 参数说明:为读入图片命名(Image)
- * 文件名(’plastics/plastics_01’)
- read_image(Image,'plastics/plastics_01')
- * 参数说明:之前读入或生成的图片(Image)
- * 图片的宽(Width)
- * 图片的高(Height)
- get_image_size(Image,Width,Height) //获取图片的长宽;
- * 打开一个新的图像窗口
- * 参数说明:起始坐标(0,0)
- * 大小(Width,Height)
- * 背景颜色(’Black’)
- * 窗口句柄(WindowHandle)
- dev_open_window(0, 0, Width, Height, 'black', WindowHandle)
- *设置不依赖操作系统的字体
- *参数说明:窗口句柄(WindowHandle)
- * 字体大小(14)
- * 字体类型(’mono’)
- * 是否黑体(’ture’)
- * 是否倾斜(’false’)
- set_display_font(WindowHandle, 14, 'mono', 'true', 'false')
- *定义区域填充模式
- *参数说明:填充模式(’Margin'或者'Fill’)
- dev_set_draw ('margin')
- *设置输出区域轮廓线的线宽
- *可以修改参数来看最后缺陷区域标示的区别
- dev_set_line_width(3)
- *设置一种或者多种输出颜色
- dev_set_color('red')
- *Optimize the fft speed for the specific image size(根据指定图像大小进行fft速度最优化)
- *参数说明:图片大小(Width,Height)
- * 优化模式(’standard’)
- optimize_rft_speed(Width,Height,'standard') //对指定大小的图片的fft速度进行优化
- *Construct a suitable filter by combining two Gaussian filters(结合两个高斯滤波器构造一*个合适的滤波器)
- Sigma1 := 20.0
- Sigma2 := 3.0 //定义两个常量
- * 如何知道缺陷的频率范围->选用适合的滤波器
- * 1、
- * 2、
- * 3、
- *在频域生成两个高斯滤波器
- *参数说明: 生成的高斯滤波器(GaussFilter)
- * 空域中高斯在主方向上的标准差[Sigma1 >= 0]
- * 空域中高斯在正交于主方向的方向上的标准差[Sigma2 >= 0]
- * 滤波器主方向的角度[0.0]
- * 滤波器的规范['n', 'none' ]
- * 直流项在频域的位置['dc_center', 'dc_edge', 'rft' ]
- * 图片的大小(Width,Height)
- *高斯函数 高斯-平滑滤波器 无论在空间域还是在频率域都是十分有效的低通滤波器 高斯函数具有五个十分重要的性质,它们是:
- * (1)二维高斯函数具有旋转对称性 ,即滤波器在各个方向上的平滑程度是相同的.一般来说,一幅图像的边缘方向是事先不知道的,
- * 因此,在滤波前是无法确定一个方向上比另一方向上需要更多的平滑.旋转对称性意味着高斯平滑滤波器在后续边缘检测 中不会偏向任一方向.
- * (2)高斯函数是单值函数.这表明,高斯滤波器用像素邻域 的加权均值来代替该点的像素值,而每一邻域像素点权值是随该点与中心点的距离单调增减的.
- * 这一性质是很重要的,因为边缘是一种图像局部特征,如果平滑运算对离算子 中心很远的像素点仍然有很大作用,则平滑运算会使图像失真.
- * (3)高斯函数的付立叶变换频谱 是单瓣的.正如下面所示,这一性质是高斯函数付立叶变换等于高斯函数本身这一事实的直接推论.
- * 图像常被不希望的高频信号 所污染(噪声和细纹理 ).而所希望的图像特征(如边缘),既含有低频分量,又含有高频分量.
- * 高斯函数付立叶变换的单瓣意味着平滑图像不会被不需要的高频信号所污染,同时保留了大部分所需信号.
- * (4)高斯滤波器宽度(决定着平滑程度)是由参数σ表征的,而且σ和平滑程度的关系是非常简单的.σ越大,高斯滤波器的频带 就越宽,
- * 平滑程度就越好.通过调节平滑程度参数σ,可在图像特征过分模糊(过平滑)与平滑图像中由于噪声和细纹理所引起的过多的不希望突变量(欠平滑)之间取得折衷.
- * (5)由于高斯函数的可分离性,大高斯滤波器可以得以有效地实现.二维高斯函数卷积 可以分两步来进行,
- * 首先将图像与一维 高斯函数进行卷积,然后将卷积结果与方向垂直的相同一维高斯函数卷积.因此,二维高斯滤波的计算量随滤波模板宽度成线性 增长而不是成平方增长.
- * 调节Sigma1和Sigma2,其中:
- * 1、调节Sigma1:
- * 2、调节Sigma1:
- * 3、调节Sigma1与调节Sigma2关系:
- gen_gauss_filter(GaussFilter1,Sigma1,Sigma1,0.0,'none','rft',Width,Height)
- gen_gauss_filter(GaussFilter2,Sigma2,Sigma2,0.0,'none','rft',Width,Height)
- *两图片相减(灰度)
- *sub_image(ImageMinuend, ImageSubtrahend : ImageSub : Mult, Add : )
- *g' := (g1 - g2) * Mult + Add
- *以上为函数原型以及运算公式
- sub_image(GaussFilter1,GaussFilter2,Filter,1,0)
- *Process the images iteratively(对图像进行迭代运算)
- NumImages := 11
- for Index := 1 to NumImages by 1
- *Read an image and convert it to gray values
- read_image(Image,'plastics/plastics_'+Index$'02')
- *将原图转化为灰度图,第一个参数为原图
- rgb1_to_gray(Image,Image)
- *Perform the convolution in the frequency domain
- *对计算一幅图片实部进行快速傅里叶变换
- *参数说明:输入的图片(Image)
- * 傅里叶变换后输出的图片(ImageFFT)
- * 变换方向(’to_freq'或'from_freq’)
- * 变换因子的规范(’none’)
- * 输出图片的数据类型(’complex’)
- * 图片的宽(Width)
- rft_generic(Image,ImageFFT,'to_freq','none','complex',Width)
- *参数说明:输入的图片(ImageFFT)
- * 频域滤波器(Filter)
- * 运算后输出的结果
- *对图片用一个滤波器在频域进行卷积运算
- convol_fft(ImageFFT,Filter,ImageConvol)
- *对滤波后的图片进行傅里叶反变换
- rft_generic(ImageConvol,ImageFiltered,'from_freq','n','real',Width)
- *Process the filtered image
- *参数说明:输入的图片(ImageFiltered)
- * 输出的灰度范围图(ImageResult)
- * 矩形掩膜大小(10,10)
- gray_range_rect(ImageFiltered,ImageResult,10,10)//用一个矩形掩膜计算像素点的灰度范围
- *判断区域内灰度值的最大和最小值
- * ???? min_max_gray
- *参数说明:
- * 待分析图片区域(ImageResult)
- * 图片(ImageResult)
- * 被去除的直方图两边像素点所
- * 占总像素数的百分比(0)
- * 得到的最小值最大值及灰度值范围(Min,Max,Range)
- min_max_gray(ImageResult,ImageResult,0,Min,Max,Range)
- *利用全局阈值对图像进行分割
- *参数说明:输入的图片(ImageResult)
- * 分割后得到的区域(RegionDynThresh)
- * 阈值(max([5.55,Max*0.8]),255)
- * 公式:MinGray <= g <= MaxGray
- threshold(ImageResult,RegionDynThresh,max([5.55,Max*0.8]),255)
- *计算区域内的连通部分
- *参数说明:输入的图片(RegionDynThresh)
- * 得到的连通区域(ConnectedRegions)
- connection(RegionDynThresh,ConnectedRegions)
- *根据指定的形态特征选择区域
- *参数说明:输入的图片(ConnectedRegions)
- * 满足条件的区域(SelectedRegions)
- * 将要计算的形态特征(’area’)
- * 独立特征间的连接关系(’and’)
- * 特征的最小限制(4)
- * 特征的最大限制(99999)
- select_shape(ConnectedRegions,SelectedRegions,'area','and',4,99999)
- *返回包含所有区域的集合
- *参数说明:包含所有区域的待计算区域的图片(tedRegions)
- * 所有输入区域合(RegionUnion)
- union1(SelectedRegions,RegionUnion)
- *用一个圆圈来封闭一个区域
- *参数说明:将要被封闭的区域(RegionUnion)
- * 被封闭的区域(RegionClosing)
- * 圆圈的半径(10)
- closing_circle(RegionUnion,RegionClosing,10)
- connection(RegionClosing,ConnectedRegions1)
- select_shape(ConnectedRegions1,SelectedRegions1,'area','and',10,99999)
- * 计算区域的面积以及中心位置
- *参数说明:待计算的区域(SelectedRegions1)
- * 区域的面积(Area)
- * 区域中心的行(Row)
- * 区域中心的列(Column)
- area_center(SelectedRegions1,Area,Row,Column)
- *Display the results
- dev_display(Image) //显示原图
- Number := |Area| //将区域面积赋给Number用于后面检查是否存在缺陷
- if(Number)
- *构造一个与设定的圆弧或圆相一致的边界
- *参数说明:生成的边界(ContCircle)
- * 圆弧或圆的中心坐标(Row,Cloumn)
- * 圆弧或圆的半径(gen_tuple_const(Number,30))
- * 圆弧或圆的起始角度(gen_tuple_const(Number,0))
- * 圆弧或圆的结束角度(gen_tuple_const(Number,rad(360)))
- * 不明白是什么意思
- * 相邻两点间的距离(1)
- gen_circle_contour_xld(ContCircle,Row,Column,gen_tuple_const(Number,30),gen_tuple_const(Number,0), gen_tuple_const(Number,rad(360)),'positive',1)
- ResultMessage := ['Not OK',Number + 'defect(s) found']
- Color := ['red','black']
- dev_display(ContCircle)
- else
- ResultMessage := 'OK'
- Color := 'forest green'
- endif
- disp_message(WindowHandle,ResultMessage,'window',12,12,Color,'true')
- if(Index#NumImages)
- disp_continue_message(WindowHandle,'black','true')
- stop()
- endif
- endfor