日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

otsu阈值分割

發布時間:2024/8/1 编程问答 47 豆豆
生活随笔 收集整理的這篇文章主要介紹了 otsu阈值分割 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、OTSU法(大津閾值分割法)介紹

??OTSU算法是由日本學者OTSU于1979年提出的一種對圖像進行二值化的高效算法,是一種自適應的閾值確定的方法,又稱大津閾值分割法,是最小二乘法意義下的最優分割。

二、單閾值OTSU法

??設圖像包含L個灰度級,灰度值為i的像素點個數為Ni,像素總點數為:

N=N0+N1+?+NL?1N=N0+N1+?+NL?1

下面給出python源代碼。

#coding:utf-8
import cv2
import numpy as np
from matplotlib import pyplot as plt

image = 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_OTSU
plt.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。則最大類間方差為:

σ2B(T?1,T?2,?,T?m)=max0T1T2?L?1{σ2B(T1,T2,?,Tm)}σB2(T1?,T2?,?,Tm?)=max0≤T1≤T2≤?≤L?1{σB2(T1,T2,?,Tm)}
??為求得最優閾值,需要使用窮舉搜索,隨著m增大,計算量驟增。若使用牛頓迭代等優化搜索方法,容易陷入局部最優解。

四、遺傳算法解OTSU

??遺傳算法是一種基于自然選擇和群體遺傳機理的搜索算法。它模擬了自然選擇和自然遺傳過程中發生的繁殖、交配和突變現象,將每一個可能的解看作是群體的一個個體,并將每個個體編碼,根據設定的目標函數對每個個體進行評價,給出一個適應度值。開始時隨機產生一些個體,利用遺傳算子產生新一代的個體,新個體繼承上一代的優良性狀,逐步向更優解進化。由于遺傳算法在每一代同時搜索參數空間的不同區域,從而能夠使找到全局最優解的可能性大大增加。遺傳算法屬于啟發式算法,無限趨緊最優解并收斂。

??那么怎么將圖像分割問題抽象成遺傳問題,即怎么將問題編碼成基因串,如何構造適應度函數來度量每條基因的適應度值。假設如上述三所示,將圖像分為m+1類,則m個閾值按順序排列起來構成一個基因串:

α={T1,T2,?,Tm}α={T1,T2,?,Tm}
由于灰度為0~255,所以可以使用8位二進制代碼表示每個閾值,此時每個基因串由長度為8*m個比特位的傳組成。

??將類間方差作為其適應度函數,類間方差越大,適應度函數值就越高。

??python代碼如下所示:

#coding:utf-8
import cv2
import numpy as np
from matplotlib import pyplot as plt
import random

#將不足8m位的染色體擴展為8m位
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 k

def Hist(image):
a=[0]256
h=image.shape[0]
w=image.shape[1]
MN=hw
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

<span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">256</span>):g_muT = g_muT + i * p[i]<span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(len(seed)):th = getTh(seed[i], m)<span class="hljs-keyword">for</span> j <span class="hljs-keyword">in</span> range(len(th)-<span class="hljs-number">1</span>):w = [<span class="hljs-number">0.0</span>] * (len(th)-<span class="hljs-number">1</span>)muT = [<span class="hljs-number">0.0</span>] * (len(th)-<span class="hljs-number">1</span>)mu = [<span class="hljs-number">0.0</span>] * (len(th)-<span class="hljs-number">1</span>)<span class="hljs-keyword">for</span> k <span class="hljs-keyword">in</span> range(th[j], th[j+<span class="hljs-number">1</span>]):w[j] = w[j] + p[k]muT[j] = muT[j] + + p[k] * k<span class="hljs-keyword">if</span> w[j] &gt; <span class="hljs-number">0</span>:mu[j] = muT[j] / w[j]Var[i] = Var[i] + w[j] * pow(mu[j] - g_muT, <span class="hljs-number">2</span>) <span class="hljs-keyword">return</span>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

# main
imagesrc = 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:20m] #產生隨機x坐標
y = items_y[0:20m] #產生隨機y坐標
seed = []
Var = 0.0
times = 0
k = 0
P, average = Hist(gray) #計算直方圖,P為各灰度的概率的數組,average為均值
for i in range(0, 20):
code = long(0)
for j in range(0, m):
code = code + gray[x[ij]][y[ij]] << 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 + 1

for j in range(len(Var)):
if Var[j] == max(Var):
k = getTh(Next[j], m)
print k

plt.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阈值分割的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。