阈值化分割(二)OTSU法-附Python实现
来源:互联网 发布:淘宝考试以下不是催情 编辑:程序博客网 时间:2024/06/07 09:57
阈值化分割(二)OTSU法
本人邮箱:sylvester0510@163.com,欢迎交流讨论,
欢迎转载,转载请注明网址http://blog.csdn.net/u010128736/
一、OTSU法(大津阈值分割法)介绍
OTSU算法是由日本学者OTSU于1979年提出的一种对图像进行二值化的高效算法,是一种自适应的阈值确定的方法,又称大津阈值分割法,是最小二乘法意义下的最优分割。
二、单阈值OTSU法
设图像包含L个灰度级,灰度值为i的像素点个数为Ni,像素总点数为:
则灰度值为i的点的概率为:
根据期望公式,图像灰度的均值为:
按图像的灰度特性,使用阈值T将图像分成目标c0和背景c1两类,则ω0(T)和ω1(T)分别表示阈值为T时,c0和c1发生的概率,即:
c0和c1的均值为:
σ^2(T)表示直方图中阈值为T的类间方差,定义为:
最优阈值定义为类间方差最大时对应的T值,即:
下面给出python源代码。
#coding:utf-8import cv2import numpy as npfrom matplotlib import pyplot as pltimage = cv2.imread("E:/python/cv/OTSU/test.jpg")gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)plt.subplot(131), plt.imshow(image, "gray")plt.title("source image"), plt.xticks([]), plt.yticks([])plt.subplot(132), plt.hist(image.ravel(), 256)plt.title("Histogram"), plt.xticks([]), plt.yticks([])ret1, th1 = cv2.threshold(gray, 0, 255, cv2.THRESH_OTSU) #方法选择为THRESH_OTSUplt.subplot(133), plt.imshow(th1, "gray")plt.title("OTSU,threshold is " + str(ret1)), plt.xticks([]), plt.yticks([])plt.show()
结果如下所示。可以看到,使用OTSU法计算出来的阈值为165。
三、多阈值OTSU法
将单阈值的OTSU推广到多阈值的图像分割中,假设将图像直方图分为m+1类,对应的阈值为T1,T2,···,Tm。则最大类间方差为:
其中,
为求得最优阈值,需要使用穷举搜索,随着m增大,计算量骤增。若使用牛顿迭代等优化搜索方法,容易陷入局部最优解。
四、遗传算法解OTSU
遗传算法是一种基于自然选择和群体遗传机理的搜索算法。它模拟了自然选择和自然遗传过程中发生的繁殖、交配和突变现象,将每一个可能的解看作是群体的一个个体,并将每个个体编码,根据设定的目标函数对每个个体进行评价,给出一个适应度值。开始时随机产生一些个体,利用遗传算子产生新一代的个体,新个体继承上一代的优良性状,逐步向更优解进化。由于遗传算法在每一代同时搜索参数空间的不同区域,从而能够使找到全局最优解的可能性大大增加。遗传算法属于启发式算法,无限趋紧最优解并收敛。
那么怎么将图像分割问题抽象成遗传问题,即怎么将问题编码成基因串,如何构造适应度函数来度量每条基因的适应度值。假设如上述三所示,将图像分为m+1类,则m个阈值按顺序排列起来构成一个基因串:
由于灰度为0~255,所以可以使用8位二进制代码表示每个阈值,此时每个基因串由长度为8*m个比特位的传组成。
将类间方差作为其适应度函数,类间方差越大,适应度函数值就越高。
python代码如下所示:
#coding:utf-8import cv2import numpy as npfrom matplotlib import pyplot as pltimport random#将不足8*m位的染色体扩展为8*m位def expand(k, m): for i in range(len(k)): k[i] = k[i][:2] + '0'*(8*m+2 - len(k[i])) + k[i][2:len(k[i])] return kdef Hist(image): a=[0]*256 h=image.shape[0] w=image.shape[1] MN=h*w average=0.0 for i in range(w): for j in range(h): pixel=int(image[j][i]) a[pixel]=a[pixel]+1 for i in range(256): a[i]=a[i]/float(MN) average=average+a[i]*i return a, average#解析多阈值基因串def getTh(seed, m): th = [0, 256] seedInt = long(seed, 2) for i in range(0, m): tmp = seedInt & 255 if tmp != 0: th.append(tmp) seedInt = seedInt >> 8 th.sort() return th#适应度函数 Ostu全局算法def fitness(seed, p, average, m): Var = [0.0] * len(seed) g_muT = 0.0 for i in range(256): g_muT = g_muT + i * p[i] for i in range(len(seed)): th = getTh(seed[i], m) for j in range(len(th)-1): w = [0.0] * (len(th)-1) muT = [0.0] * (len(th)-1) mu = [0.0] * (len(th)-1) for k in range(th[j], th[j+1]): w[j] = w[j] + p[k] muT[j] = muT[j] + + p[k] * k if w[j] > 0: mu[j] = muT[j] / w[j] Var[i] = Var[i] + w[j] * pow(mu[j] - g_muT, 2) return Var#选择算子 轮盘赌选择算法def wheel_selection(seed, Var): var = [0.0]*len(Var) s = 0.0 n = ['']*len(seed) sumV = sum(Var) for i in range(len(Var)): var[i] = Var[i]/sumV for i in range(1, len(Var)): var[i] = var[i] + var[i-1] for i in range(len(seed)): s = random.random() for j in range(len(var)): if s <= var[j]: n[i] = seed[j] return n#单点交叉算子def Cross(Next, m): for i in range(0, len(Next) - 1, 2): if random.random() < 0.7: if m > 2: tmp = Next[i][10:] Next[i] = Next[i][:10] + Next[i+1][10:] Next[i+1] = Next[i+1][:10] + tmp else: tmp = Next[i][6:] Next[i] = Next[i][:6] + Next[i+1][6:] Next[i+1] = Next[i+1][:6] + tmp return Next#变异算子def Variation(Next): for i in range(len(Next)): if random.random()<0.06: Next[i]=bin(long(Next[i],2)+2) return Next#多阈值分割def genetic_thres(image, k, m): th = image for i in range(image.shape[0]): for j in range(image.shape[1]): for t in range(1, len(k)-1): if k[t-1] <= image[i][j] < k[t]: th[i][j] = int(k[t-1]) return th# mainimagesrc = cv2.imread("E:/python/cv/OTSU/test2.jpg")gray = cv2.cvtColor(imagesrc, cv2.COLOR_BGR2GRAY)m = 3 #阈值数items_x = range(0, imagesrc.shape[0])items_y = range(0, imagesrc.shape[1])random.shuffle(items_x)random.shuffle(items_y)x = items_x[0:20*m] #产生随机x坐标y = items_y[0:20*m] #产生随机y坐标seed = []Var = 0.0times = 0k = 0P, average = Hist(gray) #计算直方图,P为各灰度的概率的数组,average为均值for i in range(0, 20): code = long(0) for j in range(0, m): code = code + gray[x[i*j]][y[i*j]] << j*8 #将阈值连起来组成一个8*m比特的基因串 seed.append(bin(code)) #生成第一代while times < 2000: Var = fitness(seed, P, average, m) Next = wheel_selection(seed, Var) Next = Cross(Next, m) Next = expand(Variation(Next), m) seed = Next times = times + 1for j in range(len(Var)): if Var[j] == max(Var): k = getTh(Next[j], m)print kplt.subplot(131), plt.imshow(imagesrc, "gray")plt.title("source image"), plt.xticks([]), plt.yticks([])plt.subplot(132), plt.hist(imagesrc.ravel(), 256)plt.title("Histogram"), plt.xticks([]), plt.yticks([])th1 = genetic_thres(gray, k, m)plt.subplot(133), plt.imshow(th1, "gray")titleName = ''for i in range(1, len(k)-1): titleName = titleName + str(k[i]) + ', 'titleName = titleName[:len(titleName)-2]plt.title("threshold is " + titleName), plt.xticks([]), plt.yticks([])plt.show()
这里使用的是标准二进制,若使用格雷码,应该能收敛得更好。结果如下所示:
- 阈值化分割(二)OTSU法-附Python实现
- 阈值化分割(二)OTSU法-附Python实现
- 阈值化分割(一)双峰法-附Python实现
- 阈值化分割(一)双峰法-附Python实现
- #Otsu双阈值的二值化分割(opencv2实现)
- 图像的二值化分割,otsu类间方差法
- 【OpenCV3图像处理】阈值化操作得到二值图像(附Otsu算法和三角法原理与源码)
- 自动阈值法:Otsu法 用MATLAB实现Otsu算法:
- 图像分割·阈值化分割
- 灰度图像阈值化分割常见方法总结及VC实现
- 灰度图像阈值化分割常见方法总结及VC实现
- 灰度图像阈值化分割常见方法总结及VC实现
- 灰度图像阈值化分割常见方法总结及VC实现
- 灰度图像阈值化分割常见方法总结及VC实现
- 灰度图像阈值化分割常见方法总结及VC实现
- 灰度图像阈值化分割常见方法总结及VC实现
- 灰度图像阈值化分割常见方法总结及VC实现
- 灰度图像阈值化分割常见方法总结及VC实现
- 【21.28%】【codeforces 707D】Persistent Bookcase
- Python学习笔记DAY3---函数
- @NotNull和@NotEmpty和@NotBlank区别
- JavaScript创建对象的方式
- C++之引用
- 阈值化分割(二)OTSU法-附Python实现
- 圆桌游戏(区间DP)
- jQuery-跑马灯(文字无缝向上翻动)(自已封装的第三个插件)
- MySQL 指南(一)
- JDBC-SQL注入问题
- new分配内存栈堆静态区的区别
- 【Day21】关于mysql数据库索引所涉及的一些知识(新)
- Unity5.4.1与NGUI出现的问题Ignoring menu item NGUI because it is in no submenu!
- 设计模式之原型模式20