第7章 目標檢測與識別

第7章 目標檢測與識別

7.1 目標檢測與識別技術

目標檢測用來確定圖像的某個區域是否包含要識別的對象

本章用到的技術:

梯度直方圖

圖像金字塔

滑動窗口

 

 

7.1.1 HOG描述符

HOG是一個特徵描述符,與SIFT、SURF、ORB類型相同。

目標檢測的內部機制都差不多:將圖像劃分爲多個部分,計算各個部分的梯度。

HOG是基於梯度計算直方圖的,HOG得到的特徵描述符能爲特徵匹配和目標檢測提供非常重要的信息。

 

 

 

 

下面是卡車圖像和對應的HOG圖

 

 

 

 

 

 

 

 

 

 

 

HOG提取的特徵可以識別車輛的主要結構。

HOG將卡車圖像分成小單元,每個單元包含了視角表示,視覺表示是按8個方向計算的顏色梯度。每個單元的8個值就是直方圖。

將直方圖外推成描述符是相當複雜的過程。首相計算每個單元的局部直方圖,這些單元會合成較大的區域(塊)。進行人類檢測時,一個塊包含2x2的單元時效果最好。僅僅比較兩幅圖像的單元是行不通的,除非兩幅圖像相同。

要解決兩個方面的問題:

1.尺度問題(大小不同)

2.位置問題(要找到目標區域)

兩個概念

(1)圖像金字塔(pyramid)

圖像金字塔式圖像的多尺度表示,有助於解決不同尺度下的目標檢測問題。

構建圖像金字塔:

1.獲取圖像。

2.使用任意尺度的參數來調整圖像大小

3.平滑圖像(使用高斯模糊)

4.如果圖像比最小尺寸還大,重複上述步驟。

 

 

(2)滑動窗口

包括圖像中要移動部分的檢測以及使用圖像金字塔對各部分檢測,這是爲了在多尺度下檢測對象。

滑動窗口通過掃描較大圖像的較小區域來解決定位問題,進而在同一圖像的不同尺度下重複掃描。

這種技術獎圖像分解爲多個部分,然後丟棄不太可能包含對象的部分,對剩餘部分進行分類。

 

7.1.2 檢測人

import cv2
import numpy as np

def is_inside(o,i):
    ox,oy,ow,oh = o
    ix,iy,iw,ih = i
   
return ox>ix and oy>iy and ox+ow < ix+iw and oy+oh<iy+ih

def draw_person(image,person):
    x,y,w,h = person
    cv2.rectangle(image,(x,y),(x+w,y+h),(
0,255,0),2)


img = cv2.imread(
"./images/people.jpg")
hog = cv2.HOGDescriptor()
hog.setSVMDetector(cv2.HOGDescriptor_getDefaultPeopleDetector())
found,w = hog.detectMultiScale(img)
found_filtered = []

for ri,r in enumerate(found):
   
for qi,q in enumerate(found):
       
if ri != qi and is_inside(r,q):
           
break;
       
else:
            found_filtered.append(r)


for person in found_filtered:
    draw_person(img,person)

cv2.imshow(
"people detection",img)
cv2.waitKey()
cv2.destroyAllWindows()








 

7.1.3 創建和訓練目標檢測器

構建分類器

*概念

詞袋(BOW)

BOW用來在文檔中計算詞出現的次數,然後用這些次數構成的向量來重新表示文檔,。

2、計算機視覺中的BOW

BOW方法實現步驟:

1.取一個樣板數據集

2.對數據集中的圖像提取描述符

3.將描述符添加到BOW訓練器中。

4.將描述符 聚類到k簇中

 

k-means聚類

對於給定的數據集,k表示要分割的數據集中的簇數,means是均值。

 

 

 

7.2 汽車檢測

https://blog.csdn.net/sinat_38685910/article/details/95511133

 

import cv2
import numpy as np
from os.path import join

# 此數據集爲UIUC Car Detection 百度雲鏈接可下載
datapath = 'D:\\PY_TEST\\car\\CarData\\TrainImages\\'


def path(cls, i):
   
return "%s/%s%d.pgm" % (datapath, cls, i + 1)


pos, neg =
"pos-", "neg-"  # 數據集中圖片命名方式

detect = cv2.xfeatures2d.SIFT_create()  # 提取關鍵點
extract = cv2.xfeatures2d.SIFT_create()  # 提取特徵
# FLANN匹配器有兩個參數:indexParams和searchParams,以字典的形式進行參數傳參

flann_params = dict(algorithm=1, trees=5# 1爲FLANN_INDEX_KDTREE
matcher = cv2.FlannBasedMatcher(flann_params, {})  # 匹配特徵
# 創建bow訓練器,簇數爲40

bow_kmeans_trainer = cv2.BOWKMeansTrainer(40)
# 初始化bow提取器
extract_bow = cv2.BOWImgDescriptorExtractor(extract, matcher)


def extract_sift(fn):  # 參數爲路徑
   
im = cv2.imread(fn, 0)
   
return extract.compute(im, detect.detect(im))[1# 返回描述符


# 讀取8個正樣本和8個負樣本

for i in range(8):
    bow_kmeans_trainer.add(extract_sift(path(pos, i)))
    bow_kmeans_trainer.add(extract_sift(path(neg, i)))

# 利用訓練器的cluster()函數,執行k-means分類並返回詞彙
# k-means:屬於聚類算法,所謂的聚類算法屬於無監督學習,將樣本x潛在所屬類別Y找出來

voc = bow_kmeans_trainer.cluster()
extract_bow.setVocabulary(voc)



def bow_features(fn):
    im = cv2.imread(fn,
0)
   
return extract_bow.compute(im, detect.detect(im))


# 兩個數組,分別爲訓練數據和標籤,並用bow提取器產生的描述符填充
traindata, trainlabels = [], []
for i in range(120):
    traindata.extend(bow_features(path(pos, i)));
    trainlabels.append(
1# 1爲正匹配
   
traindata.extend(bow_features(path(neg, i)));
    trainlabels.append(-
1# -1爲負匹配
# 創建SVM實例,將訓練數據和標籤放到numpy數組中進行訓練,有關SVM知識稍後寫一篇補上

svm = cv2.ml.SVM_create()
svm.train(np.array(traindata), cv2.ml.ROW_SAMPLE, np.array(trainlabels))



def predict(fn):
    f = bow_features(fn)
    p = svm.predict(f)
   
print(fn, "\t", p[1][0][0])
   
return p


# 預測結果

car = 'car8.jpg'
car_img = cv2.imread(car)

car_predict = predict(car)


# 添加文字說明
font = cv2.FONT_HERSHEY_SIMPLEX

if (car_predict[1][0][0] == 1.0):  # predict結果爲1.0表示能檢測到汽車
   
cv2.putText(car_img, 'Car Detected', (10, 30), font, 1, (0, 255, 0), 2, cv2.LINE_AA)

if (car_predict[1][0][0] == -1.0):  # predict結果爲-1.0表示不能檢測到汽車
   
cv2.putText(car_img, 'Car Not Detected', (10, 30), font, 1, (0, 0, 255), 2, cv2.LINE_AA)

while (True):
    cv2.imshow(
'BOW + SVM Success', car_img)
   
# 按q退出
   
if (cv2.waitKey(1000 // 12) & 0xff == ord("q")):
       
break
cv2.destroyAllWindows()

 

 

7.2.2 SVM和滑動窗口

滑動窗口:即選擇一個矩形區域,每次往右滑動一步,直至最右,然後往下繼續這個過程,直到全圖結束。