超像素分割学习笔记
學習目標
掌握超像素分割的原理、超像素分割方法的推導過程以及實現方法
1.1 超像素
超像素是指將具有相似紋理、顏色、亮度等特征的相鄰像素聚合成某一個像素塊,結合超像素的思想,這樣可以使少量的像素塊代替原本大量的像素。
目前超像素廣泛應用于圖像分割、目標識別等領域。
1.2 SLIC
SLIC(Simple Linear IterativeClustering,簡單線性迭代聚類)是超像素分割中使用比較多的方法,主要特點(優點)如下:
1.基于LAB顏色空間
2.運行速度快,生成的超像素緊湊
3.思想比較簡單
1.3 SLIC實現的具體步驟
1.初始化種子點
在圖像內均勻分布種子點(與Kmeans不同)
若圖像像素為N*N,預想分為K個像素塊,則:
-
每個像素塊的初始大小為N?N/KN*N/KN?N/K
-
相鄰種子點間的步長S為 N?N/K\sqrt {N*N/K}N?N/K?(假設初始每個像素塊的大小是均勻的)
2.重新選擇種子點
結合圖像中的梯度信息,在n*n鄰域內重新選擇種子點(一般n取3)。重新選擇種子點是為了防止均勻初始化后的種子點處于邊緣或是噪聲,將種子點移動到梯度比較小的位置。
3.以各像素塊種子點為中心更新標簽
以超像素的種子點為中心,在其上下左右2S的范圍內搜索(和Kmeans 不同,這里的搜索不是全局范圍的)
4.計算距離
計算各像素點與種子點的距離,距離包括顏色距離與空間位置的距離。
顏色距離dcd_cdc?的計算方法如下:
lj?li)2+(ai?aj)2+(bi?bj)2\sqrt {l_j-l_i)^2+(a_i-a_j)^2+(b_i-b_j)^2}lj??li?)2+(ai??aj?)2+(bi??bj?)2?
空間距離dsd_sds?的計算方法如下:
(xj?xi)2+(yi?yj)2\sqrt {(x_j-x_i)^2+(y_i-y_j)^2}(xj??xi?)2+(yi??yj?)2?
總距離DDD的計算方法如下:
(dcm)2+(dsS)2\sqrt {(\frac{d_c}{m})^2+(\frac{d_s}{S})^2}(mdc??)2+(Sds??)2?
其中mmm為常數,取值范圍在[1,40],常以10代替
因為搜索范圍在種子點的[-2S,2S]內,有些像素點會被重復搜索到,所以應該同時記錄距離,最終取最小值對應的種子點作為其聚類中心
將上述3-4過程不斷迭代,一直到滿足最大迭代次數或者中心種子點不再發生變化為止。
5.增強連通性
經過迭代之后有可能會出現過分割、多連通、單個超像素被分割成多個不連續的超像素等,需要增強連通性
主要思路是:新建一張標記表,表內元素均為-1,按照“Z”型走向(從左到右,從上到下順序)將不連續的超像素、尺寸過小超像素重新分配給鄰近的超像素,遍歷過的像素點分配給相應的標簽,直到所有點遍歷完畢為止
2 實戰
import cv2 import numpy as np from skimage import img_as_float import matplotlib.pyplot as plt1.初始化種子點
def init_cluster(pic,n_segments):cluster_w,cluster_h=int(cluster_S/2),int(cluster_S/2) #計算出每個的長和寬center={}i=0while cluster_h<pic.shape[0]: #shape[0]是高度while cluster_w<pic.shape[1]:center[i]=[cluster_w,cluster_h,pic[cluster_w,cluster_h,0],pic[cluster_w,cluster_h,1],pic[cluster_w,cluster_h,2]]cluster_w=cluster_w+cluster_Si=i+1cluster_w=int(cluster_S/2)cluster_h=cluster_h+cluster_Sreturn center2.計算梯度
def caculate_grad(w,h):if h+1>=pic.shape[0] or w+1>=pic.shape[1]:w=w-2h=h-2grad=np.sum(pic[w+1,h+1,:]-pic[w,h,:])return grad3.在3*3鄰域內根據計算得到的梯度,更新種子點
def update_center(center):#更新中心點for i in range(0,len(center)):w,h=center[i][0],center[i][1] now_grad=caculate_grad(w,h) #計算當前的梯度for dw in range(-1,2): #在3*3鄰域內for dh in range(-1,2):new_grad=caculate_grad(w+dw,h+dh) #計算新梯度if new_grad<now_grad:now_grad=new_gradcenter[i]=[w+dw,h+dh,pic[w+dw,h+dh,0],pic[w+dw,h+dh,1],pic[w+dw,h+dh,2]]return center4.可視化種子點
def draw_center(center)for i in range(0,len(center)): cv2.circle(ori_pic,(center[i][0],center[i][1]),1, (255, 0, 0),4) #將初始化中心標出來fig=plt.figure()ax=fig.add_subplot(1,1,1)ax.imshow(ori_pic)plt.show() n_segments=50 ori_pic=cv2.imread('Lenna.png') ori_pic=cv2.cvtColor(ori_pic,cv2.COLOR_BGR2RGB) pic=cv2.cvtColor(ori_pic,cv2.COLOR_BGR2LAB) cluster_shape=pic.shape[0]*pic.shape[1]/n_segments #每個超像素塊中包含的像素數 cluster_S=int(np.sqrt(cluster_shape)) #超像素塊的長/寬/初始種子點之間的距離(假設形狀規則) center=init_cluster(pic,n_segments) #初始化中心 center=update_center(center) #更新中心,避免中心在梯度高(噪聲點等) draw_center(center) #可視化初始中心點得到初始的種子點(已經進行了梯度更新,可以看出中心點分布不是絕對均勻)
5.初始化距離矩陣(用來存儲每個像素點與其中心點間的距離)
def init_distance():distance=[]for i in range(pic.shape[0]):distance_item=[np.inf for j in range(pic.shape[1])]distance.append(distance_item)return distance7.初始化像素矩陣(用來記錄每個像素塊中包含的具體像素位置)
def init_pixel():pixel={}for i in range(0,len(center)):pixel[i]=[]return pixel8.計算某像素與其種子點之間的距離(這里M取10)
def caculate_distance(w_,h_,center_):#根據顏色空間和像素位置進行更新color_dic=np.sqrt(np.sum(np.square(pic[w_,h_,:]-np.array(center_[2:]))))geo_dic=np.sqrt(np.sum(np.square(np.array([w_,h_])-np.array(center_[:2]))))dis=np.sqrt(np.square(color_dic/10)+np.square(geo_dic/cluster_S))return dis9.計算各個像素點所屬的標簽(即所屬種子點)
def get_cluster(center,distance,label,pixel):for i in range(0,len(center)):for dw in range(center[i][0]-2*cluster_S,center[i][0]+2*cluster_S): #在2S范圍內if dw<0 or dw>=pic.shape[0]: continue for dh in range(center[i][1]-2*cluster_S,center[i][1]+2*cluster_S):if dh<0 or dh>=pic.shape[1]: continuedis=caculate_distance(dw,dh,center[i])#計算距離if dis<distance[dw][dh]:distance[dw][dh]=dislabel[(dw,dh)]=center[i] #記錄當前的中心點for j in list(pixel.values()):if(dw,dh) in j:#若該像素點之前已經隸屬于某個中心,需要先將其去掉,再添加至新的中心j.remove((dw,dh))pixel[i].append((dw,dh))return label,distance,pixel10.更新各超像素的中心(所屬種子點)
def update_cluster(center,pixel):#更新中心for i,item in enumerate(pixel.values()): #{1:[(),()]w,h=0,0for j in item: w+=j[0]h+=j[1]center_w=int(w/len(item))center_h=int(h/len(item))center[i]=[center_w,center_h,pic[center_w,center_h,0],pic[center_w,center_h,1],pic[center_w,center_h,2]]return center11.可視化超像素分割結果
def save_cluster(center,pixel):image_arr = np.copy(ori_pic)for i,item in enumerate(pixel.values()): #{1:[(),()]for j in item:image_arr[j[0],j[1],0]=image_arr[center[i][0],center[i][1],0]image_arr[j[0],j[1],1]=image_arr[center[i][0],center[i][1],1]image_arr[j[0],j[1],2]=image_arr[center[i][0],center[i][1],2]fig=plt.figure()ax=fig.add_subplot(1,1,1)ax.imshow(image_arr)plt.show() label={} distance=init_distance() pixel=init_pixel()#初始化簇內的像素點 形如:{0: [], 1: [], 2: [], 3: [], 4: [], 5: []}for epoch in range(10):#循環迭代十次old_label=labelprint('epoch:',epoch)label,distance,pixel=get_cluster(center,distance,old_label,pixel)center=update_cluster(center,pixel)save_cluster(center,pixel)最終可以得到超像素分割的結果為:
調包:
參考文獻
[1] Achanta,Radhakrishna, et al. “SLIC superpixels compared to state-of-the-artsuperpixel methods.” Pattern Analysis and Machine Intelligence, IEEETransactions on 34.11 (2012): 2274-2282.
總結
- 上一篇: VGG16网络,VGG19
- 下一篇: 免费下载外文文献