畢業(yè)設(shè)計(jì) 機(jī)器視覺車位識(shí)別車道線檢測(cè)系統(tǒng)
?? 這兩年開始畢業(yè)設(shè)計(jì)和畢業(yè)答辯的要求和難度不斷提升,傳統(tǒng)的畢設(shè)題目缺少創(chuàng)新和亮點(diǎn),往往達(dá)不到畢業(yè)答辯的要求,這兩年不斷有學(xué)弟學(xué)妹告訴學(xué)長(zhǎng)自己做的項(xiàng)目系統(tǒng)達(dá)不到老師的要求。
為了大家能夠順利以及最少的精力通過畢設(shè),學(xué)長(zhǎng)分享優(yōu)質(zhì)畢業(yè)設(shè)計(jì)項(xiàng)目,今天要分享的是
?? ?深度學(xué)習(xí) 機(jī)器視覺 車位識(shí)別車道線檢測(cè)
難度系數(shù):3分
工作量:3分
創(chuàng)新點(diǎn):4分
畢設(shè)幫助,選題指導(dǎo),技術(shù)解答,歡迎打擾,見B站個(gè)人主頁(yè)
https://space.bilibili.com/33886978
簡(jiǎn)介
你是不是經(jīng)常在停車場(chǎng)周圍轉(zhuǎn)來轉(zhuǎn)去尋找停車位。如果你的車輛能準(zhǔn)確地告訴你最近的停車位在哪里,那是不是很爽?事實(shí)證明,基于深度學(xué)習(xí)和OpenCV解決這個(gè)問題相對(duì)容易,只需獲取停車場(chǎng)的實(shí)時(shí)視頻即可。
該項(xiàng)目可推薦用于畢業(yè)設(shè)計(jì)
檢測(cè)效果
廢話不多說, 先上效果圖


注意車輛移動(dòng)后空車位被標(biāo)記上


車輛移動(dòng)到其他車位

實(shí)現(xiàn)方式
整體思路
這個(gè)流程的第一步就是檢測(cè)一幀視頻中所有可能的停車位。顯然,在我們能夠檢測(cè)哪個(gè)是沒有被占用的停車位之前,我們需要知道圖像中的哪些部分是停車位。
第二步就是檢測(cè)每幀視頻中的所有車輛。這樣我們可以逐幀跟蹤每輛車的運(yùn)動(dòng)。
第三步就是確定哪些車位目前是被占用的,哪些沒有。這需要結(jié)合前兩步的結(jié)果。
最后一步就是出現(xiàn)新車位時(shí)通知我。這需要基于視頻中兩幀之間車輛位置的變化。
這里的每一步,我們都可以使用多種技術(shù)用很多種方式實(shí)現(xiàn)。構(gòu)建這個(gè)流程并沒有唯一正確或者錯(cuò)誤的方式,但不同的方法會(huì)有優(yōu)劣之分。
使用要使用到兩個(gè)視覺識(shí)別技術(shù) :識(shí)別空車位停車線,識(shí)別車輛
檢測(cè)空車位
車位探測(cè)系統(tǒng)的第一步是識(shí)別停車位。有一些技巧可以做到這一點(diǎn)。例如,通過在一個(gè)地點(diǎn)定位停車線來識(shí)別停車位。這可以使用OpenCV提供的邊緣檢測(cè)器來完成。但是如果沒有停車線呢?
我們可以使用的另一種方法是假設(shè)長(zhǎng)時(shí)間不移動(dòng)的汽車停在停車位上。換句話說,有效的停車位就是那些停著不動(dòng)的車的地方。但是,這似乎也不可靠。它可能會(huì)導(dǎo)致假陽(yáng)性和真陰性。
那么,當(dāng)自動(dòng)化系統(tǒng)看起來不可靠時(shí),我們應(yīng)該怎么做呢?我們可以手動(dòng)操作。與基于空間的方法需要對(duì)每個(gè)不同的停車位進(jìn)行標(biāo)簽和訓(xùn)練不同,我們只需標(biāo)記一次停車場(chǎng)邊界和周圍道路區(qū)域即可為新的停車位配置我們的系統(tǒng)。
在這里,我們將從停車位的視頻流中截取一幀,并標(biāo)記停車區(qū)域。Python庫(kù)matplotlib 提供了稱為PolygonSelector的功能。它提供了選擇多邊形區(qū)域的功能。
我制作了一個(gè)簡(jiǎn)單的python腳本來標(biāo)記輸入視頻的初始幀之一上的多邊形區(qū)域。它以視頻路徑作為參數(shù),并將選定多邊形區(qū)域的坐標(biāo)保存在pickle文件中作為輸出。

import os
import numpy as np
import CV2
import pickle
import argparse
import matplotlib.pyplot as plt
from matplotlib.patches import Polygon
from matplotlib.widgets import PolygonSelector
from matplotlib.collections import PatchCollection
from shapely.geometry import box
from shapely.geometry import Polygon as shapely_poly
points = []
prev_points = []
patches = []
total_points = []
breaker = False
class SelectFromCollection(object):
def __init__(self, ax):
self.canvas = ax.figure.canvas
self.poly = PolygonSelector(ax, self.onselect)
self.ind = []
def onselect(self, verts):
global points
points = verts
self.canvas.draw_idle()
def disconnect(self):
self.poly.disconnect_events()
self.canvas.draw_idle()
def break_loop(event):
global breaker
global globSelect
global savePath
if event.key == 'b':
globSelect.disconnect()
if os.path.exists(savePath):
os.remove(savePath)
print("data saved in "+ savePath + " file")
with open(savePath, 'wb') as f:
pickle.dump(total_points, f, protocol=pickle.HIGHEST_PROTOCOL)
exit()
def onkeypress(event):
global points, prev_points, total_points
if event.key == 'n':
pts = np.array(points, dtype=np.int32)
if points != prev_points and len(set(points)) == 4:
print("Points : "+str(pts))
patches.append(Polygon(pts))
total_points.append(pts)
prev_points = points
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('video_path', help="Path of video file")
parser.add_argument('--out_file', help="Name of the output file", default="regions.p")
args = parser.parse_args()
global globSelect
global savePath
savePath = args.out_file if args.out_file.endswith(".p") else args.out_file+".p"
print("\n> Select a region in the figure by enclosing them within a quadrilateral.")
print("> Press the 'f' key to go full screen.")
print("> Press the 'esc' key to discard current quadrilateral.")
print("> Try holding the 'shift' key to move all of the vertices.")
print("> Try holding the 'ctrl' key to move a single vertex.")
print("> After marking a quadrilateral press 'n' to save current quadrilateral and then press 'q' to start marking a new quadrilateral")
print("> When you are done press 'b' to Exit the program\n")
video_capture = CV2.VideoCapture(args.video_path)
cnt=0
rgb_image = None
while video_capture.isOpened():
success, frame = video_capture.read()
if not success:
break
if cnt == 5:
rgb_image = frame[:, :, ::-1]
cnt += 1
video_capture.release()
while True:
fig, ax = plt.subplots()
image = rgb_image
ax.imshow(image)
p = PatchCollection(patches, alpha=0.7)
p.set_array(10*np.ones(len(patches)))
ax.add_collection(p)
globSelect = SelectFromCollection(ax)
bbox = plt.connect('key_press_event', onkeypress)
break_event = plt.connect('key_press_event', break_loop)
plt.show()
globSelect.disconnect()
(PS: 若代碼出現(xiàn)bug可反饋博主, 及時(shí)修改)
車輛識(shí)別
要檢測(cè)視頻中的汽車,我使用Mask-RCNN。它是一個(gè)卷積神經(jīng)網(wǎng)絡(luò),對(duì)來自幾個(gè)數(shù)據(jù)集(包括COCO數(shù)據(jù)集)的數(shù)百萬個(gè)圖像和視頻進(jìn)行了訓(xùn)練,以檢測(cè)各種對(duì)象及其邊界。 Mask-RCNN建立在Faster-RCNN對(duì)象檢測(cè)模型的基礎(chǔ)上。
除了每個(gè)檢測(cè)到的對(duì)象的類標(biāo)簽和邊界框坐標(biāo)外,Mask RCNN還將返回圖像中每個(gè)檢測(cè)到的對(duì)象的像pixel-wise mask。這種pixel-wise masking稱為“ 實(shí)例分割”。我們?cè)谟?jì)算機(jī)視覺領(lǐng)域所看到的一些最新進(jìn)展,包括自動(dòng)駕駛汽車、機(jī)器人等,都是由實(shí)例分割技術(shù)推動(dòng)的。
M-RCNN將用于視頻的每一幀,它將返回一個(gè)字典,其中包含邊界框坐標(biāo)、檢測(cè)對(duì)象的masks、每個(gè)預(yù)測(cè)的置信度和檢測(cè)對(duì)象的class_id。現(xiàn)在使用class_ids過濾掉汽車,卡車和公共汽車的邊界框。然后,我們將在下一步中使用這些框來計(jì)算IoU。
由于Mask-RCNN比較復(fù)雜,這里篇幅有限,需要mask-RCNN的同學(xué)聯(lián)系博主獲取, 下面僅展示效果:

畢設(shè)幫助,選題指導(dǎo),技術(shù)解答,歡迎打擾,見B站個(gè)人主頁(yè)
https://space.bilibili.com/33886978