圖像識別sift+bow+svm


本文概述

利用SIFT特征進行簡單的花朵識別

SIFT算法的特點有:

  1. SIFT特征是圖像的局部特征,其對旋轉、尺度縮放、亮度變化保持不變性,對視角變化、仿射變換、噪聲也保持一定程度的穩定性;
  2. SIFT算法提取的圖像特征點數不是固定值,維度是統一的128維。
  3. 獨特性(Distinctiveness)好,信息量豐富,適用於在海量特征數據庫中進行快速、准確的匹配;
  4. 多量性,即使少數的幾個物體也可以產生大量的SIFT特征向量;
  5. 高速性,經優化的SIFT匹配算法甚至可以達到實時的要求;
  6. 可擴展性,可以很方便的與其他形式的特征向量進行聯合。

KMeans聚類獲得視覺單詞,構建視覺單詞詞典

現在得到的是所有圖像的128維特征,每個圖像的特征點數目還不一定相同(大多有差異)。現在要做的是構建一個描述圖像的特征向量,也就是將每一張圖像的特征點轉換為特征向量。這兒用到了詞袋模型,詞袋模型源自文本處理,在這兒用在圖像上,本質上是一樣的。詞袋的本質就是用一個袋子將所有維度的特征裝起來,在這兒,詞袋模型的維度需要我們手動指定,這個維度也就確定了視覺單詞的聚類中心數。

將圖像特征點映射到視覺單詞上,得到圖像的特征向量:

熟悉聚類算法的同學已經明白了,上面講的簇就是通過聚類算法得到的,聚類算法將類別相近,屬性相似的樣本框起來,是一種無監督學習算法。在本文中,我使用了Kmeans算法來聚類得到視覺單詞,通過聚類得到了聚類中心,通過聚類得到了表征詞袋的特征點。

我們得到k個聚類中心(一個聚類中心表征了一個維度特征,k由自己手動設置)和先前SIFT得到的所有圖片的特征點,現在就是要通過這兩項來構造每一張圖像的特征向量。
在本文中,構造的思路跟簡單,就是比對特征點與所有聚類中心的距離,將特征點分配到距離最近的特征項,比如經計算某特征點距離leg這個聚類中心最近,那么這個圖像中leg這個特征項+1。以此類推,每一張圖像特征向量也就構造完畢。

pickle讀取文件

pickle可以存儲什么類型的數據呢?

  1. 所有python支持的原生類型:布爾值,整數,浮點數,復數,字符串,字節,None。

  2. 由任何原生類型組成的列表,元組,字典和集合。

  3. 函數,類,類的實例

  4. pickle模塊中常用的方法有:

     1.pickle.dump(obj, file, protocol=None,)
    

    必填參數obj表示將要封裝的對象

    必填參數file表示obj要寫入的文件對象,file必須以二進制可寫模式打開,即“wb”

    可選參數protocol表示告知pickler使用的協議,支持的協議有0,1,2,3,默認的協議是添加在Python 3中的協議3

     2.pickle.load(file,*,fix_imports=True,encoding="ASCII", errors="strict")
    

    必填參數file必須以二進制可讀模式打開,即“rb”,其他都為可選參數

支持向量機

支持向量機的兩個參數(調參增大准確率)

SVM模型有兩個非常重要的參數C與gamma。其中 C是懲罰系數,即對誤差的寬容度。c越高,說明越不能容忍出現誤差,容易過擬合。C越小,容易欠擬合。C過大或過小,泛化能力變差

gamma是選擇RBF函數作為kernel后,該函數自帶的一個參數。隱含地決定了數據映射到新的特征空間后的分布,gamma越大,支持向量越少,gamma值越小,支持向量越多。支持向量的個數影響訓練與預測的速度。

此外大家注意RBF公式里面的sigma和gamma的關系如下:

這里面大家需要注意的就是gamma的物理意義,大家提到很多的RBF的幅寬,它會影響每個支持向量對應的高斯的作用范圍,從而影響泛化性能。我的理解:如果gamma設的太大,會很小,很小的高斯分布長得又高又瘦, 會造成只會作用於支持向量樣本附近,對於未知樣本分類效果很差,存在訓練准確率可以很高,(如果讓無窮小,則理論上,高斯核的SVM可以擬合任何非線性數據,但容易過擬合)而測試准確率不高的可能,就是通常說的過訓練;而如果設的過小,則會造成平滑效應太大,無法在訓練集上得到特別高的准確率,也會影響測試集的准確率。

算法流程:

  1. SIFT提取每幅圖像的特征點:

     import csv
     import os
     from sklearn.cluster import KMeans
     import cv2
     import numpy as np
     
     
     def knn_detect(file_list,cluster_nums, randomState = None):
         content = []
         input_x = []
         labels=[]
         features = []
         count = 0
         csv_file = csv.reader(open(file_list,'r'))
     	#讀取csv文件
         for line in csv_file:
             if(line[2] !='label'):
                 subroot = 'F:\\train\\g' + str(line[2])
     			#路徑拼接成絕對路徑
                 filename =os.path.join(subroot, line[1])
                 sift = cv2.xfeatures2d.SIFT_create(200)
                 img = cv2.imdecode(np.fromfile(filename,dtype=np.uint8),-1)
     			#用np讀圖像,避免了opencv讀取圖像失敗的問題
                 if img is not None:
     
                     gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
                     kpG, desG = sift.detectAndCompute(gray, None)
     				#關鍵點描述符
     
                     if desG is None:
     					#關鍵點不存在就結束循環
                         continue 
                     print(count)
                     count+=1
                     ll = np.array(line[2]).flatten()
                     labels.append(ll)
     				#得到標簽
                     features.append(desG) 
     				#得到圖像的特征矩陣
                     input_x.extend(desG)
         print(len(input_x))
         return features,labels,input_x
    
    
     #訓練集圖片處理
     des_list = []
     labelG = []
     input_x1 = []
     des_list,labelG,input_x1 = knn_detect('E:\\py\\train.csv',50)
     #測試機圖片處理
     festures_test = []
     labels_test  = []
     input_x2 = []
     features_test,labels_test,input_x2 = knn_detect('E:\\py\\test.csv',50)
    

結果截圖:

  1. 保存中間變量:

     #利用pickle保存中間變量
     import numpy as np
     import matplotlib.pyplot as plt
     import pandas as pd
     import pickle
     
     output = open('input_x2.pkl', 'wb')
     pickle.dump(input_x2, output)
     output.close()
     
     output = open('features_test.pkl', 'wb')
     pickle.dump(features_test, output)
     output.close()
     
     output = open('labels_test.pkl', 'wb')
     pickle.dump(labels_test, output)
     output.close()
     
     output = open('input_x22.pkl', 'wb')
     pickle.dump(input_x2, output,protocol=2)
     output.close()
    
  2. 將圖像特征點映射到視覺單詞上,得到圖像特征:

     df=open('input_x2.pkl','rb')#注意此處是rb
     #此處使用的是load(目標文件)
     input_x1=pickle.load(df)
     df.close()
     kmeans = KMeans(n_clusters = 50, n_jobs =4,random_state = None).fit(input_x1)
     #開四個線程加快計算
     centers = kmeans.cluster_centers_
    
  3. 將圖像特征點映射到視覺單詞上,得到圖像的特征向量:

     def des2feature(des,num_words,centures):
     '''
     des:單幅圖像的SIFT特征描述
     num_words:視覺單詞數/聚類中心數
     centures:聚類中心坐標  
     計算特征矩陣中特征點離聚類中心最近的加1 
     return: feature vector 1*num_words
     '''
     img_feature_vec=np.zeros([num_words])
     for fi in des:
         diffMat = np.tile(fi, (50, 1)) - centers
         sqSum = (diffMat**2).sum(axis=1)
         dist = sqSum**0.5
         sortedIndices = dist.argsort()
         idx = sortedIndices[0] # index of the nearest center
     	#排序得到距離最近的聚類中心坐標的索引
         img_feature_vec[idx] += 1
     return img_feature_vec
    
     def get_all_features(des_list,num_words):
     # 獲取所有圖片的特征向量
     allvec=np.zeros((len(des_list),num_words),'float32')
     for i in range(len(des_list)):
         if des_list[i].any()!=None:
             allvec[i]=des2feature(centures=centers,des=des_list[i],num_words=num_words)
     return allvec
    
     df=open('des_list.pkl','rb')#注意此處是rb
     #此處使用的是load(目標文件)
     des_list=pickle.load(df)
     df.close()
     a =get_all_features(des_list,50)
     print(len(a))
     output = open('特征向量.pkl', 'wb')
     pickle.dump(a, output)
     output.close()
    
  4. svm訓練,查看准確率:

     import numpy as np
     import matplotlib.pyplot as plt
     import pandas as pd
     import pickle
     from sklearn.preprocessing import StandardScaler
     df=open('label_train.pkl','rb')#注意此處是rb
     #此處使用的是load(目標文件)
     label_train=pickle.load(df)
     df.close()
     df=open('label_test.pkl','rb')#注意此處是rb
     #此處使用的是load(目標文件)
     label_test =pickle.load(df)
     df.close()
     sc = StandardScaler()
     X_train = sc.fit_transform(a)
     X_test = sc.fit_transform(b)
     
     from sklearn.svm import SVC
     classifier = SVC(C=15)
     #適當調整參數,不是一個固定值
     classifier.fit(X_train,label_train)
     
     y_pred = classifier.predict(X_test)
     
     print(classifier.score(X_train,label_train))
     from sklearn.metrics import classification_report
     print(classification_report(label_test,y_pred))
    

結果截圖:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM