Halcon中阈值二值化的算子众多,通常用得最多的有threshold、binary_threshold、dyn_threshold等。

threshold是最简单的阈值分割算子,理解最为简单;binary_threshold是自动阈值算子,它可以自动选出暗(dark)的区域,或者自动选出亮(light)的区域,理解起来也没有难度。

动态阈值算子dyn_threshold理解起来稍微复杂一点,使用dyn_threshold算子的步骤基本是这样的:

① 将原图进行滤波平滑处理。

② 用原图和平滑后的图逐个像素做比较,它可以根据参数分割出原图比平滑后的图灰度高(或者低)若干个灰度值的区域。

举例如下:

处理程序是这样的:

 read_image (Image, 'C:/Users/happy xia/Desktop/dynPic.png')
mean_image (Image, ImageMean, 9, 9)
dyn_threshold (Image, ImageMean, RegionDynThresh, 10, 'dark')

程序分析:本例中,将图片模糊后,点阵字的黑色扩散了,随之就是字的黑色不如原图那么黑了,那么通过给定的限值“10”和“dark”,就可以将原图比模糊后的图暗10个灰阶以上的区域(即黑色文字部分)选出来了。

以上所说的三个算子并不是本文的重点,但却是理解下面的两个阈值分割算子的准备知识。

1、dual_threshold

先看程序和效果图再分析。

 read_image (Image, 'C:/Users/happy xia/Desktop/2.png')
dual_threshold (Image, RegionCrossings, 174, 200, 180)

dual_threshold(Image : RegionCrossings : MinSize, MinGray, Threshold : )

该算子签名中:Threshold 表示用于分割的阈值数值,MinSize表示分割出来的区域的最小面积(即数像素的数目个数),MinGray表示分割出来的区域对应的原图中图像像素的最高灰度不能低于MinGray设定值。

注意图中蓝色矩形小色块的面积是175个像素,因此当MinSize = 174时,它可以被分割出来。

OK,我知道这么说比较拗口。下面我边改变参数边观察效果图,并做简要分析:

 read_image (Image, 'C:/Users/happy xia/Desktop/2.png')
dual_threshold (Image, RegionCrossings, , , )

效果图如下:

由于最小面积设置为176,那么面积为175像素的矩形小色块就没有被分割出来。

再来改变MinGray参数:

 read_image (Image, 'C:/Users/happy xia/Desktop/2.png')
dual_threshold (Image, RegionCrossings, , , )

此时观察到,最右边那个齿轮本来分割出来的区域没有了!

通过取色器观察可知,这块区域最亮的灰度大概比211高一点点。

我们把这个值略微调低再看看:

 read_image (Image, 'C:/Users/happy xia/Desktop/2.png')
dual_threshold (Image, RegionCrossings, , 210, )

最右边那个齿轮右下角那一块又被分割出来了!

相信通过这样参数的反复调节,大家已经彻底明白了dual_threshold算子的意义和用法。

我们看这个算子的名称——dual是“双”的意思,也就是双阈值。如果我们让参数列表中的MinGray = Threshold,那就是单阈值了。

 read_image (Image, 'C:/Users/happy xia/Desktop/2.png')
dual_threshold (Image, RegionCrossings, , 180, 180)

这个算子是很高效的。如果要完成上面这个程序这样的功能,用threshold算子的话,代码要这样写:

 read_image (Image, 'C:/Users/happy xia/Desktop/2.png')
threshold (Image, Region, , )
connection (Region, ConnectedRegions)
select_shape (ConnectedRegions, SelectedRegions, 'area', 'and', , )

也就是说dual_threshold一条算子顶这三条算子。

dual_threshold算子的缺陷:它只能分割出灰度值高的亮区域,不能分割出灰度值低的暗区域。

下面介绍var_threshold算子。

2、var_threshold

先看var_threshold算子的签名:

var_threshold(Image : Region : MaskWidth, MaskHeight, StdDevScale, AbsThreshold, LightDark : )

MaskWidth、 MaskHeight是用于滤波平滑的掩膜单元;StdDevScale是标准差乘数因子(简称标准差因子);AbsThreshold是设定的绝对阈值;LightDark有4个值可选,'light'、'dark'、'equal'、'not_equal'

需要强调的是var_threshold算子和dyn_threshold算子极为类似。不同的是var_threshold集成度更高,并且加入了“标准差×标准差因子”这一变量。

举例:

 read_image (Image, 'C:/1.png')
var_threshold (Image, Region, , , 0.2, , 'dark')

在该程序中,先用4×4的掩膜在图像上逐像素游走,用原图中的当前像素和对应掩膜中16个像素的灰度均值对比,找出暗(dark)的区域。当原图像素灰度比对应的掩膜灰度均值低(0.2,12)个灰阶时,该区域被分割出来。本程序中StdDevScale = 0.2, AbsThreshold = 12,问题的关键就是理解如何通过StdDevScaleAbsThreshold来确定用于分割的阈值。

var_threshold的帮助文档中是这么写的:

说明:

1、d(x,y)指的是遍历每个像素时,掩膜覆盖的那些像素块(本例中是4×4 = 16个像素)灰度的标准差;StdDevScale 是标准差因子。

2、当标准差因子StdDevScale ≥ 0 时,v(x,y) 取(StdDevScale ×标准差)和AbsThreshold 中较大的那个。

3、当标准差因子StdDevScale < 0 时,v(x,y) 取(StdDevScale ×标准差)和AbsThreshold 中较小的那个。实测发现,这里的比较大小是带符号比较,由于标准差是非负数,当StdDevScale < 0 时,(StdDevScale ×标准差)≤ 0恒成立。所以此时的取值就是(StdDevScale ×标准差)。

文档是这么说的:

If StdDevScale*dev(x,y) is below AbsThreshold for positive values of StdDevScale or above for negative values StdDevScale, AbsThreshold is taken instead.

大致意思是:

当StdDevScale为正时,如果StdDevScale*dev(x,y) 低于 AbsThreshold,则采用AbsThreshold。

当StdDevScale为负时,如果StdDevScale*dev(x,y) 高于 AbsThreshold,则采用AbsThreshold。

我找了一块黑白过渡处4×4的像素块,求得它的灰度标准差为51.16(或49.53):

帮助文档中StdDevScale 的推荐值范围是-1~1,一般通过上面的例子可知,一般的明显的黑白过度处的标准差在50左右,乘以StdDevScale即-50 ~ 50 ,50的灰度差异,对于分割来说一般是够了的。

文档还说:推荐的值是0.2,如果参数StdDevScale太大,可能分割不出任何东西;如果参数StdDevScale太小(例如-2),可能会把整个图像区域全部输出,也就说达不到有效分割的目的。(……with 0.2 as a suggested value. If the parameter is too high or too low, an empty or full region may be returned.)

最后再看看是怎么分割像素的:

其中g(x,y)指的是原始图像当前像素的灰度值;m(x,y)指的是遍历像素时,掩膜覆盖的像素的平均灰度值(mean)。

LightDark = ‘dark’为例,当满足m(x,y) - g(x,y) ≥ v(x,y)时(即原始图像对应像素灰度比掩膜像素灰度均值低v(x,y)个灰度值以上),相应的灰度值低的暗像素被分割出来。

最后看几个例子体会一下:(对比之前的例子var_threshold (Image, Region, 4, 4, 0.2, 12, 'dark')的效果)

① 将AbsThreshold 由12改成30,此时分割出的区域变小。

 read_image (Image, 'C:/1.png')
var_threshold (Image, Region, , , 0.2, , 'dark')

② AbsThreshold 保持12不变,将StdDevScale由0.2改成0.7,此时分割出的区域变小。

③ 将参数改为var_threshold (Image, Region, 4, 4, -0.01, 12, 'dark'),此时分割出的区域大大增加,由前面的分析可知,此时参数AbsThreshold = 12无效,事实上,此时将AbsThreshold 改为1、50甚至200都对最终结果没有任何影响。

通过本人的分析,我认为StdDevScale取负值意义不大,因为它会分割出大量的不需要的区域,故一般推荐使用该算子时,StdDevScale取正值。

需要强调的是:在黑白过渡处,一般掩膜覆盖的像素的标准差较大,而在其他平缓的地方,标准差较小;因此最终采用的分割阈值随着掩膜在不断遍历像素的过程中,在(StdDevScale×标准差)和AbsThreshold 之间不断切换。

var_threshold和dyn_threshold的区别和联系:

dyn_threshold是将原图和滤波平滑后的图对比,var_threshold是将原图和对应像素掩膜覆盖的像素的平均灰度值对比。

在算子var_threshold中,如果参数StdDevScale = 0,那么就可以用动态阈值的方式非常近似地模拟。以下两种算法的效果极为类似:

 read_image (Image, 'C:/1.png')
var_threshold (Image, Region, , , , , 'dark')
 read_image (Image, 'C:/1.png')
mean_image (Image, ImageMean, , )
dyn_threshold (Image, ImageMean, RegionDynThresh, , 'dark')

两种方法的效果图:

那么当StdDevScale > 0 时,var_threshold对比dyn_threshold还存在什么优点呢?我认为是在黑白过渡处能减少分割出不需要的区域的概率。(因为黑白过渡处标准差大,当然前提是StdDevScale 不能设置得太小)

(网上关于这两个算子的系统介绍很少,我的理解难免有不足之处,欢迎大家回复讨论)

Halcon阈值化算子dual_threshold和var_threshold的理解的更多相关文章

  1. HALCON中的算子大全(中英对照)

    HALCON中的算子大全(中英对照) Chapter 1 :Classification1.1 Gaussian-Mixture-Models1.add_sample_class_gmm功能:把一个训 ...

  2. OpenCV3编程入门笔记(4)腐蚀、膨胀、开闭运算、漫水填充、金字塔、阈值化、霍夫变换

    腐蚀erode.膨胀dilate 腐蚀和膨胀是针对图像中的白色部分(高亮部分)而言的,不是黑色的.除了输入输出图像外,还需传入模板算子element,opencv中有三种可以选择:矩形MORPH_RE ...

  3. 【学习opencv第七篇】图像的阈值化

    图像阈值化的基本思想是,给定一个数组和一个阈值,然后根据数组中每个元素是低于还是高于阈值而进行一些处理. cvThreshold()函数如下: double cvThreshold( CvArr* s ...

  4. 灰度图像阈值化分割常见方法总结及VC实现

    转载地址:http://blog.csdn.net/likezhaobin/article/details/6915755 在图像处理领域,二值图像运算量小,并且能够体现图像的关键特征,因此被广泛使用 ...

  5. S0.4 二值图与阈值化

    目录 二值图的定义 二值图的应用 阈值化 二值化/阈值化方法 1,无脑简单判断 opencv3函数threshold()实现 2,Otsu算法(大律法或最大类间方差法) OpenCV3 纯代码实现大津 ...

  6. opencv学习之路(13)、图像阈值化threshold

    一.图像阈值化简介 二.固定阈值 三.自适应阈值 #include<opencv2/opencv.hpp> using namespace cv; void main(){ Mat src ...

  7. opencv2函数学习之threshold:实现图像阈值化

    在opencv2中,threshold函数可以进行阈值化操作. double threshold( const Mat& src, Mat& dst, double thresh,do ...

  8. 图像阈值化-threshold、adaptivethreshold

    在图像处理中阈值化操作,从一副图像中利用阈值分割出我们需要的物体部分(当然这里的物体可以是一部分或者整体).这样的图像分割方法是基于图像中物体与背景之间的灰度差异,而且此分割属于像素级的分割.open ...

  9. opencv之图像阈值化处理

    一.函数简介 1.threshold-图像简单阈值化处理 函数原型:threshold(src, thresh, maxval, type, dst=None) src:图像矩阵 thresh:阈值 ...

随机推荐

  1. Linux运维学习笔记-文件系统知识体系总结

    文件系统知识总结 新买的硬盘要存放数据需要怎么做? 首先将硬盘装机做RAID,做完RAID后进行分区,分完区后格式化创建文件系统,最后存放数据. 硬盘的内外部结构: 物理形状: 接口类型: IDE(I ...

  2. Python 傅里叶分析

    0. 一维序列卷积 np.convolve,注意 same/valid参数下(默认为 full),序列卷积出的结果的长度: >> np.convolve([1, 2, 3], [0, 1, ...

  3. VMware ESXi 网卡

    esxcfg-vswitch -A "VMkernel09" vswitch0 esxcfg-vmknic -a "VMkernel09" -i 172.10. ...

  4. 总是有人问我,那你能造出你自己都搬不动的石头吗? 我说不能,但我能写出个我自己都无法 fix 的 bug。

    总是有人问我,那你能造出你自己都搬不动的石头吗? 我说不能,但我能写出个我自己都无法 fix 的 bug.

  5. ThinkJava-压缩

    尽管存在许多种压缩算恙,但是Zip和GZIP可能是最常用的.因此我们可以很容易地使用多 种可读写这些格式的工具来操纵我们的压缩数据.   1 用GZIP进行简单压缩 GZIP接口非常简单, 因此如果我 ...

  6. java wab----遇到经常用到集合list/map/

    List与Vector的区别: vector适用:对象数量变化少,简单对象,随机访问元素频繁 list适用:对象数量变化大,对象复杂,插入和删除频] List首先是链表,它的元素不是连续的.vecto ...

  7. Java-Runoob-高级教程-实例-环境设置实例:3.Java 实例 - 如何执行指定class文件目录(classpath)?

    ylbtech-Java-Runoob-高级教程-实例-环境设置实例:3.Java 实例 - 如何执行指定class文件目录(classpath)? 1.返回顶部 1. Java 实例 - 如何执行指 ...

  8. jemalloc内存分配器详解

    前言 C 中动态内存分配malloc 函数的背后实现有诸派:dlmalloc 之于 bionic:ptmalloc 之于 glibc:allocation zones 之于 mac os x/ios: ...

  9. new 运算符干了什么

    为了追本溯源, 我顺便研究了new运算符具体干了什么?发现其实很简单,就干了三件事情. var obj = {}; obj.__proto__ = F.prototype; F.call(obj); ...

  10. Advanced Simulation Library(ASL)&& An adaptive and distributed-memory parallel implementation of the immersed boundary (IB) method (IBAMR)

    How to install asl and ibamr tools: ASL 和 IBAMR 都是有限元分析的工具,流体力学等,ASL可以使用GPU加速计算, 主机配置,i7 6代,1060, 32 ...