作者|李秋鍵
出品|AI科技大本營(ID:rgznai100)
引言
目標檢測是一種與計算機視覺和影像處理有關的計算機技術, 用于檢測數字影像和視頻中特定類別的語意物件 (例如人、建筑物或汽車等), 其在視頻安防,自動駕駛, 交通監控, 無人機場景分析和機器人視覺等領域有廣闊的應用前景,近年來, 由于卷積神經網路的發展和硬體算力提升, 基于深度學習的目標檢測取得了突破性的進展,目前, 深度學習演算法已在計算機視覺的整個領域得到廣泛采用, 包括通用目標檢測和特定領域目標檢測. 大多數最先進的目標檢測演算法都將深度學習網路用作其骨干網和檢測網路, 分別從輸入影像 (或視頻), 分類和定位中提取特征,
目標檢測包括分類和定位兩方面,目標檢測應用領域廣泛,包括人臉檢測、行人檢測、車輛檢測等,由于檢測物體形狀各異,實際場景存在背景復雜、遮擋嚴重及光照影響等問題,設計高精度的檢測模型具有很大挑戰,傳統的目標檢測演算法分為3個步驟,如下圖所示,

(1)候選區域選擇:
通常使用滑動視窗演算法,通過不同大小的滑窗在輸入影像上劃定目標可能存在的區域,對目標進行初步定位,
(2)特征提取:
使用區域二值模式、方向梯度直方圖等演算法對候選區域進行特征提取,
(3)分類:
通過支持向量機、Adaboost等演算法對提取的影像特征進行分類,
傳統目標檢測演算法沒有針對性地使用滑動視窗去檢測目標,不僅效率低,準確率也不高,而且人工選擇的特征對于形狀各異的不規則物體魯棒性較差,隨著深度學習技術的發展,利用卷積神經網路提取影像特征,從而實作目標檢測,已成為機器視覺領域研究的熱點之一,
目前,基于深度學習的目標檢測方法主要有兩大分支,分別是基于區域提取的兩階段目標檢測模型和直接進行位置回歸的一階段目標檢測模型,
故本專案通過采用深度學習方法實作對吸煙行為的目標檢測,使用python語言搭建YOLO演算法實作對吸煙行為的實時監測,其最終實作效果如下圖可見:

1、基本介紹
1.1 環境要求
本次環境使用的是python3.6.5+windows平臺,主要用的庫有:
opencv模塊,在計算機視覺專案的開發中,opencv作為較大眾的開源庫,擁有了豐富的常用影像處理函式庫,采用C/C++語言撰寫,可以運行在Linux/Windows/Mac等作業系統上,能夠快速的實作一些影像處理和識別的任務,
numpy模塊,numpy系統是Python的一種開源的數值計算擴展,這種工具可用來存盤和處理大型矩陣,比Python自身的嵌套串列結構要高效得多(該結構也可以用來表示矩陣,
pillow模塊,PIL是理想的影像存檔和批處理應用程式,您可以使用庫創建縮略圖,在檔案格式、列印影像等之間進行轉換,它提供了廣泛的檔案格式支持、高效的內部表示和相當強大的影像處理功能,核心影像庫是為快速訪問以幾種基本像素格式存盤的資料而設計的,為通用影像處理工具提供了堅實的基礎,
keras模塊,Keras是一個由Python撰寫的開源人工神經網路庫,可以作為Tensorflow、Microsoft-CNTK和Theano的高階應用程式介面,進行深度學習模型的設計、除錯、評估、應用和可視化 ,
1.2 目標檢測演算法介紹
深度學習目標檢測演算法大體上可以分為雙階段和單階段兩種,前者需要將整體分為兩部分,然后生成識別框分別對兩部分進行識別,后者是將整個流程放在一起直接進行檢測,
雙階段目標檢測演算法需要先借助SelectiveSearch選出影像中的候選區域,之后還需要對候選區域進行再次檢測,從而得出最后檢測結果,比較常用的演算法主要有OverFeat、R-CNN、MaskR-CNN等,
單階段目標檢測演算法依據的是回歸分析思想,所以也被稱作回歸分析目標檢測演算法,該演算法之所以被稱作單階段目標檢測演算法是因為該演算法不需要生成候選區域,而是直接對整個影像進行檢測,從而獲得目標位置類別和位置資訊,比較常用的檢測演算法主要有YOLO和SSD,
其中YOLO目標檢測演算法是考慮到雙階段目標檢測演算法的檢測效率比較低,所以一些學者提出了單階段目標檢測,JosephRedmon等人在2016年的時候提出了由卷積層和FC層構成的YOLO目標檢測演算法,先要在最頂層特征圖中標出邊界框,之后就可以對每個類別概率進行預測,最后再激活函式就可以得到最終資訊,下圖為YOLO的殘差網路結構:

2、模型搭建
2.1 初始函式搭建
其中包括YOLO初始化基本引數,初始化類別、獲取先驗框、計算會話等,
def __init__(self, **kwargs):
self.__dict__.update(self._defaults)
self.class_names = self._get_class()
self.anchors = self._get_anchors()
self.sess = K.get_session()
self.boxes, self.scores, self.classes = self.generate()
def _get_class(self):
classes_path = os.path.expanduser(self.classes_path)
with open(classes_path) as f:
class_names = f.readlines()
class_names = [c.strip() for c in class_names]
return class_names
def _get_anchors(self):
anchors_path = os.path.expanduser(self.anchors_path)
with open(anchors_path) as f:
anchors = f.readline()
anchors = [float(x) for x in anchors.split(',')]
return np.array(anchors).reshape(-1, 2)

2.2 YOLO網路層搭建
YOLO演算法將整幅影像分為了多個網格單元,對每個網格中心目標進行檢測,該演算法不用生成候選區域,在一個卷積網路中就可以完成特征提取、分類回歸等任務,檢測程序得到了簡化,檢測速度也變得更快,但該演算法對于小尺度目標的檢測不夠準確,如果影像中存在重疊遮擋等現象就可能出現遺漏,整個網路模型搭建包括DarknetConv2D、 BatchNormalization和 LeakyReLU卷積塊的設定以及卷積層特征提取,
def DarknetConv2D(*args, **kwargs):
darknet_conv_kwargs = {'kernel_regularizer': l2(5e-4)}
darknet_conv_kwargs['padding'] = 'valid' if kwargs.get('strides')==(2,2) else 'same'
darknet_conv_kwargs.update(kwargs)
return Conv2D(*args, **darknet_conv_kwargs)
def DarknetConv2D_BN_Leaky(*args, **kwargs):
no_bias_kwargs = {'use_bias': False}
no_bias_kwargs.update(kwargs)
return compose(
DarknetConv2D(*args, **no_bias_kwargs),
BatchNormalization(),
LeakyReLU(alpha=0.1))
03、模型呼叫
常見的目標檢測演算法常分為三個步驟進行:
第一步:分類,用事前確定好的類別或實體ID對化為資訊的影像結構進行描述,
第二步:檢測,上一步是對整張圖片內容的描述,這一步則需要選定一個物體目標進行檢測,獲取物體所處位置以及類別資訊,
第三步:分割,這一步需要對語意和實體進行分割,并得出像素屬于哪個目標物體或哪個場景的結論,
流程為調整輸入影像或視頻流的尺寸以滿足模型規范輸入大小,通過模型預測出類別、框體大小和分數,
其中模型呼叫顯示框圖代碼如下:
def detect_image(self, image):
boolen=False
start = timer()
new_image_size = self.model_image_size
boxed_image = letterbox_image(image, new_image_size)
image_data = np.array(boxed_image, dtype='float32')
image_data /= 255.
image_data = np.expand_dims(image_data, 0) # Add batch dimension.
out_boxes, out_scores, out_classes = self.sess.run(
[self.boxes, self.scores, self.classes],
feed_dict={
self.yolo_model.input: image_data,
self.input_image_shape: [image.size[1], image.size[0]],
K.learning_phase(): 0
})
print('Found {} boxes for {}'.format(len(out_boxes), 'img'))
font = ImageFont.truetype(font='font/simhei.ttf',
size=np.floor(3e-2 * image.size[1] + 0.5).astype('int32'))
thickness = (image.size[0] + image.size[1]) // 300
small_pic=[]
for i, c in list(enumerate(out_classes)):
predicted_class = self.class_names[c]
box = out_boxes[i]
score = out_scores[i]
top, left, bottom, right = box
top = top - 5
left = left - 5
bottom = bottom + 5
right = right + 5
top = max(0, np.floor(top + 0.5).astype('int32'))
left = max(0, np.floor(left + 0.5).astype('int32'))
bottom = min(image.size[1], np.floor(bottom + 0.5).astype('int32'))
right = min(image.size[0], np.floor(right + 0.5).astype('int32'))
# 畫框框
label = '{} {:.2f}'.format(predicted_class, score)
draw = ImageDraw.Draw(image)
label_size = draw.textsize(label, font)
label = label.encode('utf-8')
if predicted_class=='smoke':
boolen=True
if top - label_size[1] >= 0:
text_origin = np.array([left, top - label_size[1]])
else:
text_origin = np.array([left, top + 1])
for i in range(thickness):
draw.rectangle(
[left + i, top + i, right - i, bottom - i],
outline=self.colors[c])
draw.rectangle(
[tuple(text_origin), tuple(text_origin + label_size)],
fill=self.colors[c])
draw.text(text_origin, str(label,'UTF-8'), fill=(0, 0, 0), font=font)
del draw
end = timer()
print(end - start)
return image,boolen


完整代碼:
鏈接:
????https://pan.baidu.com/s/1vmjV1HwhcMOdUqFhKwH4Mg
提取碼:pqsv
作者簡介:
李秋鍵,CSDN博客專家,CSDN達人課作者,碩士在讀于中國礦業大學,開發有taptap競賽獲獎等,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/297075.html
標籤:AI
上一篇:20+頂尖高校同時開打《王者榮耀》!實際上是一場科研battle,你能信?
下一篇:執行緒的死鎖
