1. 了解一些概念
- 适用场景:光度立体法可以看作是2.5维,适用于检测金属物料上面的凹凸特征。
- 原理:重建法向量,将灰度图变成曲率图。
- 光源:光度立体法不需要特殊的光源,只需要从不同的角度打光而已。
- 反射类型:
- 理想镜面反射;
- 理想散射;
- 镜面反射和散射的组合。
- 表面片辐射:决定场景表面片辐射的因素:
- 投在场景表面片上的照明:
投在某一特定表面片上的照明量取决于该表面片在场景中相对于光源的分布位置; - 表面片反射的入射照明部分:
在某一特定方向上被表面片反射的入射照明部分取决于表面材料的光学特性。
- 投在场景表面片上的照明:
2. 认识两个算子
- 注意:光度立体法需要使用灰度图,而且至少需要3张图像,最好是4张。
* 使用光度立体法重建表面
photometric_stereo (Images : HeightField, Gradient, Albedo : Slants, Tilts, ResultType, ReconstructionMethod, GenParamName, GenParamValue : )
* Images:输入图像(4张)
* HeightField:返回重建高度场
* Gradient:返回表面的梯度场
* Albedo: 表面的反射率
* Slants:光源光线与摄像机光轴的夹角(下面有示意图)
* Tilts: 光源光线投影与被测物主轴的夹角
* ResultType: 请求结果类型(高度场/梯度场/反射率)
* ReconstructionMethod: 重建方法类型
* GenParamName: 一般参数名称
* GenParamValue: 一般参数设置
Slants:光源光线与摄像机光轴的夹角(下面有示意图)
Tilts:光源光线投影与被测物主轴的夹角
这个角度是以图像为准的,比如光从图像右侧打过来,角度就是0°,从上面打过来,角度是90°,从左面打过来,角度是180°,下边打过来是270°。
* 梯度场转平均曲率场
derivate_vector_field(VectorField : Result : Sigma, Component : )
* VectorField: 梯度场图像
* Result: 返回平均曲率场图像
* Sigma: 高斯系数
* Component: 组件计算
3. 初试光度立体法
如下图,从银行卡背面识别凹进去的数字,如果采用常规的Blob分析或者频域等方法,是很难达到目的的。但是采用光度立体就能比较容易的将前景和背景分离。
* 下面这段代码是我在连上相机后,分别在0/90/180/270度方向打光,然后保存图像
* open_framegrabber ('KsjCamera_Release-19_11_x64', 1, 1, 0, 0, 0, 0, 'progressive', 8, 'default', -1, 'false', 'default', '255', 0, -1, AcqHandle)
* set_framegrabber_param (AcqHandle, 'exposure_lines', 3693)
* grab_image_start (AcqHandle, -1)
* num:=1
* while (true)
* grab_image_async (Image, AcqHandle, -1)
* decompose3 (Image, R, G, B)//我用了凯视佳的彩色相机
* write_image (R, 'png', 0, './'+num)
* num:=num+1
* endwhile
* close_framegrabber (AcqHandle)
dev_update_off ()
ImageFiles := []
ImageFiles[0] := './1.png'
ImageFiles[1] := './2.png'
ImageFiles[2] := './3.png'
ImageFiles[3] := './4.png'
gen_empty_obj (Images)
for Index := 0 to |ImageFiles| - 1 by 1
read_image (Image, ImageFiles[Index])
concat_obj (Images, Image, Images)
wait_seconds (0.3)
dev_display (Image)
endfor
Slants:=[45,45,45,45]
Tilts:=[0,90,180,270]
* 光度立体法
photometric_stereo (Images, HeightField, Gradient, Albedo, Slants, Tilts, 'all', 'poisson', [], [])
* 梯度场转平均曲率场
derivate_vector_field (Gradient, Result, 1, 'mean_curvature')
* 镜像
mirror_image (Result, Image, 'row')
mirror_image (Image, ImageMirror, 'column')
* 将灰度值分布在0到255之间
scale_image_max (ImageMirror, ImageScaleMax)
* 尝试在频域中继续处理
fft_generic (ImageScaleMax, ImageFFT, 'to_freq', -1, 'sqrt', 'dc_center', 'complex')
* 得到背景
get_image_size (ImageFFT, Width, Height)
gen_gauss_filter (ImageGauss, 10, 10, 0, 'none', 'dc_center', Width, Height)
gen_lowpass (ImageLowpass, 0.05, 'none', 'dc_center', Width, Height)
convol_fft (ImageFFT, ImageGauss, ImageConvol)
fft_generic (ImageConvol, ImageBackground, 'from_freq', 1, 'sqrt', 'dc_center', 'byte')
* 差分,去掉背景
sub_image (ImageScaleMax, ImageBackground, ImageSub, 1, 128)
median_image (ImageSub, ImageMedian, 'circle', 3, 'mirrored')
***字符识别
gen_rectangle1 (ROI_0, 629.385, 382.235, 852.788, 1221.93)
reduce_domain (ImageMedian, ROI_0, ImageReduced)
threshold (ImageReduced, Regions, 132, 205)
closing_circle (Regions, RegionClosing, 1.5)
connection (RegionClosing, ConnectedRegions)
select_shape (ConnectedRegions, SelectedRegions, ['area','width'], 'and', [850.44,14.96], [2000.01,53.38])
sort_region (SelectedRegions, SortedRegions, 'character', 'true', 'row')
reduce_domain (ImageReduced, SelectedRegions, ImageReduced1)
paint_region (ImageReduced, ImageReduced, WihteBackground, 255, 'fill')
paint_region (SortedRegions, WihteBackground, ImageResult, 0, 'fill')
read_ocr_class_mlp ('Industrial_0-9_NoRej.omc', OCRHandle)
do_ocr_multi_class_mlp (SortedRegions, ImageResult, OCRHandle, Class, Confidence)
dev_display (ImageResult)
dev_get_window (WindowHandle)
set_display_font (WindowHandle, 26, 'mono', 'true', 'false')
disp_message (WindowHandle, '由光度立体法求得:', 'image', 12, 12, 'black', 'true')
disp_message (WindowHandle, '账户余额:'+sum(Class) + '元', 'image', 162, 12, 'black', 'true')
dev_update_on ()
4. 药片外包装破损的检测(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)
* 显示
count_obj (Regions1, Number)
if(Number>0)
area_center (Regions1, Area, Row, Column)
gen_circle_contour_xld (ContCircle, Row, Column, 20, 0, 6.28318, 'positive', 1)
dev_set_color ('blue')
dev_set_line_width (2)
dev_display (Result)
dev_display (ContCircle)
endif