欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Halcon表面缺陷检测-光度立体法

程序员文章站 2022-07-04 16:04:02
...

来自halcon中的simple.相关介绍光度立体算法.

相关的例子:

inspect_blister_photometric_stereo.hdev

inspect_flooring_photometric_stereo.hdev

inspect_flooring_uncalib_photometric_stereo.hdev

inspect_leather_photometric_stereo.hdev

inspect_shampoo_label_photometric_stereo.hdev

主要涉及的算子 photometric_stereo -- 通过光度立体技术重建表面

photometric_stereo(Images : HeightFieldGradient,Albedo : SlantsTiltsResultType,ReconstructionMethodGenParamNameGenParamValue : )

  • 描述:
    photometric_stereo可以用来从一个物体的两维纹理,例如它的打印照片,来区分出它的三维形状。这个算子需要至少需要三张使用已知的不同方向的光源拍摄的相同物体的图像。注意,拍摄这些照片时,相机的视角应该是固定的。(译者注:即固定相机和物体,从多个已知的不同方向打光拍摄)
    物体的这种三维形状从根本上来说是通过计算3维表面的局部梯度。这些梯度可以被进一步综合起来获取到一个高度场,也就是说,一张图片的每个像素都与一个相对高度相关联。(译者注:计算得出的)二维的纹理被称为反照率,与对局部光源的吸收和反射表面特征有关,把所有的阴影都排除在外。

    • 光照立体法的典型应用
      光照立体法的典型应用是用来检测表面的变化,这种变化可能意味着缺陷,或者被用来将拍照时光照角度的影响排除在外,例如用于非扁平字符的打印检查。注意,光度立体法不适用于重建绝对高度,也就是说,它不能替代传统的3D重建算法,如对焦测距和激光三角测量。

    • 光度立体法的局限性
      光度立体法是基于Woodham算法,因此假设相机表现为无畸变的投影。这也就意味着,你必须使用一个远心镜头或者长焦镜头。另一方面,它假设了每个光源发出的都是平行的等截面的光。这也就是说,你使用的照明必须是远心光源,有着均匀的强度,或者作为替代,远距离的点光源。此外,这个物体必须有朗伯反射特性,也就是说它对光的反射是漫反射。有镜面反射的物体或者区域(镜子或者光滑的表面)不能被正确处理,会得到一个错误的结果。

    • 照片采集设置
      这个使用远心镜头的相机必须被放置得和被重建的平面正交,即互相垂直。相机和平面的角度在采集过程中一定不能改变。相反,光源和平面的夹角必须至少改变三次来获取三张灰度图片。

    • 具体说明光照的角度
      对每张图片,光线的方向用两个角度来表示,使用参数Slants和Tilts,这两个参数描述了光线和平面的方向。来理解一下这两个参数,记住,光源被假设发出的是平行光,照相机有一个远心镜头,相机被放置在重建表面的正交方向。
      • Slants
        这个角度指的是相机的光轴和光线的夹角。如图:
        Halcon表面缺陷检测-光度立体法

      • Tilts
        这个角度使用物体平面或者其他与之平行的平面,例如图片表面来进行测量。特别的,它描述了图片中心点向右延伸和光线方向投影到平面上的夹角。也即,当在看图片或者相关的平面时,一个0度的角意味着光从右边来,90度意味着光从顶上来,180度意味着光从左边来,等等。如图:
        Halcon表面缺陷检测-光度立体法

      正如之前所说的,光度立体法需要至少三张光线不同情况下拍摄的照片。然而,一个三维的几何体通常会有阴影。在阴影区域,光线有效方向的数量(the number of effectively available directions of illumination)被削减了,这会导致不明确(译者注:ambiguities?模棱两可?)。尽管如此,获取一个鲁棒性好的结果,赘余是需要的。因此,通常会使用超过三个不同方向的光源。但是记住,光线方向的增加,会导致更多的图片需要被处理,因此需要花费更多的处理时间。在绝大多数应用中,4-6个光源是合理的。根据经验法则,slant角度会在30°-60°之间选择。Tilt角度通常会均等得分布在被测物体的周围。请记住,光线的角度必须是经过选择的,以使得他们(译者注:他们是指?)能够不在同一平面上(即:光线的方向必须是独立的)。否则,计算会失败,程序会抛出一个异常。

    • 输入图片和定义的区域
      图片必须以一个图片数组输入。如前所述:每张图片必须是使用不同的光线角度的。如果图片是通过存储在多通道图片中的,通过 image_to_channels 可以容易地转换为图片数组。作为替代,图片数组可以通过 concat_obj 来创建。
      光度立体法依赖于对光度测定信息的评估,也就是存储在图像中的灰度值。因此,这些信息应当是无偏并且是准确的。我们建议保证用来采集图像的相机有线性特征。如果有非线性特征,你可以使用算子 radiometric_self_calibration 来测定你的相机的特征,使用 lut_trans 来校正灰度信息。此外,如果需要精确的测量,我们建议运用相机的全动态范围,因为这可以获得更精确的灰度信息。为了相同的原因,使用高于8位深度(bit-depth)的图像(例如:使用uint2的图像(译者注:灰度范围0~65535)而不是byte(0~255)类型的图像)可以带来更高的准确率。
      输入图像的定义域决定了内部会使用哪一种算法来处理图像。有三种可用的算法:
      * 如果整个图像都是定义域(译者注:可以理解为这张图的每个像素点都有灰度值),会使用最快的算法。这被推荐使用在大多数的应用中。
      * 如果输入的图像共享了相同的削减过的定义域,只有定义域内的像素会被处理。这种模式会被用来排除图像上的某些区域。通常的,已知显示出非朗伯反射特性或者不感兴趣的区域会被排除,例如表面的孔洞。(译者注:每张图的定义域都是相同的)
      * 如果提供了包含清晰定义域的图像,每张图像上包含在范围内的灰度值会被使用。只有在三张图像上拥有独立的slant和tilt角度的像素会被处理(译者注:?only those pixels are processed that have independent slant and tilt angles in at least three images)。这种模式在某些情况下是合适的,例如在图像处理时排除个别图像上的特别的区域。这些区域可能是已知的表现出非朗伯反射特性的区域或者包含了偏光信息的区域,例如影子。排除这些点可以导致更准确的结果。请注意,最后一种模式与前两种相比,显著需要更多的处理时间。(译者注:这种情况下每张图片的定义域都有可能不同)

    • 输出图片
      这个算子输出了重建图像的梯度,反射率,和表面的高度场图像。
      * 梯度图像是一个向量场,包含了表面的偏导数。记住,梯度可以被用作算子 reconstruct_height_field_from_gradient 的输入参数。为了更直观的目的,替代表面梯度,可以返回标准化之后的表面梯度。为了达到这样的目的,‘ResulltType‘ 必须被设置为 normalized_gradient 而不是 gradient。这里,行和列元素代表了标准化之后的行和列。如果 ResultType被设置为了 all ,就会使用gradient 而不是 normalized_gradient 。
      * 反射率图像描述了反射辐射和入射辐射的比例,数值在1(白色表面)-0(黑色表面)之间。因此,反射率是表面的一个特征。举个例子,对一个印刷表面来说,反射率与把所有入射光排除在外(阴影,明暗)的印刷图片有关。
      * 高度场图像的每个像素与相对高度相关。

    默认情况下,上面这些对象都会返回,也就是说,参数ResultType设置为all。在只需要某些结果的情况下,这个参数可以设置为数组,仅将一些需要的值放在其中,可以放的值有‘gradient‘, ‘albedo‘, 和 ‘height_field‘。记住,在特定的应用中,像表面检测任务,只有梯度和反射率图像是有需要的。这里,不构建高度场图像可以显著得增快重建的速度。
    记住,在光度立体法内部,最先计算出梯度值,如果有需要,结合这些值来获取高度场。这个结合操作与 reconstruct_height_field_from_gradient 使用的是相同的算法,他们可以通过参数ReconstructionMethod, GenParamName, 和 GenParamValue进行控制。请参阅reconstruct_height_field_from_gradient的帮助来获取更多关于这些参数的信息。如果ResultType中没有height_field,那么这几个参数会被忽略。

  • 注意
    photometric_stereo基于方形像素的假定。此外,它假定在物体空间内,高度在步幅是1的格子上计算出来的。如果不是这种情况,相机的像素投射到物体表面不是1,返回的高度场必须乘上实际的步长(像素尺寸投射都物体空间的值)。像素在物体空间的尺寸通过相机中的像素尺寸除以被镜头放大的倍数得到。

  • 执行信息
    • 多线程类型:可重入(可以和非排他性算子并行运行)
    • 多线程作用域:全局(可能在任意线程中调用)
    • 在内部数据层级上自动并行处理
  • 参数
    略。

  • 结果
    如果参数是有效的,返回2。如果有必要,会抛出异常。

  • 可能的前调函数
    optimize_fft_speed

  • 所属模块
    三维计量

图片来源于官方文档

 

* 该示例通过使用光度立体技术检测药片包装背面的缺陷
* 输入是4张不同的药片包装背面图片,光从不同的角度照射

* Initialization
dev_close_window ()
dev_update_off ()
dev_open_window (0, 0, 512, 512, 'black', WindowHandle)
set_display_font (WindowHandle, 14, 'mono', 'true', 'false')
Message := 'Inspect the backside of a blister'
Message[1] := 'using photometric stereo. In this case four'
Message[2] := 'different light orientations were used.'
disp_message (WindowHandle, Message, 'window', 12, 12, 'black', 'true')
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
* 
* Show input images with different illumination
* 1 读图像,依次读取多张图像
* 下面的for循环,依次显示4张从不同角度拍摄的药片包装的背面图像
read_image (Images, 'photometric_stereo/blister_back_0' + [1:4])
for I := 1 to 4 by 1
    Message := 'Acquire image ' + I + ' of 4'
    select_obj (Images, ObjectSelected, I)
    dev_display (ObjectSelected)
    disp_message (WindowHandle, Message, 'window', 12, 12, 'black', 'true')
    wait_seconds (0.5)
endfor
* 
* Apply photometric stereo to determine the albedo
* and the surface gradient.
* 2. 应用光度立体得到反照率图像和表面梯度图像

* 描述了从图像中心指向右侧的方向与投射到平面中的光的方向之间的角度。 
* 也就是说,当观察图像(或相应的场景)时,倾斜角度为0表示光线来自右侧,
* 倾斜角度为90表示光线来自顶部,倾斜角度为180表示 光是从左边来的
Tilts := [6.1,95.0,-176.1,-86.8]
* 物平面与照明方向之间的角度
Slants := [41.4,42.6,41.7,40.9]
ResultType := ['gradient','albedo']
* 该算子得到反照率图像和表面梯度图像
photometric_stereo (Images, HeightField, Gradient, Albedo, Slants, Tilts, ResultType, 'poisson', [], [])
* 
* Display the albedo image
* 显示反照率图像
dev_display (Albedo)
disp_message (WindowHandle, 'Albedo image', 'window', 12, 12, 'black', 'true')
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
* 
* Calculate the gaussian curvature of the surface
* using the gradient field as input for the operator
* 3. 使用之前得到的表面梯度,计算表面的高斯曲率,得到高斯曲率图像
* derivate_vector_field.
* Defects are usually easy to detect in the curvature image.
* 在曲率图像上能更容易的进行检测
* 该算子通过之前得到的表面梯度得到高斯曲率图像
derivate_vector_field (Gradient, GaussCurvature, 1, 'gauss_curvature')
* 
* Detect defects
* 检测缺陷
* 
* Segment the tablet areas in the curvature image
* 4. 对高斯曲率图像进行预处理和Blob分析,从而得到缺陷区域
* 在曲率图像中,我们先分开各个药片区域
regiongrowing (GaussCurvature, Regions, 1, 1, 0.001, 250)
* 通过宽和高的特征,进行特征选择
select_shape (Regions, TabletRegions, ['width','height'], 'and', [150,150], [200,200])
* 凸性形状转换,针对区域
shape_trans (TabletRegions, TabletRegions, 'convex')
* 区域联合
union1 (TabletRegions, TabletRegions)
* 腐蚀
erosion_circle (TabletRegions, TabletRegions, 3.5)
* Search for defects inside the tablet areas
* 在药片区域搜寻缺陷
* 抠图
reduce_domain (GaussCurvature, TabletRegions, ImageReduced)
* 计算图像各个像素的绝对值,存在此次处理的原因是:高斯曲率图像存在负值
* 缺陷处,高斯曲率会比较大
abs_image (ImageReduced, ImageAbs)
* 二值化 ,灰度直方图
threshold (ImageAbs, Region, 0.03, 255)
* 闭运算
closing_circle (Region, RegionClosing, 10.5)
* 断开得到连通域
connection (RegionClosing, ConnectedRegions)
* 通过面积特征,进行特征选择
select_shape (ConnectedRegions, Defects, 'area', 'and', 10, 99999)
* 获得缺陷区域的中心点行列坐标
area_center (Defects, Area, Row, Column)
* 生成圆形区域
gen_circle (Circle, Row, Column, gen_tuple_const(|Row|,20.5))
* Display the defects in curvature image
* 5. 接下来在高斯曲率图像中标记缺陷区域
dev_set_draw ('margin')
dev_set_color ('red')
dev_set_line_width (2)
dev_display (GaussCurvature)
dev_display (Circle)
Message := 'The defect can easily be detected'
Message[1] := 'in the surface curvature image'
disp_message (WindowHandle, Message, 'window', 12, 12, 'black', 'true')
stop ()
* Display the defects in the albedo image
* 6. 在反照率图像中标记出缺陷
dev_set_draw ('margin')
dev_set_color ('red')
dev_display (Albedo)
dev_display (Circle)
disp_message (WindowHandle, 'Defect in albedo image', 'window', 12, 12, 'black', 'true')

 

相关标签: HALCON