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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

计算机视觉编程——图像聚类

發布時間:2025/4/5 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 计算机视觉编程——图像聚类 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

  • 圖像聚類
    • 1 K-means聚類
      • 1.1 SciPy聚類包
      • 1.2 圖像聚類
      • 1.3 像素聚類
    • 2 層次聚類
      • 2.1 圖像聚類
    • 3 譜聚類

圖像聚類

將物理或抽象對象的集合分成由類似的對象組成的多個類的過程被稱為聚類。由聚類所生成的簇是一組數據對象的集合,這些對象與同一個簇中的對象彼此相似,與其他簇中的對象相異。聚類可以用于識別、劃分圖像數據集、組織和導航,以及對聚類后的圖像進行相似性可視化。

1 K-means聚類

K-means聚類是一種將輸入數據劃分成k個簇的簡單的聚類方法。其算法要反復提煉初始評估的類中心:

  • 以隨機或猜測的方式初始化類中心
  • 將每個數據點歸并到離它最近的類中心所屬的類
  • 對所有屬于該類的數據點求平均,將平均值作為新的類中心
  • 重復步驟2,3直到收斂
  • K-means算法最大的缺陷在于必須預先設定聚類數k,如果選擇不恰當則會導致聚類出的結果很差。其優點是容易實現可以并行計算,并且對于很多別的問題不需要任何調整就能夠直接使用。

    1.1 SciPy聚類包

    SciPy矢量量化包scipy.cluster.vq中有K-means的實現,下面是使用方法:

    from scipy.cluster.vq import *class1 = 1.5 * randn(100, 2) class2 = randn(100, 2) + array([5, 5]) features = vstack((class1, class2))centroids, variance = kmeans(features, 2)code, distance = vq(features, centroids)figure() ndx = where(code == 0)[0] plot(features[ndx, 0], features[ndx, 1], '*') ndx = where(code == 1)[0] plot(features[ndx, 0], features[ndx, 1], 'r') plot(centroids[:, 0], centroids[:, 1], 'go')axis('off')show()

    上面的代碼生成兩類二維正態分布數據,用k=2對這些數據進行聚類。由于SciPy中實現的K-means會計算若干次,并選擇方差最小的結果,所以這里返回的方差并不是真正需要的。接下來使用SciPy包中的矢量量化函數對每個數據點進行歸類。為了將其可視化,可以畫出這些數據點以及最終的聚類中心。繪制的結果如下圖所示:

    圖1 對二維數據用K-means進行聚類

    1.2 圖像聚類

    使用來自字體數據集的fontinages的圖像的前40個主成分進行投影,用投影系數作為作為每幅圖像的向量描述。用pickle模塊載入模型文件,在主成分上對圖像進行投影,然后用下面的方法聚類:

    import imtools import pickle from scipy.cluster.vq import *imlist = imtools.get_imlist('selected_fontimages/') imnbr = len(imlist)with open('a_pca_modes.pkl', 'rb') as f:immean = pickle.load(f)V = pickle.load(f)immatrix = array([array(Image.open(im)).flatten() for im in imlist], 'f')immean = immean.flatten()projected = array([dot(V[:40], immatrix[i] - immean) for i in range(imnbr)])projected = whiten(projected)centroids, distortion = kmean(projected, 4)code, distance = vq(projected, centroids)

    上述代碼中的code變量中包含的是每幅圖像屬于哪個簇。設定聚類數為4,同時用SciPy的whiten()函數對數據“白化”處理,并進行歸一化操作,使每個特征具有單位方差。利用下面的代碼可視化聚類后的結果:

    for k in range(4):ind = where(code == k)[0]figure()gray()for i in range(minimum(len(ind), 40)):subplot(4, 10, i + 1)imshow(immatrix[ind[i]].reshape((25, 25)))axis('off')show()

    這里將每個簇顯示在一個獨立圖像窗口中,且在該圖形窗口中最多可以顯示40幅圖像。用Pylab的subplot()函數設定網格,聚成4類的可視化結果如圖所示:

    圖2 用40個主成分對字體圖像進行K-means聚類
    我們用PIL中的ImageDraw模塊進行可視化:

    h, w = 1200, 1200 img = Image.new('RGB', (w, h), (255, 255, 255)) draw = ImageDraw.Draw(img)draw.line((0, h / 2, w, h / 2), fill = (255, 0, 0)) draw.line((w / 2, 0, w / 2, h), fill = (255, 0, 0))scale = abs(projected).max(0) scaled = floor(array([(p / scale) * (w / 2 - 20, h / 2 - 20) + (w / 2, h / 2) for p in projected]))for i in range(imnbr):nodeim = Image.open(imlist[i])nodeim.thumbnail((25, 25))ns = nodeim.sizebox = (int(scaled[i][0] - ns[0] // 2), int(scaled[i][1] - ns[1] // 2),int(scaled[i][0] + ns[0] // 2 + 1), int(scaled[i][1] + ns[1] // 2 + 1))img.paste(nodeim, box)img.save('pca_font.jpg')

    得到的圖像如下圖所示:

    圖3 在主成分上投影的字體圖像
    這個圖像說明了,這些字體圖像在40維里的分布情況,二維投影后相似的字體圖像距離較近。

    1.3 像素聚類

    將圖像區域或像素合并成有意義的部分稱為圖像分割。除了在一些簡單的圖像上,單純在像素水平上應用K-means得出的結論往往是毫無意義的。要產生有意義的結果,往往需要更復雜的類模型而非平均像素色彩或空間一致性。

    下面的代碼示例載入一幅圖像,用一個步長為steps的方形網格在圖像上滑動,每滑一次對網格中圖像區域像素求平均值,將其作為新生成的低分辨率圖像對應位置處的像素值,并用K-means進行聚類:

    from scipy.cluster.vq import * from scipy.misc import imresizesteps = 50 im = array(Image.open('jimei_grey.jpg'))dx = im.shape[0] dy = im.shape[1]features = [] for x in range(steps):for y in range(steps):R = mean(im[x * dx: (x + 1) * dx, y * dy: (y + 1) * dy, 0])G = mean(im[x * dx: (x + 1) * dx, y * dy: (y + 1) * dy, 1])B = mean(im[x * dx: (x + 1) * dx, y * dy: (y + 1) * dy, 2])features.append([R, G, B])features = array(features, 'f')centroids, variance = kmeans(features, 3) code, distance = vq(features, centroids)codeim = code.reshape(steps, steps) codeim = imresize(codeim, im.shape[:2], interp = 'nearest')figure() imshow(codeim) show()

    K-means的輸入是一個有steps*steps行的數組,數組的每一行有3列,各列分別為區域塊R、G、B三個通道的像素平均值。為可視化最后的結果,我們用Scipy的imresize()函數在原圖像坐標中顯示這幅圖像。參數interp指定插值方法采用最近鄰差值,以便在類間進行變換時不需要引入新的像素值。結果如下圖所示:

    圖4 基于顏色像素值用K-means對像素聚類

    2 層次聚類

    層次聚類是另一種簡單但有效的聚類算法,其思想是基于樣本間成對距離建立一個簡相似性樹。該算法首先將特征向量距離最近的兩個樣本歸并為一組,并在樹中創建一個“平均”節點,將這兩個距離最近的樣本作為該“平均”節點的下的兒子節點。然后在剩下的包含任意平均節點的樣本中尋找下一個最近的對,重復進行前面的操作。在每一個節點處保存了兩個子節點之間的距離。遍歷整個樹,通過設定的閾值,遍歷過程可以在比閾值大的節點位置終止,從而提取出聚類簇。

    層次聚類有若干優點。例如,利用樹結構可以可視化數據間的關系,并顯示這些簇是如何關聯的。在樹中,一個好的特征向量可以給出一個很好的分離結果。另外一個優點是,對于給定的不同閾值,可以直接利用原來的樹而不需要重新計算。不足之處是,對于實際需要的聚類簇需要給出一個合適的閾值。

    from itertools import combinationsclass ClusterNode(object):def __init__(self,vec,left,right,distance=0.0,count=1):self.left = leftself.right = rightself.vec = vecself.distance = distanceself.count = count def extract_clusters(self,dist):""" Extract list of sub-tree clusters from hcluster tree with distance<dist. """if self.distance < dist:return [self]return self.left.extract_clusters(dist) + self.right.extract_clusters(dist)def get_cluster_elements(self):""" Return ids for elements in a cluster sub-tree. """return self.left.get_cluster_elements() + self.right.get_cluster_elements()def get_height(self):""" Return the height of a node, height is sum of each branch. """return self.left.get_height() + self.right.get_height()def get_depth(self):""" Return the depth of a node, depth is max of each child plus own distance. """return max(self.left.get_depth(), self.right.get_depth()) + self.distanceclass ClusterLeafNode(object):def __init__(self,vec,id):self.vec = vecself.id = iddef extract_clusters(self,dist):return [self] def get_cluster_elements(self):return [self.id]def get_height(self):return 1def get_depth(self):return 0def draw(self,draw,x,y,s,imlist,im):nodeim = Image.open(imlist[self.id])nodeim.thumbnail([20,20])ns = nodeim.sizeim.paste(nodeim,[int(x),int(y-ns[1]//2),int(x+ns[0]),int(y+ns[1]-ns[1]//2)])def L2dist(v1,v2):return sqrt(sum((v1-v2)**2))def L1dist(v1,v2):return sum(abs(v1-v2))def hcluster(features,distfcn=L2dist):distances = {}node = [ClusterLeafNode(array(f),id=i) for i,f in enumerate(features)]while len(node)>1:closest = float('Inf')for ni,nj in combinations(node,2):if (ni,nj) not in distances: distances[ni,nj] = distfcn(ni.vec,nj.vec)d = distances[ni,nj]if d<closest:closest = d lowestpair = (ni,nj)ni,nj = lowestpairnew_vec = (ni.vec + nj.vec) / 2.0new_node = ClusterNode(new_vec,left=ni,right=nj,distance=closest)node.remove(ni)node.remove(nj)node.append(new_node)return node[0]import hcluster from numpy.random import randn from pylab import * from PIL import Imageclass1 = 1.5 * randn(100, 2) class2 = randn(100, 2) + array([5, 5]) features = vstack((class1, class2))tree = hcluster.hcluster(features)clusters = tree.extract_clusters(5)print('number of clusters', len(clusters))for c in clusters:print(c.get_cluster_elements())

    代碼運行后在控制臺打印的結果如下:

    圖5 對隨機創建的二維數據點聚類
    理想情況下應該得到一個聚類簇,但是在實際數據中,可能會得到三類或者更多。這主要依賴于實際生成的二維數據。

    2.1 圖像聚類

    import os import hclusterpath = 'flickr-sunsets/' imlist = [os.path.join(path, f) for f in os.listdir(path) if f.endswith('.jpg')]features = zeros([len(imlist), 512]) for i, f in enumerate(imlist):im = array(Image.open(f))h, edges = histogramdd(im.reshape(-1, 3), 8, normed = True, range = [(0, 255), (0, 255), (0, 255)])features[i] = h.flatten()tree = hcluster.hcluster(features)

    將R、G、B三個顏色通道作為特征向量,將其傳遞到Numpy的histogramdd()中。該函數能夠計算多維直方圖。為了可視化聚類樹,可以畫出樹狀圖,這樣在判定給出的描述子向量好壞以及在特征場合考慮什么是相似的時候提供有用的信息。

    tree = hcluster.hcluster(projected)hcluster.draw_dendrogram(tree, imlist, filename = 'fonts.jpg')clusters = tree.extract_clusters(0.23 * tree.distance)for c in clusters:elements = c.get_cluster_elements()nbr_elements = len(elements)if nbr_elements > 3:figure()for p in range(minimum(nbr_elements, 20)):subplot(4, 5, p + 1)im = array(Image.open(imlist[elements[p]]))imshow(im)axis('off')show()

    使用上述代碼對前文的字體創建一個層次聚類后的樹狀圖:

    圖6 對字體圖像進行層次聚類后的樹狀圖

    3 譜聚類

    譜聚類與K-means和層次聚類方法截然不同。

    對于n個元素,相似矩陣是一個n*n的矩陣,矩陣每個元素表示兩兩之間的相似性分數。譜聚類是由相似性矩陣構建譜矩陣而得名的。對該譜矩陣進行特征分解得到的特征向量可以用于降維,然后聚類。其優點在于僅需輸入相似性矩陣,并且可以采用任意度量方式構建相似性矩陣。

    n = len(projected) S = array([[sqrt(sum((projected[i] - projected[j]) ** 2)) for i in range(n)] for j in range(n)], 'f')rowsum = sum(S, axis = 0) D = diag(1 / sqrt(rowsum)) I = identity(n) L = I - dot(D, dot(S, D))U, sigma, V = linalg.svd(L)k = 5 features = array(V[:k]).Tfeatures = whiten(features) centroids,distortion = kmeans(projected,k) code,distance = vq(projected,centroids)for c in range(k):ind = where(code==c)[0]figure()for i in range(minimum(len(ind),39)):im = Image.open('selected_fontimages/' + imlist[ind[i]])subplot(4,10,i+1)imshow(array(im))axis('equal')axis('off') show()

    上述代碼中使用兩兩間的歐式距離創建矩陣S,并對k個特征向量用常規的K-means進行聚類,最后繪制出這些聚類簇。

    圖7 用拉普拉斯矩陣的特征向量對字體圖像譜聚類

    《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀

    總結

    以上是生活随笔為你收集整理的计算机视觉编程——图像聚类的全部內容,希望文章能夠幫你解決所遇到的問題。

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