ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 效率神器,一键搞定繁琐工作
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
让更多数据处理,一键完成 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
查看: 12757|回复: 14

[分享] 灰度图片二值化

[复制链接]

TA的精华主题

TA的得分主题

发表于 2015-8-11 13:19 | 显示全部楼层 |阅读模式
本帖已被收录到知识树中,索引项:图像处理和GDI
图像的二值化,就是将图像上的像素点的灰度值设置为0或255,也就是将整个图像呈现出明显的只有黑和白的视觉效果。

一幅图像包括目标物体、背景以及噪声,要想从多值二值化的数字图像中直接提取出目标物体,最常用的方法就是设定一个阈值T,用T将图像的数据分成两部分:大于T的像素群和小于T的像素群。
这是研究灰度变换的最特殊的方法,称为图像的二值化(BINARIZATION)



根据阈值选取的不同,二值化的算法分为固定阈值和自适应阈值两种方式。
比较常用的二值化方法则有:双峰法、P参数法、迭代法、OTSU法(即大律法)和Kittler法等

本帖将就双峰法、迭代法、大律法和kittler法等,进行举例。

TA的精华主题

TA的得分主题

 楼主| 发表于 2015-8-11 13:40 | 显示全部楼层
本帖最后由 wangg913 于 2015-8-11 14:11 编辑

数据准备

图像的二值化过程,是对灰度图像进行二值化,因此首先要将真彩--色图像像素转换为灰度图。

  1. Private Sub getGreyScale(Col() As Byte)     '真彩---色转换为灰度色
  2.     Dim I As Long, J As Long
  3.     Dim R As Long, G As Long, B As Long
  4.     ReDim lGreyLvl(lWid - 1, lHei - 1)
  5.     For I = 0 To lHei - 1           '加权平均法灰度转换
  6.         For J = 0 To lWid - 1
  7.             R = Col(J * 3 + 2, I)
  8.             G = Col(J * 3 + 1, I)
  9.             B = Col(J * 3, I)
  10.             lGreyLvl(J, I) = (R * 77 + G * 150 + B * 29) \ 256
  11.         Next
  12.     Next
  13. End Sub
复制代码


lWid 为图片的宽度
lHei 为图片的高度
数组 col(BytesPerLine-1,lHei-1) 由BMP图片文件读入
BytesPerLine 为图片的宽度字节数,为适应数据存储的方式,字节数必须字为4的倍数,因此:
BytesPerLine =  int ((lWid * 3 +3) / 4) * 4

数组 lGreyLvl(J, I) 为使用加权平均法计算求得的灰度值

评分

1

查看全部评分

TA的精华主题

TA的得分主题

 楼主| 发表于 2015-8-11 13:44 | 显示全部楼层
本帖最后由 wangg913 于 2015-8-11 13:46 编辑

生成灰度直方图

生成灰度直方图,就是统计图片的灰度值的分布。
因为24位真彩*色只有256级灰度,即灰度值在 0~255 之间

获取灰度直方图的代码如下:
  1. Private Sub GetHistogram()      '获取直方图
  2.     Dim E As Long, F As Long
  3.     For E = 0 To 255            '直方图初始化
  4.         lHistogram(E) = 0
  5.     Next
  6.     For E = 0 To lWid - 1
  7.         For F = 0 To lHei - 1
  8.             lHistogram(lGreyLvl(E, F)) = lHistogram(lGreyLvl(E, F)) + 1
  9.         Next
  10.     Next
  11. End Sub
复制代码

评分

1

查看全部评分

TA的精华主题

TA的得分主题

 楼主| 发表于 2015-8-11 14:09 | 显示全部楼层
本帖最后由 wangg913 于 2015-8-11 15:47 编辑

迭代法获取最佳阈值
首先假定一个阈值 T0
T0为最大灰度值和最小灰度值的平均值
即,分别求出最大灰度值 iMax 和最小灰度值 iMin
  1. T0=(iMax + iMin) \ 2
复制代码
第二步,根据 T0 将灰度图片分为前景色和背景色,分别求出前景色平均灰度值AvgFore和背景色的平均灰度值AvgBack
  1. AvgBack = (∑( i = iMin to T0) i * Histogram(i)) / (∑( i = iMin to T0)  Histogram(i))
复制代码
  1. AvgFore = (∑( i =(T0 + 1) to iMax) i * Histogram(i)) / (∑( i = (T0 + 1) to iMax)  Histogram(i))
复制代码
然后求得迭代阈值 T1,并进行判断是否为目标阈值。
  1. T1 = (AvgBack + AvgFore) \ 2
复制代码
如果 T1 = T0 ,则 T1 即为目标阈值;
否则,T0 = T1,继续从第二步进行迭代取值,直至 T1 = T0 为止。
完整代码如下:
  1. Private Function Iteration() As Boolean     '迭代法获取最佳阈值
  2.     Dim A As Long, B As Long, C As Long
  3.     Dim iMin As Integer, iMax As Integer
  4.     Dim iItThreshold As Integer, bError As Byte
  5.     Dim lIntegralBack As Long, lIntegralFore As Long
  6.     Dim lSumBack As Long, lSumFore As Long
  7.     Dim dAvgBack As Double, dAvgFore As Double
  8.     For A = 0 To lWid - 1
  9.         For B = 0 To lHei - 1
  10.             If iMin > lGreyLvl(A, B) Then
  11.                 iMin = lGreyLvl(A, B)
  12.             End If
  13.             If iMax < lGreyLvl(A, B) Then
  14.                 iMax = lGreyLvl(A, B)
  15.             End If
  16.         Next
  17.     Next
  18.     bError = 1      '设定误差范围
  19.     C = 0
  20.     iThreshold = 0
  21.     iItThreshold = (iMax + iMin) \ 2        '设定初始迭代阈值为最大灰度值和最小灰度值的均值
  22.     Do While Math.Abs(iThreshold - iItThreshold) > bError
  23.         lSumBack = 0
  24.         lSumFore = 0
  25.         lIntegralBack = 0
  26.         lIntegralFore = 0
  27.         For A = iMin To iItThreshold                '背景色阈值
  28.             lSumBack = lSumBack + lHistogram(A)
  29.             lIntegralBack = lIntegralBack + lHistogram(A) * A
  30.         Next
  31.         For B = iItThreshold + 1 To iMax            '前景色阈值
  32.             lSumFore = lSumFore + lHistogram(B)
  33.             lIntegralFore = lIntegralFore + lHistogram(B) * B
  34.         Next
  35.         dAvgBack = IIf(lSumBack <> 0, lIntegralBack / lSumBack, 0)
  36.         dAvgFore = IIf(lSumFore <> 0, lIntegralFore / lSumFore, 0)
  37.         iThreshold = iItThreshold
  38.         iItThreshold = (dAvgBack + dAvgFore) \ 2        '渐进逼近目标阈值
  39.         C = C + 1
  40.         If C > 999 Then
  41.             Iteration = False
  42.             Exit Function
  43.         End If
  44.     Loop
  45.     Iteration = True
  46. End Function
复制代码

评分

1

查看全部评分

TA的精华主题

TA的得分主题

 楼主| 发表于 2015-8-11 15:01 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
本帖最后由 wangg913 于 2015-8-11 15:52 编辑

大律法二值化大津法由由日本学者大津(Nobuyuki Otsu)于1979年提出的。
对于图像,假设 T 为前景与背景的分割阈值,假设前景点数占图像比例为w0,平均灰度为 u0;背景点数占比为w1,平均灰度为u1。
因此,图像的总平均灰度为:
  1. u = w0 * u0 + w1 * u1
复制代码
从最小灰度值到最大灰度值遍历 T 阈值,当 T 使得值 g=w0 * (u0 - u)^2+w1 * (u1 - u) ^ 2 最大时,T即为分割的最佳阈值。
该式实际上是类间方差值,因为方差是灰度分布均匀性(或偏离程度)的一种度量。
方差值越大,说明构成图像的前景和背景两部分差别越大, 当部分前景错分为背景或部分背景错分为前景时都会导致两部分差别变小,因此使类间方差最大的分割意味着错分概率最小。
直接应用大津法计算量是较大,因此通常采用其等价的公式
  1. g = w0 * w1 * (u0 - u1)^2
复制代码
代码如下:
  1. Private Sub OtsuBinarization()      '大律法二值化
  2.     Dim lTotal As Long, lSum As Long
  3.     Dim lTotalBack As Double, lSumBack As Double
  4.     Dim du As Double, dv As Double
  5.     Dim dOstu As Double, dMaxOstu As Double
  6.     Dim A As Long, B As Long
  7.     iThreshold = 0
  8.     For A = 0 To 255
  9.         lTotal = lTotal + lHistogram(A)
  10.         lSum = lSum + lHistogram(A) * A
  11.     Next
  12.     For A = 0 To 255
  13.         lTotalBack = 0
  14.         lSumBack = 0
  15.         For B = 0 To A
  16.             lTotalBack = lTotalBack + lHistogram(B)
  17.             lSumBack = lSumBack + lHistogram(B) * B
  18.         Next
  19.         du = IIf(lTotalBack > 0, lSumBack / lTotalBack, 0)
  20.         If lTotal - lTotalBack > 0 Then
  21.             dv = (lSum - lSumBack) / (lTotal - lTotalBack)
  22.         Else
  23.             dv = 0
  24.         End If
  25.         dOstu = lTotalBack * (lTotal - lTotalBack) * (du - dv) * (du - dv)
  26.         If dOstu > dMaxOstu Then
  27.             dMaxOstu = dOstu
  28.             iThreshold = A
  29.         End If
  30.     Next
  31. End Sub
复制代码
iThreshold 即为最终阈值。

TA的精华主题

TA的得分主题

 楼主| 发表于 2015-8-11 15:22 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
本帖最后由 wangg913 于 2015-8-11 15:35 编辑

双峰法二值化
双峰法的原理极其简单,它认为图像由前景和背景组成,在灰度直方图上,前后二景都形成高峰,在双峰之间的最低谷处就是图像的阈值所在。
双峰法在应对前景和背景对比强烈时效果较好,否则基本无效。
为改善这一特点,本帖对灰度直方图使用累积法进行平滑化,然后迭代求阈,效果有所改善。
  1. Private Function PeakValley() As Boolean     '双峰法迭代获取最佳阈值
  2.     Dim A As Long, C As Long
  3.     Dim dSubHisto(255) As Double, dConHisto(255) As Double
  4.     Dim isPeak As Boolean
  5.    
  6.     For A = 0 To 255
  7.         dSubHisto(A) = lHistogram(A)
  8.         dConHisto(A) = lHistogram(A)
  9.     Next
  10.     Do While Not HasTwoPeaks(dConHisto)
  11.         dConHisto(0) = (dSubHisto(0) * 2 + dSubHisto(1)) / 3        '灰度直方图连续三个灰度值进行平滑化
  12.         For A = 1 To 255 - 1
  13.             dConHisto(A) = (dSubHisto(A - 1) + dSubHisto(A) + dSubHisto(A + 1)) / 3
  14.         Next
  15.         dConHisto(A) = (dSubHisto(A - 1) + dSubHisto(A) * 2) / 3
  16.         For A = 0 To 255                                            '备份平滑化后的直方图,以备再次迭代
  17.             dSubHisto(A) = dConHisto(A)
  18.         Next
  19.         C = C + 1
  20.         If C > 999 Then
  21.             PeakValley = False
  22.             Exit Function
  23.         End If
  24.     Loop
  25.     isPeak = False
  26.     For A = 1 To 255 - 1
  27.         If (dConHisto(A - 1) < dConHisto(A)) And (dConHisto(A + 1) < dConHisto(A)) Then     '判断首峰
  28.             isPeak = True
  29.         End If
  30.         If isPeak And (dConHisto(A - 1) >= dConHisto(A)) And (dConHisto(A + 1) >= dConHisto(A)) Then        '二峰
  31.             PeakValley = True
  32.             iThreshold = A - 1
  33.             Exit Function
  34.         End If
  35.     Next
  36.     PeakValley = False
  37. End Function

  38. Private Function HasTwoPeaks(Histo() As Double) As Boolean      '是否存在双峰,超过2个或只有1个峰,都返回否定
  39.     Dim A As Integer
  40.     Dim PeakNum As Byte
  41.     For A = 1 To 255 - 1
  42.         If (Histo(A - 1) < Histo(A)) And (Histo(A + 1) < Histo(A)) Then
  43.             PeakNum = PeakNum + 1
  44.             If PeakNum > 2 Then
  45.                 HasTwoPeaks = False
  46.                 Exit Function
  47.             End If
  48.         End If
  49.     Next
  50.     HasTwoPeaks = (PeakNum = 2)
  51. End Function
复制代码

评分

1

查看全部评分

TA的精华主题

TA的得分主题

发表于 2015-8-11 16:56 | 显示全部楼层
头版,都开始研究这个啦,哇塞
完全看不懂

点评

娱乐一下  发表于 2015-8-11 17:17

TA的精华主题

TA的得分主题

发表于 2015-8-13 18:50 | 显示全部楼层
好高深的样子,我要收藏慢慢看哈{:soso_e113:}

TA的精华主题

TA的得分主题

发表于 2016-7-1 22:46 | 显示全部楼层
版主:要是能传上实例,就更好了,不知道怎么调用,好像没有调用文件的picture吗?文章发表的时间不长。
版主的电脑里应该保存的,怎么调用,请版主指导!

TA的精华主题

TA的得分主题

发表于 2017-1-9 17:47 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
求版主上传实例供学习
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

手机版|关于我们|联系我们|ExcelHome

GMT+8, 2024-12-25 15:20 , Processed in 0.040861 second(s), 9 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

沪公网安备 31011702000001号 沪ICP备11019229号-2

本论坛言论纯属发表者个人意见,任何违反国家相关法律的言论,本站将协助国家相关部门追究发言者责任!     本站特聘法律顾问:李志群律师

快速回复 返回顶部 返回列表