- 📢博客主页:https://blog.csdn.net/weixin_43197380
- 📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正!
- 📢本文由 Loewen丶原创,首发于 CSDN,转载注明出处🙉
- 📢现在的付出,都会是一种沉淀,只为让你成为更好的人✨
文章预览:
缺陷检测算法不同于尺寸、二维码、OCR等算法。后者应用场景比较单一,基本都是套用一些成熟的算子,所以门槛较低,比较容易做成标准化的工具。而缺陷检测极具行业特点,不同行业的缺陷算法迥然不同,常见的是对物品表面缺陷的检测,比如工件表面的斑点、凹坑、划痕、色差、缺损等缺陷进行检测。随着缺陷检测要求的提高,机器学习和深度学习也成了缺陷领域一个不可或缺的技术难点,接下来我会对标准缺陷检测算法、以及半导体行业的非标算法做一个简单分析:
所谓标准,就是不针对行业特点,这里基本分为如下几类:
标准的做法一般都是拿标准的算法块进行组合,以达到缺陷检测的效果,缺陷检测标准流程一般是:
1设置基准图模板——>2当前图模板定位——>3生成仿射变换矩阵——>4旋转平移图像或者区域——>5预处理差分——>6预处理滤波/腐蚀/膨胀——>7Blob检测——>8面积检测
相对与标准做法,非标的做法就非常多,有些非标的目的是为了减少操作步骤,例如将上面的组合流程变成一个工具,这个我们称之为业务逻辑非标。还有一些非标主要是做图像预处理部分,例如修改一些标准预处理的算子和预处理流程,将瑕疵提取出来。当然,对数学理论掌握程度较高的朋友,会推导理论公式,然后直接实现数学公式达到检测效果。
总的来说,缺陷检测的算法包括:
标准缺陷检测我觉得用差分法还是蛮多的。顾名思义,差分就是通过对两幅图像或和两个区域作差,来找出其中有差异的区域。处理流程基本就是定位Blob分析+差分或模板匹配+差分的方式,主要用来检测物品损坏,凸起,破洞,缺失,以及质量检测等。两种方式的具体流程如下:
检测流程如下:
流程解析:以标准图像中的灰度值为模板,计算处检测图像的灰度值,并与标准图像作差,灰度值差异越大,则证明检测图像中存在与标准图比有明显灰度变化的区域,即这部分区域就是我们所要筛选出的缺陷区域。
示例分析:提取灰度值明显的缺陷区域
*1.使用`intensity()`算子计算出模板图(即标准图,图1)的检测区域图像的灰度平均值`OriginalMean`
intensity(OriginalRegion, ImageReduced1, OriginalMean, Deviation1)
*2.再`intensity()`算子计算出待测图(图2)的检测区域图像的灰度平均值`DetectMean`,计算出两幅图像灰度均值的差值
intensity (DetectRegion, ImageReduced2, DetectMean, Deviation2)
tuple_abs (OriginalMean-DetectMean, Abs)
*3.
*如果两个区域的灰度值差值大于10(if(Abs>10)),则生成一副图像(图3),其灰度值为模板图中计算得到的的平均灰度值;
*如果两个区域的灰度值差值小于10(if(Abs<10)),则生成一副图像(图3),其灰度值为待测图中计算得到的的平均灰度值。
*ps:这里计算结果是差值小于10,也就是检测图的灰度值差异和模板图差异不大,直接生成一个后者的灰度均值图像
if(Abs>10)
gen_image_proto (ImageReduced2, ImageCleared, OriginalMean)
else
gen_image_proto (ImageReduced2, ImageCleared, DetectMean)
endif
reduce_domain (ImageCleared, RegionDifference, ImageReduced1)
*4.将待测图与新生成的灰度值图像做差值(图4),可以找到待测图和模板图灰度值有差异的区域
abs_diff_image (ImageReduced2, ImageReduced1, ImageAbsDiff, 1)
invert_image (ImageAbsDiff, ImageInvert)
threshold (ImageInvert, Region1, 0, 30)
opening_circle (Region1, RegionOpening, 1.5)
connection (RegionOpening, ConnectedRegions)
select_shape (ConnectedRegions, SelectedRegions, 'area', 'and', 10, 99999)
检测效果如下:

没理解的,再列举一些Halcon中的差分例程练练手:
1.检测毛刺(Blob+差分法)—— fin.hdev
2.电路板线路缺陷检测(Blob+差分法)—— pcb_inspection.hdev
3.瓶口破损缺陷检测(Blob+差分法)—— inspect_bottle_mouth.hdev(注意直角坐标系和极坐标系之间的转换)

流程如下:
示例分析:印刷质量缺陷检测(可变现模板匹配+差分法)—— print_check.hdev
ps:里面没用difference做差分,而是用了Halcon为变形模板提供的专门的差分算子:compare_variation_model();
Blob分析适用于需要整张图都是Roi区域或图像某处Roi区域通过预处理很容易提取出来的情况。而Blob分析没办法定位到图像R区域的时候就需要用到模板匹配了,通过模板匹配(形状匹配或局部变形匹配)定位到图像Roi区域,然后用差异模型去检测缺陷,可以理解为模板匹配 + 差分是Blob分析 + 差分的进阶版,比较容易处理的可以交给儿子Blob分析处理,难的话爸爸模板匹配上。
傅里叶变换是一种函数在空间域和频率域的变换,从空间域到频率域的变换是傅里叶变换,而从频率域到空间域是傅里叶的反变换。
时域与频域:
信号在频率域的表现:
在频域中,频率越大说明原始信号 变化速度越快;频率越小说明原始信号越平缓。当频率为0时,表示直流信号,没有变化。因此,频率的大小反应了信号的变化快慢。高频分量解释信号的突变部分,而低频分量决定信号的整体形象。
在图像处理中,频率反应了图像在空域灰度变化剧烈程度,也就是图像灰度的变化速度,也就是图像的梯度大小。对图像而言,图像的边缘部分是突变部分,变化较快,因此反应在频域上是高频分量;图像的噪声大部分情况下是高频部分;图像平缓变化部分则为低频分量。也就是说,傅立叶变换提供另外一个角度来观察图像, 可以将图像从灰度分布转化到频率分布上来观察图像的特征。书面一点说就是,傅里叶变换提供了一条从空域到频率自由转换的途径。对图像处理而言,以下概念非常的重要。
由布布丶全权冠名的“ 第一届图像杯拳王挑战锦标赛 "`正式开始,有请:
加强理解:图像噪声一般是白点或者黑点,因为它与正常的点颜色不一样了,也就是说该像素点灰度值明显不一样了,也就是灰度有快速地变化了,所以是高频部分;图像细节处也是属于灰度值急剧变化的区域,正是因为灰度值的急剧变化,才会出现细节,也属于高频部分;所以一般会对信号先进行低通滤波处理,即过滤掉图像中的高频部分(噪声/细节/边缘),留下低频(图像轮廓),结果就是图像模糊了。
ps:图像处理中,有书上说低频反应轮廓,高频反应细节;有的文章里面说低频反应的是背景,高频反应的是边缘;低频反应轮廓,这里的轮廓指的不是边缘(很多人会搞混觉得轮廓是指的就是边缘),打个比方,近视眼的人摘了眼镜,人们通常会说:“我什么也看不清,仅仅能看到一个大致轮廓。”就是类似的意思。所以图像的边缘提取仍是提起的边缘的高频信息,这两种说法并不矛盾。
总结:低频代表图像整体轮廓,高频代表了图像噪声、边缘和细节,中频代表图像纹理等。
使用傅里叶变换进行频域分析的应用场景:
在Halcon中,使用频域进行检测的思路是先从空间域到频域,在频域中进行适当滤波,选择自己想要的频段,然后再返回到空间域中去,其中有两个步骤是比较关键的:
1. 生成合适的滤波器
对应的关键算子:
gen_std_bandpass
gen_sin_bandpass
*创建一个高斯滤波器,sigma越小滤波器越小,通过的信号更加的集中在低频,这样做的目的是得到背景
gen_gauss_filter( : ImageGauss : Sigma1, Sigma2, Phi, Norm, Mode, Width, Height : )(常用)
gen_mean_filter
gen_derivative_filter
gen_bandpass
gen_bandfilter
gen_highpass
gen_lowpass
2. 快速傅里叶变换(空间域和频域之间的相互转换)
对应的关键算子:
fft_generic(Image : ImageFFT : Direction, Exponent, Norm, Mode, ResultType : )
rft_generic(Image : ImageFFT : Direction, Norm, ResultType, Width : )
两个算子共同点:
这两个算子都可以进行空间域—>频域,频域—>空间域的变换,只需要针对参数Direction分别进行选择,参数'to_freq'是进行的是空间域—>频域的变换,'from_freq'是频域—>空间域的变换
针对参数ResultType,如果是to_freq',那么ResultType一般选择'complex';如果是'from_freq',ResultType一般选择’byte’(灰度图像)。
两个算子不同点:
fft_generic:DC项在频域中的位置可选在左上角(Mode:'dc_edge')或者原点平移到中心(Mode:'dc_center')
rft_generic:没有设置项Mode,原点在默认在左上角。
除此之外,fft_image:也可进行快速傅里叶变化(空间域到频域),等价于fft_generic(Image,ImageFFT,‘to_freq’,-1,‘sqrt’,‘dc_center’,‘complex’)
🐨 塑料制品的表面进行缺陷检测 —— detect_indent_fft.hdev
* 1.对指定大小的图片的fft速度进行优化
optimize_rft_speed (Width, Height, 'standard')
Sigma1 := 10.0
Sigma2 := 3.0
* 2.构造两个高斯滤波器,ps:Sigma参数的选取很重要
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 (GaussFilter1, GaussFilter2, Filter, 1.025, 0)
NumImages := 16
for Index := 1 to NumImages by 1
read_image (Image, 'plastics/plastics_' + Index$'02')
rgb1_to_gray (Image, Image)
* 3.计算一个图像的实值快速傅里叶变换(空间域转至频域)
rft_generic (Image, ImageFFT, 'to_freq', 'none', 'complex', Width)
* 4.用在频域内的滤波器使一个图像卷积。
convol_fft (ImageFFT, Filter, ImageConvol)
* 5.卷积后的频域图像转至空间域
rft_generic (ImageConvol, ImageFiltered, 'from_freq', 'n', 'real', Width)
* 6.滤波之后的图像交给形态学来分析
* 空间域上的blob图像分割
*原图矩形内的灰度值范围(max-min)作为输出图像像素值,扩大了亮的部分
gray_range_rect (ImageFiltered, ImageResult, 10, 10)
* 获得图像最大灰度值和最小灰度值
min_max_gray (ImageResult, ImageResult, 0, Min, Max, Range)
*二值化提取( 5.55是经验值,在调试中得到)
threshold (ImageResult, RegionDynThresh, max([5.55,Max * 0.8]), 255)
select_shape (RegionDynThresh, SelectedRegions, 'area', 'and', 1, 99999)

对于处理这种细微的缺陷,也可使用频域处理。该例程的关键就是使用两个低通滤波器,进行相减后构造了一个带阻滤波器(先通过高反差保留让中高频通过,然后通过高斯模糊抑制高频,最终的结果是让中频通过)来提取缺陷分量。
此外,Halcon中关于傅里叶变换的例程还有:detect_mura_defects_texture.hdev
🐒 检测布料表面划痕
*《Halcon机器视觉算法原理与编程实战》16-1
* 将测试图像转化为单通道的灰度图像
rgb1_to_gray (Image, ImageGray)
* 1.创建一个高斯滤波器,用于将傅里叶转换后的图像进行滤波
gen_gauss_filter (GaussFilter, 3.0, 3.0, 0.0, 'none', 'rft', Width, Height)
* 对灰度图像进行颜色反转
invert_image (ImageGray, ImageInvert)
* 2.对反转后的图像进行傅里叶变换
rft_generic (ImageInvert, ImageFFT, 'to_freq', 'none', 'complex', Width)
* 3.对傅里叶图像做卷积,使用之前创建的高斯滤波器作为卷积核
convol_fft (ImageFFT, GaussFilter, ImageConvol)
* 4.将卷积后的傅里叶图像还原为空间域图像。可见图像的突变部分得到了增强
rft_generic (ImageConvol, ImageFiltered, 'from_freq', 'n', 'real', Width)
* 5.设置提取线条的参数,将图像中的有灰度差异的线条提取出来
calculate_lines_gauss_parameters (17, [25,3], Sigma, Low, High)
lines_gauss (ImageFiltered, Lines, Sigma, Low, High, 'dark', 'true', 'gaussian', 'true')

🐎 木板划痕检测
*http://www.ihalcon.com/read-13031-1.html
dev_update_off ()
dev_close_window ()
read_image (Image, '缺陷检测木板划痕提取.jpg')
* 1.彩色转灰度图
count_channels (Image, Channels)
if (Channels == 3 or Channels == 4)
rgb1_to_gray (Image, Image)
endif
get_image_size (Image, Width, Height)
dev_open_window_fit_size (0, 0, Width, Height, -1, -1, WindowHandle)
dev_display (Image)
* 2.傅里叶变换去背景
fft_generic (Image, ImageFFT, 'to_freq', -1, 'sqrt', 'dc_center', 'complex')
gen_rectangle2 (Rectangle1, 308.5, 176.56, rad(-0), 179.4, 7.725)
gen_rectangle2 (Rectangle2, 306.955, 175, rad(-90), 180.765, 4.68)
union2 (Rectangle1, Rectangle2, UnionRectangle)
paint_region (UnionRectangle, ImageFFT, ImageResult, 0, 'fill')
fft_generic (ImageResult, ImageFFT1, 'from_freq', 1, 'sqrt', 'dc_center', 'byte')
* 3.提取划痕
threshold (ImageFFT1, Regions, 5, 240)
connection (Regions, ConnectedRegions)
select_shape (ConnectedRegions, SelectedRegions, 'area', 'and', 20, 99999)
union1 (SelectedRegions, RegionUnion)
dilation_rectangle1 (RegionUnion, RegionDilation, 5, 5)
connection (RegionDilation, ConnectedRegions1)
select_shape (ConnectedRegions1, SelectedRegions1, ['width','height'], 'and', [30,15], [150,100])
dilation_rectangle1 (SelectedRegions1, RegionDilation1, 11, 11)
union1 (RegionDilation1, RegionUnion1)
skeleton (RegionUnion1, Skeleton)
* 4.显示
dev_set_color ('red')
dev_display (Image)
dev_display (Skeleton)

在工业领域,表面检测是一个非常广泛的应用领域。在halcon中,使用增强的光度立体视觉方法,三维表面检测被加强。利用阴影可方便快速的检测物体表面的缺口或凹痕。 使用光度立体视觉方法可在复杂图像中轻松找到表面缺陷 。
算子photometric_stereo详解:
* 使用光度立体法重建表面
photometric_stereo (Images : HeightField, Gradient, Albedo : Slants, Tilts, ResultType, ReconstructionMethod, GenParamName, GenParamValue : )
* Images:输入图像(4张)
* HeightField:返回重建高度场
* Gradient:返回表面的梯度场
* Albedo: 表面的反射率
* Slants:光源光线与摄像机光轴的夹角(下面有示意图)
* Tilts: 光源光线投影与被测物主轴的夹角
* ResultType: 请求结果类型(高度场/梯度场/反射率)
* ReconstructionMethod: 重建方法类型
* GenParamName: 一般参数名称
* GenParamValue: 一般参数设置
算子derivate_vector_field详解:
* 梯度场转平均曲率场
derivate_vector_field(VectorField : Result : Sigma, Component : )
* VectorField: 梯度场图像
* Result: 返回平均曲率场图像
* Sigma: 高斯系数
* Component: 组件计算
🐨 药片外包装破损的检测
Halcon案例:方法-光度立体法- inspect_blister_photometric_stereo.hdev
read_image (Images, './blister_back_0' + [1:4])
for I := 1 to 4 by 1
select_obj (Images, ObjectSelected, I)
*wait_seconds (0.1)
endfor
Tilts := [6.1,95.0,-176.1,-86.8]
Slants := [41.4,42.6,41.7,40.9]
* 光度立体
photometric_stereo (Images, HeightField, Gradient, Albedo, Slants, Tilts, 'all', 'poisson', [], [])
* 梯度场转平均曲率场
derivate_vector_field (Gradient, Result, 1, 'mean_curvature')
*scale_image_max (Result, ImageScaleMax)
* 种子生长
regiongrowing (Result, Regions, 1, 1, 0.01, 250)
select_shape (Regions, SelectedRegions, 'area', 'and', 16332.6, 28629.5)
shape_trans (SelectedRegions, RegionTrans, 'convex')
union1 (RegionTrans, RegionUnion)
erosion_circle (RegionUnion, RegionErosion, 3.5)
reduce_domain (Result, RegionErosion, ImageReduced)
* 求图像的绝对值
abs_image (ImageReduced, ImageAbs)
threshold (ImageAbs, Regions1, 0.3, 0.5)
* 显示

此外,Halcon中关于光度立体法的例程还有:
1.洗发水瓶身缺陷检测(inspect_shampoo_label_photometric_stereo.hdev)
2.皮革表面缺陷检测(inspect_leather_photometric_stereo.hdev)
例程解析参考:halcon——缺陷检测常用方法总结(光度立体)
| 戳戳小手帮忙点个免费的赞和关注吧,嘿嘿。 |
参考资料:
1.微信公众号:机器视觉那些事儿
2.https://www.cnblogs.com/xyf327/p/14872873.html
3.http://www.ihalcon.com/read-16432.html
4.https://blog.csdn.net/weixin_38566632/article/details/116377384
6.https://libaineu2004.blog.csdn.net/article/details/105366681
6.傅里叶分析之掐死教程(完整版)更新于2014.06.06 - 知乎 (zhihu.com);
7.图像的傅里叶变换
8.光度立体
我正在尝试测试是否存在表单。我是Rails新手。我的new.html.erb_spec.rb文件的内容是:require'spec_helper'describe"messages/new.html.erb"doit"shouldrendertheform"dorender'/messages/new.html.erb'reponse.shouldhave_form_putting_to(@message)with_submit_buttonendendView本身,new.html.erb,有代码:当我运行rspec时,它失败了:1)messages/new.html.erbshou
我在从html页面生成PDF时遇到问题。我正在使用PDFkit。在安装它的过程中,我注意到我需要wkhtmltopdf。所以我也安装了它。我做了PDFkit的文档所说的一切......现在我在尝试加载PDF时遇到了这个错误。这里是错误:commandfailed:"/usr/local/bin/wkhtmltopdf""--margin-right""0.75in""--page-size""Letter""--margin-top""0.75in""--margin-bottom""0.75in""--encoding""UTF-8""--margin-left""0.75in""-
我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t
我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为
为了将Cucumber用于命令行脚本,我按照提供的说明安装了arubagem。它在我的Gemfile中,我可以验证是否安装了正确的版本并且我已经包含了require'aruba/cucumber'在'features/env.rb'中为了确保它能正常工作,我写了以下场景:@announceScenario:Testingcucumber/arubaGivenablankslateThentheoutputfrom"ls-la"shouldcontain"drw"假设事情应该失败。它确实失败了,但失败的原因是错误的:@announceScenario:Testingcucumber/ar
我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer
我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server
在MRIRuby中我可以这样做:deftransferinternal_server=self.init_serverpid=forkdointernal_server.runend#Maketheserverprocessrunindependently.Process.detach(pid)internal_client=self.init_client#Dootherstuffwithconnectingtointernal_server...internal_client.post('somedata')ensure#KillserverProcess.kill('KILL',
我已经从我的命令行中获得了一切,所以我可以运行rubymyfile并且它可以正常工作。但是当我尝试从sublime中运行它时,我得到了undefinedmethod`require_relative'formain:Object有人知道我的sublime设置中缺少什么吗?我正在使用OSX并安装了rvm。 最佳答案 或者,您可以只使用“require”,它应该可以正常工作。我认为“require_relative”仅适用于ruby1.9+ 关于ruby-主要:Objectwhenrun
我花了三天的时间用头撞墙,试图弄清楚为什么简单的“rake”不能通过我的规范文件。如果您遇到这种情况:任何文件夹路径中都不要有空格!。严重地。事实上,从现在开始,您命名的任何内容都没有空格。这是我的控制台输出:(在/Users/*****/Desktop/LearningRuby/learn_ruby)$rake/Users/*******/Desktop/LearningRuby/learn_ruby/00_hello/hello_spec.rb:116:in`require':cannotloadsuchfile--hello(LoadError) 最佳