1.Halcon语法
一、语法介绍
①赋值和逻辑比较
1) 赋值等号: := 例如: A :=1000
2) 不等号: # 例如: if(A # B)
3) 注释符: *
4) 字符串赋值: str := ’halcon’
5) 等于比较符: = 例如: if (X = 10 )
6) 逻辑与and 例如: if (A>1 and A<30 )
7) 逻辑或or 例如: if(A>1 or A<30 )
8) 逻辑反not 例如: if( not(A=10 ) )
②元组的操作
赋值
St := [ St, iterm ]
访问
iterm := St[ i ]
③控制语句
1)For 循环:
例如:
for I := 0 to NumBalls - 1 by 1
语句
endfor
2) While 循环:
例如:
while (x==1)
语句
Endwhile
3) 异常捕获:
例如:
Try
语句
catch (Exception)
语句
Endtry
Switch多分支:
例如:
switch (Index)
case 1:
break
case 2:
break
default:
break
endswitch
④Halcon开发流程
二、代码实例(在HDevelop运行)
①显示图片代码
* 引入图片
read_image(Image,'C:/Users/Pictures/Pictures/image.jpg')
read_image(Image1,'fabrik') 软件安装目录下的image,不需要写全部路径
* 获取图像大小
get_image_size(Image, Width, Height)
* 打开图像窗口
* WindowHandle:窗口管理者(handle句柄,在某一个进程中的唯一索引)
dev_open_window(0, 0, Width, Height, 'black', WindowHandle)
*设置当前填充区域
dev_set_draw('margin')
* 显示图像
dev_display(Image)
②基础语法运行代码
* 语法学习
* 声明变量
* C#语法是 int x = 1
* halcon赋值语法是 x:=1
x:=1
y:='Hello halcon'
i:=1.0
* 分支语句判断 if
if(i=x)
i:=2.2
endif
* 不等于
if(x#2)
i:=1.0
endif
* > < 和C#都是一样的
if(i>6)
endif
if(i<6)
endif
* else if 判断
if(i>0)
i:=2.0
elseif(i<2)
endif
* 逻辑与 &&
if(x>0 and x<3)
i:=4.0
endif
* 逻辑或 ||
if(x>0 or x<3)
i:=5.0
endif
* 逻辑非 !=
if(not(x=8))
i:=8
endif
* 数组
nums:=[1,2,3,4,5]
nums2:=[1,2,3,4.5]
nums3:=[1,2,3,'4.5']
* for循环(j从0到5,步长为1)
for j:=0 to 5 by 1
endfor
* while 循环
a:=1
while(a==1)
a:=2
endwhile
* switch case 循环
switch(a)
case 1:
a:=5
break
case 2:
a:=6
break
endswitch
* 元组
nums:=[1,2,3,4,5]
* 元组长度
len := |nums|
* 异常捕获
try
* nums-1 长度-1
* nums-1 长度在这里有问题,需要换成 |nums|
for Index := 0 to |nums| by 1
a:=nums[Index]
endfor
catch (Exception)
*disp_message (3600, Exception, 'window', 12, 12, 'black', 'true')
endtry
* 进制:halcon对进制可以直接转换。
i1 := 123$'#o' //8进制,0代表前缀
i2 := 123$'#x' //16进制,0x为前缀,7b代表赋值
i2 := 123$'#X' //7B为赋值,7b=7B
i3 := 123$'#f' //double类型,默认保留小数点后六位
i4 := 123$'#g' //
i5 := 123$'#G' //
i6 := 123$'#e' //转成科学计数
i7 := 123$'#E' //
* 整数
d1 := 123$'6' // 小于6位文本右对齐,大于6位忽略
d2 := 123456$'6' //
d3 := 123$'-6' // 小于6位文本左对齐,大于6位忽略
d4 := 123456$'-6' //
d5 := 123$'.6' // 小于6位时,文本左补零
d6 := 123$'10.5' // 小于十位时,文本右对齐,小于五位补零
d7:= 12345$'10.5' //
d8:= 1234567891$'10.5' //
* 四舍五入
e := 1.5555
e1 := e$'.0f'
e2 := e$'.1f'
e3 := e$'.2f'
e4 := e$'.3f'
③元组(数组)运行代码
元组(Tuple)
是一种基本的数据结构,用于存储和处理一组有序的元素。
元组可以包含不同类型的数据,如整数、实数、字符串等,甚至可以包含其他元组。
元组在 HALCON 中被广泛应用于表示和操作图像处理和计算机视觉中的数据。
* 元组
Tuple := [1,0,3,4,5,6,7,8]
* 根据索引来操作元组
Tuple[0] := 2
* 批量操作元组的值
Tuple[1,3,5] := 'abc'
*批量为元组赋值,自动填充0~100的连续值
tuple2:=[0:100]
*批量为元组赋值,从0到150的连续值,步长为3
tuple3:=[0:3:150]
* 批量为元组赋值,从100~-100的连续值,步长为-10
tuple4:=[100:-10:-100]
*合并(合并在一起并去重 并存入第三个参数中)
tupleInt1:=[0,1,2,3,4,5]
tupleInt2:=[9,8,7,6,5]
tuple_union(tupleInt1, tupleInt2, Union)
*交集(两个元组中一样的元素 并存入第三个参数中)
tupleInt3:=[0,1,2,3,4,5]
tupleInt4:=[9,8,7,6,5]
tuple_intersection (tupleInt3, tupleInt4, Intersection)
* 替换(注意:[0,1]代表的是数组的下标,而不是数组的值)
tupleInt5:=[0,1,2,3,4,5]
tuple_replace (tupleInt5,[0,1],['a','b'],Replaced)
* 插入
tupleInt6:=[0,1,2,3,4,5]
tuple_insert(tupleInt6,3,'x',Replaced2)
* 求绝对值
tuple_abs ([1,-23,-4,-5],Abs)
* const与元组的使用
* 长度为10,元素为const类型的新元组
tuple_gen_const(10,2,Newtuple)
* 链接
a:=[tupleInt1,tupleInt2]
* 获取索引对应的值
b:=a[1]
* 批量获取索引的值
c:=a[1:5]
* 选取数组下标为3的元素
d:=subset(Replaced2,3)
*移除,对应索引的值
e:=remove(Replaced2,3)
*产生10个5存入Newtuple中
tuple_gen_const (10,5,Newtuple)
三、第一个Halcon程序
目的:检测红框内的物体中心点
思路:寻找物体的特征 发现物体的灰度与周围相比偏高 再用面积筛选出合适大小的连通域 获取该连通域的面积中心 绘制十字星
*读取图像
read_image (Image, 'fabrik.png')
*获取图像大小
get_image_size (Image, Width, Height)
*关闭窗口
dev_clear_window()
*打开窗口
dev_open_window(0, 0, Width, Height, 'black', WindowHandle)
*显示图像
dev_display(Image)
* 限制灰度值范围:128-最小灰度值 255-最大灰度值
threshold (Image, Region, 128, 255)
* 连通域搜索:寻找闭合图像
connection (Region, ConnectedRegions)
* 选择形状: 面积范围: 最小 最大
select_shape (ConnectedRegions, SelectedRegions, 'area', 'and', 8144, 8500)
*获取面积中心
area_center(SelectedRegions, Area, Row, Column)
*生成十字星
gen_cross_contour_xld (Cross, Row, Column, 30, 0.0)
注意:单步调试的时候需要开启和显示 才可以正常覆盖显示十字星
四、第二个Halcon程序
目的:识别骰子并给筛子标上不同的颜色
// 读一张图片(可以用F1进行帮助文档 或者打开算子窗口)
read_image (Image, 'dice')
//打开一个窗口 并获得句柄WindowHandle
//其中的参数0,0为坐标值 580和440代表窗口大小 black代表背景颜色
dev_open_window (0, 0, 580, 440, 'black', WindowHandle)
dev_display (Image) //显示窗口
stop()
* // Stop()函数是暂停程序的执行
//定义最高和最低灰度值
MinGray := 85
MaxGray := 255
//threshold算子输入的是Image 输出的是Region 条件是最大和最小灰度
threshold (Image, Region, MinGray, MaxGray)
dev_display (Region)
stop()
//connection算子输入的是Region 输出的是ConnectedRegions
//作用是将Region连起来 相当于数组储存到ConnectedRegions
connection (Region, ConnectedRegions)
dev_display (ConnectedRegions)
2.高斯公式(成像光路)
主要是放大率和焦距的计算
3.镜头的选型
焦距越小 视场角越大 拍摄距离越近
相机选型中1英寸=16毫米(mm)
远心镜头
主要是为了解决被测物体不在同一物面上的情况
4.镜头的MTF曲线
5.机器视觉和计算机视觉的区别
6.工作原理
7.光圈
光圈决定镜头的进光量(进光量越多,画面越亮)
大光圈----景深较短
小光圈----景深较长
8.Halcon介绍
安装路径为C:\Program Files\MVTec\HALCON-12.0
(1).算子(Operators)
输入和输出参数严格区分开
* 开启两个窗口
dev_open_window(0,0,Width, Height, 'black', WindowHandle1)
dev_open_window(0,0,Width, Height, 'black', WindowHandle2)
* 激活窗口
dev_set_window(WindowHandle2)
* 显示图片
dev_display(Image)
*让亮的区域更亮 暗的区域更暗
gray_range_rect(Image : ImageResult : MaskHeight, MaskWidth : )
*求解区域的方向角度
orientation_region(Regions : : : Phi)
*根据区域Regions创建一个轮廓xld
gen_contour_region_xld(Regions : Contours : Mode : )
* 将输入的区域Region转换为一个'byte'图像,并将区域内的所有像素赋予前景灰度值ForegroundGray
* 如果输入的区域大于生成的图像,则将其裁剪到图像边界。背景设置为BackgroundGray。
region_to_bin(Region, BinImage : ForegroundGray, BackgroundGray, Width, Height : )
*计算每个输入轮廓或多边形的平行于坐标轴的包围矩形
*包围矩形由左上角点和右下角点像素的坐标(Row1、Column1、Row2、Column2)描述
*如果传递的轮廓或多边形多于一个,则结果按照与XLD中相应轮廓或多边形相同的顺序存储在元组中
smallest_rectangle1_xld(XLD : : : Row1, Column1, Row2, Column2)
*计算由轮廓或多边形XLD所围成的区域的面积和重心(质心)和沿边界的点的顺序
*如果轮廓或多边形中的点按逆时针顺序排列(即按照数学上的正方向),则PointOrder将为'positive'
area_center_xld(XLD : : : Area, Row, Column, PointOrder)
*将元组Tuple中的所有元素按升序进行排序,并返回排序后的元组元素相对于输入元组Tuple的索引
*作为前提条件,元组Tuple的单个元素必须是可比较的
tuple_sort_index(Tuple : : : Indices)
*计算轮廓或多边形XLD的长度
*长度被计算为轮廓或多边形上相邻点之间的欧几里德距离的总和
*如果传递了多个轮廓或多边形,结果按照与XLD中相应轮廓或多边形相同的顺序存储在元组中
length_xld(XLD : : : Length)
*确定包含轮廓或多边形的最小包围圆,即所有包含轮廓的圆中面积最小的圆
*该函数计算出最小包围圆的中心坐标(Row, Column)和半径(Radius)
smallest_circle_xld(XLD : Row, Column, Radius)
(2).HDevelop自带图片素材存储地
C:\Users\Public\Documents\MVTec\HALCON-12.0\examples\images
(3).直方图(通过直方图确定灰度范围和面积范围)
在这里打开
(4).获取图像
①获取非实时图像
②获取实时图像
异步读取:图像从采集设备获取,非实时,取像与处理并行,对图像处理时间把控比较严;
同步读取:通过相机取像,实时,取像与处理是串行的,取像周期长。
③通道
通道就是代表RBG中的某一个
灰度图片通道为1
彩色图片通道为3
④图片展示设置
将三幅图片进行平铺展示
⑤图像灰度值
在灰度图像中,像素的颜色强度是由其对应的灰度级决定的
范围通常从0(黑色)到255(白色)
亮度越高、颜色越接近白色的地方,相应的像素值就越大
而在图像的深色区域,像素值则较小
灰度图像中的高亮通常表示像素值较大。
9、ROI(对图片感兴趣区域)
①图形化工具的形式(左键选择 右键结束)
可以求多个图形的交并补集 也可以直接插入代码
②代码的形式
(1)非交互方式
read_image (image,'C:/Users/Public/Documents/MVTec/HALCON-12.0/examples/images/claudia.png')
* 生成矩形区域区域为左上(100,100)到右下(300,300)
gen_rectangle1 (Region1,50,100,120,280)
* 从原始图片中选择出被覆盖的区域
reduce_domain(image,Region1,ImageReduced)
(2)交互的方式
read_image (image,'C:/Users/Public/Documents/MVTec/HALCON-12.0/examples/images/claudia.png')
get_image_size (image,Width,Height)
* 绘制窗口 并得到窗口句柄(在坐标(0,0)位置处 宽和高为Width,Height)
dev_open_window(0,0,Width, Height, 'black', WindowHandle)
dev_display(image)
* 产生一个交互式的绘图 左键选择右键结束 输入的是窗口句柄WindowHandle
* 输出的是左上和右下的坐标 Row1, Column1, Row2, Column2
draw_rectangle1(WindowHandle, Row1, Column1, Row2, Column2)
* 绘制窗口 用的是上面所选中的区域(输入是Row1, Column1, Row2, Column2 输出是Rectangle)
gen_rectangle1 (Rectangle, Row1, Column1, Row2, Column2)
* 从原始图片中选择出被覆盖的区域(输入是image,Rectangle 输出是ImageReduced)
reduce_domain(image,Rectangle,ImageReduced)
绘制多边形的时候比较特殊(不需要连接到首 会自动首尾相连)(绘制完多边形 需要进行填充)
read_image (image,'C:/Users/Public/Documents/MVTec/HALCON-12.0/examples/images/claudia.png')
get_image_size (image,Width,Height)
* 绘制窗口 并得到窗口句柄(在坐标(0,0)位置处 宽和高为Width,Height)
dev_open_window(0,0,Width, Height, 'black', WindowHandle)
dev_display(image)
* 绘制多边形
draw_polygon (PolygonRegion, WindowHandle)
* 对多边形进行填充(保证任意两点相连都在区域内部)
shape_trans(PolygonRegion, RegionTrans, 'convex')
* 从原始图片中选择出被覆盖的区域
reduce_domain(image, RegionTrans, ImageReduced1)
10、图像的变换和校正
Halcon的坐标轴为
①图形的平移—齐次坐标(竖着的x,y,m 其中m一般为1)
②图形的旋转
③图形的缩放
④相似变换
由一个平面/立体图形变换到另一个平面/立体图形,在改变的过程中保持形状不变(大小方向和位置可变),任何相似变换都可以分解为等比例缩放、平移、旋转的组合相似变换
⑤仿射变换
由一个平面/立体图形变换到另一个平面/立体图形,在改变的过程中保持直线和平行线不变(平行线映射为平行线),任何仿射变换都可以分解为缩放、平移、旋转和切变(Shearing)的组合
* 平移
* 输入HomMat2D,Tx,Ty
* 输出HomMat2Dtranslate
hom_mat2d_translate(::HomMat2D,Tx,Ty:HomMat2Dtranslate)
* 旋转
* 输入HomMat2D,phi,Tx,Ty(phi代表旋转角度)(Tx,Ty代表旋转原点)
* 输出HomMat2Droute
hom_mat2d_rotate(::HomMat2D,phi,Tx,Ty:HomMat2Drotate)
* 缩放
* 输入HomMat2D,Sx,Sy,Px,Py(Sx,Sy是缩放系数)(Px,Py是变换不动点)
* 输出HomMat2Dscale
hom_mat2d_scale(::HomMat2D,Sx,Sy,Px,Py:HomMat2Dscale)
* 仿射变换
(1)创建一个仿射变换单位矩阵
hom_mat2d_identity(:::HomeMat2dIdentity)
(2)设置可变换的参数 可以设置平移、缩放以及旋转的参数
(3)进行仿射变换 输入Image 得到仿射变换后端图ImageAffinTrans
affine_trans_image (Image:ImageAffinTrans:HomMat2D,Interpolation,AdaptImageSize:)
⑥投影变换
变换过程中,直线映射为直线(但不一定保证平行度),任何二维投影变换都可以用3x3可逆矩阵表示,而任何三维投影变换都可以用4x4可逆矩阵表示
* 通过P和Q两组点确定投影变换的矩阵
* 通过P和Q两个点确定齐次变换的矩阵(至少需要4对)
* method是就是进行归异化处理的方法
hom_vector_to_proj_hom_mat2d(::Px,Py,Pw,Qx,Qy,Qw,Method:HomMat2D)
* 进行投影变换
* 输入校正前的图片Image 输出校正完成的图片Image_rectified 变换的矩阵为HomMat2D
projective_trans_image (Image, Image_rectified, HomMat2D, 'bilinear', 'false', 'false')
具体可以参考–二维码的简单校验.hdev
11、常见的插值算法
**插值:**利用已知数据去预测未知数据
图像插值:给定一个像素点,根据它周围像素点的信息来对该像素点的值进行预测。
①自适应插值
根据插值的不同像素点内容进行改变(尖锐的边缘或者是平滑的纹理)
②非自适应插值
对每个像素点的处理都是同样的
(1)最近邻插值:选取离目标点最近的点的灰度值作为新的插入点的灰度值
(2)线性插值
(3)双线性插值
(4)双三次插值
在双三次插值法中,选取最近的16个像素点计算目标图像处像素值
12、图像增强
图像增强是有目的地强调图像的整体或局部特性,将原来不清晰的图像变得清晰或强调某些感兴趣的特征,扩大图像中不同物体特征之间的差别,抑制不感兴趣的特征,改善图像质量,丰富信息量,加强图像判读和识别效果,满足某些特殊分析的需要
①图像取反算子
* 取反算子 将亮变暗 暗变亮
invert_image(Image:ImageInvert::)
②增加图像对比度算子
emphasize(Image:ImageEmphasize:MaskWidth,MaskHeight,Factor:)
③缩放图像的灰度
scale_image(Image:ImageScaled:Mult,Add:)
13、直方图修正法
①直方图均衡化
equ_histo_image(GrayImage,ImageEquHisto)
②直方图规定化
14、图像的平滑
①噪声
(1)高斯噪声
* 生成高斯噪声
gauss_distribution(20,Distribution)
*将灰度图片GrayImage 进行添加噪声处理 得到 ImageNoise
add_noise_distribution(GrayImage,ImageNoise,Distribution)
(2)椒盐噪声
* 生成椒盐噪声
sp_distribution(3,3,Distribution)
*将灰度图片GrayImage 进行添加噪声处理 得到 ImageNoise
add_noise_distribution(GrayImage,ImageNoise,Distribution)
②滤波
(1)均值滤波–适合处理高斯噪声
图像邻域平均法算法简单,计算速度快
但它的主要缺点是在降低噪声的同时使图像产生模糊,特别在边缘和细节处
图像所用的邻域半径越大,则图像的模糊程度越大
mean_image(Image:ImageMean:MaskWidth,MaskHeight:)
(2)中值滤波—适合处理椒盐噪声
15、图像的锐化–增强图像的边缘或轮廓
在图像的识别中常需要突出边缘和轮廓信息
图像锐化就是增强图像的边缘或轮廓
横向微分运算
纵向微分运算
双向一次微分运算
Robert存在一定的缺陷 因为图片存在噪声的情况下 会增强大量无用的数据
sobel算子
sobel算子在一定程度上克服了这个问题(sobel会使边缘锐化更明显)
* sobel算子
* FilterType代表滤波的类型
sobel_amp(Image:EdgeAmplitude:FilterType,Size:)
*读取图像
read_image (Image, 'C:/Users/ZW/Desktop/机器视觉/资料/B站课程资料/《机器视觉案例》/案例原图/第四章/4-8.png')
*边缘检测
sobel_amp (Image, EdgeAmplitude, 'sum_abs', 3)
*阈值分割
threshold (EdgeAmplitude, Region, 10, 255)
*提取边缘框架 将图片边缘进行细化
skeleton (Region, Skeleton)
*显示图片
dev_display (Image)
*设置输出颜色为红色
dev_set_color ('red')
*显示边缘框架
dev_display (Skeleton)
基于二阶微分的图像增强–拉普拉斯算子
* 拉普拉斯算子
laplace(Image:ImageLaplace:ResultType,MaskSize,FileterMask:)
*找出过零点的像素点
zero_crossing(Image:RegionCrossing::)
*关闭窗口
dev_close_window ()
*获取图像
read_image (Image, 'C:/Users/ZW/Desktop/机器视觉/资料/B站课程资料/《机器视觉案例》/案例原图/第四章/4-9.png')
*获取图像尺寸
get_image_size (Image, Width, Height)
*打开适应图片大小的窗口
dev_open_window (0, 0, Width, Height, 'black', WindowHandle)
*显示图片
dev_display (Image)
*对图像进行拉普拉斯算子处理 signed代表有符号 3代表MaskSize
laplace (Image, ImageLaplace, 'signed', 3, 'n_8_isotropic')
*显示处理后的图像
dev_display (ImageLaplace)
16、频域处理法
低通滤波器(Low-pass Filter)和高通滤波器(High-pass Filter)是两种常见的频域滤波器,用于图像处理中的频率分析和图像增强。
-
低通滤波器(Low-pass Filter):
低通滤波器允许低频信号通过,抑制高频信号。它的作用是平滑图像、去除高频噪声、模糊图像的细节,使图像变得更加平滑。低通滤波器通常用于图像模糊、降噪和图像压缩等应用。常见的低通滤波器包括:
- 均值滤波器(平均滤波器):用邻域像素的平均值替代中心像素的值。
- 高斯滤波器:使用高斯函数作为权重来平滑图像,具有更好的平滑效果和较好的边缘保留性能。
- 中值滤波器:用邻域像素的中值替代中心像素的值,对于去除椒盐噪声等非常有效。
低通滤波器可以通过控制滤波器的大小或频率响应来调整平滑程度。较大的滤波器将导致更强的平滑效果,但可能会损失图像的细节。
-
高通滤波器(High-pass Filter):
高通滤波器允许高频信号通过,抑制低频信号。它的作用是突出图像中的细节、边缘和纹理,增强图像的锐度和边缘信息。高通滤波器通常用于图像增强、边缘检测和纹理分析等应用。常见的高通滤波器包括:
- 拉普拉斯滤波器:用于增强图像的高频部分,使边缘更加明显。
- Sobel滤波器:用于检测图像中的边缘,通过计算梯度来突出边缘。
- Prewitt滤波器:类似于Sobel滤波器,用于检测图像中的边缘。
高通滤波器可以通过控制滤波器的大小或频率响应来调整增强效果。较小的滤波器将突出较细的边缘和细节,而较大的滤波器将突出更粗的边缘和纹理。
一幅图像灰度均匀的区域对应低频部分
图像中的噪声、边缘、细节对应高频部分
比较亮的是低频 比较暗的是高频
低通滤波是保留低频 过滤高频
高通滤波是保留高频 过滤低频
*进行快速傅里叶变换
*其中'to_freq'代表正向 ‘from_freq’代表反向
*ResultType表示结果类型(傅里叶变换得到的结果有实部和虚部 默认为complex复数形式)
fft_generic(Image:ImageFFT:'to_freq',Exponent,Norm,Mode,ResultType:)
①低通滤波器
*读取带有椒盐噪声图像
read_image (Image, 'C:/Users/ZW/Desktop/机器视觉/资料/B站课程资料/《机器视觉案例》/案例原图/第四章/4-10.png')
*获得图像尺寸
get_image_size (Image, Width, Height)
*关闭窗口
dev_close_window ()
*打开适应图像大小的窗口
dev_open_window (0, 0, 512, 512, 'black', WindowHandle)
*显示图像
dev_display (Image)
*图像转灰度化
rgb1_to_gray (Image, GrayImage)
*获得一个低通滤波模型 超过0.1就去除
gen_lowpass (ImageLowpass, 0.1, 'none', 'dc_center', Width, Height)
*对噪声图像进行傅里叶变换,得到频率图像
fft_generic (Image, ImageFFT, 'to_freq', -1, 'sqrt', 'dc_center', 'complex')
*对频率图像进行低通滤波
convol_fft (ImageFFT, ImageLowpass, ImageConvol)
*对频率图像进行傅里叶变换
fft_generic (ImageConvol, ImageFFT1, 'from_freq',1, 'sqrt', 'dc_center', 'complex')
②高通滤波器
*关闭窗口
dev_close_window ()
*读取图像
read_image (Image, 'C:/Users/ZW/Desktop/机器视觉/资料/B站课程资料/《机器视觉案例》/案例原图/第四章/4-11.png')
*图像灰度化
rgb1_to_gray (Image, GrayImage)
*获取图像大小
get_image_size (GrayImage, Width, Height)
*打开图像适应大小窗口
dev_open_window (0, 0, Width, Height, 'black', WindowHandle)
*得到高通滤波模型
gen_highpass (ImageHighpass, 0.1, 'n', 'dc_center', Width, Height)
*对图像进行傅里叶变换
fft_generic(GrayImage,ImageFFT,'to_freq',-1,'none','dc_center','complex')
*对频率图像进行高通滤波
convol_fft(ImageFFT,ImageHighpass,ImageConvol)
*对得到的频率图像进行傅里叶反变换
fft_generic(ImageConvol,ImageResult,'from_freq',1,'none','dc_center','byte')
*显示图像
dev_display (ImageResult)
③同态滤波增强—解决图像照度不均匀(或者有阴影)
17、图像分割
阈值分割(Threshold Segmentation):
- 阈值分割是一种简单而常用的分割方法,它基于简单的像素灰度值比较来确定目标和背景之间的阈值。
- 阈值分割将图像中的像素根据其灰度值与给定阈值的关系分为两个类别:目标和背景。
- 阈值分割通常使用整数阈值进行像素分类,将低于阈值的像素标记为背景,高于或等于阈值的像素标记为目标。
- 阈值分割是一种简单快速的分割方法,适用于许多应用场景,但对于复杂的图像或具有多个目标的情况可能效果有限。
亚像素阈值分割(Subpixel Thresholding):
- 亚像素阈值分割是一种进一步提高分割精度的技术,它允许对像素进行更精细的分类,而不仅仅是简单的目标和背景。
- 亚像素阈值分割通过使用更高精度的阈值(通常是浮点数)来对像素进行分类,从而实现更精确的分割结果。
- 亚像素阈值分割可以将像素分类为多个类别,例如目标、背景和边界区域,并且可以提供更准确的边界位置信息。
- 亚像素阈值分割通常需要更复杂的计算和处理过程,相对于传统的阈值分割方法而言,计算成本更高。
阈值分割是一种简单快速的分割方法,适用于许多场景
亚像素阈值分割则是一种更精确的分割技术,适用于对分割精度要求更高的任务
①全局阈值分割—根据灰度不同进行分割
(1)基于直方图谷底进行阈值分割
* 读取图像
read_image (Image, 'C:/Users/ZW/Desktop/机器视觉/资料/B站课程资料/《机器视觉案例》/案例原图/第五章/5-1.png')
*转为单通道的灰度图
*rgb1_to_gray (Image, GrayImage)
get_image_size (Image, Width, Height)
dev_close_window ()
dev_open_window (0, 0, Width, Height, 'black', WindowHandle)
*设置显示选中的颜色
dev_set_color ('red')
*计算图像的灰度直方图
*得到绝对的AbsoluteHisto和相对的RelativeHisto(除以了灰度的总数值在0-1之间)
gray_histo (Image, Image, AbsoluteHisto, RelativeHisto)
*从直方图中确定灰度值阈值 得到最小灰度值MinThresh和最大灰度值MaxThresh
* 其中的8 代表平滑度
histo_to_thresh (RelativeHisto, 8, MinThresh, MaxThresh)
*设置最多有12种颜色
dev_set_colored (12)
*进行阈值分割
threshold (Image, Region, MinThresh[0], MaxThresh[0])
dev_display (Region)
(2)基于直方图的自动自动阈值分割
*获取图像
read_image (Image, 'C:/Users/ZW/Desktop/机器视觉/资料/B站课程资料/《机器视觉案例》/案例原图/第五章/5-2.png')
*新开一个窗口
dev_open_window_fit_image (Image, 0, 0, -1, -1, WindowHandle)
dev_display (Image)
rgb1_to_gray (Image, GrayImage)
*自动阈值分割 5代表的是平滑度
auto_threshold (Image, Regions, 5)
*显示分割区域
dev_display (Regions)
②局部阈值分割
在动态阈值分割方法中,基于图像和参考图像的像素值之间的差异来进行分割。具体步骤如下:
- 对于原始图像
Image
和平滑后的图像ImageMean
的每个像素位置(i, j),计算它们的差值:diff = abs(Image[i,j] - ImageMean[i,j])
。 - 根据阈值偏移量,将差值与阈值比较。如果差值大于阈值,将该位置标记为目标区域。
- 对于所有被标记为目标区域的位置,构建一个连通区域,将相邻的目标像素归为同一区域。
- 最后,将提取出的圆形区域存储在
RegionDynThresh
变量中。
算子为dyn_threshold
dyn_threshold(OrigImage,ThresholdImage:RegionDynThresh:Offset,LightDark:)
下面是对该函数的详细解释:
Image: 原始图像,用作分割的输入图像。
ImageMean: 平滑处理后的图像,用来计算动态阈值的参考图像。
RegionDynThresh: 存储分割结果的变量,提取出的圆形区域将存储在该变量中。
15: 阈值偏移量,用于调整动态阈值的灵敏度。增加偏移量将导致更多的区域被认为是目标区域,而减少偏移量则会导致较少的区域被认为是目标区域。
'not_equal': 分割操作符,指定了使用不相等关系进行分割。这意味着对于图像中的每个像素,如果其值与对应位置的均值图像像素值不相等,则被视为目标区域。
*关闭窗口
dev_close_window ()
*获取图像
read_image (Image, 'photometric_stereo/embossed_01')
*获得图像尺寸
get_image_size (Image, Width, Height)
*打开适应图像大小的窗口
dev_open_window (0, 0, Width, Height, 'black', WindowHandle1)
*在图像上使用均值滤波器进行适当平滑
mean_image (Image, ImageMean, 59, 59)
*动态阈值分割,提取圆区域 15代表偏移量
* dark--代表找暗区 亮--代表亮区 equal--代表找既不是暗也不是亮区 now_equal--代表找亮和暗区
dyn_threshold (Image, ImageMean, RegionDynThresh, 15, 'not_equal')
* 显示图像
dev_display (Image)
*显示提取区域
dev_display (RegionDynThresh)
③边缘检测
(1)prewitt算子
(相比于sobel算子,抑制噪声的影响的效果更好)
*读取图像
read_image (Image, 'fabrik')
*用prewitt算子进行边缘提取
prewitt_amp (Image, ImageEdgeAmp)
*进行阈值操作
threshold (ImageEdgeAmp, Region, 20, 255)
*骨骼化操作
skeleton (Region, Skeleton)
*显示图像
dev_display (Image)
*设置输出颜色为红色
dev_set_color ('red')
*显示骨骼图像
dev_display (Skeleton)
(2)kirsch算子
*读取图像
read_image (Image, 'fabrik')
*用kirsch算子进行边缘检测
kirsch_amp (Image, ImageEdgeAmp)
*进行阈值操作
threshold (ImageEdgeAmp, Region, 70, 255)
*骨骼化操作
skeleton (Region, Skeleton)
*显示图像
dev_display (Image)
*设置输出颜色为红色
dev_set_color ('red')
*显示骨骼图像
dev_display (Skeleton)
(3)log算子(laplace_of_gauss)
(4)canny算子
canny算子和log算子类似 都是先平滑后求导
*获取图像
read_image (Image, 'fabrik')
*使用canny算法进行边缘提取
edges_image (Image, ImaAmp, ImaDir, 'canny', 0.5, 'nms', 12, 22)
*阈值分割
threshold (ImaAmp, Edges, 1, 255)
*骨骼化
skeleton (Edges, Skeleton)
*将骨骼化的区域转化为XLD (轮廓)
gen_contours_skeleton_xld (Skeleton, Contours, 1, 'filter')
*显示图像
dev_display (Image)
*设置6种输出颜色
dev_set_colored (6)
*显示XLD
dev_display (Contours)
亚像素级别的边缘提取
* 关闭窗口
dev_close_window ()
* 读取图像
read_image (Image, 'fabrik')
* 打开适应图像大小的窗口
dev_open_window_fit_image (Image, 0, 0, -1, -1, WindowHandle)
* 对图像进行亚像素区域提取
edges_sub_pix (Image, Edges, 'canny', 2, 12, 22)
* 放大图像用于详细的边缘检查
dev_set_part (160, 250, 210, 300)
dev_display (Image)
dev_display (Edges)
④区域分割–将具有相同属性的像素归为同一个区域
(1)区域生长
halcon的生长算子
regiongrowing_mean
中指明了起始的生长坐标
*读取图像
read_image (Image, 'fabrik')
*对图像进行均值处理,选用circle类型的中值滤波器 对图片进行去噪操作
median_image (Image, ImageMedian, 'circle', 2, 'mirrored')
*使用regiongrowing算子寻找颜色相近的邻域 输入ImageMedian 得到生长后的区域Regions
*对图片进行区域生长 1(ROW)和1(COL)代表一个点距离下一个点之间的像素差距是多少
*2代表的是灰度值的差值 5000代表的是输出区域的每个区域至少是5000
regiongrowing (ImageMedian, Regions, 1, 1, 2, 5000)
*对图像进行区域分割,提取满足各个条件的各个独立区域
*找到每一个分割好的区域的中心 存入到Centers
shape_trans (Regions, Centers, 'inner_center')
*将每个中心依次存入到SingleCenters
connection (Centers, SingleCenters)
*计算出初步提取的区域的中心点坐标
area_center (SingleCenters, Area, Row, Column)
*以均值灰度图像为输入,进行区域增长计算,计算的起始坐标为上一步的各区域中心
*种子点为刚刚所获得的每个区域中心点坐标
regiongrowing_mean (ImageMedian, RegionsMean, Row, Column, 25, 100)
(2)区域分裂合并法
(3)Hough变换–检测线
将间断的边缘链接成有意义的完整边缘,同时去除假边缘
*读取图像
read_image (Image, 'fabrik')
*获得目标区域图像
rectangle1_domain (Image, ImageReduced, 170, 280, 310, 360)
* 用Sobel边缘检测算子提取边缘
sobel_dir (ImageReduced, EdgeAmplitude, EdgeDirection, 'sum_abs', 3)
*设置输出颜色为红色
dev_set_color ('red')
*阈值分割得到图像
threshold (EdgeAmplitude, Region, 55, 255)
* 截取刚刚用阈值分割所覆盖的图像
reduce_domain (EdgeDirection, Region, EdgeDirectionReduced)
* 进行Hough变换
*输入的是边缘检测得到的方向图(EdgeDirection)
*输出的是hough变换的映射图和检测的Lines图
*4代表的是方向的不确定度(即可以容忍的角度偏差度为多少)
*2代表的是角度的分辨率
*’mean’代表的是平滑处理(为了去除噪点) 3代表做平滑处理的模板大小
*25代表投票数需要达到25才有效
*前一个5约束角度 后一个5约束距离
*‘true’代表是否产生Line Region
*输出Angle(角度)和Dist(距离)
hough_lines_dir (EdgeDirectionReduced, HoughImage, Lines, 4, 2, 'mean', 3, 25, 5, 5, 'true', Angle, Dist)
*将霍夫变换提取直线以普通形式描述的输入行存储为区域
gen_region_hline (LinesHNF, Angle, Dist)
*显示图像
dev_display (Image)
*设置输出颜色数目
dev_set_colored (12)
*设置输出填充方式为“轮廓”
dev_set_draw ('margin')
*显示LinesHNF
dev_display (LinesHNF)
*设置输出填充方式为“填充”
dev_set_draw ('fill')
*显示Lines
dev_display (Lines)
(4)Hough变换—检测圆
Halcon算子
其中Percent代表圆占整个图片的百分比
Mode代表确定圆位置的模式(用外圈还是内圈)
⑤分水岭算法—基于边缘的图像分割
为了解决过度分割的问题,可以使用基于标记(mark)图像的分水岭算法,就是通过先验知识,来指导分水岭算法,以便获得更好的图像分段效果。
在这个区域的洪水淹没过程中,水平面都是从定义的高度开始的,这样可以避免一些很小的噪声极值区域的分割。
这个就是阈值化的提取
*获取图像
read_image (Br2, 'particle')
*对单通道图像进行高斯平滑处理,去除噪声
gauss_filter (Br2, ImageGauss, 9)
*将图像颜色进行反转
invert_image (ImageGauss, ImageInvert)
*对高斯平滑后的图像进行分数岭处理,提取出盆地区域
*输入图像 输出分水岭和盆地
watersheds (ImageInvert, Basins, Watersheds)
*对图像进行带阈值的分水岭处理 阈值为30
*输入图像和阈值 输出分水岭
watersheds_threshold (ImageInvert, Basins1,30)
18、特征提取
①特征的分类
②区域形状特征
*获得Regions区域的每个对象面积,中心点Row,Col信息
area_center(Regions:::Area,Row,Column)
*获得封闭区域孔洞的面积 一个区域包含多个孔洞 所以返回的是所有孔洞的面积之和
area_holes(Regions:::Area)
*根据特征提取出符合条件的区域
select_shape(Regions:SelectedRegions:Features,Operation,Min,Max:)
*计算每个区域的内接圆
inner_circle(Regions:::Row,Column,Radius)
*计算区域外接矩形
*第一种是是平行的矩形 得到左上角点和右下角点
smallest_rectangle1(Regions:::Row1,Column1,Row2,Column2)
*第二种是可以旋转的矩形 得到固定点、旋转角度、半宽、半高
smallest_rectangle1(Regions:::Row,Column,Phi,Length1,Length2)
选择 面积在500-2000之间 而且 区域宽和高的比值在1-1.7
③基于灰度值的特征
*用于计算指定区域的灰度值特征值
gray_features(Regions,Image::Features:Value)
*计算区域的灰度值平均值和方差
intensity(Regions,Image:::Mean,Deviation)
*计算区域的最大最小灰度值 Percent代表向内收缩的比例 因为希望去除噪声的影响
min_max_gray(Regions,Image::Percent:Min,Max,Range)
*提取灰度区域的面积和中心(每个点的灰度值求和 其实是重心的坐标)
area_center_gray(Regions,Image:::Area,Row,Column)
*根据灰度特征值选择区域
select_gray(Regions,Image:SelectedRegions:Features,Operation,Min,Max:)
④基于图像纹理的特征
*创建图像中某个区域的共生矩阵 ldGray代表灰度级 Direction代表方向(0,45,90,135)
gen_cooc_matrix(Regions,Image:Matrix:LdGray,Direction:)
*基于灰度共生矩阵计算特征值
* 输入灰度共生矩阵 输出 能量 相关性 局部均匀性 对比度
cooc_feature_matrix(CoocMatrix:::Energy,Correlation,Homogeneity,Contrast)
*二合一算子
*计算共生矩阵 并且 导出灰度值特征
cocc_feature_image(Regions,Image::LdGray,Direction:Energy,Correlation,Homogeneity,Contrast)
19、二值图像的形态学处理
①反射的概念
②腐蚀
注意:
使用结构元素腐蚀完后 所有的中心点就构成了一个新图形(所以腐蚀区域与结构元素的大小有关)
*使用圆形结构元素对区域进行腐蚀
erosion_circle(Region:RegionErosion:Radius:)
*使用矩形结构元素对区域进行腐蚀
erosion_rectangle1(Region:RegionErosion:Width,Hright:)
*使用生成的结构元素对区域进行腐蚀(参考点为结构元素的中心)
*Iterations是迭代次数的含义 代表要腐蚀多少次
erosion1(Region,StructElement:RegionErosion:Iterations:)
*使用生成的结构元素对区域进行腐蚀(可以手动设置参考点的位置)
erosion1(Region,StructElement:RegionErosion:Row,Column,Iterations:)
③膨胀
只要结构元素与被腐蚀图像存在交集即可
*使用圆形结构元素对区域进行膨胀
dilation_circle(Region:RegionDilation:Radius:)
*使用矩形结构元素对区域进行膨胀
dilation_rectangle1(Region:RegionDilation:Width,Height:)
*使用生成结构元素对区域进行膨胀(参考点为结构元素的中心)
dilation1(Region,StructElement:RegionDilation:Iterations:)
*使用生成结构元素对区域进行膨胀(参考点可以自行设置)
dilation2(Region,StructElement:RegionDilation:Row,Column,Iterations:)
④开闭运算
开运算—先腐蚀后膨胀—去毛刺杂质
闭运算—先膨胀,后腐蚀—填空隙
*使用生成结构元素对区域进行开运算
opening(Region,StructElement:RegionOpening::)
*使用圆形结构元素对区域进行开运算
opening_circle(Region:RegionOpening:Radius:)
*使用矩形结构元素对区域进行开运算
opening_rectangle1(Region:RegionOpening:Width,Height:)
*使用生成结构元素对区域进行闭运算
closing(Region,StructElement:RegionClosing::)
*使用圆形结构元素对区域进行闭运算
closing_circle(Region:RegionClosing:Radius:)
*使用矩形结构元素对区域进行闭运算
closing_rectangle1(Region:RegionClosing:Width,Height:)
⑤击中和击不中
*击中与击不中算子
*输入图像区域 并且输入两个结构元素 两个结构元素交集是空集 一个是击中 一个是击不中
*Row,Column代表的是参考点的行和列坐标
hit_or_miss(Region,StructElement1,StructElement2:RegionHitMiss:Row,Column:)
20、灰度图像的形态学处理
①灰度图像的形态学操作
②灰度腐蚀与膨胀运算
灰度腐蚀能够被用来 分开相互连接的亮物体 和 连接支离破碎的暗物体
*使用生成结构元素对灰度图像进行腐蚀操作
gray_erosion(Image,SE:ImageErosion::)
*使用矩形结构元素对灰度图像进行腐蚀操作
gray_erosion_rect(Image:ImageMin:MaskHeight,MaskWidth:)
*使用多边形结构元素对灰度图像进行腐蚀操作
gray_erosion_shape(Image:ImageMin:MaskHeight,MaskWidth,MaskShape:)
*使用生成结构元素对灰度图像进行膨胀操作
gray_dilation(Image,SE:ImageDilation::)
*使用矩形结构元素对灰度图像进行膨胀操作
gray_dilation_rect(Image:ImageMax:MaskHeight,MaskWidth:)
*使用多边形结构元素对灰度图像进行膨胀操作
gray_dilation_shape(Image:ImageMax:MaskHeight,MaskWidth,MaskShape:)
③灰度开运算与闭运算
经过 开运算 后,图片 先腐蚀后膨胀
图片的整体色调变暗,但是图片中阴影和明亮处的界限并未改变,每一部分的亮部和暗部都更加平滑了
Gray Opening Shape(灰度开运算)是先对图像进行腐蚀操作,再进行膨胀操作。它的作用是消除图像中的细小尖锐物体、噪点或细小连接区域。灰度开运算可以使图像中较亮的区域变得更暗,而较暗的区域则不会有太大的变化,也就是会增加暗的像素点
----------灰度开运算用于去除细小的尖锐物体或噪点
*使用生成结构元素对灰度图像进行开运算
gray_opening(Image,SE:ImageOpening::)
*使用矩形结构元素对灰度图像进行开运算
gray_opening_rect(Image:ImageOpening:MaskHeight,MaskWidth:)
*使用多边形结构元素对灰度图像进行开运算
gray_opening_shape(Image:ImageOpening:MaskHeight,MaskWidth,MaskShape:)
经过 闭运算 后,图片 先膨胀后腐蚀
图片的整体色调变亮,界限没有改变,明亮也更加平滑了
Gray Closing Shape(灰度闭运算)是先对图像进行膨胀操作,再进行腐蚀操作。它的作用是填充图像中的小孔洞,平滑图像的边界并连接相邻的区域。灰度闭运算可以使图像中较暗的区域变得更亮,而较亮的区域则不会有太大的变化,也就是会增加亮的像素点
-------灰度闭运算用于填充小孔洞、连接相邻区域
*使用生成结构元素对灰度图像进行闭运算
gray_closing(Image,SE:ImageClosing::)
*使用矩形结构元素对灰度图像进行闭运算
gray_closing_rect(Image:ImageClosing:MaskHeight,MaskWidth:)
*使用多边形结构元素对灰度图像进行闭运算
gray_closing_shape(Image:ImageClosing:MaskHeight,MaskWidth,MaskShape:)
④顶帽和底帽运算
顶帽和底帽运算就是在开运算和闭运算的基础上,来处理图像中出现的各种杂点、空洞、小的间隙、毛躁的边缘等
顶帽操作的效果等同于原图-开运算,即原图减去开运算的图像-------通常用来去除背景
底帽操作的效果等同于原图-闭运算,即原图减去闭运算的图像
*顶帽运算
gray_tophat(Image, SE : ImageTopHat : : )
*底帽运算
gray_bothat(Image, SE : ImageBotHat : : )
21、边界提取
边界提取得到的仍然是region类型
* 提取边界的算子
* BoundaryType可选inner(内边界),outer(外边界),inner_filled(内边界,并且将内部孔洞填充);
boundary(Region:RegionBorder:BoundaryType:)
22、孔洞填充
*孔洞填充
fIll_up(Region:RegionFillUp)c
*选择一些特定区域进行填充
fill_uo_shape(Region:RegionFillUp:Frature,min,max)
23、骨架提取
骨架提取得到的仍然是region类型
*骨架骨骼提取
skeleton(Region:Skeleton::)
24、图像模板匹配
图像模板匹配:在整个图像区域发现与给定子图像匹配的小块区域
①基于相关性匹配
适用于光照不均匀 光线明暗变化较大的 但背景不是特别复杂的场景
注意:
在相关性匹配的过程中 模板图片的角度会归为0度 所以仿射变换的过程中是从0度开始变换的
并且 在创建模板和寻找的过程中 做好是360度匹配(rad(0)–rad(360))(但是圆不需要)
基于相关性的匹配算法模板
*抠图 抠出模板图片
*创建NCC匹配模板
create_ncc_model(Template::NumLevels,AngleStart,AngleExtent,AngleStep,MetricLModelID)
*搜索NCC最佳匹配
find_ncc_model(Image::ModelID,AngleStart,AngleExtent,MinScore,NumMatches,MaxOverlap,SubPixel,Numlevels:Row.Column,Angle,Score)
*进行仿射变换(把原先画的区域移到找到区域的位置)
vector_angle_to_rigid (ModelRow, ModelColumn, 0, Row, Column, Angle, HomMat2D)
affine_trans_region (ModelRegion, RegionAffineTrans, HomMat2D, 'nearest_neighbor')
*释放模板资源
clear_ncc_model(ModelID)
②基于像素灰度值的模板匹配
*创建带旋转角度的灰度匹配模板
create_template(Template : : FirstError, NumLevel, Optimize, GrayValues : TemplateID)
*创建不带旋转角度的灰度匹配模板
create_template_rot(Template : : NumLevel, AngleStart, AngleExtend, AngleStep, Optimize, GrayValues : TemplateID)
*搜索最佳匹配 _rot代表带角度的 _mg代表带金字塔层数的
best_match_rot_mg(Image : : TemplateID, AngleStart, AngleExtend, MaxError, SubPixel, NumLevels : Row, Column, Angle, Error)
*再进行划线展示(仿射变换 或者 disp直接显示)
*释放模板资源
clear_ncc_model(ModelID)
*计算区域与图像的平均值和差值 看这个区域的差别在哪里
intensity(Regions, Image : : : Mean, Deviation)
*根据均值进行自适应调整
set_offset_template( : : TemplateID, GrayOffset : )
③基于特征的模板匹配------不变矩匹配法
④基于形状特征的匹配
注意
轮廓的位置会自动移到(0,0)的位置 所以起始变化点是(0,0)
XLD(eXtended Line Descriptions):换句话说XLD就是一个轮廓函数,它不是基于像素,人们通常称他为亚像素,只不过它比像素更精确,可以精确到像素内部的一种描述。
在Halcon中,使用XLD表示亚像素的轮廓和多边形。常用edges_sub_pix算子来提取亚像素轮廓。
我们都知道图片是由像素组成,当我们用halcon读取图像Image或者region的时候,获得的数据就是像素。这些数据结构都是像素级别的。
获得图像后,我们可以通过亚像素阈值分割或者亚像素边缘提取,这样这些处理得到的结果其实就是用亚像素轮廓来表示。。
上述所述亚像素轮廓其实在halcon中指的就是xld,它可以表示直线或多边形,是一组有序的控制点集合,控制点顺序用来说明彼此相连的关系。
多模板匹配例程所在位置
可以获得区域的轮廓
inspect_shape_model (Image, ModelImages, ModelRegions, 1, 30)
*抠图 抠出模板图片
--------------------------创建形状匹配模板-----------------;
create_shape_model(Template : : NumLevels, AngleStart, AngleExtent, AngleStep, Optimization, Metric, Contrast, MinContrast : ModelID)
*创建行和列均匀收缩变化的形状匹配模板
create_scaled_shape_model(Template : : NumLevels, AngleStart, AngleExtent, AngleStep, ScaleMin, ScaleMax, ScaleStep, Optimization, Metric, Contrast, MinContrast : ModelID)
*创建行和列不均匀收缩变化的形状匹配模板
create_aniso_shape_model(Template : : NumLevels, AngleStart, AngleExtent, AngleStep, ScaleRMin, ScaleRMax, ScaleRStep, ScaleCMin, ScaleCMax, ScaleCStep, Optimization, Metric, Contrast, MinContrast : ModelID)
-----------------------------获取形状模板的轮廓------------------;
get_shape_model_contours( : ModelContours : ModelID, Level : )
-------------------------------*寻找最佳匹配--------------------
------注意find_shape_models代表多个模板匹配 在model后面加一个s-----------;
find_shape_model(Image : : ModelID, AngleStart, AngleExtent, MinScore, NumMatches, MaxOverlap, SubPixel, NumLevels, Greediness : Row, Column, Angle, Score)
*寻找最佳匹配(这个模板是进行等比例大小缩放过的)
find_scaled_shape_model(Image : : ModelID, AngleStart, AngleExtent, ScaleMin, ScaleMax, MinScore, NumMatches, MaxOverlap, SubPixel, NumLevels, Greediness : Row, Column, Angle, Scale, Score)
*寻找最佳匹配(这个模板是进行非等比例大小缩放过的)
find_aniso_shape_model(Image : : ModelID, AngleStart, AngleExtent, ScaleRMin, ScaleRMax, ScaleCMin, ScaleCMax, MinScore, NumMatches, MaxOverlap, SubPixel, NumLevels, Greediness : Row, Column, Angle, ScaleR, ScaleC, Score)
----------------------将形状模板的轮廓进行仿射变换最佳匹配的位置------------;
vector_angle_to_rigid (0, 0, 0, RowRef, ColumnRef, 0, HomMat2D)
affine_trans_contour_xld (Model, ModelTrans, HomMat2D)
Metric (input_control) string → (string)
Match metric.
Default value: 'use_polarity'
List of values: 'ignore_color_polarity', 'ignore_global_polarity', 'ignore_local_polarity', 'use_polarity'
'ignore_color_polarity'(忽略颜色极性):在这种模式下,匹配过程中将忽略图像中物体的颜色信息,仅考虑物体的形状信息。这意味着无论物体是亮色还是暗色,都将被视为相同的形状进行匹配。这种模式适用于只关注物体的形状特征,而对颜色不敏感的应用场景。
'ignore_global_polarity'(忽略全局极性):在这种模式下,匹配过程中将忽略图像中物体的全局极性信息,只考虑局部极性和形状信息。全局极性指的是整个物体区域的亮度变化趋势,而局部极性指的是物体局部区域的亮度变化趋势。通过忽略全局极性,匹配算法将主要关注物体的局部形状信息,而不受整体亮度变化的影响。这种模式适用于物体具有局部形状特征并且整体亮度可能变化较大的情况。
'ignore_local_polarity'(忽略局部极性):在这种模式下,匹配过程中将忽略物体的局部极性信息,只考虑全局极性和形状信息。与上述模式相反,它将主要关注物体的全局形状信息,而不受局部亮度变化的影响。这种模式适用于物体的整体形状特征对匹配更重要,而局部亮度变化对匹配结果影响较小的情况。
'use_polarity'(使用极性信息和形状信息进行匹配,默认选项):这是默认的匹配度量标准选项。在这种模式下,匹配过程中同时考虑物体的极性信息(包括全局和局部极性)和形状信息。极性信息指的是物体区域的亮度变化趋势,包括明暗变化、边缘方向等。这种模式综合考虑了颜色、亮度和形状等多个特征,适用于大多数情况下的模板匹配任务。
⑤Matching助手工具
25、图像金字塔
低分辨率关注的是基础纹理(大纹理)
高分辨率下关注的是更精细的纹理
根据金字塔层数和对比度检查要生成的模板是否合适
*读取图像的新算子
open_framegrabber ('File', 1, 1, 0, 0, 0, 0, 'default', -1, 'default', -1, 'default', 'rings/rings.seq', 'default', -1, 1, FGHandle)
*创建基于金字塔层数的模型表示
inspect_shape_model
26、相机标定(Camera Calibration–标定,校准)
①标定的概念
标定的主要目标是获得相机的内部参数和外部参数,以便将图像像素坐标转换为真实世界中的物理坐标。
②标定的流程
27、 双目立体视觉----模拟人的双眼
过程
例程
28、OCR识别
注意Halcon自带的字体默认字体是黑色背景是亮色
①常用的将断开字符连接上的方法
* 膨胀
dilation_circle (Region, RegionDilation, 3.5)
* 连接(打散成单个区域)
connection (RegionDilation, ConnectedRegions)
* 求交集(将字母i和j断开的区域连接上)
intersection (ConnectedRegions, Region, RegionIntersection)
②ocr的识别流程
*创建并且存储训练集
write_ocr_trainf (Characters, Image, Classes, TrainFile)
*创建 OCR 分类器
------从训练文件中读取类别名称
read_ocr_trainf_names (TrainFile, CharacterNames, CharacterCount)
------创建 MLP OCR 分类器
create_ocr_class_mlp (8, 10, 'constant', 'default', CharacterNames, 20, 'canonical_variates', 26, 42, OCRHandle)
*使用训练文件进行训练分类器
trainf_ocr_class_mlp (OCRHandle, TrainFile, 100, 0.01, 0.01, Error, ErrorLog)
*从文件中直接读取一个分类器
read_ocr_class_mlp (FontName, OCRHandle)
*单个匹配或者多个匹配
do_ocr_single_class_mlp(Character, Image : : OCRHandle, Num : Class, Confidence)
do_ocr_multi_class_mlp(Character, Image : : OCRHandle : Class, Confidence)
③对于弯曲的字符可以进行极坐标旋转
polar_trans_image_ext (Image, ImagePolar, Row, Column, 0, rad(360), Radius - 30, Radius - 5, WidthP, HeightP, 'bilinear')
dev_open_window (0, 0, WidthP, HeightP, 'black', WindowHandle2)
rotate_image (ImagePolar, ImageRotate, 180, 'constant')
④OCR识别字符的流程
read_image (Image11, 'C:/Users/ZW/Desktop/机器视觉/Halcon视频教程 第2套初级班+强化班/初级班视频/实战图片/字符.bmp')
dev_close_window ()
get_image_size (Image11, Width, Height)
dev_open_window (0, 0, Width/4, Height/4, 'black', WindowID)
set_display_font (WindowID, 40, 'mono', 'true', 'false')
*图片翻转为正向
mirror_image (Image11, ImageMirror, 'row')
mirror_image (ImageMirror, ImageMirror1, 'column')
*选择感兴趣的区域
scale_image (ImageMirror1, ImageScaled, 3.98438, -749)
threshold (ImageScaled, Regions, 0, 52)
connection (Regions, ConnectedRegions)
select_shape (ConnectedRegions, SelectedRegions, ['area','rectangularity'], 'and', [111408,0.61765], [5e+006,1])
reduce_domain (ImageMirror1, SelectedRegions, ImageReduced)
*选择需要识别的内容(26)
threshold (ImageReduced, Regions1, 0, 144)
connection (Regions1, ConnectedRegions1)
select_shape (ConnectedRegions1, SelectedRegions1, ['area','width','rectangularity'], 'and', [0,54.23,0], [9647.27,204.14,0.8545])
union1 (SelectedRegions1, RegionUnion)
*将断开区域进行连接
gen_rectangle2 (Rectangle, 16, 16, rad(45), 4, 4)
closing (RegionUnion, Rectangle, RegionClosing)
*注意要将连通好的单个区域 与 二值化后的区域 进行交集运算
connection (RegionClosing, ConnectedRegions2)
intersection (ConnectedRegions2, Regions1, RegionIntersection)
read_ocr_class_mlp ('Industrial_0-9A-Z_NoRej.omc', OCRHandle)
do_ocr_multi_class_mlp (RegionIntersection, ImageReduced, OCRHandle, Class, Confidence)
smallest_rectangle1 (RegionIntersection, Row11, Column1, Row2, Column21)
count_obj (RegionIntersection, NumberFinal)
dev_display (ImageMirror1)
for i := 1 to NumberFinal by 1
disp_message (WindowID, Class[i - 1], 'image',Row2[i - 1], Column1[i - 1], 'red', 'false')
endfor
⑤OCR识别环形字体
区别点主要在于将圆形区域进行极坐标转换(拉直操作)
*读取图像
read_image (Image,'C:/Users/ZW/Desktop/机器视觉/Halcon视频教程 第2套初级班+强化班/初级班视频/实战图片/1.1.bmp')
dev_close_window ()
dev_open_window (0,0,480,480,'black', WindowHandle)
dev_display (Image)
rgb1_to_gray (Image, GrayImage)
*提取外圆的半径
threshold (GrayImage, Regions, 4, 103)
*得到外圆的圆心和半径
smallest_circle (Regions, Row, Column, OuterRadius)
*得到整个外圆
shape_trans (Regions, outcircle, 'outer_circle')
*求外环的补集 也就是得到内圆
complement (Regions, RegionComplement)
connection (RegionComplement, InnerCircle)
select_shape (InnerCircle, SelectedRegions, ['area','circularity'], 'and', [200,0.8422], [2.29055e+006,1])
*得到内圆的圆心和半径
smallest_circle (SelectedRegions, InnerRow, InnerColumn, InnerRadius)
*极坐标转换
*输入的参数
* Image---输入原图片 PolarTransImage--得到的转换后的图
* Row, Column圆心的坐标
* rad(360), 0 这个表示需要处理哪些角度的 (这个就代表360度均处理)
* OuterRadius - 100 这个表示字体的顶部到圆心的距离
* InnerRadius + 40 这个表示字体的底部到圆心的距离
* 1440代表极坐标的宽度
* 100代表待识别字体的高度
polar_trans_image_ext (Image, PolarTransImage, Row, Column, rad(360), 0, OuterRadius - 100, InnerRadius + 40, 1440, 100, 'bilinear')
*接下来就和之前一样 对字体进行处理
*颜色翻转
invert_image (PolarTransImage, ImageInvert)
*对比度改变
scale_image (ImageInvert, ImageScaled1, 6.71053, -1429)
*字符分割
binary_threshold (ImageScaled1, Region2, 'max_separability', 'light', UsedThreshold2)
connection (Region2, ConnectedRegions3)
select_shape (ConnectedRegions3, SelectedRegions1, 'area', 'and', 64.69, 1000)
*对字符进行膨胀处理 然后connection连通后求交集
dilation_rectangle1 (SelectedRegions1, RegionDilation, 5, 5)
union1 (RegionDilation, RegionUnion)
connection (RegionUnion, ConnectedRegions2)
dev_clear_window ()
dev_display (ConnectedRegions2)
intersection (ConnectedRegions2, Region2, RegionIntersection)
sort_region (RegionIntersection, SortedRegions1, 'character', 'true', 'column')
*识别
read_ocr_class_mlp ('C:/Program Files/MVTec/HALCON-12.0/ocr/Industrial_0-9A-Z_NoRej.omc', OCRHandle)
do_ocr_multi_class_mlp (SortedRegions1, PolarTransImage, OCRHandle, Class, Confidence)
*显示
count_obj (SortedRegions1, Number)
area_center (SortedRegions1, Area, Row2, Column2)
for Index := 1 to Number by 1
disp_message (WindowHandle, Class[Index-1], 'PolarTransImage', 40, Column2[Index-1]-20, 'black', 'true')
endfor
29、测量和拟合
①测量矩形边缘宽度的过程
*形成测量矩形
gen_rectangle2 (Rectangle1, Row + Rect1Row, Column + Rect1Col, RectPhi, RectLength1, RectLength2)
gen_measure_rectangle2( : : Row, Column, Phi, Length1, Length2, Width, Height, Interpolation : MeasureHandle)
*进行边缘对测量
*sigma代表平滑参数
*Threshold 边缘幅度 Transition 边缘方向
*IntraDistance 两个边缘之间的距离
*InterDistance 相邻边缘对之间的距离
measure_pairs(Image : : MeasureHandle, Sigma, Threshold, Transition, Select : RowEdgeFirst, ColumnEdgeFirst, AmplitudeFirst, RowEdgeSecond, ColumnEdgeSecond, AmplitudeSecond, IntraDistance, InterDistance)
*释放测量矩形
close_measure(MeasureHandle)
*以单个边缘的形式进行测量 而不是边缘对
measure_pos(Image : : MeasureHandle, Sigma, Threshold, Transition, Select : RowEdge, ColumnEdge, Amplitude, Distance)
例程:fuse.hdev
* fuse.hdev: measuring the width of a fuse wire
*
dev_update_window ('off')
dev_close_window ()
* ****
* step: acquire image
* ****
read_image (Fuse, 'fuse')
get_image_size (Fuse, Width, Height)
dev_open_window_fit_image (Fuse, 0, 0, Width, Height, WindowID)
set_display_font (WindowID, 12, 'mono', 'true', 'false')
dev_set_draw ('margin')
dev_set_line_width (3)
dev_display (Fuse)
set_display_font (WindowID, 12, 'mono', 'true', 'false')
disp_continue_message (WindowID, 'black', 'true')
stop ()
* ****
* step: create measure object
* ****
* -> specify ROI
Row := 297
Column := 545
Length1 := 80
Length2 := 10
Angle := rad(90)
gen_rectangle2 (ROI, Row, Column, Angle, Length1, Length2)
* -> create measure object
gen_measure_rectangle2 (Row, Column, Angle, Length1, Length2, Width, Height, 'bilinear', MeasureHandle)
dev_display (ROI)
disp_continue_message (WindowID, 'black', 'true')
stop ()
* ****
* step: measure
* ****
measure_pairs (Fuse, MeasureHandle, 1, 1, 'negative', 'all', RowEdgeFirst, ColumnEdgeFirst, AmplitudeFirst, RowEdgeSecond, ColumnEdgeSecond, AmplitudeSecond, IntraDistance, InterDistance)
disp_continue_message (WindowID, 'black', 'true')
stop ()
* ****
* step: visualize results
* ****
for i := 0 to |RowEdgeFirst| - 1 by 1
gen_contour_polygon_xld (EdgeFirst, [-sin(Angle + rad(90)) * Length2 + RowEdgeFirst[i],-sin(Angle - rad(90)) * Length2 + RowEdgeFirst[i]], [cos(Angle + rad(90)) * Length2 + ColumnEdgeFirst[i],cos(Angle - rad(90)) * Length2 + ColumnEdgeFirst[i]])
gen_contour_polygon_xld (EdgeSecond, [-sin(Angle + rad(90)) * Length2 + RowEdgeSecond[i],-sin(Angle - rad(90)) * Length2 + RowEdgeSecond[i]], [cos(Angle + rad(90)) * Length2 + ColumnEdgeSecond[i],cos(Angle - rad(90)) * Length2 + ColumnEdgeSecond[i]])
dev_set_color ('cyan')
dev_display (EdgeFirst)
dev_set_color ('magenta')
dev_display (EdgeSecond)
dev_set_color ('blue')
if (i == 0)
set_tposition (WindowID, RowEdgeFirst[i] + 5, ColumnEdgeFirst[i] + 20)
else
set_tposition (WindowID, RowEdgeFirst[i] - 40, ColumnEdgeFirst[i] + 20)
endif
write_string (WindowID, 'width: ' + IntraDistance[i] + ' pix')
endfor
disp_continue_message (WindowID, 'black', 'true')
stop ()
* ****
* step: destroy measure object
* ****
close_measure (MeasureHandle)
dev_update_window ('on')
dev_clear_window ()
②measure助手
③定位测量的思路(先做模板匹配定位 然后 再进行测量)
例程:pm_measure_board.hdev
dev_update_pc ('off')
dev_update_window ('off')
dev_update_var ('off')
open_framegrabber ('File', 1, 1, 0, 0, 0, 0, 'default', -1, 'default', -1, 'default', 'board/board.seq', 'default', -1, 1, FGHandle)
grab_image (Image, FGHandle)
get_image_size (Image, Width, Height)
dev_close_window ()
dev_open_window (0, 0, Width, Height, 'black', WindowHandle)
dev_open_window (Height + 70, 0, Width, 120, 'black', WindowHandleText)
dev_set_window (WindowHandle)
set_display_font (WindowHandle, 16, 'mono', 'true', 'false')
set_display_font (WindowHandleText, 16, 'mono', 'true', 'false')
dev_set_color ('red')
dev_display (Image)
Row1 := 188
Column1 := 182
Row2 := 298
Column2 := 412
gen_rectangle1 (Rectangle, Row1, Column1, Row2, Column2)
area_center (Rectangle, Area, Row, Column)
Rect1Row := -102
Rect1Col := 5
Rect2Row := 107
Rect2Col := 5
RectPhi := 0
RectLength1 := 170
RectLength2 := 5
gen_rectangle2 (Rectangle1, Row + Rect1Row, Column + Rect1Col, RectPhi, RectLength1, RectLength2)
gen_rectangle2 (Rectangle2, Row + Rect2Row, Column + Rect2Col, RectPhi, RectLength1, RectLength2)
reduce_domain (Image, Rectangle, ImageReduced)
create_shape_model (ImageReduced, 4, 0, rad(360), rad(1), 'none', 'use_polarity', 30, 10, ModelID)
get_shape_model_contours (ShapeModel, ModelID, 1)
hom_mat2d_identity (HomMat2DIdentity)
hom_mat2d_translate (HomMat2DIdentity, Row, Column, HomMat2DTranslate)
affine_trans_contour_xld (ShapeModel, ShapeModelTrans, HomMat2DTranslate)
dev_display (Image)
dev_set_color ('green')
dev_display (ShapeModelTrans)
dev_set_color ('blue')
dev_set_draw ('margin')
dev_set_line_width (3)
dev_display (Rectangle1)
dev_display (Rectangle2)
dev_set_draw ('fill')
dev_set_line_width (1)
dev_set_color ('yellow')
disp_message (WindowHandle, ['Press left button to start','and stop the demo'], 'image', 12, 12, 'black', 'true')
get_mbutton (WindowHandle, Row3, Column3, Button1)
wait_seconds (0.5)
Button := 0
while (Button != 1)
dev_set_window (WindowHandle)
dev_set_part (0, 0, Height - 1, Width - 1)
grab_image (ImageCheck, FGHandle)
dev_display (ImageCheck)
count_seconds (S1)
find_shape_model (ImageCheck, ModelID, 0, rad(360), 0.7, 1, 0.5, 'least_squares', 4, 0.7, RowCheck, ColumnCheck, AngleCheck, Score)
count_seconds (S2)
dev_display (ImageCheck)
if (|Score| > 0)
dev_set_color ('green')
hom_mat2d_identity (HomMat2DIdentity)
hom_mat2d_translate (HomMat2DIdentity, RowCheck, ColumnCheck, HomMat2DTranslate)
hom_mat2d_rotate (HomMat2DTranslate, AngleCheck, RowCheck, ColumnCheck, HomMat2DRotate)
affine_trans_contour_xld (ShapeModel, ShapeModelTrans, HomMat2DRotate)
dev_display (ShapeModelTrans)
affine_trans_pixel (HomMat2DRotate, Rect1Row, Rect1Col, Rect1RowCheck, Rect1ColCheck)
affine_trans_pixel (HomMat2DRotate, Rect2Row, Rect2Col, Rect2RowCheck, Rect2ColCheck)
gen_rectangle2 (Rectangle1Check, Rect1RowCheck, Rect1ColCheck, AngleCheck, RectLength1, RectLength2)
gen_rectangle2 (Rectangle2Check, Rect2RowCheck, Rect2ColCheck, AngleCheck, RectLength1, RectLength2)
dev_set_color ('blue')
dev_set_draw ('margin')
dev_set_line_width (3)
dev_display (Rectangle1Check)
dev_display (Rectangle2Check)
dev_set_draw ('fill')
count_seconds (S3)
gen_measure_rectangle2 (Rect1RowCheck, Rect1ColCheck, AngleCheck, RectLength1, RectLength2, Width, Height, 'bilinear', MeasureHandle1)
gen_measure_rectangle2 (Rect2RowCheck, Rect2ColCheck, AngleCheck, RectLength1, RectLength2, Width, Height, 'bilinear', MeasureHandle2)
measure_pairs (ImageCheck, MeasureHandle1, 2, 90, 'positive', 'all', RowEdgeFirst1, ColumnEdgeFirst1, AmplitudeFirst1, RowEdgeSecond1, ColumnEdgeSecond1, AmplitudeSecond1, IntraDistance1, InterDistance1)
measure_pairs (ImageCheck, MeasureHandle2, 2, 90, 'positive', 'all', RowEdgeFirst2, ColumnEdgeFirst2, AmplitudeFirst2, RowEdgeSecond2, ColumnEdgeSecond2, AmplitudeSecond2, IntraDistance2, InterDistance2)
close_measure (MeasureHandle1)
close_measure (MeasureHandle2)
count_seconds (S4)
dev_set_color ('red')
disp_line (WindowHandle, RowEdgeFirst1 - RectLength2 * cos(AngleCheck), ColumnEdgeFirst1 - RectLength2 * sin(AngleCheck), RowEdgeFirst1 + RectLength2 * cos(AngleCheck), ColumnEdgeFirst1 + RectLength2 * sin(AngleCheck))
disp_line (WindowHandle, RowEdgeSecond1 - RectLength2 * cos(AngleCheck), ColumnEdgeSecond1 - RectLength2 * sin(AngleCheck), RowEdgeSecond1 + RectLength2 * cos(AngleCheck), ColumnEdgeSecond1 + RectLength2 * sin(AngleCheck))
disp_line (WindowHandle, RowEdgeFirst2 - RectLength2 * cos(AngleCheck), ColumnEdgeFirst2 - RectLength2 * sin(AngleCheck), RowEdgeFirst2 + RectLength2 * cos(AngleCheck), ColumnEdgeFirst2 + RectLength2 * sin(AngleCheck))
disp_line (WindowHandle, RowEdgeSecond2 - RectLength2 * cos(AngleCheck), ColumnEdgeSecond2 - RectLength2 * sin(AngleCheck), RowEdgeSecond2 + RectLength2 * cos(AngleCheck), ColumnEdgeSecond2 + RectLength2 * sin(AngleCheck))
dev_set_line_width (1)
NumLeads := |IntraDistance1| + |IntraDistance2|
MinDistance := min([InterDistance1,InterDistance2])
dev_set_window (WindowHandleText)
dev_set_part (0, 0, 119, Width - 1)
dev_clear_window ()
disp_message (WindowHandleText, 'Matching: Time: ' + ((S2 - S1) * 1000)$'5.2f' + 'ms , Score: ' + Score$'7.5f', 'image', 20, 20, 'green', 'false')
disp_message (WindowHandleText, 'Measure: Time: ' + ((S4 - S3) * 1000)$'5.2f' + ' ms, Num. leads: ' + NumLeads$'2d', 'image', 50, 20, 'red', 'false')
disp_message (WindowHandleText, ' Min. lead dist: ' + MinDistance$'6.3f', 'image', 80, 20, 'red', 'false')
endif
dev_error_var (Error, 1)
dev_set_check ('~give_error')
get_mposition (WindowHandle, R, C, Button)
dev_error_var (Error, 0)
dev_set_check ('give_error')
if (Error != H_MSG_TRUE)
Button := 0
endif
endwhile
dev_set_window (WindowHandleText)
dev_close_window ()
clear_shape_model (ModelID)
close_framegrabber (FGHandle)
④测量弧形边缘宽度的过程
*形成测量弧形
disp_arc (WindowHandle, Row, Column, AngleExtent, RowPoint, ColPoint)
gen_measure_arc( : : CenterRow, CenterCol, Radius, AngleStart, AngleExtent, AnnulusRadius, Width, Height, Interpolation : MeasureHandle)
*进行边缘测量
measure_pos(Image : : MeasureHandle, Sigma, Threshold, Transition, Select : RowEdge, ColumnEdge, Amplitude, Distance)
*释放测量弧形
close_measure(MeasureHandle)
例程:measure_arc.hdev
* Example for the application of the measure package
* including a lot of visualization operators
*
read_image (Zeiss1, 'zeiss1')
get_image_size (Zeiss1, Width, Height)
dev_close_window ()
dev_open_window (0, 0, Width / 2, Height / 2, 'black', WindowHandle)
set_display_font (WindowHandle, 14, 'mono', 'true', 'false')
dev_display (Zeiss1)
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
* draw_circle (WindowHandle, Row, Column, Radius)
Row := 275
Column := 335
Radius := 107
AngleStart := -rad(55)
AngleExtent := rad(170)
dev_set_draw ('fill')
dev_set_color ('green')
dev_set_line_width (1)
get_points_ellipse (AngleStart + AngleExtent, Row, Column, 0, Radius, Radius, RowPoint, ColPoint)
disp_arc (WindowHandle, Row, Column, AngleExtent, RowPoint, ColPoint)
dev_set_line_width (3)
gen_measure_arc (Row, Column, Radius, AngleStart, AngleExtent, 10, Width, Height, 'nearest_neighbor', MeasureHandle)
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
count_seconds (Seconds1)
n := 10
for i := 1 to n by 1
measure_pos (Zeiss1, MeasureHandle, 1, 10, 'all', 'all', RowEdge, ColumnEdge, Amplitude, Distance)
endfor
count_seconds (Seconds2)
Time := (Seconds2 - Seconds1) / n
disp_continue_message (WindowHandle, 'black', 'true')
* stop ()
distance_pp (RowEdge[1], ColumnEdge[1], RowEdge[2], ColumnEdge[2], IntermedDist)
* dev_display (Zeiss1)
dev_set_color ('red')
* disp_circle (WindowHandle, RowEdge, ColumnEdge, RowEdge - RowEdge + 1)
disp_line (WindowHandle, RowEdge[1], ColumnEdge[1], RowEdge[2], ColumnEdge[2])
dev_set_color ('yellow')
disp_message (WindowHandle, 'Distance: ' + IntermedDist, 'image', 250, 80, 'yellow', 'false')
* dump_window (WindowHandle, 'tiff_rgb', 'C:\\Temp\\zeiss_result')
close_measure (MeasureHandle)
dev_set_line_width (1)
* disp_continue_message (WindowHandle, 'black', 'true')
stop ()
dev_clear_window ()
⑤边缘轮廓拟合的方法
拟合就是为了得到各种想要的参数
*读入图像并且预处理
*亚像素边缘提取
edges_sub_pix(Image : Edges : Filter, Alpha, Low, High : )
*从输入图像Image中以亚像素精度提取阈值为Threshold的水平交叉线
*提取的水平交叉线以XLD轮廓的形式返回到Border中
*threshold_sub_pix不返回区域
*而是返回将灰度值低于Threshold的区域与灰度值高于Threshold的区域分隔开的线条。
threshold_sub_pix(Image : Border : Threshold : )
*根据具体需求对轮廓进行处理
*例如:分割轮廓
segment_contours_xld(Contours : ContoursSplit : Mode, SmoothCont, MaxLineDist1, MaxLineDist2 : )
*例如:联合轮廓
*联合共圆的轮廓
union_cocircular_contours_xld(Contours : UnionContours : MaxArcAngleDiff, MaxArcOverlap, MaxTangentAngle, MaxDist, MaxRadiusDiff, MaxCenterDist, MergeSmallContours, Iterations : )
*联合临近的轮廓
union_adjacent_contours_xld(Contours : UnionContours : MaxDistAbs, MaxDistRel, Mode : )
*联合直线的轮廓
union_collinear_contours_xld(Contours : UnionContours : MaxDistAbs, MaxDistRel, MaxShift, MaxAngle, Mode : )
*拟合轮廓(其实就是用一条边缘 拟合出最符合的形状)(校正形状)
*圆形拟合
fit_circle_contour_xld(Contours : : Algorithm, MaxNumPoints, MaxClosureDist, ClippingEndPoints, Iterations, ClippingFactor : Row, Column, Radius, StartPhi, EndPhi, PointOrder)
*椭圆拟合
fit_ellipse_contour_xld(Contours : : Algorithm, MaxNumPoints, MaxClosureDist, ClippingEndPoints, VossTabSize, Iterations, ClippingFactor : Row, Column, Phi, Radius1, Radius2, StartPhi, EndPhi, PointOrder)
*根据得到的参数画出图形
gen_circle_contour_xld
gen_ellipse_contour_xld
*距离计算
例程:circles.hdev
read_image (Image, 'double_circle')
*
* Init window
dev_close_window ()
get_image_size (Image, Width, Height)
dev_open_window (0, 0, Width, Height, 'black', WindowHandle)
*
* Segment a region containing the edges
fast_threshold (Image, Region, 0, 120, 7)
boundary (Region, RegionBorder, 'inner')
clip_region_rel (RegionBorder, RegionClipped, 5, 5, 5, 5)
dilation_circle (RegionClipped, RegionDilation, 2.5)
reduce_domain (Image, RegionDilation, ImageReduced)
*
* In the subdomain of the image containing the edges,
* extract subpixel precise edges.
edges_sub_pix (ImageReduced, Edges, 'canny', 2, 20, 60)
segment_contours_xld (Edges, ContoursSplit, 'lines_circles', 5, 4, 3)
count_obj (ContoursSplit, Number)
dev_display (Image)
dev_set_draw ('margin')
dev_set_color ('white')
dev_update_window ('off')
for I := 1 to Number by 1
select_obj (ContoursSplit, ObjectSelected, I)
get_contour_global_attrib_xld (ObjectSelected, 'cont_approx', Attrib)
* Fit a circle to the line segment that are arcs of a circle
if (Attrib > 0)
fit_circle_contour_xld (ObjectSelected, 'ahuber', -1, 2, 0, 3, 2, Row, Column, Radius, StartPhi, EndPhi, PointOrder)
gen_circle_contour_xld (ContCircle, Row, Column, Radius, 0, rad(360), 'positive', 1.0)
dev_display (ContCircle)
endif
endfor
dev_set_colored (12)
dev_set_line_width (3)
dev_display (ContoursSplit)
⑥边缘联合
*联合共圆的轮廓
union_cocircular_contours_xld(Contours : UnionContours : MaxArcAngleDiff, MaxArcOverlap, MaxTangentAngle, MaxDist, MaxRadiusDiff, MaxCenterDist, MergeSmallContours, Iterations : )
*联合临近的轮廓
union_adjacent_contours_xld(Contours : UnionContours : MaxDistAbs, MaxDistRel, Mode : )
*联合直线的轮廓
union_collinear_contours_xld(Contours : UnionContours : MaxDistAbs, MaxDistRel, MaxShift, MaxAngle, Mode : )
例程:close_contour_gaps.hdev
dev_close_window ()
dev_update_window ('off')
* ****
* step: create synthetic image
* ****
gen_rectangle1 (Rectangle, 30, 20, 100, 100)
region_to_bin (Rectangle, BinImage, 130, 100, 120, 130)
rectangle1_domain (BinImage, ImageReduced, 20, 48, 40, 52)
mean_image (ImageReduced, SmoothedImage, 15, 15)
paint_gray (SmoothedImage, BinImage, Image)
get_image_size (Image, Width, Height)
dev_open_window_fit_image (Image, 0, 0, Width, Height, WindowID)
dev_set_draw ('margin')
dev_set_line_width (3)
dev_display (Image)
stop ()
* ****
* step: create contours
* ****
rectangle1_domain (Image, ImageReduced, 5, 5, 125, 115)
edges_sub_pix (ImageReduced, Edges, 'lanser2', 1.1, 22, 30)
dev_display (Image)
dev_display (Edges)
stop ()
* ****
* step: process contours
* ****
segment_contours_xld (Edges, LineSegments, 'lines', 5, 4, 2)
* LineSegments 是用于表示线段的数据类型
* regress_contours_xld 函数用于将线段进行线性回归,得到最佳拟合的直线
* 返回的结果是一个轮廓对象 RegressContours
regress_contours_xld (LineSegments, RegressContours, 'no', 1)
union_collinear_contours_xld (RegressContours, UnionContours, 10, 1, 2, 0.1, 'attr_keep')
sort_contours_xld (UnionContours, SortedContours, 'upper_left', 'true', 'column')
dev_display (Image)
colored_display (SortedContours, ['yellow','white','white','yellow'])
dev_update_window ('on')
⑦预处理
预处理方法有:
1.去噪声
2.增强
对灰度进行缩放
对图像灰度进行腐蚀
⑧同心度
同心度是评价圆柱形工件的一项重要技术指标,它指的是圆心的偏移程度,是同轴度的特殊形式。
30、一维码
①理论介绍
窄单元(条纹或间隔)表示逻辑值“0”
宽单元(条纹或间隔)表示逻辑值“1”
宽单元通常是窄单元的2~3倍。
条码码制即指条码条和空的排列规则
常用的一维码的码制包括:EAN码、39码、交叉25码、UPC码、128码、93码,及Codabar(库德巴码)等。
不同的码制有它们各自的应用领域
-
EAN 码:是国际通用的符号体系,是一种长度固定、无含意的条码,所表达的信息全部为数字,主要应用于商品标识
-
39码和128码:为目前国内企业内部自定义码制,可以根据需要确定条码的长度和信息,它编码的信息可以是数字,也可以包含字母,主要应用于工业生产线领域、图书管理等
-
93码:是一种类似于39码的条码,它的密度较高,能够替代39码
-
25码:只要应用于包装、运输以及国际航空系统的机票顺序编号等
-
Codabar码:应用于血库、图书馆、包裹等的跟踪管理
将 Code 39 条形码转换为 Code 32 条形码可以扩展可编码的字符范围,使得条形码可以包含更多类型的数据
convert_decoded_string_code39_to_code32( : : DecodedDataStringCode39 : ConvertedDataStringCode32)
②识别的过程
*创建一维码识别模板
create_bar_code_model( : : GenParamNames, GenParamValues : BarCodeHandle)
*设置一维码识别模板选择的参数
set_bar_code_param( : : BarCodeHandle, GenParamNames, GenParamValues : )
*在图像中检测和读取条形码符号
find_bar_code(Image : SymbolRegions : BarCodeHandle, CodeType : DecodedDataStrings)
*获得条形码的信息
*得到条码符号的解码过程中的信息
get_bar_code_result( : : BarCodeHandle, CandidateHandle, ResultName : BarCodeResults)
*得到条码符号的解码过程中的对象
get_bar_code_object( : BarCodeObjects : BarCodeHandle, CandidateHandle, ObjectName : )
*得到条码符号的解码过程中的参数
get_bar_code_param( : : BarCodeHandle, GenParamNames : GenParamValues)
③一维码识别算子的一些参数的解释
(1) 在Halcon中,set_bar_code_param
函数用于设置条形码参数。具体而言,'check_char'
参数用于设置条形码中的校验字符(Check Character)的要求。
set_bar_code_param(BarCodeHandle, 'check_char', 'absent')
:这行代码将BarCodeHandle
对应的条形码对象的校验字符要求设置为“absent”(缺失)。这意味着条形码中的校验字符可以被省略,即不强制要求存在校验字符。set_bar_code_param(BarCodeHandle, 'check_char', 'present')
:这行代码将BarCodeHandle
对应的条形码对象的校验字符要求设置为“present”(存在)。这意味着条形码中的校验字符是必需的,即要求条形码中包含校验字符。
(2) element_size_variable
它用于控制条形码读取器在处理某些具有形变的条形码图像时的行为。
这些形变可能是由于透视投影或条形码所打印的表面的形变(例如瓶子上的桶形畸变)引起的。
默认情况下,条形码读取器无法处理此类形变。
然而,如果将 element_size_variable
设置为 true
,条形码读取器会尝试对这些形变进行补偿。
(3) majority_voting
的参数,它控制解码结果的选择模式。
如果该参数的值为 false
,那么当找到最小数量的相同解码扫描线时,将返回一个成功的解码结果。
如果将该参数设置为true
,将使用多数投票方案来在不同的扫描线结果之间进行选择,由大多数扫描线解码的结果将被选为最终结果。
请注意,将该参数设置为 true
会导致运行时间略微增加,因为需要考虑几乎所有的扫描线,而不仅仅是最小相同的扫描线。该参数仅对非堆叠条形码类型支持。
为了减少错误的解码结果,建议启用该参数。
(4) persistence
是一个控制条形码模型是否在解码过程中存储一些中间结果的参数。
当将 persistence
设置为 1 时,模型会存储一些中间结果,以便进行条形码打印质量评估(使用 ‘get_bar_code_result’ 和 ‘quality_isoiec15416’)或检查解码扫描线(使用 ‘get_bar_code_object’ 和 ‘scanlines_all’ 或 ‘scanlines_valid’)。启用persistence
模式会增加条形码模型结构的内存需求。
默认情况下,它的值是 0,这意味着模型不会存储中间结果。
(5)meas_param_estimation
是一个控制条形码阅读器是否使用参数估计来处理候选区域的参数。
当 meas_param_estimation
设置为 false
时,扫描线上的灰度值会根据参数 element_size_min
的值进行平滑处理。简单来说,灰度值的变化会被平滑处理,以减少噪声对解码的影响。这在处理大多数情况下是有效的。
当 meas_param_estimation
设置为 true
时,条形码阅读器会使用不同的方法。它会估计每个条形码候选区域的元素大小,并在候选处理过程中使用该估计值。这对于条形码元素非常小(小于1.5个像素)的情况特别有用。通过估计元素大小,可以更好地适应小尺寸的条形码,提高解码的准确性。
默认情况下,meas_param_estimation
的值是 false
,这意味着条形码阅读器将使用平滑处理的方法。如果您的条形码具有非常小的元素大小,并且您希望利用参数估计的方法来处理候选区域,您可以将 meas_param_estimation
设置为 true
。
注意,启用参数估计的方法会稍微增加运行时间,因为需要进行更复杂的处理步骤来估计元素大小。
(6)meas_thresh_abs
是一个用于防止在图像区域中没有或只有非常小的灰度值动态范围(例如,在所有灰度值接近255的白色区域)时,基于meas_thresh
计算出不合理小的边缘检测阈值的参数。
就是为了把边缘变化明显的才提取出来,不明显的就不提取
通常情况下,如果基于 meas_thresh
计算出的阈值比 meas_thresh_abs
的值更小,那么将使用 meas_thresh_abs
作为阈值。这是为了防止误检测,因为在上述情况下,使用较小的阈值可能会导致大量错误的边缘检测结果。
默认情况下,meas_thresh_abs
的值为 5.0。对于噪声水平较高的图像,可能需要使用更大的值。
在无噪声且对比度非常弱的图像中,该参数可能会干扰对真实边缘的检测,因此可能需要减小或完全禁用它,将其设置为 0.0
meas_thresh_abs
值范围是 [0.0 … 10.0]。您可以根据图像的噪声水平和对比度情况来调整该值,以获得准确的边缘检测结果。
(7)stop_after_result_num
是一个控制解码过程何时停止的参数。它表示成功解码的条形码数量达到一定值后,解码过程将停止。
通常情况下,如果预先知道期望的条形码数量,可以设置该参数。
这样,当找到一定数量的条形码后,条形码阅读器可以终止进一步的解码过程,从而减少整体的解码时间。
默认情况下,stop_after_result_num
的值是 0,表示不设置解码停止条件,解码过程将解码所有的候选区域。
stop_after_result_num
值范围是 [0, 1, 2, …]。您可以根据预期的条形码数量来设置该值,以控制解码过程的停止时机。例如,如果预期只有一个条形码,您可以将 stop_after_result_num
设置为 1,以在找到一个条形码后停止解码过程。
(8)check_char
是一个控制条形码解码过程中如何处理校验字符的参数。
某些条形码类型(例如Code 39、Codabar、2/5 Industrial和2/5 Interleaved)可以包含一个可选的校验字符。根据 check_char
参数的设置,对这些条形码类型进行解释。
默认设置为 absent
,表示假定没有校验字符。在这种情况下,不进行校验,并将所有字符作为数据返回。
当 check_char
设置为 present
时,期望存在一个校验字符,并用于验证条形码的正确性。如果校验和不匹配,将不返回条形码结果,并且从数据中去除校验字符。
如果不希望去除校验字符,可以使用 preserved
模式,在保留校验字符的同时验证条形码。
请注意,对于必须包含校验字符的条形码类型,始终将其视为 present
模式。这包括Code 128、EAN-8、EAN-13和UPC-A等类型的条形码。
该参数可以使用 ‘set_bar_code_param_specific’ 操作符针对不同类型的条形码进行特定设置。
check_char
参数的可选值列表为 [‘absent’, ‘present’, ‘preserved’]。
(9)composite_code
是一个用于控制是否解码附加的 2D GS1 Composite Code 组件的参数。
大多数符合 GS1 标准的条形码可以附加一个额外的 2D GS1 Composite Code 组件。
如果将 composite_code
设置为 ‘CC-A/B’,则会查找和解码这个 Composite Code 组件。
composite_code
设置为 ‘none’,即禁用这个功能。如果搜索的条形码符号没有附加的 Composite Code 组件,那么只返回条形码本身的结果。目前,Composite Code 仅适用于 GS1 DataBar 系列的条形码。
该参数可以使用 ‘set_bar_code_param_specific’ 操作符针对不同类型的条形码进行特定设置。
composite_code
参数的可选值列表为 [‘none’, ‘CC-A/B’]。
默认情况下,composite_code
的值为 ‘none’,表示不解码附加的 Composite Code 组件
(10)barcode_width_min
是一个用于设置最小条形码宽度的参数。
该参数用于指定条形码的最小宽度。当设置了barcode_width_min
参数时,将启用该参数的训练模式。
训练模式是一种用于调整和优化参数的机制。在这种情况下,通过设置barcode_width_min
参数并启用训练模式,系统会根据当前的条形码图像数据来自动学习并确定一个合适的最小条形码宽度。系统可能会根据训练数据中的条形码图像的特征和要求,自动调整最小宽度的阈值,以适应不同的条形码类型和应用场景。
(11)barcode_height_min
是一个用于设置最小条形码高度的参数。
该参数的值以像素为单位定义。默认值为 -1,表示条形码阅读器会根据其他参数自动确定一个合理的高度。只有在非常扁平或非常高的条形码情况下,可能需要手动调整该参数。
对于高度小于 16 像素的条形码,用户应该手动设置相应的高度。需要注意的是,最小值为 8 像素。如果条形码非常高,即 70 像素或更高,则手动调整到相应的高度可能会加快后续的查找和读取操作速度。
barcode_height_min
参数允许您指定条形码图像中的最小高度。这在读取和解码条形码时非常重要,因为条形码的可靠性和准确性与条形码的高度相关。
(12)orientation
代表条形码方向角度的参数
orientation_tol
代表的是条形码总的角度范围
(13)contrast_min
是一个用于设置条形码元素的前景与背景之间最小对比度的参数。
contrast_min
参数用于定义条形码元素的前景(条纹)与背景之间的最小对比度。设置此参数为大于5的值将帮助操作员优化候选区域的搜索过程。find_bar_code 将拒绝所有对比度值低于contrast_min
的候选区域。因此,设置较高的contrast_min
值将提高 find_bar_code 的运行性能。
但是,请注意,所有对比度值低于 contrast_min
的条形码都将无法被读取。计算的对比度值是为了加快执行时间而进行的近似值。尝试将contrast_min
的阈值设置较低,以找到可能被拒绝的、对比度接近指定 contrast_min
的条形码。
可以选择在 [0, 40, 90, 120, … ] 等范围内的值来设置 ‘contrast_min’。
默认情况下,contrast_min
参数的值为 0,表示没有设置最小对比度的要求。这意味着 find_bar_code 将接受任何对比度的条形码进行解码。
(14)num_scanlines
是一个用于设置在扫描(候选)条形码时使用的最大扫描线数的参数。
num_scanlines
参数用于定义扫描(候选)条形码时使用的最大扫描线数。
如果未设置 ‘num_scanlines’(参数值为0),则最大扫描线数将在内部确定。
对于所有单行条形码,最大扫描线数为10
对于 GS1 DataBar Stacked Omnidirectional 条形码为20
对于 GS1 DataBar Expanded Stacked 条形码为55。
通过设置此参数,您可以在两种情况下提高性能:
第一种情况是图像中包含许多错误的候选区域。尽管条形码本身通常在一两个扫描后解码成功(除了堆叠条形码,见下文),但默认情况下,错误的候选区域会使用默认值为10的扫描线进行扫描,这会不必要地增加运行时间。减少扫描线数可以在具有许多错误候选区域的图像中提高性能。作为经验法则,质量较高的图像需要较少的扫描线,而质量较低的图像需要更多的扫描线。对于一般图像,值在2到5之间应该足够。然而,如果减少扫描线数后无法检测到条形码,则需要增加扫描线数。
第二种情况涉及堆叠条形码(目前包括 GS1 DataBar Stacked、GS1 DataBar Stacked Omnidirectional 和 GS1 DataBar Expanded Stacked)。在这种情况下,会评估所有扫描线,而不是像单行条形码(如Code 128、EAN 13或GS1 DataBar Limited)那样在成功解码后停止扫描。由于扫描扫描线实际上是 find_bar_code 算法中耗时最长的部分之一,调整 num_scanlines
可能会导致重要的性能改进。这对于 GS1 DataBar Expanded Stacked 尤为有效。GS1 DataBar Expanded Stacked 符号可能有多达11行,因此需要55条扫描线来稳定地检测所有行。如果预期只有较少行数的符号,则可以减少 num_scanlines
,保留每行1.5到5条扫描线。
可以使用 set_bar_code_param_specific 操作符针对不同类型的条形码单独设置该参数。
可以选择在 [0, 5, 10, 20 …] 等范围内的值来设置 num_scanlines
④弯曲的条形码的识别方法
例程:grid_rectification.hdev
根据棋盘格的弯曲映射得到Map 然后对图片进行相同的Map处理即可
* This example illustrates how to use the operators for the grid-rectification.
*
* The following command creates a postscript file
* that contains the rectification grid. This grid must be
* printed. Then it must be mounted on the object surface.
WidthOfGrid := 0.17
NumSquares := 17
create_rectification_grid (WidthOfGrid, NumSquares, 'rectification_grid.ps')
*
* Read the image of the object wrapped by the rectification grid
* and reopen the window with an appropriate size.
read_image (Image, 'can_with_grid')
get_image_size (Image, ImageWidth, ImageHeight)
dev_close_window ()
dev_open_window (0, 0, ImageWidth * 0.75, ImageHeight * 0.75, 'black', WindowID1)
dev_display (Image)
dev_update_off ()
set_display_font (WindowID1, 14, 'mono', 'true', 'false')
*
*
* Part 1: Determination of the image map
* The surface to be rectified is wrapped by a checkered pattern, which
* is used to determine the mapping between the distorted image and
* the rectified image. Note the orientation of the two circular marks. When
* in gen_grid_rectification_map() the parameter Rotation is 'auto', the rectified
* image is rotated such that the black mark is left of the white mark.
*
* Determine region of interest
*确定图像映射的第一部分:确定感兴趣区域和网格点
MinContrast := 25
Radius := 10
find_rectification_grid (Image, GridRegion, MinContrast, Radius)
*
dev_display (GridRegion)
disp_message (WindowID1, 'Grid region', 'window', 12, 12, 'black', 'true')
disp_continue_message (WindowID1, 'black', 'true')
stop ()
reduce_domain (Image, GridRegion, ImageReduced)
*
* Determine grid points
SigmaSaddlePoints := 1.5
Threshold := 5
*saddle_points_sub_pix特别适用于检测角点,即不同强度的区域如象棋棋盘上的黑白方块相接的位置。
*由于角点具有高对比度和特定的形状,因此可以更容易地定位和确定其精确位置。
saddle_points_sub_pix (ImageReduced, 'facet', SigmaSaddlePoints, Threshold, Row, Col)
*
dev_set_color ('blue')
*通过指定输入点的坐标(Row,Col),可以生成一个由两条长度为Size的线段组成的轮廓
*这两条线段在输入点处精确相交。线段的方向由Angle确定。生成的十字轮廓存储在Cross参数中。
gen_cross_contour_xld (SaddlePoints, Row, Col, 6, 0.785398)
dev_display (Image)
dev_display (SaddlePoints)
disp_message (WindowID1, 'Grid points', 'window', 12, 12, 'black', 'true')
disp_continue_message (WindowID1, 'black', 'true')
stop ()
*
* Connect points to grid
SigmaConnectGridPoints := 0.9
MaxDist := 5.0
GridSpacing := 20
dev_set_color ('red')
connect_grid_points (ImageReduced, ConnectingLines, Row, Col, SigmaConnectGridPoints, MaxDist)
*
dev_display (ConnectingLines)
disp_message (WindowID1, 'Connected grid points', 'window', 12, 12, 'black', 'true')
disp_continue_message (WindowID1, 'black', 'true')
stop ()
*
* Determine image map
*用于根据规则网格上的点计算畸变图像与矫正图像之间的映射关系。
*Map:输出的映射数据,可以是多通道图像或矢量场图像
gen_grid_rectification_map (ImageReduced, ConnectingLines, Map, Meshes, GridSpacing, 0, Row, Col, 'bilinear')
map_image (ImageReduced, Map, ImageMapped)
*
get_image_size (Map, MapWidth, MapHeight)
dev_open_window (0, (ImageWidth * 0.75) + 12, MapWidth, MapHeight, 'black', WindowID2)
set_display_font (WindowID2, 14, 'mono', 'true', 'false')
dev_display (ImageMapped)
disp_message (WindowID2, 'Rectified grid', 'window', 12, 12, 'black', 'true')
stop ()
*
*
* Part 2: Application of the image map
* The original surface (without the checkered pattern) is rectified
* using the previously calculated image map.
*
* Read in the image to be rectified
read_image (Image, 'can')
*
* Rectify image using the previously calculated image map
dev_set_window (WindowID2)
*使用之前生成的图像映射Map对原始图像进行校正。
map_image (Image, Map, ImageMapped)
*
dev_set_window (WindowID1)
dev_display (Image)
disp_message (WindowID1, 'Original image', 'window', 12, 12, 'black', 'true')
dev_set_window (WindowID2)
dev_display (ImageMapped)
disp_message (WindowID2, 'Rectified image', 'window', 12, 12, 'black', 'true')
⑤Halcon联合Vs显示完整的图片区域
GetImageSize(ho_Image, &hv_Width, &hv_Height);
if (HDevWindowStack::IsOpen())
SetPart(HDevWindowStack::GetActive(), 0, 0, hv_Height-1, hv_Width-1);
31、二维码
①理论介绍
二维条码:指在一维条码的基础上扩展出另一维具有可读性的条码,使用黑白矩形图案表示二进制数据,被设备扫描后可获取其中所包含的信息。
一维条码的宽度记载着数据,而其长度没有记载数据。二维条码的长度、宽度均记载着数据。
二维条码有一维条码没有的“定位点”和“容错机制”。容错机制在即使没有辨识到全部的条码、或是说条码有污损时,也可以正确地还原条码上的信息。
二维条码的种类很多,不同的机构开发出的二维条码具有不同的结构以及编写、读取方法。堆叠式/行排式二维条码,如,Code 16K、Code 49、PDF417等矩阵式二维码,最流行莫过于QR CODE。
二维码存储的数据量更大;可以包含数字、字符,及中文文本等混合内容;有一定的容错性,(在部分损坏以后可以正常读取),空间利用率高等。
②识别的过程
*创建二维码识别模板
create_data_code_2d_model( : : SymbolType, GenParamNames, GenParamValues : DataCodeHandle)
*设置二维码识别模板选择的参数
set_data_code_2d_param( : : DataCodeHandle, GenParamNames, GenParamValues : )
*在图像中检测和读取二维码符号
find_data_code_2d(Image : SymbolXLDs : DataCodeHandle, GenParamNames, GenParamValues : ResultHandles, DecodedDataStrings)
*获得二维码的信息
*得到二维码的解码过程中的信息
get_data_code_2d_results( : : DataCodeHandle, CandidateHandle, ResultNames : ResultValues)
*得到条二维码的解码过程中的对象
get_data_code_2d_objects( : DataCodeObjects : DataCodeHandle, CandidateHandle, ObjectName : )
*得到条二维码的解码过程中的参数
get_data_code_2d_param( : : DataCodeHandle, GenParamNames : GenParamValues)
③二维码识别算子的一些参数的解释
(1)二维码的最小单位是模块
module_gap_*
参数来设置模块之间的间隙:
可以指定相邻的前景模块是否连接在一起,或者它们之间是否存在或可能存在间隙。
如果前景模块是连接在一起并完全填充模块空间的,间隙参数可以设置为 no
(无)。
如果两个模块之间存在非常小的间隙,即<模块尺寸的10%,则将该参数设置为 small
(小)。
如果间隙较大(相对于模块尺寸而言:<模块尺寸的50%),则可以将其设置为 big
(大)。
即使前景模块是连接在一起的,但如果它们在外观上显得较细,比如由于亮光引起的绽放效果,最后两个设置也可能会有用。
如果前景模块只是非常小的点,通常需要对图像进行适当的预处理以检测或放大模块(例如,通过 gray_erosion_shape 或 gray_dilation_shape
)。
module_gap_min
表示最小模块间隙,含义是将’module_gap_col_min’和’module_gap_row_min’设置为相同的值。
module_gap_max
表示最大模块间隙,含义是将’module_gap_col_max’和’module_gap_row_max’设置为相同的值。
(2)default_parameters
的作用是将模型的所有参数重置为三种基本的默认设置之一:标准(standard)、增强(enhanced)或最大(maximum)。除了参数值之外,模型的训练状态也会被重置。
可选的取值为’standard_recognition’(标准识别)、‘enhanced_recognition’(增强识别)和’maximum_recognition’(最大识别)。
默认值是’standard_recognition’(标准识别设置)。
需要注意的是,如果将此参数与其他参数的列表一起设置,那么此参数必须位于列表的第一个位置。
maximum_recognition > enhanced_recognition > standard_recognition
可以参考例程:2d_data_codes_default_settings.hdev
(3)module_size_min
参数用于设置图像中模块的最小尺寸,单位为像素。需要注意的是,为了获得最佳的识别性能,建议将模块的尺寸设置为至少3-4个像素。
取值范围:[1 … 100]
默认值:6(增强模式下为2,最大模式下为1)
module_size_max
参数用于设置图像中模块的最大尺寸,单位为像素。
取值范围:[2 … 100]
默认值:20(增强模式下为100)
module_size
参数用于将module_size_min
和module_size_max
设置为相同的值。
这些参数的作用是控制图像中模块的尺寸范围。模块是指二维码或其他类似的矩阵形式的图像中的小方块或小元素。通过设置最小和最大尺寸,您可以限制模块的大小范围,并根据应用需求进行调整。
例如,如果您将module_size
参数设置为10,那么module_size_min
和module_size_max
将都被设置为10。
这样做的目的是确保模块的尺寸保持一致,以便在图像处理和识别算法中使用。
(4)polarity
参数描述了图像中符号的极性,即参数确定符号是在黑色背景上显示为亮色还是在亮色背景上显示为暗色。
取值:dark_on_light
(暗色在亮色背景上)、light_on_dark
(亮色在暗色背景上)、any
(任意)。
默认值:dark_on_light
(增强模式下为’any’)。
这个参数用于指定符号在图像中的颜色对比度。例如,如果您将polarity
参数设置为dark_on_light
,那么符号将被假设为在亮色背景上显示为暗色。相反,如果将其设置为light_on_dark
,则符号将被假设为在暗色背景上显示为亮色。而选择any
选项则表示符号的颜色对比度可以是任意的,即无论背景颜色如何,都能正确处理。
默认情况下,推荐使用dark_on_light
作为常规设置,因为大多数二维码和条形码通常在白色背景上显示为黑色。在增强模式下,any
选项可以更灵活地处理不同颜色对比度的符号。
(5)mirrored
参数描述了符号是否或可能是镜像的(即交换符号的行和列)。
取值:no
(不是镜像)、yes
(是镜像)、any
(任意)。
默认值:any
。
这个参数用于指定符号是否允许镜像或是否可能存在镜像的情况。
如果将mirrored
参数设置为no
,则表示符号不是镜像的,不允许进行镜像操作。
如果将其设置为yes
,则表示符号是镜像的,可以进行镜像操作。
选择any
选项则表示符号可能是镜像的,无论是否镜像都可以进行处理。
默认情况下,any
选项是推荐设置,因为在某些情况下,符号可能会出现镜像的情况。通过设置为any
,可以灵活地处理符号是否镜像的情况。
(6)contrast_min
参数用于设置符号的前景与背景之间的最小对比度(即符号的前景与背景之间的最小梯度)。
取值范围:[1 … 100]
默认值:30(增强模式下为10)
这个参数用于控制符号前景和背景之间的对比度,即前景元素与背景之间的明暗差异。通过设置最小对比度,可以限制符号的清晰度和可识别性。
取较高的对比度值(例如设置为100),意味着要求前景和背景之间的明暗差异非常明显,符号的清晰度要求更高。
取较低的对比度值(例如设置为1),则意味着允许前景和背景之间的明暗差异非常微弱,符号的清晰度要求较低。
默认情况下,推荐使用较高的对比度值(30)作为常规设置,以确保符号的清晰度和可识别性。在增强模式下,可以使用较低的对比度值(10)以适应更宽范围的图像条件。
(7)symbol_size
是控制整个二维码的大小的
(8)small_modules_robustness
参数用于控制对具有非常小模块尺寸的数据码的解码鲁棒性。
当将参数small_modules_robustness
设置为high
时,增加了解码具有非常小模块尺寸的数据码的可能性。在这种情况下,还应相应地调整最小模块尺寸,即将module_size_min
和 module_width_min
(对于PDF417)设置为预期的最小模块尺寸和宽度。
将small_modules_robustness
设置为 high
可能会显著增加find_data_code_2d函数的内存使用量。
参数取值范围:low
(低)、high
(高)
默认情况下,在常规设置中,推荐将small_modules_robustness
设置为low
(低)。这意味着默认情况下,函数将使用较少的内存,并对非常小的模块尺寸的数据码的解码鲁棒性较低。
在增强模式下,也建议将small_modules_robustness
设置为low
(低)。
而在最大模式下,可以将small_modules_robustness
设置为high
(高)以提高对非常小模块尺寸数据码的解码鲁棒性,但需要注意这会增加内存使用量。
(9)finder_pattern_tolerance
参数用于控制对于有缺陷或部分遮挡的查找图案的容忍度。
查找图案包括L形边和相对的交替边。取决于该参数,在 find_data_code_2d
函数中的符号搜索过程中使用不同的算法。
在一种情况下( low
),假设查找图案存在且几乎没有任何扰动。
在另一种情况下(high
),查找图案可能存在缺陷或部分遮挡,但不会影响符号的识别和读取。
然而,请注意,在这种模式下,应通过使用 set_data_code_2d_param
来尽可能限制符号搜索的参数范围,否则find_data_code_2d
函数的运行时间可能会显著增加。
注意,这两种算法在鲁棒性方面略有差异。这可能会导致不同的结果,具体取决于finder_pattern_tolerance
的值,即使符号的查找图案没有受到干扰。例如,如果选择了high
,则只能找到具有等距模块网格的符号,因此对于透视畸变的鲁棒性会降低。最后,如果将finder_pattern_tolerance
设置为any
,则两种算法都会应用。
参数取值范围: low
(低)、high
(高)、any
(任意)
默认情况下,在常规设置中,推荐将finder_pattern_tolerance
设置为 low
(低)。这意味着默认情况下,假设查找图案存在且几乎没有扰动。
在增强模式下,也建议将finder_pattern_tolerance
设置为 low
(低)。
而在最大模式下,可以将finder_pattern_tolerance
设置为any
(任意),以应用两种算法并提高对于有缺陷或部分遮挡的查找图案的容忍度。
(10)contrast_tolerance
参数用于描述对于局部对比度变化(例如,光晕或反射)的搜索容忍度。
如果将contrast_tolerance
设置为high
,则在存在强烈的局部对比度变化时可以提高鲁棒性。
如果将contrast_tolerance
设置为low
,则算法在存在强烈的局部对比度变化时的鲁棒性较低,但速度较快,并且仍然能够在正常情况下处理对比度变化,因此在大多数情况下应使用该选项。
如果将contrast_tolerance
设置为any
,则会应用两种算法。
参数取值范围:low
(低)、high
(高)、any
(任意)
默认情况下,在常规设置中,推荐将contrast_tolerance
设置为low
(低)。这意味着默认情况下,算法在强烈的局部对比度变化下的鲁棒性较低,但速度较快,并且仍然能够处理正常情况下的对比度变化。
在增强模式下,也建议将contrast_tolerance
设置为low
(低)。
而在最大模式下,可以将contrast_tolerance
设置为any
(任意),以应用两种算法并提高在存在强烈的局部对比度变化时的鲁棒性。
(11)strict_quiet_zone
参数用于控制 find_data_code_2d
函数在检测到可能可读但在其静默区域中显示缺陷的符号时的行为。
如果将strict_quiet_zone
设置为yes
,则会对所有解码的符号的静默区域进行验证,类似于用于打印质量检查的方法。静默区域评分较低的符号不会作为结果返回。它们的 status
将设置为 quiet zone is missing
(静默区域缺失)。
如果将strict_quiet_zone
设置为no
(默认情况),则所有可读的符号将作为结果返回。
参数取值范围:yes
(是)、no
(否)
默认情况下,在常规设置中,strict_quiet_zone
参数的默认值为no
(否)。这意味着默认情况下,所有可读的符号都将作为结果返回,而不管其静默区域的质量如何。
32、联合相机的sdk开发
需要拷贝的文件有头文件(include)、链接文件(lib)、dll文件
*根据RGB创建一个halcon的三通道图像对象
gen_image3_extern( : Image : Type, Width, Height, PointerRed, PointerGreen, PointerBlue, ClearProc : )
Image(输出对象):创建的HALCON图像。
Type(输入控制):像素类型。
Width(输入控制):图像的宽度。
Height(输入控制):图像的高度。
PointerRed(输入控制):指向第一个通道的第一个灰度值的指针。
PointerGreen(输入控制):指向第二个通道的第一个灰度值的指针。
PointerBlue(输入控制):指向第三个通道的第一个灰度值的指针。
ClearProc(输入控制):用于在删除图像对象时释放图像内存的过程。
①vc++图像转为halcon图像
(1)初始化相机
(2)枚举相机类
(3)设置回调函数
(4)定义回调函数
(5) 基于RGB或者Gray转为halcon图像( gen_image1_extern
或者 gen_image3_extern
)
②halcon图像转vc++图像
(1)在halcon中利用相机助手导出c++代码
(2)使用 GetImagePointer1
或 GetImagePointer3
得到halcon中图像的指针
(3)进行一系列的转换和赋值
(将halcon的 height 和 width转为vc++的数据 并且将 RGB三通道指针 转为 vc++的指针 )
33、Vs2022配置Halcon环境
第一步
选择 C/C++ 下的 常规 选项
将
C:\Program Files\MVTec\HALCON-12.0\include
C:\Program Files\MVTec\HALCON-12.0\include\halconcpp
两个目录添加到 附加包含目录
第二步
选择 链接器 下的 常规 选项
将
C:\Program Files\MVTec\HALCON-12.0\lib\x64-win64
添加到附加库目录
第三步
选择 链接器 下的 输入 选项
将
halconcpp.lib
添加到 附加依赖项
第四步
在 **文件名+Dlg.h ** 的最上方加上
#include"HalconCpp.h" using namespace HalconCpp;
34、串口通信
①理论
(1)串口和并口
串口就是我们的数据是一位一位传输出去的 串口传输效率低,但是传输距离长
并口就是我们的数据通过多条数据线同时传输出去 并口传输的速度快,效率快缺点是长距离传输有困难
(2)同步通信和异步通信
同步通信(SYNC :synchronous data communication)是指在约定的通信速率下,发送端和接收端的时钟信号频率和相位始终保持一致(同步),这样就保证了通信双方在发送和接收数据时具有完全一致的定时关系。同步通信把许多字符组成一个信息组(信息帧),每帧的开始用同步字符来指示,一次通信只传送一帧信息。在传输数据的同时还需要传输时钟信号,以便接收方可以用时针信号来确定每个信息位。
同步通信的优点是:
传送信息的位数几乎不受限制,一次通信传输的数据有几十到几千个字节,通信效率较高。
同步通信的缺点是:
要求在通信中始终保持精确的同步时钟,即发送时钟和接收时钟要严格的同步(常用的做法是两个设备使用同一个时钟源)。打个比喻,同步通信就像两个人实时打电话一样,必须同时实时保搏通话沟通,整个节奏是一致的,就像两个人在同一个指挥棒下通话。
异步通信(ASYNC:asynchronous data communication),又称为起止式异步通信,是以字符为单位进行传输的,字符之间没有固定的时间间隔要求,而每个字符中的各位则以固定的时间传送。在异步通信中,收发双方取得同步是通过在字符格式中设置起始位和停止位的方法来实现的。具体来说就是,在一个有效字符正式发送之前,发送器先发送一个起始位,然后发送有效字符位,在字符结束时再发送一个停止位,起始位至停止位构成一帧。停止位至下一个起始位之间是不定长的空闲位,并且规定起始位为低电平(逻辑值为0),停止位和空闲位都是高电平(逻辑值为1),这样就保证了起始位开始处一定会有一个下跳沿,由此就可以标志一个字符传输的起始。而根据起始位和停止位也就很容易的实现了字符的界定和同步。
显然,采用异步通信时,发送端和接收端可以由各自的时钟来控制数据的发送和接收,这两个时钟源彼此独立,可以互不同步。再来打个比喻,异步通信就像两个人玩微信语音一样,各自一套自己的机制发送和接收机制,两个人在不同的指挥棒下通话。
②串口通信一般调用步骤
(1)初始化串口(配置波特率,数据位,校验位,停止位等)
CString temp;
CString m_bote="2400";
CString m_data="8";
CString m_jiaoyan="None“;
CString m_stop="1";
int SelPortNo,SelBaudRate,SelDataBits,SelStopBits;
char SelParity;
temp = "COM6";
temp.Delete(0,3);
SelPortNo=atoi(temp);
SelBaudRate=atoi(m_bote);
SelDataBits=atoi(m_data);
SelStopBits=atoi(m_stop);
SelParity=m_jiaoyan.GetAt(0);
if(m_SerialPort.InitPort(this,SelPortNo,SelBaudRate,SelDataBits,SelStopBits,EV_RXCHAR|EV_CTS,512))
{
m_SerialPort.StartMonitoring();
}
else
{
AfxMessageBox("该串口已经被占用!")
}
(2)发送 或 接受 数据
CString data;
data = "FF 01 00 02 40 00 43";
//如果发送的数据是16进制 那么需要进行数据转换
data=pMainFrame->ChangeCharstr2Hexstr(data);
//发送数据
PmainFrame->m_SerialPort.WriteToPort(data.GetBuffer(data.GetLength()),data.GetLength());
CString str;
str.Format("%c",ch);
//16进制转换
str.Format("%02X",ch);
m_ReceiveData+=str;
(3)关闭串口
③halcon串口通信例程
serial.hdev
*初始化串口
OpSystem := environment('OS')
if (OpSystem == 'Windows_NT')
open_serial ('COM1', SerialHandle)
else
open_serial ('/dev/tty', SerialHandle)
endif
*设置各种参数
set_serial_param (SerialHandle, 9600, 8, 'none', 'none', 1, 1000, 'unchanged')
*发送数据
write_serial (SerialHandle, ords('Hello world!\n\r'))
*接受数据
read_serial (SerialHandle, 10, Data)
if (|Data| > 0)
Read := chrt(Data)
endif
*关闭串口
close_serial (SerialHandle)
35、网络通信
①理论
(1)UDP全称为用户数据报协议。UDP 为应用程序提供了一种无需建立连接就可以发送封装的 IP 数据包的方法
特点:
无连接:只知道对端的IP和端口号就可以发送,不需要实现建立连接。(就像寄信)。
不可靠:没有确认机制, 没有重传机制。如果因为网络故障该段无法发到对方, UDP协议层也不会给应用层返回任何错误信息。
面向数据报: 应用层交给UDP多长的报文, UDP原样发送既不会拆分,也不会合并。所以UDP不能够灵活的控制读写数据的次数和数量。
UDP存在接收缓冲区,但不存在发送缓冲区。UDP没有发送缓冲区,在调用send to时会直接将数据交给内核,由内核将数据传给网络层协议进行后续的传输动作。UDP具有接收缓冲区,但是这个接收缓冲区不能保证收到的UDP报文的顺序和发送UDP报的顺序一致,如果缓冲区满了再到达的UDP数据报就会被丢弃。
(2)TCP全称传输控制协议,必须对数据的传输进行控制
特点:
面向连接:必须建立连接
可靠:可靠传输的话就像你在淘宝跟客服小姐姐聊天,你发出的信息下面会有一个状态就是未读或者已读这么两个状态,这就代表我发出的消息是已经传输到对方那的,不存在说我消息没有发送过去,在聊天框中会出现这条消息标识为<已读>状态,就是能够感知到消息是否传输过去了(传输失败的时候软件会提醒你的),这就是可靠传输
面向字节流: TCP和文件操作类型,都是“流”式的(由于这里传输的都是字节,所以称为字节流)
②TCP服务器端和客户端编写流程
服务器端:
1、进行版本协商(WSAStartup)
2、创建一个套接字(socket)
3、将套接字设置为监听状态(listen)
4、接受客户端的发送请求( accept )
5、发送或者接受数据 ( send / recv )
6、关闭套接字 ( closesocket ),一次通信结束
7、继续等待接受客户端的发送请求
客户端
1、进行版本协商(WSAStartup)
2、创建一个套接字(socket)
3、连接到服务器 (connect)
4、发送或者接受消息 ( send / recv )
5、关闭套接字 ( closesocket )
6、释放资源( WSACleanup)
③UDP服务器端和客户端编写流程
服务器端:
1、进行版本协商(WSAStartup)
2、创建一个套接字(socket)
3、绑定套接字(bind)
4、发送或者接受数据 ( sendto / recvfrom )
5、关闭套接字 ( closesocket )
6、释放资源(WSACleanup)
客户端
1、进行版本协商(WSAStartup)
2、创建一个套接字(socket)
3、发送或者接受消息 ( sendto / recvfrom )
4、关闭套接字 ( closesocket )
5、释放资源( WSACleanup)
36、缺陷检测
①常见的缺陷
凹凸、污点、瑕疵、孔洞、破损、划痕
②处理的方法
1、blob分析+特征检测
例程:check_hazelnut_wafers.hdev
例程:inspect_bottle_mouth.hdev
(极坐标转换)
例程:novelty_detection_dyn_threshold.hdev
(动态/局部 二值化dyn_threshold)
例程:check_blister.hdev
(定位)
2、blob分析+特征检测+差分
例程:fin.hdev
例程:pcb_inspection.hdev
(灰度开运算和灰度闭运算)
例程:novelty_detection_dyn_threshold.hdev
3、频域+空间域
例程:detect_indent_fft.hdev
(检测缺陷随机,缺陷较小)
例程:detect_mura_blur.hdev
(频域+空间域+差分)
* 测图像中的线条及其宽度的操作符
* 用高斯平滑核的偏导数来提取线条,并将线条以亚像素精度的XLD轮廓形式返回
lines_gauss(Image : Lines : Sigma, Low, High, LightDark, ExtractWidth, LineModel, CompleteJunctions : )
4、光度立体法
5、测量+拟合
例程:measure_fill_level.hdev
例程:fit_rectangle2_contour_xld.hdev
6、特征训练的过程
*创建 MLP 分类器
create_class_mlp( : : NumInput, NumHidden, NumOutput, OutputFunction, Preprocessing, NumComponents, RandSeed : MLPHandle)
*将图像Image中的训练样本添加到 MLP 的训练数据中
add_samples_image_class_mlp(Image, ClassRegions : : MLPHandle : )
*设置 MLP 分类器的参数
set_rejection_params_class_mlp( : : MLPHandle, GenParamName, GenParamValue : )
*训练分类器
train_class_mlp( : : MLPHandle, MaxIterations, WeightTolerance, ErrorTolerance : Error, ErrorLog)
*进行识别分类
classify_image_class_mlp(Image : ClassRegions : MLPHandle, RejectionThreshold : )
例程:novelty_detection_mlp.hdev
* This example program shows how to use the MLP classifier for novelty
* detection to perform a web inspection task. To perform the novelty detection,
* a rejection class is trained internally.
* For the web inspection task, the MLP can subsequently be used to detect
* textures that do not correspond to the texture of the trained good objects.
*
dev_update_off ()
*
ReadPretrainedClassifier := false
* Uncomment the following line to read the pretrained classifier from
* disk. The training may last up to half a minute.
* ReadPretrainedClassifier := true
SaveClassifier := false
* Uncomment the following line to write the MLP classifier to disk after training.
* SaveClassifier := true
*
read_image (Image, 'plastic_mesh/plastic_mesh_01')
get_image_size (Image, Width, Height)
dev_close_window ()
dev_open_window (0, 0, Width, Height, 'black', WindowHandle)
dev_set_color ('red')
set_display_font (WindowHandle, 16, 'mono', 'true', 'false')
get_system ('example_dir', HalconExamples)
* The texture filters used for the classification will return artifacts at the image
* borders because the images of the plastic mesh to be inspected do not
* contain an integer number of mesh cells. Because this would lead to wrongly
* detected errors at the image borders, we must exclude the area close to the
* image border from the training and classification. This is done with the following
* rectangle. Note that the image is later scaled down by a factor of two.
gen_rectangle1 (Rectangle, 10, 10, Height / 2 - 11, Width / 2 - 11)
if (ReadPretrainedClassifier)
* Read the pretrained classifier from disk.
dev_display (Image)
disp_message (WindowHandle, 'Reading classifier from disk...', 'window', 10, 10, 'black', 'true')
read_class_mlp (HalconExamples + '/hdevelop/Segmentation/Classification/novelty_detection.gmc', MLPHandle)
wait_seconds (1.5)
else
* Create the MLP classifier.
create_class_mlp (5, 6, 2, 'softmax', 'principal_components', 3, 42, MLPHandle)
* The training is based on five images that contain no errors.
gen_empty_region (EmptyRegion)
concat_obj (Rectangle, EmptyRegion, ObjectsConcat)
for J := 1 to 5 by 1
read_image (Image, 'plastic_mesh/plastic_mesh_' + J$'02')
* The images are zoomed down because the resolution of the mesh is very
* high. This saves a large amount of processing time.
zoom_image_factor (Image, ImageZoomed, 0.5, 0.5, 'constant')
dev_display (ImageZoomed)
disp_message (WindowHandle, 'Adding training samples...', 'window', 10, 10, 'black', 'true')
* Generate the texture image.
gen_texture_image (ImageZoomed, ImageTexture)
* Add the samples to the classifier.
add_samples_image_class_mlp (ImageTexture, ObjectsConcat, MLPHandle)
endfor
dev_display (ImageZoomed)
* Now configure the MLP that a rejection class will be added during training.
set_rejection_params_class_mlp (MLPHandle, 'sampling_strategy', 'hyperbox_ring_around_each_class')
set_rejection_params_class_mlp (MLPHandle, 'rejection_sample_factor', .3)
* Train the MLP.
disp_message (WindowHandle, 'Training MLP...', 'window', 10, 10, 'black', 'true')
train_class_mlp (MLPHandle, 200, 1, 0.01, Error, ErrorLog)
if (SaveClassifier)
write_class_mlp (MLPHandle, HalconExamples + '/hdevelop/Segmentation/Classification/novelty_detection.gmc')
endif
endif
* Now detect errors in the plastic meshes.
for J := 1 to 14 by 1
read_image (Image, 'plastic_mesh/plastic_mesh_' + J$'02')
zoom_image_factor (Image, ImageZoomed, 0.5, 0.5, 'constant')
dev_display (ImageZoomed)
*给图像添加纹理
gen_texture_image (ImageZoomed, ImageTexture)
reduce_domain (ImageTexture, Rectangle, ImageTextureReduced)
* Classify samples belonging to the trained class with the MLP.
classify_image_class_mlp (ImageTextureReduced, ClassRegions, MLPHandle, 0.5)
* Post process the returned raw errors to remove insignificant parts of the
* detected errors.
select_obj (ClassRegions, Correct, 1)
select_obj (ClassRegions, Errors, 2)
opening_circle (Errors, ErrorsOpening, 4.5)
closing_circle (ErrorsOpening, ErrorsClosing, 10.5)
connection (ErrorsClosing, ErrorsConnected)
select_shape (ErrorsConnected, FinalErrors, 'area', 'and', 100, 1000000)
count_obj (FinalErrors, NumErrors)
dev_set_color ('red')
dev_set_draw ('margin')
dev_set_line_width (5)
dev_display (FinalErrors)
if (NumErrors > 0)
disp_message (WindowHandle, 'Mesh not OK', 'window', 10, 10, 'black', 'true')
else
disp_message (WindowHandle, 'Mesh OK', 'window', 10, 10, 'black', 'true')
endif
if (J < 14)
disp_continue_message (WindowHandle, 'black', 'true')
endif
stop ()
endfor
clear_class_mlp (MLPHandle)
③药品检测的代码
*读入图片
dev_close_window ()
read_image (Image, 'C:/Users/ZW/Desktop/机器视觉/Halcon视频教程 第2套初级班+强化班/强化班视频/实战图片/药品检测.png')
dev_open_window_fit_image (Image, 0, 0, -1, -1, WindowHandle)
dev_display (Image)
*设置显示
set_display_font (WindowHandle, 14, 'mono', 'true', 'false')
dev_set_draw ('margin')
dev_set_line_width (3)
*阈值分割 提取边界
scale_image (Image, ImageScaled, 2.5, -7)
threshold (ImageScaled, Regions, 0, 114)
connection (Regions, ConnectedRegions)
select_shape (ConnectedRegions, SelectedRegions, 'area', 'and', 67942.9, 78903.9)
fill_up (SelectedRegions, RegionFillUp)
*边界更加平滑
shape_trans (RegionFillUp, Blister, 'convex')
*校正图片
orientation_region (Blister, Phi)
area_center (Blister, Area1, Row, Column)
vector_angle_to_rigid (Row, Column, Phi, Row, Column, 0, HomMat2D)
affine_trans_image (Image, Image2, HomMat2D, 'constant', 'false')
*挨个画圆
gen_empty_obj (Chambers)
for I := 0 to 1 by 1
Row := 190 + I * 110
for J := 0 to 5 by 1
Column := 165 + J * 80
gen_circle (Circle, Row, Column, 35)
concat_obj (Chambers, Circle, Chambers)
endfor
endfor
*得到扣除圆圈的图像
affine_trans_region (Blister, Blister, HomMat2D, 'nearest_neighbor')
difference (Blister, Chambers, Pattern)
union1 (Chambers, ChambersUnion)
*得到变换的角度
orientation_region (Blister, PhiRef)
PhiRef := rad(180) + PhiRef
area_center (Blister, Area2, RowRef, ColumnRef)
*重新读入图像
dev_close_window ()
dev_open_window_fit_image (Image, 0, 0, -1, -1, WindowHandle)
dev_display (Image2)
*抠出图像
reduce_domain (Image2, ChambersUnion, ImageReduced)
threshold (ImageReduced, Regions1, 0, 125)
connection (Regions1, ConnectedRegions1)
select_shape (ConnectedRegions1, SelectedRegions1, 'area', 'and', 1346.85, 2000)
dev_set_draw ('margin')
dev_display (Image2)
dev_display (SelectedRegions1)
*进行检测
count_obj (Chambers, Number)
gen_empty_obj (WrongPill)
gen_empty_obj (MissingPill)
gen_empty_obj (CrackPill)
for I := 1 to Number by 1
select_obj (Chambers, Chamber, I)
intersection (Chamber, SelectedRegions1, Pill)
area_center (Pill, Area, Row1, Column1)
*如果存在裂缝 就会存在孔洞面积
area_holes (Pill, AreaHole)
if(AreaHole > 0)
concat_obj (CrackPill, Pill, CrackPill)
endif
if (Area > 0)
min_max_gray (Pill, Image2, 0, Min, Max, Range)
if (Area < 1400 or Min > 40)
concat_obj (WrongPill, Pill, WrongPill)
endif
else
concat_obj (MissingPill, Chamber, MissingPill)
endif
dev_clear_window ()
dev_display (Image2)
dev_set_color ('forest green')
count_obj (SelectedRegions1, NumberP)
count_obj (WrongPill, NumberWP)
count_obj (MissingPill, NumberMP)
count_obj (CrackPill, NumberCp)
dev_display (SelectedRegions1)
if (NumberMP > 0 or NumberWP > 0)
disp_message (WindowHandle, 'Not OK', 'window', 10, 10 + 600, 'red', 'true')
else
disp_message (WindowHandle, 'OK', 'window', 10, 10 + 600, 'forest green', 'true')
endif
disp_message (WindowHandle, '# correct pills: ' + (NumberP - NumberWP - NumberCp), 'window', 10, 10, 'black', 'true')
disp_message (WindowHandle, '# wrong pills : ' + NumberWP, 'window', 10 + 25, 10, 'black', 'true')
if (NumberWP > 0)
disp_message (WindowHandle, NumberWP, 'window', 10 + 25, 10 + 180, 'red', 'true')
endif
disp_message (WindowHandle, '# missing pills: ' + NumberMP, 'window', 10 + 50, 10, 'black', 'true')
disp_message (WindowHandle, '# crack pills: ' + NumberCp, 'window', 10 + 75, 10, 'black', 'true')
if (NumberMP > 0)
disp_message (WindowHandle, NumberMP, 'window', 10 + 50, 10 + 180, 'red', 'true')
endif
dev_set_color ('red')
dev_display (WrongPill)
dev_display (MissingPill)
dev_display (CrackPill)
endfor
37、OCV(光学字符检测)
例程:write_ocv.hdev
* 1、采集图像
read_image (Image, 'a01')
* 2、提取字符
threshold (Image, Region, 0, 100)
* 3、抠出图像
shape_trans (Region, RegionTrans, 'rectangle1')
dilation_rectangle1 (RegionTrans, RegionDilation, 10, 10)
* Reduce the domain of an image.
reduce_domain (Image, RegionDilation, ImageReduced)
* 3、创建模型 进行训练
* Create a new OCV tool based on gray value projections
create_ocv_proj ('A', OCVHandle)
traind_ocv_proj (ImageReduced, OCVHandle, 'A', 'single')
* 4、保存训练好的模型
write_ocv (OCVHandle, 'test_ocv.ocv')
close_ocv (OCVHandle)
* 下次使用时读出训练好的模型
read_ocv ('test_ocv.ocv', OCVHandle)
close_ocv (OCVHandle)
例程:print_quality.hdev
read_image (Image, 'fonts/arial_a1')
get_image_size (Image, Width, Height)
dev_close_window ()
dev_open_window (0, 0, Width / 2, Height / 2, 'black', WindowHandle)
dev_display (Image)
dev_set_draw ('margin')
gen_rectangle1 (Rectangle, 37, 69, 115, 141)
reduce_domain (Image, Rectangle, ImageReduced)
*创建模型 进行训练
create_ocv_proj ('A', OCVHandle)
traind_ocv_proj (ImageReduced, OCVHandle, 'A', 'single')
dev_set_color ('red')
for I := 1 to 9 by 1
read_image (Image, 'fonts/arial_a' + I)
binary_threshold (Image, Region, 'max_separability', 'dark', UsedThreshold)
connection (Region, ConnectedRegions)
select_shape (ConnectedRegions, SelectedRegions, 'area', 'and', 150, 99999)
sort_region (SelectedRegions, SortedRegions, 'character', 'true', 'row')
select_obj (SortedRegions, ObjectSelected, 1)
shape_trans (ObjectSelected, RegionTrans, 'rectangle1')
dilation_rectangle1 (RegionTrans, RegionDilation, 15, 15)
reduce_domain (Image, RegionDilation, ImageReduced)
*识别函数 do_ocv_simple
* Quality的值越大 识别的正确率越高
* 5代表阈值 值越大要求越高
do_ocv_simple (ImageReduced, OCVHandle, 'A', 'true', 'true', 'true', 'true', 5, Quality)
set_tposition (WindowHandle, 15, 12)
write_string (WindowHandle, 'Quality = ' + Quality)
stop ()
endfor
close_ocv (OCVHandle)
38、频域+空间域
①理论
频率图像中心一般是低频成分,从中心往外频率是逐渐增加的
每一点亮度值越高表示这个频率的特征很突出。亮点越多表示该频率的成分越多
一幅图像灰度均匀的区域,变化不剧烈的部分对应低频部分------频谱图中较亮部分
图像中的噪声、边缘、细节,变化剧烈的部分对应高频部分------频谱图中较暗部分
整个图像区域中一般最多的就是背景图
去除掉较亮的区域(成分多的内容) 就是去除了背景图
留下了较暗的区域 就是留下了细节内容
②傅里叶变换的算子
*fft_image函数计算输入图像(Image)的傅里叶变换,将图像转换到频率域
*采用的算法是快速傅里叶变换(FFT)。该函数对整个图像进行变换,忽略图像的域
fft_image(Image : ImageFFT : : )
*fft_generic提供了更灵活的选项,可以选择傅里叶变换的方向、指数符号、归一化因子和直流分量位置等
fft_generic(Image : ImageFFT : Direction, Exponent, Norm, Mode, ResultType : )
* 傅里叶反变换 频率图变为灰度图
fft_image_inv(Image : ImageFFTInv : : )
*进行快速傅里叶变换
*其中'to_freq'代表正向 ‘from_freq’代表反向
*ResultType表示结果类型(傅里叶变换得到的结果有实部和虚部 默认为complex复数形式)
fft_generic(Image:ImageFFT:'to_freq',Exponent,Norm,Mode,ResultType:)
-
低通滤波器(Low-pass Filter):
低通滤波器允许低频信号通过,抑制高频信号。它的作用是平滑图像、去除高频噪声、模糊图像的细节,使图像变得更加平滑。低通滤波器通常用于图像模糊、降噪和图像压缩等应用。常见的低通滤波器包括:
- 均值滤波器(平均滤波器):用邻域像素的平均值替代中心像素的值。
- 高斯滤波器:使用高斯函数作为权重来平滑图像,具有更好的平滑效果和较好的边缘保留性能。
- 中值滤波器:用邻域像素的中值替代中心像素的值,对于去除椒盐噪声等非常有效。
低通滤波器可以通过控制滤波器的大小或频率响应来调整平滑程度。较大的滤波器将导致更强的平滑效果,但可能会损失图像的细节。
-
高通滤波器(High-pass Filter):
高通滤波器允许高频信号通过,抑制低频信号。它的作用是突出图像中的细节、边缘和纹理,增强图像的锐度和边缘信息。高通滤波器通常用于图像增强、边缘检测和纹理分析等应用。常见的高通滤波器包括:
- 拉普拉斯滤波器:用于增强图像的高频部分,使边缘更加明显。
- Sobel滤波器:用于检测图像中的边缘,通过计算梯度来突出边缘。
- Prewitt滤波器:类似于Sobel滤波器,用于检测图像中的边缘。
高通滤波器可以通过控制滤波器的大小或频率响应来调整增强效果。较小的滤波器将突出较细的边缘和细节,而较大的滤波器将突出更粗的边缘和纹理。
③喷图处理(除滤波器外)
read_image (Image11, 'C:/Users/ZW/Desktop/机器视觉/Halcon视频教程 第2套初级班+强化班/强化班视频/实战图片/11.png')
rgb1_to_gray (Image11, GrayImage)
*傅里叶变换
fft_image (GrayImage, ImageFFT)
gen_rectangle1 (ROI_0, -0.5, 399.311, 169.691, 423.571)
gen_rectangle1 (TMP_Region, 158.828, 313.914, 225.215, 455.595)
union2 (ROI_0, TMP_Region, ROI_0)
gen_rectangle1 (TMP_Region, 220.387, 397.37, 298.844, 421.63)
union2 (ROI_0, TMP_Region, ROI_0)
gen_rectangle1 (TMP_Region, 291.602, 399.311, 303.672, 421.63)
union2 (ROI_0, TMP_Region, ROI_0)
gen_rectangle1 (TMP_Region, 313.328, 404.163, 616.293, 418.719)
union2 (ROI_0, TMP_Region, ROI_0)
paint_region (ROI_0, ImageFFT, ImageResult, 0, 'fill')
*傅里叶反变换
fft_image_inv (ImageResult, ImageFFTInv)
④转为功率图
转为功率图之前
转为功率图之后
例程:remove_textture_fft.hdev
dev_update_off ()
dev_close_window ()
Scale := [1.0,.65]
MinGray := [50,100]
for Index := 0 to 1 by 1
*
* Read and display the image
read_image (Image, 'plan_' + (Index + 1)$'02')
get_image_size (Image, Width, Height)
dev_open_window (0, 0, Width * Scale[Index], Height * Scale[Index], 'black', WindowHandle)
set_display_font (WindowHandle, 14, 'mono', 'true', 'false')
dev_set_part (0, 0, Height - 1, Width - 1)
dev_display (Image)
disp_message (WindowHandle, 'Original image', 'image', 12, 12, 'black', 'true')
*
* Perform fft and display spectrum
optimize_fft_speed (Width, Height, 'standard')
*
* We used 'fft_generic' 'sqrt' and 'dc_center' mainly
* for visualization purposes.
* To speed up the program, rft_generic should be used;
* but of course, the peak detection algorithm has to be
* adjusted in this case.
fft_generic (Image, ImageFFT, 'to_freq', -1, 'sqrt', 'dc_center', 'complex')
dev_open_window (0, Width * Scale[Index] + 7, Width * Scale[Index], Height * Scale[Index], 'black', WindowHandle1)
dev_set_color ('red')
dev_set_draw ('margin')
set_display_font (WindowHandle1, 14, 'mono', 'true', 'false')
dev_set_part (0, 0, Height - 1, Width - 1)
dev_display (ImageFFT)
disp_message (WindowHandle1, 'Fourier spectrum', 'image', 12, 12, 'black', 'true')
disp_cont_message (WindowHandle1, 'black', 'true')
stop ()
*
* Detect the eight most significant peaks in the spectrum
*重点函数
power_real (ImageFFT, PowerSpectrum)
binomial_filter (PowerSpectrum, ImageSmooth, 9, 9)
threshold (ImageSmooth, Region, MinGray[Index], 100000)
connection (Region, ConnectedRegions)
select_shape (ConnectedRegions, SelectedRegions, 'area', 'and', 5, 200)
union1 (SelectedRegions, RegionUnion)
reduce_domain (ImageSmooth, RegionUnion, ImageReduced)
local_max (ImageReduced, LocalMaxima)
*
* Next, detect peaks one octave higher, i.e., at twice
* the frequency of the most significant peaks
shape_trans (LocalMaxima, RegionTrans, 'convex')
* Construct ROI band at twice the frequency
hom_mat2d_identity (HomMat2DIdentity)
hom_mat2d_scale (HomMat2DIdentity, 2.1, 2.1, Height / 2, Width / 2, HomMat2DScale)
affine_trans_region (RegionTrans, RegionTrans1, HomMat2DScale, 'nearest_neighbor')
hom_mat2d_scale (HomMat2DIdentity, 1.9, 1.9, Height / 2, Width / 2, HomMat2DScale)
affine_trans_region (RegionTrans, RegionTrans2, HomMat2DScale, 'nearest_neighbor')
difference (RegionTrans1, RegionTrans2, RegionDifference)
* Extract the peaks at twice the frequency
reduce_domain (ImageSmooth, RegionDifference, ImageReduced)
threshold (ImageReduced, Region, 15, 100000)
reduce_domain (ImageSmooth, Region, ImageReduced)
local_max (ImageReduced, LocalMaxima2)
*
* Merge the peaks of both octaves and enlarge them to
* integrate the relevant frequencies into the filter
union2 (LocalMaxima, LocalMaxima2, RegionUnion)
dilation_circle (RegionUnion, RegionDilation, 15.5)
paint_region (RegionDilation, ImageFFT, ImageFFTFiltered, 0, 'fill')
dev_display (ImageFFT)
dev_display (RegionDilation)
disp_message (WindowHandle1, 'Frequencies of the\nbackground texture', 'image', 12, 12, 'black', 'true')
disp_cont_message (WindowHandle1, 'black', 'true')
stop ()
*
* Apply the filter and display the results
fft_generic (ImageFFTFiltered, ImageFiltered, 'from_freq', 1, 'sqrt', 'dc_center', 'byte')
dev_display (ImageFiltered)
disp_message (WindowHandle1, 'Filtered image', 'image', 12, 12, 'black', 'true')
*
dev_open_window (0, 2 * (Width * Scale[Index]) + 14, Width * Scale[Index], Height * Scale[Index], 'black', WindowHandle2)
set_display_font (WindowHandle2, 14, 'mono', 'true', 'false')
dev_set_part (0, 0, Height - 1, Width - 1)
sub_image (Image, ImageFiltered, ImageTexture, 1, 128)
dev_display (ImageTexture)
disp_message (WindowHandle2, 'Removed texture', 'window', 12, 12, 'black', 'true')
if (Index < 1)
disp_cont_message (WindowHandle2, 'black', 'true')
stop ()
dev_close_window ()
dev_close_window ()
dev_close_window ()
endif
endfor
39、标定助手进行标定
创建描述文件
*用于生成校准板描述文件和相应的PostScript文件的算子
gen_caltab( : : XNum, YNum, MarkDist, DiameterRatio, CalPlateDescr, CalPlatePSFile : )
XNum(输入控制):校准板在x方向上的标记数量,默认值为7。
YNum(输入控制):校准板在y方向上的标记数量,默认值为7。
MarkDist(输入控制):标记之间的距离(以米为单位),默认值为0.0125。
DiameterRatio(输入控制):标记直径与标记距离的比率,默认值为0.5。
CalPlateDescr(输入控制):校准板描述文件的文件名,默认为'caltab.descr'。
CalPlatePSFile(输入控制):PostScript文件的文件名,默认为'caltab.ps'。
标定助手
标定过程
得到的结果
40、单相机标定—畸形矫正
标定完成后插入代码中的插入数据得到两个参数
CameraParameters(内参数) 和 CameraPose(外参数)
一般只会使用内参数
* 根据指定的径向畸变系数来确定新的相机参数
* CamParamIn是得到的初始参数
change_radial_distortion_cam_par( : : Mode, CamParamIn, DistortionCoeffs : CamParamOut)
* 根据内部相机参数CamParamIn(原始参数)和计算得到的CamParamOut(新参数)计算与径向畸变变化相对应的图像映射
gen_radial_distortion_map( : Map : CamParamIn, CamParamOut, MapType : )
*使用一个任意的转换Map来转换图像Image
map_image(Image, Map : ImageMapped : : )
41、VS一些操作
①上锁
// 上锁
::EnableWindow(GetDlgItem(IDC_MATH)->GetSafeHwnd(), FALSE);
// 解锁
::EnableWindow(GetDlgItem(IDC_DRAW)->GetSafeHwnd(), TRUE);
②滑动条的设置
先增加控件
再进行设置(在 OnInitDialog()
进行设置 )
//设置范围
m_yuzhi_cabin.SetRange(0, 255);
//设置初始位置
m_yuzhi_cabin.SetPos(141);
//设置显示刻度的间隔
m_yuzhi_cabin.SetTicFreq(1);
③绑定窗口设置(在 OnInitDialog()
进行设置 )
//开启第一个窗口---hv_WindowHandle
HWND hwnd;
CRect rect;
GetDlgItem(IDC_IMAGE1)->GetWindowRect(&rect);
hwnd = GetDlgItem(IDC_IMAGE1)->m_hWnd;
Hlong WWindowID = (Hlong)hwnd;
OpenWindow(0, 0, rect.Width(), rect.Height(), WWindowID, "", "", &hv_WindowHandle);
//SetWindowAttr("background_color", "white");
HDevWindowStack::Push(hv_WindowHandle);
//开启第二个窗口------hv_WindowHandle1
HWND hwnd1;
CRect rect1;
GetDlgItem(IDC_IMAGE2)->GetWindowRect(&rect1);
hwnd1 = GetDlgItem(IDC_IMAGE2)->m_hWnd;
Hlong WWindowID1 = (Hlong)hwnd1;
OpenWindow(0, 0, rect1.Width(), rect1.Height(), WWindowID1, "", "", &hv_WindowHandle1);
SetWindowAttr("background_color", "black");
HDevWindowStack::Push(hv_WindowHandle1);
//激活其中某个窗口
HDevWindowStack::SetActive(hv_WindowHandle);
④列表控件ListControl
添加ListControl
设置view变量 让ListControl竖着或者横着
CString head[] = { TEXT("姓名"),TEXT("年龄"),TEXT("性别") };
CString name[] = { TEXT("小赵"),TEXT("小凡"),TEXT("小夏"),
TEXT("小川"),TEXT("小卉"),TEXT("小余") };
//设置主题
m_List.SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES | LVS_EX_DOUBLEBUFFER);
//插入列标题
m_List.InsertColumn(0, head[0], LVCFMT_LEFT, 100);
m_List.InsertColumn(1, head[1], LVCFMT_LEFT, 100);
m_List.InsertColumn(2, head[2], LVCFMT_LEFT, 100);
//插入正文内容
for (int i = 0; i < 6; i++)
{
//确定行数
m_List.InsertItem(i, name[i]);
//设置列内容
int j = 0;
int age = 23;
m_List.SetItemText(i, ++j, TEXT("18"));
m_List.SetItemText(i, ++j, TEXT("女"));
42、VS与Halcon变量的转换
① Halcon中的HTuple → VS 数据类型
HTuple hTuple = 1234;
int i = hTuple[0].I(); // i=1234
long l = hTuple[0].L(); // l=1234
long lNumber = hTuple.Num(); // lNumber=1,数据个数
double d = hTuple[0].D(); // d=1234.0000
hTuple = “1234”;
CString strBuffer = hTuple[0].S(); // strBuffer=“1234”
②VS 数据类型 → Halcon中的数据类型
int ii = 1234;
double dd = 1234.1234;
CString strTemp = “Halcon”;
HTuple hTuple2;
hTuple2[0] = ii; // hTuple2[0].I() = 1234
hTuple2[1] = dd; // hTuple2[1].D() = 1234.1234
hTuple2[2] = strTemp.GetBuffer(); // hTuple2[2].S() = “Halcon”
i = hTuple2[0].I(); // i = 1234
d = hTuple2[1].D(); // d = 1234.1234
str = hTuple2[2].S(); // str = “Halcon”
lNumber = hTuple2.Num(); // lNumber = 3,数据个数
③如果Halcon的数据类型中有多个数据
//定义vs中的CString类型
CString str1;
//将HTuple → VS 中 double类型
double m_mianji = hv_UserArea[i].D();
//CString 类型 的格式化
str1.Format("%0.2f", m_mianji);
生成校准板描述文件和相应的PostScript文件的算子
gen_caltab( : : XNum, YNum, MarkDist, DiameterRatio, CalPlateDescr, CalPlatePSFile : )
XNum(输入控制):校准板在x方向上的标记数量,默认值为7。
YNum(输入控制):校准板在y方向上的标记数量,默认值为7。
MarkDist(输入控制):标记之间的距离(以米为单位),默认值为0.0125。
DiameterRatio(输入控制):标记直径与标记距离的比率,默认值为0.5。
CalPlateDescr(输入控制):校准板描述文件的文件名,默认为’caltab.descr’。
CalPlatePSFile(输入控制):PostScript文件的文件名,默认为’caltab.ps’。
### 标定助手
[外链图片转存中...(img-JJzmGLhe-1721797993008)]
### 标定过程
[外链图片转存中...(img-xGMrCycb-1721797993009)]
### 得到的结果
[外链图片转存中...(img-ZigoLtSm-1721797993009)]
## 40、单相机标定---畸形矫正
标定完成后插入代码中的插入数据得到两个参数
**CameraParameters**(内参数) 和 **CameraPose**(外参数)
一般只会使用内参数
[外链图片转存中...(img-4euQ1fz0-1721797993009)]
```c#
* 根据指定的径向畸变系数来确定新的相机参数
* CamParamIn是得到的初始参数
change_radial_distortion_cam_par( : : Mode, CamParamIn, DistortionCoeffs : CamParamOut)
* 根据内部相机参数CamParamIn(原始参数)和计算得到的CamParamOut(新参数)计算与径向畸变变化相对应的图像映射
gen_radial_distortion_map( : Map : CamParamIn, CamParamOut, MapType : )
*使用一个任意的转换Map来转换图像Image
map_image(Image, Map : ImageMapped : : )
41、VS一些操作
①上锁
// 上锁
::EnableWindow(GetDlgItem(IDC_MATH)->GetSafeHwnd(), FALSE);
// 解锁
::EnableWindow(GetDlgItem(IDC_DRAW)->GetSafeHwnd(), TRUE);
②滑动条的设置
先增加控件
[外链图片转存中…(img-6qmGcYrQ-1721797993009)]
再进行设置(在 OnInitDialog()
进行设置 )
//设置范围
m_yuzhi_cabin.SetRange(0, 255);
//设置初始位置
m_yuzhi_cabin.SetPos(141);
//设置显示刻度的间隔
m_yuzhi_cabin.SetTicFreq(1);
③绑定窗口设置(在 OnInitDialog()
进行设置 )
//开启第一个窗口---hv_WindowHandle
HWND hwnd;
CRect rect;
GetDlgItem(IDC_IMAGE1)->GetWindowRect(&rect);
hwnd = GetDlgItem(IDC_IMAGE1)->m_hWnd;
Hlong WWindowID = (Hlong)hwnd;
OpenWindow(0, 0, rect.Width(), rect.Height(), WWindowID, "", "", &hv_WindowHandle);
//SetWindowAttr("background_color", "white");
HDevWindowStack::Push(hv_WindowHandle);
//开启第二个窗口------hv_WindowHandle1
HWND hwnd1;
CRect rect1;
GetDlgItem(IDC_IMAGE2)->GetWindowRect(&rect1);
hwnd1 = GetDlgItem(IDC_IMAGE2)->m_hWnd;
Hlong WWindowID1 = (Hlong)hwnd1;
OpenWindow(0, 0, rect1.Width(), rect1.Height(), WWindowID1, "", "", &hv_WindowHandle1);
SetWindowAttr("background_color", "black");
HDevWindowStack::Push(hv_WindowHandle1);
//激活其中某个窗口
HDevWindowStack::SetActive(hv_WindowHandle);
④列表控件ListControl
添加ListControl
[外链图片转存中…(img-r8SPQwWK-1721797993009)]
设置view变量 让ListControl竖着或者横着
[外链图片转存中…(img-0kF1CTXp-1721797993010)]
CString head[] = { TEXT("姓名"),TEXT("年龄"),TEXT("性别") };
CString name[] = { TEXT("小赵"),TEXT("小凡"),TEXT("小夏"),
TEXT("小川"),TEXT("小卉"),TEXT("小余") };
//设置主题
m_List.SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES | LVS_EX_DOUBLEBUFFER);
//插入列标题
m_List.InsertColumn(0, head[0], LVCFMT_LEFT, 100);
m_List.InsertColumn(1, head[1], LVCFMT_LEFT, 100);
m_List.InsertColumn(2, head[2], LVCFMT_LEFT, 100);
//插入正文内容
for (int i = 0; i < 6; i++)
{
//确定行数
m_List.InsertItem(i, name[i]);
//设置列内容
int j = 0;
int age = 23;
m_List.SetItemText(i, ++j, TEXT("18"));
m_List.SetItemText(i, ++j, TEXT("女"));
[外链图片转存中…(img-pPzquVog-1721797993010)]
42、VS与Halcon变量的转换
① Halcon中的HTuple → VS 数据类型
HTuple hTuple = 1234;
int i = hTuple[0].I(); // i=1234
long l = hTuple[0].L(); // l=1234
long lNumber = hTuple.Num(); // lNumber=1,数据个数
double d = hTuple[0].D(); // d=1234.0000
hTuple = “1234”;
CString strBuffer = hTuple[0].S(); // strBuffer=“1234”
②VS 数据类型 → Halcon中的数据类型
int ii = 1234;
double dd = 1234.1234;
CString strTemp = “Halcon”;
HTuple hTuple2;
hTuple2[0] = ii; // hTuple2[0].I() = 1234
hTuple2[1] = dd; // hTuple2[1].D() = 1234.1234
hTuple2[2] = strTemp.GetBuffer(); // hTuple2[2].S() = “Halcon”
i = hTuple2[0].I(); // i = 1234
d = hTuple2[1].D(); // d = 1234.1234
str = hTuple2[2].S(); // str = “Halcon”
lNumber = hTuple2.Num(); // lNumber = 3,数据个数
③如果Halcon的数据类型中有多个数据
//定义vs中的CString类型
CString str1;
//将HTuple → VS 中 double类型
double m_mianji = hv_UserArea[i].D();
//CString 类型 的格式化
str1.Format("%0.2f", m_mianji);