北科資工二多媒體技術與應用 第六周團隊作業 - 對兩類別影像進行 SIFT 特徵提取並送入SVM分類

筆記說明

此筆記用途在於台北科技大學資訊工程系大二下多媒體技術與應用作業紀錄
並非所有人都適用,部分對我而言稍加容易的內容並不會寫在此內。
這是學習後心得的筆記,可能不太適用會未來的學生

由於我沒有學習過裡面的理論,因此這是資工大二學生透過網路與自身理解的筆記,學習價值並不高、且可能擁有大量錯誤。

SIFT 簡介

SIFT(Scale Invariant Feature Transform) 中文名為尺度不變特徵轉換,是機器用來偵測或描述影響的演算法,SIFT 對旋轉、尺度縮放、亮度變化有良好的完整性。

由 David G.Lowe 教授發表。

SIFT 優點

  • 局部特徵、旋轉、尺度縮放、亮度變化,有很好的完整性;對視角變化、仿射變換、噪聲,也有一定的穩定度
  • 保留圖片獨特性、訊息量大,適合大量特徵,可進行快速、準確的匹配
  • 如果只有少數幾張圖片也可以產生大量的 SIFT 特徵
  • 最佳化的 SIFT 不需要花費時間就能完成
  • 方便與其他特徵向量結合

題目說明

如果不想看那麼多話,建議可以直接略過。總之就像標題說的,對兩類別影像進行 SIFT 特徵提取並送入SVM分類。

資料集

這裡我們採用兩組資料集來使用 SIFT 特徵辨識

連結為個人在 google 圖片進行搜尋時的圖片,如果有版權冒犯請通知我,我會進行下架

心得

自從上次學習過天佑的程式碼加上這次助教 pdf 詳細的解說後,我對於機器學習有著還不錯的了解,但只僅限在應用上XD,大該知道要怎麼進行訓練、辨識了XD。

總之,謝謝在學習多媒體技術與應用時一路幫助過我的人,如果沒有他們幫助我,我可能到現在還甚麼都不會。

其中,python 有兩個語法很相像,一個是 sklearn.cluster.KMeans 另一個是 scipy.cluster.vq.kmeans,我們要使用的是後者,請大家不要搞錯喔XD。

我自己就搞錯了,花一堆時間除錯QQQQ

也謝謝發明此演算法的大師,可以讓我運用,讓我學會此應用方式,沒有大家我都做不好QQ。

參考來源

北科大二下多媒體技術與應用 L6 SIFT 特徵 PDF (幫最多忙)
scipy.cluster.vq.kmeans¶ by sciPy.org
sklearn.cluster.KMeans by scikit learn
np.vstack, np.hstack by cltdevelop

程式碼

直接透過程式碼來進行說明,相信會比較好理解。

程式碼我將它分為兩部分,其中一份為 function,另一份則為主要的程式檔案

function

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# -*- coding: utf-8 -*-
"""
Created on Sun Apr 18 15:58:29 2021
@author: user

"""

import cv2
import numpy as np
from skimage.feature import hog
from sklearn import svm
from scipy.cluster.vq import kmeans, vq
from sklearn.model_selection import train_test_split
#如果懶惰的小夥伴們可以用 train_test_split 編寫

def read(path, data_amount): #讀取圖片用,path 是圖片路徑、data_amount 是數量
data = list()
for i in range(1, data_amount+1):
image = cv2.imread(path % i) #讀資料
image = cv2.resize(image, (349,256)) # resize
data.append(image)
return data #回傳 list

def sift(data): #SIFT 特徵取出 data 為讀取近 python 的原始圖片
output = list()
for image in data:
sift = cv2.SIFT_create() #初始化特徵點
kp, des = sift.detectAndCompute(image, None) #對圖片進行 sift 讀取
output.append(des)
return output #回傳 list

def kmeans_return_features(k, sift): #取出特徵,透過 kmeans 分辨
#k 為要分辨的特徵類別數量,建議是資料類別乘以 10,sift 為擁有圖片特徵的 list
descriptors = sift[0] #先給予一個值,以避免不能合併
for it in sift[1:]:
descriptors = np.vstack((descriptors, it)) #採用水平方式將陣列堆疊起來

voc, variance = kmeans(descriptors,k,1)
#透過 kmeans 將特徵進行分配,相似的放在一起,並分成 k 倍,只進行 1 次 iteratior
#voc 回傳陣列,長度為 k,第 i 類有著相同的特徵,
#variance 回傳觀察值與中心點,可能會有失真問題,如果不要失真或許可以使用 kmeans2 方法

#features histogram
im_features = np.zeros((len(sift), k), "float32") #生成一個全為 0 的陣列
for i in range(len(sift)): #
words, distance = vq(sift[i], voc)
#將 voc 收集到的特徵,與圖片 sift[i] 與中心點進行比較,將最相似的特徵分配給適合的圖片
#words 回傳陣列,接受此圖片最適合的所有特徵
#distance 觀察值與中心點的距離,可能會有失真的可能性

for j in words: #將特徵傳給 im_features
im_features[i][j] += 1 #表示此圖片的 j 特徵加一

return im_features #回傳 list

main

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# -*- coding: utf-8 -*-
"""
Created on Sun Apr 18 15:57:30 2021

@author: user
"""
import cv2
import numpy as np
from skimage.feature import hog
from sklearn.datasets import fetch_lfw_people
from sklearn import svm
from scipy.cluster.vq import kmeans, vq
from sklearn.model_selection import train_test_split
import hw06_fn #這是我自己寫的 functional progamming,請自行將上面的 function python code
#與此檔案放在同個資料夾底下

data_amount = 100 #每一個資料集總數 100
train_amount = 80 #訓練資料集筆數
test_amount = 20 #訓練資料集筆數

#如果想要讓電腦辨識貓跟狗,請使用這些程式碼
dogs = hw06_fn.read("../resize_dog/dog_%.3d.jpg", data_amount)
cats = hw06_fn.read("../resize_cat/cat_%.3d.jpg", data_amount)

#如果想要讓電腦辨識多拉A夢跟名偵探柯南,請使用這些程式碼
# dogs = hw06_fn.read("../Doraemon/images (%d).jpg", data_amount)
# cats = hw06_fn.read("../conan/images (%d).jpg", data_amount)

sift_dogs = hw06_fn.sift(dogs) #將資料送去 sift 特徵
sift_cats = hw06_fn.sift(cats)

train_sift = sift_dogs[:train_amount] + sift_cats[:train_amount] #產生訓練集
test_sift = sift_dogs[-test_amount:] + sift_cats[-test_amount:] #產生測試集

train_features = hw06_fn.kmeans_return_features(20, train_sift) #找出訓練集每張圖片特徵
test_features = hw06_fn.kmeans_return_features(20, test_sift) #找出測試集每張圖片特徵
train_target = [0] * train_amount + [1] * train_amount #給予其正確的類別
test_target = [0] * test_amount + [1] * test_amount #給予其正確的類別

clf = svm.SVC(kernel="linear", C=1, gamma="auto") #透過 SVC 訓練
clf.fit(train_features, train_target) #開始進行訓練

print("accuracy") #準確率
print("train:", clf.score(train_features, train_target)) #訓練集分數
print("test:", clf.score(test_features, test_target)) #測試集分數

結果

需要特別注意 scipy.cluster.vq.kmean 函式,一開始會隨機選擇一座標進行分類,因此每一次使用此函數不一定回傳值永遠相同,視每次分類而定;因此在執行我這份程式碼時,準確率與我不同並沒有錯。

貓與狗

多拉A夢與柯南

圖片辨識後結論

貓與狗

由於貓跟小狗的身材較為相像且亮度變化在這裡或許會容易誤導 SVM 進行分別,導致相同的光亮度的貓與狗不好進行分配,才會使其在訓練集的準確率就不高,在此情況下,相對測試集就不高。

可能需要白底 png 的大量貓狗照片,就能使得此機器學習辨識率更高。

多拉A夢與柯南

這組是比較正確的一組,其中我認為哆啦A夢與名偵探柯南本身的光影明亮度稍微不同、邊緣也有大不同,因此在交由 SVM 進行分辨時,較能夠分辨得出差異性。因此在訓練集時準確率可以達到 92%,在測試集也可以達到 72%,算是不錯的辨識率。

但認為可能還是需要白底的 png 照片,會讓他更為準確,我認為可能有些辨識失敗的原因是圖片有大量不相干的背景使得,那不相干的背景如果與另一類型的背景相似時,就有分辨失誤的可能性。

無註解程式碼

hw06_fn.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# -*- coding: utf-8 -*-
"""
Created on Sun Apr 18 15:58:29 2021

@author: user
"""
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Thu Apr 8 10:58:26 2021

"""

import cv2
import numpy as np
from skimage.feature import hog
from sklearn.datasets import fetch_lfw_people
from sklearn import svm
from scipy.cluster.vq import kmeans, vq
from sklearn.model_selection import train_test_split

def read(path, data_amount):
data = list()
for i in range(1, data_amount+1):
image = cv2.imread(path % i)
image = cv2.resize(image, (349,256))
data.append(image)
return data

def sift(data):
output = list()
for image in data:
sift = cv2.SIFT_create()
kp, des = sift.detectAndCompute(image, None)
output.append(des)
return output

def kmeans_return_features(k, sift):
descriptors = sift[0]
for it in sift[1:]:
descriptors = np.vstack((descriptors, it))

voc, train_variance = kmeans(descriptors,k,1)

#features histogram
im_features = np.zeros((len(sift), k), "float32")
for i in range(len(sift)):
words, distance = vq(sift[i], voc)
for j in words:
im_features[i][j] += 1

return im_features

G01.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# -*- coding: utf-8 -*-
"""
Created on Sun Apr 18 15:57:30 2021

@author: user
"""
import cv2
import numpy as np
from skimage.feature import hog
from sklearn.datasets import fetch_lfw_people
from sklearn import svm
from scipy.cluster.vq import kmeans, vq
from sklearn.model_selection import train_test_split
import hw06_fn

data_amount = 100
train_amount = 80
test_amount = 20

#return list
dogs = hw06_fn.read("../resize_dog/dog_%.3d.jpg", data_amount)
cats = hw06_fn.read("../resize_cat/cat_%.3d.jpg", data_amount)

#dogs = hw06_fn.read("../Doraemon/images (%d).jpg", data_amount)
#cats = hw06_fn.read("../conan/images (%d).jpg", data_amount)

sift_dogs = hw06_fn.sift(dogs)
sift_cats = hw06_fn.sift(cats)

train_sift = sift_dogs[:train_amount] + sift_cats[:train_amount]
test_sift = sift_dogs[-test_amount:] + sift_cats[-test_amount:]

train_features = hw06_fn.kmeans_return_features(20, train_sift)
test_features = hw06_fn.kmeans_return_features(20, test_sift)
train_target = [0] * train_amount + [1] * train_amount
test_target = [0] * test_amount + [1] * test_amount

clf = svm.SVC(kernel="linear", C=1, gamma="auto")
clf.fit(train_features, train_target)

print("accuracy")
print("train:", clf.score(train_features, train_target))
print("test:", clf.score(test_features, test_target))
  • 版權聲明: 本部落格所有文章除有特別聲明外,均採用 Apache License 2.0 許可協議。轉載請註明出處!
  • © 2020-2024 John Doe
  • Powered by Hexo Theme Ayer
  • PV: UV: