1. 程式人生 > >基於遺傳算法的Ostu法在圖像分割中的應用

基於遺傳算法的Ostu法在圖像分割中的應用

編碼 分離 所有 遊走 oss 兩個 port sel cross

像素關系
相鄰像素
位於坐標(x,y)處的像素P有4個水平和垂直的相鄰像素,其坐標為:

(x+1,y),(x-1,y),(x,y+1),(x,y-1)

這組相鄰元素稱為P的4鄰域。用N4(P)表示。類似於十字形。

P的4個對角相鄰像素坐標如下:

(x+1,y+1),(x+1,y-1),(x-1,y+1),(x-1,y+1)

用ND(P)表示。這些點與N4(P)的4個點一起稱為P的8鄰域,用N8(P)表示。

鄰接,連通,區域和邊界

V是定義鄰接性的灰度值集合。在二值圖像中,如果把具有1值的像素歸諸於鄰接像素,則V={1}。共定義三種形式的鄰接:

A.4鄰接。如果q在集合N4(p)中,則具有V中數值的兩個像素p和q是4鄰接的。

B.8鄰接。如果q在集合N8(p)中,則具有V中數值的兩個像素p和q是8鄰接的。

C.m鄰接(混合鄰接)。如果q在集合N4(p)中,或q在ND(p)中,且集合N4(p)∩N4(q)中沒有來自V中數值的像素,則具有V中數值的兩個像素p和q是m鄰接的。(m鄰接的引進是為了消除8鄰接時產生的二義性)


從坐標為(x,y)的p像素點到坐標為(s,t)的q像素點的通路是特定的像素序列,其坐標序列為(x0,y0),(x1,y1),(x2,y2),...,(xn,yn)。其中(x0,y0)為p像素坐標,(xn,yn)為q像素坐標,且(xi-1,yi-1)和(xi,yi)是鄰接的。根據鄰接的類型,可以定義為4通路,8通路,m通路。

令S是圖像中的一個像素子集。對於S中的任何像素p,S中連通到該像素的像素集稱為S的連通分量。如果S僅有一個連通分量,則稱S為連通集。

分割簡介
假設一副圖像可以被分割K個非空的子集R1,R2,...,Rn。其中這些子集滿足以下條件:

灰度圖像一般是根據邊界或區域兩種情況進行分割,當區域之間的差別很大時,區域間的邊界就很明顯,這時就可以根據邊界進行分割,其優點在於:邊緣定位準確,運算速度快;其局限性在於:邊緣的連續性和封閉性難以保證,對於復雜圖像分割效果較差,出現如:邊緣模糊、邊緣丟失等現象。邊緣檢測方法常常依賴於邊緣檢測算子,從而找到圖像邊緣;常用的檢測算子有: Roberts(精度高、對噪聲敏感)、 Sobel(對噪聲具有一定平滑,但精度低)、 Prewitt、 Canny(檢測階躍型邊緣效果好,抗噪強)、 Laplacian 和 Marr 算子(即 LOG 算子,最早由 marr 等人提出,算法簡單,速度快、但對噪聲敏感)。

若邊界不是很明顯時,就可以根據同一區域內的像素具有相似性這一特征進行分割,常見的區域分割方法主要有: 區域生長法、分裂合並法和分水嶺分割方法。

Ostu基本方法
本文使用的Ostu方法是基於全局閾值處理的方法。該方法在類間方差最大的情況下是最佳的。其基本概念是好的閾值分類就它的像素灰度值而論應該是截然不同的,反過來說,就它的灰度值而言給出最好的類間分離的閾值就是好最好的閾值。除此之外,Ostu方法還有一個重要的特性,即它完全以在一副圖像的直方圖上執行計算為基礎,直方圖是很容易得到的一維陣列。

圖像歸一化的直方圖具有分量pi=ni/MN,ni表示灰度級為i的像素數。由此整幅圖像的平均灰度為

現若假定一個閾值K,由K把輸入圖像閾值化為兩類C1和C2,C1由圖像中灰度值在範圍[0,k]內的所有像素組成,C2由灰度值在範圍[k+1,L-1]的所有像素組成。則像素被分類到C1的概率為


直至級k的累積像素灰度均值為


類間方差由此給出


從而最佳閾值為K,就是其最大化類間反差。

遺傳算法
關於遺傳算法部分,可參照前面寫過的博文 《遺傳算法詳解》 。

遺傳算法Ostu的應用
在編碼方式上面選擇由8位二進制表示像素灰度值,同時使用類間方差作為適應度函數,對於選擇算子則使用輪盤賭的方法。

下面是算法的基本實現代碼

# -*- coding: cp936 -*-
import numpy as np
import cv2
import random
#將不足8位的染色體擴展為8位
def expand(k):
for i in range(len(k)):
k[i]=k[i][0:2]+‘0‘*(10-len(k))+k[i][2:len(k)]
return k
def 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)
#適應度算子 Ostu全局算法
def fitness(k,hist,averge):
Var=[0]*len(k)
Varg=0.0
for i in range(256):
Varg=Varg+pow((i-average),2)*hist[i]
for j in range(len(k)):
P1=0.0
m=0.0
for i in range(int(k[j],2)+1):
P1=P1+hist[i]
m=m+hist[i]*i
Var[j]=pow(average*P1-m,2)/(P1*(1-P1)*Varg+0.00001)
return Var
#選擇算子 輪盤賭選擇算法
def wheel_selection(k,Var):
var=[0.0]*len(Var)
s=0.0
n=[‘‘]*len(k)
for i in range(len(Var)):
var[i]=Var[i]/sum(Var)
for i in range(1,len(Var)):
var[i]=var[i]+var[i-1]
for i in range(len(k)):
s=random.random()
for j in range(len(var)):
if s<=var[j]:
n[i]=k[j]
return n
#變異算子
def Variation(Next):
for i in range(len(Next)):
if random.random()<0.06:
Next[i]=bin(int(Next[i],2)+2)
return Next
#交叉算子
def Cross(Next):
for i in range(len(Next)-1):
if random.random()<0.6:
Next[i]=Next[i][:5]+Next[i+1][5:8]+Next[i][8:10]
return Next
#im為讀取圖像的數據
#seed表示每一代將要進行選擇,復制,變異和交叉的個體
#last_fit和now_fit分別表示父子兩代群體的最大適應度
#k為在規定代數結束後,最大適應度個體的染色體表示,即為最佳閾值
a=r‘D:\Python27\0.jpg‘
im=cv2.imread(a,0)
items=range(0,min(im.shape))
random.shuffle(items)
x=items[0:20]
y=items[21:41]
seed=[]
last_fit=0.0
now_fit=0.0
Var=0.0
times=0
k=0
hist,average=Hist(im)
for i in range(0,20):
seed.append(bin(im[x[i]][y[i]]))
while times<20:
Var=fitness(seed,hist,average)
Next=wheel_selection(seed,Var)
Next=Cross(Next)
Next=expand(Variation(Next))
seed=Next
#Var=fitness(seed,hist,average)
last_fit=now_fit
now_fit=max(Var)
times=times+1
print max(Var)
for j in range(len(Var)):
if Var[j]==max(Var):
k=int(Next[j],2)
print k


下圖為閾值分割後的效果圖,在程序多次運行中,發現結果有時會出現隨機遊走的情況,這個可以通過改變交叉概率和變異概率等參數進行一定程度地改善。

參考資料:

[1] 圖像分割方法及性能評價綜述,丁亮,張永平,張雪英,中國科技論文在線

[2] 數字圖像處理,岡薩雷斯
---------------------
作者:sam-X
來源:CSDN
原文:https://blog.csdn.net/u010945683/article/details/41780491
版權聲明:本文為博主原創文章,轉載請附上博文鏈接!

基於遺傳算法的Ostu法在圖像分割中的應用