【導(dǎo)語(yǔ)】今天這篇文章的選題非常貼近生活。營(yíng)長(zhǎng)生活在北京,深知開車出門最怕的就是堵車和找不到停車位。記得冬至那個(gè)周末,幾個(gè)小伙伴滑雪回來找了一家餃子館吃餃子,結(jié)果七拐八拐,好不容易才找到一個(gè)停車位??吹竭@篇技術(shù)文章,馬上就想要學(xué)習(xí)一下,分享給大家,希望有助于解決大家這個(gè)痛點(diǎn)問題,春節(jié)出行沒準(zhǔn)就可以用得上了。
作者通過相機(jī)結(jié)合深度學(xué)習(xí)算法,基于 Python 語(yǔ)言建立一個(gè)高精度的停車位的通知系統(tǒng),每當(dāng)有新停車位時(shí)就會(huì)發(fā)短信提醒我。聽起來好像很復(fù)雜,真的方便實(shí)用嗎?但實(shí)際上所使用的工具都是現(xiàn)成的,只要將這些工具進(jìn)行有機(jī)的組合,就可以快速、簡(jiǎn)便的實(shí)現(xiàn)。
下面我們就開始學(xué)習(xí)整個(gè)工程流程:
分解問題
解決一個(gè)復(fù)雜的問題,首先第一步是要把問題分解成幾個(gè)簡(jiǎn)單子任務(wù)。然后,針對(duì)每個(gè)子任務(wù),運(yùn)用機(jī)器學(xué)習(xí)中不同的方法來分別解決每個(gè)問題。最后把這些子任務(wù)貫穿起來,形成整套解決方案。
下面是檢測(cè)開放停車位的流程圖:
輸入:普通攝像頭采集的視頻流
有了輸入數(shù)據(jù)后,接下來我們需要知道圖像的哪一部分是停車位,而且停車位是沒有人使用的。
第一步:檢測(cè)視頻幀中所有可能的停車位。
第二步:檢測(cè)每一幀視頻中的所有車輛??梢愿櫭枯v車從一幀到另一幀的運(yùn)動(dòng)。
第三步:確定目前有哪些停車位被占用,哪些沒有被占用。這需要結(jié)合第一步和第二步的結(jié)果。
最后一步:當(dāng)停車位變成可用時(shí),系統(tǒng)發(fā)出通知。
其實(shí)可以使用多種不同的方法來完成這些步驟。不同的方法將具有不同的優(yōu)勢(shì)和缺點(diǎn)。接下來具體來看:
一、探測(cè)停車位
相機(jī)視圖如下圖所示:
需要掃描圖像,并得到有效停車區(qū)域,如下面黃色標(biāo)識(shí)出來的位置:
一個(gè)懶辦法是程序?qū)懰烂總€(gè)停車場(chǎng)的位置,而不是自動(dòng)檢測(cè)停車場(chǎng)。但是如果移動(dòng)攝像機(jī),探測(cè)不同街道上的停車位,就必須再次手動(dòng)定位停車位置。這樣看來這個(gè)方法一點(diǎn)都不好,還是要采用自動(dòng)檢測(cè)停車位的方法。
其中一個(gè)想法是識(shí)別停車計(jì)時(shí)器并假設(shè)每個(gè)計(jì)時(shí)器旁邊都有一個(gè)停車位:
但是這種方法也有一些問題。首先,并不是每個(gè)停車位有一個(gè)停車計(jì)時(shí)器,而且我們最想先找到免費(fèi)停車位。第二,知道停車計(jì)時(shí)器的位置還不能告訴我們確切的停車位置點(diǎn)。
另一個(gè)想法是搭建一個(gè)目標(biāo)檢測(cè)模型,找到在馬路上畫的停車位記號(hào),就像下圖標(biāo)識(shí)出來的:
這種方法也有兩個(gè)難點(diǎn)。首先,從遠(yuǎn)處看,停車位線的標(biāo)志很小,很難看到,增加了識(shí)別難度;其次,道路上還有各種交通標(biāo)記線,比如車道線、人行道斑馬線,這也給識(shí)別增加了難度。
或許還可以換個(gè)思維方式,回避一些技術(shù)挑戰(zhàn)。重新思考停車位到底是什么呢?無非是一個(gè)車需要停放一定時(shí)間的位置。所以我們可能根本不需要檢測(cè)停車位,只要檢測(cè)出長(zhǎng)時(shí)間不動(dòng)的車,并假設(shè)它們的位置就是停車位。
所以,如果我們能檢測(cè)出汽車,并找出哪些車在視頻幀之間沒有移動(dòng),就可以推斷停車位的位置。
二、在圖像中檢測(cè)汽車
在視頻中檢測(cè)車輛是一個(gè)經(jīng)典的目標(biāo)檢測(cè)問題。有很多機(jī)器學(xué)習(xí)方法可以實(shí)現(xiàn)。下面列出了一些最常見的目標(biāo)檢測(cè)算法:
1、通過 HOG(梯度方向直方圖)目標(biāo)檢測(cè)器檢測(cè)出所有的車。這種非深度學(xué)習(xí)方法運(yùn)行起來相對(duì)較快,但它無法處理汽車在不同方向上的旋轉(zhuǎn)問題。
2、通過 CNN(卷積神經(jīng)網(wǎng)絡(luò))目標(biāo)檢測(cè)器檢測(cè)所有的車。這種方法是準(zhǔn)確的,但是效率比較低,因?yàn)橥粡垐D像必須掃描多次,以檢測(cè)到所有的汽車。雖然它可以很容易地對(duì)不同旋轉(zhuǎn)方向的汽車定向,但是比 HOG 方法需要更多的訓(xùn)練數(shù)據(jù)。
3、使用新的深度學(xué)習(xí)方法,如 Mask R-CNN,F(xiàn)aster R-CNN 或者 YOLO 算法,兼容準(zhǔn)確性和運(yùn)行效率,大大加快了檢測(cè)過程。一旦有大量的訓(xùn)練數(shù)據(jù),在 GPU 上運(yùn)行也很快。
通常來說,我們希望選擇最簡(jiǎn)單可行的算法和最少的訓(xùn)練數(shù)據(jù),而不是一定要用那些流行的新的算法?;谀壳斑@種特殊場(chǎng)景下,Mask R- CNN 是一個(gè)不錯(cuò)的選擇。
Mask R-CNN 架構(gòu)就是在整個(gè)圖像中檢測(cè)對(duì)象,不使用滑動(dòng)窗口的方式,所以運(yùn)行速度很快。有了 GPU 處理器,我們能夠每秒處理多幀的高分辨率視頻,從中檢測(cè)到車輛。
Mask R-CNN 為我們提供了很多檢測(cè)到的信息。大多數(shù)目標(biāo)檢測(cè)算法只返回每個(gè)對(duì)象的邊框。但是 Mask R-CNN 不僅會(huì)給我們每個(gè)對(duì)象的位置,也會(huì)給出一個(gè)對(duì)象的輪廓,像這樣:
為了訓(xùn)練 Mask R-CNN 模型,我們需要很多這類檢測(cè)物體的圖片??梢曰◣滋斓臅r(shí)間出去拍攝照片,不過已經(jīng)存在一些汽車圖像的公共數(shù)據(jù)集。有一個(gè)很流行的數(shù)據(jù)集叫做COCO(Common Objects In Context的縮寫),它里面已經(jīng)有超過 12000 張汽車的圖片。下面就是一個(gè) COCO 數(shù)據(jù)集中的圖像:
這些數(shù)據(jù)可以很好的訓(xùn)練 Mask R-CNN 模型,而且已經(jīng)有很多人使用過 COCO數(shù)據(jù)集,并分享了訓(xùn)練的結(jié)果。所以我們可以直接使用一些訓(xùn)練好的模型,在本項(xiàng)目中使用 Matterport的開源模型。
不僅能識(shí)別車輛,還能識(shí)別到交通燈和人。有趣的是,它把其中一棵樹識(shí)別成“potted plant”。對(duì)于圖像中檢測(cè)到的每個(gè)對(duì)象,我們從 MaskR-CNN 模型得出以下 4 點(diǎn):
(1)不同對(duì)象的類別,COCO 模型可以識(shí)別出 80 種不同的物體,比如小轎車和卡車。
(2)目標(biāo)識(shí)別的置信度,數(shù)字越大,說明模型識(shí)別對(duì)象的精準(zhǔn)度越高。
(3)圖像中物體的邊界框,給定了 X/Y 像素的位置。
(4)位圖“mask”說明了邊框內(nèi)哪些像素是對(duì)象的一部分,哪些不是。使用“mask”數(shù)據(jù),我們也可以算出物體的輪廓。
下面是 Python 代碼,使用 Matterport 的 Mask R-CNN 的訓(xùn)練模型和 OpenCV 來檢測(cè)汽車邊框:
1importos 2importnumpyasnp 3importcv2 4importmrcnn.config 5importmrcnn.utils 6frommrcnn.modelimportMaskRCNN 7frompathlibimportPath 8 9 10#ConfigurationthatwillbeusedbytheMask-RCNNlibrary 11classMaskRCNNConfig(mrcnn.config.Config): 12NAME="coco_pretrained_model_config" 13IMAGES_PER_GPU=1 14GPU_COUNT=1 15NUM_CLASSES=1+80#COCOdatasethas80classes+onebackgroundclass 16DETECTION_MIN_CONFIDENCE=0.6 17 18 19#FilteralistofMaskR-CNNdetectionresultstogetonlythedetectedcars/trucks 20defget_car_boxes(boxes,class_ids): 21car_boxes=[] 22 23fori,boxinenumerate(boxes): 24#Ifthedetectedobjectisn'tacar/truck,skipit 25ifclass_ids[i]in[3,8,6]: 26car_boxes.append(box) 27 28returnnp.array(car_boxes) 29 30 31#Rootdirectoryoftheproject 32ROOT_DIR=Path(".") 33 34#Directorytosavelogsandtrainedmodel 35MODEL_DIR=os.path.join(ROOT_DIR,"logs") 36 37#Localpathtotrainedweightsfile 38COCO_MODEL_PATH=os.path.join(ROOT_DIR,"mask_rcnn_coco.h5") 39 40#DownloadCOCOtrainedweightsfromReleasesifneeded 41ifnotos.path.exists(COCO_MODEL_PATH): 42mrcnn.utils.download_trained_weights(COCO_MODEL_PATH) 43 44#Directoryofimagestorundetectionon 45IMAGE_DIR=os.path.join(ROOT_DIR,"images") 46 47#Videofileorcameratoprocess-setthisto0touseyour***insteadofavideofile 48VIDEO_SOURCE="test_images/parking.mp4" 49 50#CreateaMask-RCNNmodelininferencemode 51model=MaskRCNN(mode="inference",model_dir=MODEL_DIR,config=MaskRCNNConfig()) 52 53#Loadpre-trainedmodel 54model.load_weights(COCO_MODEL_PATH,by_name=True) 55 56#Locationofparkingspaces 57parked_car_boxes=None 58 59#Loadthevideofilewewanttorundetectionon 60video_capture=cv2.VideoCapture(VIDEO_SOURCE) 61 62#Loopovereachframeofvideo 63whilevideo_capture.isOpened(): 64success,frame=video_capture.read() 65ifnotsuccess: 66break 67 68#ConverttheimagefromBGRcolor(whichOpenCVuses)toRGBcolor 69rgb_image=frame[:,:,::-1] 70 71#RuntheimagethroughtheMaskR-CNNmodeltogetresults. 72results=model.detect([rgb_image],verbose=0) 73 74#MaskR-CNNassumeswearerunningdetectiononmultipleimages. 75#Weonlypassedinoneimagetodetect,soonlygrabthefirstresult. 76r=results[0] 77 78#Thervariablewillnowhavetheresultsofdetection: 79#-r['rois']aretheboundingboxofeachdetectedobject 80#-r['class_ids']aretheclassid(type)ofeachdetectedobject 81#-r['scores']aretheconfidencescoresforeachdetection 82#-r['masks']aretheobjectmasksforeachdetectedobject(whichgivesyoutheobjectoutline) 83 84#Filtertheresultstoonlygrabthecar/truckboundingboxes 85car_boxes=get_car_boxes(r['rois'],r['class_ids']) 86 87print("Carsfoundinframeofvideo:") 88 89#Draweachboxontheframe 90forboxincar_boxes: 91print("Car:",box) 92 93y1,x1,y2,x2=box 94 95#Drawthebox 96cv2.rectangle(frame,(x1,y1),(x2,y2),(0,255,0),1) 97 98#Showtheframeofvideoonthescreen 99cv2.imshow('Video',frame)100101#Hit'q'toquit102ifcv2.waitKey(1)&0xFF==ord('q'):103break104105#Cleanupeverythingwhenfinished106video_capture.release()107cv2.destroyAllWindows()
運(yùn)行該腳本后,將會(huì)看到在圖像中識(shí)別到的汽車和邊框:
同時(shí)會(huì)得到檢測(cè)的每輛車的像素坐標(biāo):
這樣我們已經(jīng)成功地在圖像中檢測(cè)到了汽車。接下來到了下一個(gè)步驟。
三、探測(cè)空車位
知道圖像中每輛車的像素位置后,通過觀察連續(xù)多幀視頻,可以很容易地算出哪幀里汽車沒有移動(dòng)。但我們?nèi)绾螜z測(cè)到汽車何時(shí)離開停車位?經(jīng)觀察,圖像中汽車的邊框部分有所重疊:
如果假設(shè)每個(gè)邊界框代表一個(gè)停車場(chǎng)空間,這個(gè)區(qū)域即使有車開走了,但是仍可能被另外汽車部分占據(jù)。因此我們需要一種方法來測(cè)量重疊,檢查出“大部分為空”的框。我們使用的度量方法稱為 Intersection Over Union(IoU)。通過計(jì)算兩個(gè)物體重疊的像素量,然后除以兩個(gè)物體所覆蓋的像素:
有了這個(gè)值,接下來就可以很容易確定一輛車是否在停車位。如果 IoU 測(cè)量值低,比如 0.15,表示汽車并沒有占據(jù)大部分的停車位空間。但是如果測(cè)量值很高,比如 0.6,就表示汽車占據(jù)了大部分的停車位,因此可以確定停車位已被占用。
IoU 是計(jì)算機(jī)視覺中常用的一種測(cè)量方法,提供了現(xiàn)成的代碼。Matterport 的Mask R-CNN 庫(kù)可以直接調(diào)用這個(gè)函數(shù) mrcnn.utils.compute_overlaps()。假設(shè)我們有一個(gè)表示停車位邊界框的列表,要檢識(shí)別到的車輛是否在這些邊界內(nèi)框很簡(jiǎn)單,只需添加一兩行代碼:
1#Filtertheresultstoonlygrabthecar/truckboundingboxes2car_boxes=get_car_boxes(r['rois'],r['class_ids'])34#Seehowmuchcarsoverlapwiththeknownparkingspaces5overlaps=mrcnn.utils.compute_overlaps(car_boxes,parking_areas)67print(overlaps)
結(jié)果顯示為:
在二維數(shù)組中,每一行表示一個(gè)停車位邊界框。同樣的,每一列表示停車場(chǎng)被汽車所覆蓋的程度。1.0 分意味著汽車完全占據(jù)了,而 0.02 這樣的低分?jǐn)?shù),意味著有重疊區(qū)域,但不會(huì)占據(jù)大部分空間。
要找到無人使用的停車位,只需要計(jì)算出這個(gè)數(shù)組。如果所有的數(shù)都是 0 或者很小,也就表示空間沒有被占用,因此一定是空停車位。
盡管 Mask R-CNN 非常精確,但目標(biāo)檢測(cè)并不能做到完美。有時(shí)也會(huì)在一段視頻中漏掉一兩輛車。所以在定位到一個(gè)空車位時(shí),還應(yīng)該檢測(cè)在一段時(shí)間內(nèi)都是空的,比如 5或10幀連續(xù)視頻。這也可以避免視頻本身出現(xiàn)故障而造成誤檢。一旦看到幾個(gè)連續(xù)視頻中都有空車位,馬上發(fā)送提醒通知!
四、發(fā)送消息
最后一步是發(fā)送 SMS 提醒消息。利用 Twilio 通過 Python 發(fā)送 SMS 消息非常簡(jiǎn)單,基本上幾行代碼就可以實(shí)現(xiàn)。當(dāng)然,Twilio 只是這個(gè)項(xiàng)目中用到的方法,你也可以用其他方式實(shí)現(xiàn)。
要使用 Twilio,先要注冊(cè)一個(gè)試用帳戶,創(chuàng)建一個(gè) Twilio 電話號(hào)碼并獲取您的帳戶憑證。然后,您需要安裝 Twilio Python 客戶端庫(kù):
下面是發(fā)送 SMS 消息的 Python 代碼(需用自己的帳戶信息替換這些值):
1fromtwilio.restimportClient 2 3#Twilioaccountdetails 4twilio_account_sid='YourTwilioSIDhere' 5twilio_auth_token='YourTwilioAuthTokenhere' 6twilio_source_phone_number='YourTwiliophonenumberhere' 7 8#CreateaTwilioclientobjectinstance 9client=Client(twilio_account_sid,twilio_auth_token)1011#SendanSMS12message=client.messages.create(13body="ThisismySMSmessage!",14from_=twilio_source_phone_number,15to="Destinationphonenumberhere"16)
在添加 SMS 發(fā)送功能時(shí)要注意,不要連續(xù)發(fā)送已經(jīng)識(shí)別過的空車位信息??梢杂靡粋€(gè) flag 來跟蹤已經(jīng)發(fā)過的短信,除非是設(shè)定一段時(shí)間后再次提醒或是檢測(cè)到新的空車位。
五、把所有流程串在一起
現(xiàn)在將每個(gè)步驟集成一個(gè)Python腳本。下面是完整代碼,要運(yùn)行這段代碼,需要安裝Python 3.6+,Matterport的 Mask R-CNN 和 OpenCV:
1importos 2importnumpyasnp 3importcv2 4importmrcnn.config 5importmrcnn.utils 6frommrcnn.modelimportMaskRCNN 7frompathlibimportPath 8fromtwilio.restimportClient 9 10 11#ConfigurationthatwillbeusedbytheMask-RCNNlibrary 12classMaskRCNNConfig(mrcnn.config.Config): 13NAME="coco_pretrained_model_config" 14IMAGES_PER_GPU=1 15GPU_COUNT=1 16NUM_CLASSES=1+80#COCOdatasethas80classes+onebackgroundclass 17DETECTION_MIN_CONFIDENCE=0.6 18 19 20#FilteralistofMaskR-CNNdetectionresultstogetonlythedetectedcars/trucks 21defget_car_boxes(boxes,class_ids): 22car_boxes=[] 23 24fori,boxinenumerate(boxes): 25#Ifthedetectedobjectisn'tacar/truck,skipit 26ifclass_ids[i]in[3,8,6]: 27car_boxes.append(box) 28 29returnnp.array(car_boxes) 30 31 32#Twilioconfig 33twilio_account_sid='YOUR_TWILIO_SID' 34twilio_auth_token='YOUR_TWILIO_AUTH_TOKEN' 35twilio_phone_number='YOUR_TWILIO_SOURCE_PHONE_NUMBER' 36destination_phone_number='THE_PHONE_NUMBER_TO_TEXT' 37client=Client(twilio_account_sid,twilio_auth_token) 38 39 40#Rootdirectoryoftheproject 41ROOT_DIR=Path(".") 42 43#Directorytosavelogsandtrainedmodel 44MODEL_DIR=os.path.join(ROOT_DIR,"logs") 45 46#Localpathtotrainedweightsfile 47COCO_MODEL_PATH=os.path.join(ROOT_DIR,"mask_rcnn_coco.h5") 48 49#DownloadCOCOtrainedweightsfromReleasesifneeded 50ifnotos.path.exists(COCO_MODEL_PATH): 51mrcnn.utils.download_trained_weights(COCO_MODEL_PATH) 52 53#Directoryofimagestorundetectionon 54IMAGE_DIR=os.path.join(ROOT_DIR,"images") 55 56#Videofileorcameratoprocess-setthisto0touseyour***insteadofavideofile 57VIDEO_SOURCE="test_images/parking.mp4" 58 59#CreateaMask-RCNNmodelininferencemode 60model=MaskRCNN(mode="inference",model_dir=MODEL_DIR,config=MaskRCNNConfig()) 61 62#Loadpre-trainedmodel 63model.load_weights(COCO_MODEL_PATH,by_name=True) 64 65#Locationofparkingspaces 66parked_car_boxes=None 67 68#Loadthevideofilewewanttorundetectionon 69video_capture=cv2.VideoCapture(VIDEO_SOURCE) 70 71#Howmanyframesofvideowe'veseeninarowwithaparkingspaceopen 72free_space_frames=0 73 74#HavewesentanSMSalertyet? 75sms_sent=False 76 77#Loopovereachframeofvideo 78whilevideo_capture.isOpened(): 79success,frame=video_capture.read() 80ifnotsuccess: 81break 82 83#ConverttheimagefromBGRcolor(whichOpenCVuses)toRGBcolor 84rgb_image=frame[:,:,::-1] 85 86#RuntheimagethroughtheMaskR-CNNmodeltogetresults. 87results=model.detect([rgb_image],verbose=0) 88 89#MaskR-CNNassumeswearerunningdetectiononmultipleimages. 90#Weonlypassedinoneimagetodetect,soonlygrabthefirstresult. 91r=results[0] 92 93#Thervariablewillnowhavetheresultsofdetection: 94#-r['rois']aretheboundingboxofeachdetectedobject 95#-r['class_ids']aretheclassid(type)ofeachdetectedobject 96#-r['scores']aretheconfidencescoresforeachdetection 97#-r['masks']aretheobjectmasksforeachdetectedobject(whichgivesyoutheobjectoutline) 98 99ifparked_car_boxesisNone:100#Thisisthefirstframeofvideo-assumeallthecarsdetectedareinparkingspaces.101#Savethelocationofeachcarasaparkingspaceboxandgotothenextframeofvideo.102parked_car_boxes=get_car_boxes(r['rois'],r['class_ids'])103else:104#Wealreadyknowwheretheparkingspacesare.Checkifanyarecurrentlyunoccupied.105106#Getwherecarsarecurrentlylocatedintheframe107car_boxes=get_car_boxes(r['rois'],r['class_ids'])108109#Seehowmuchthosecarsoverlapwiththeknownparkingspaces110overlaps=mrcnn.utils.compute_overlaps(parked_car_boxes,car_boxes)111112#Assumenospacesarefreeuntilwefindonethatisfree113free_space=False114115#Loopthrougheachknownparkingspacebox116forparking_area,overlap_areasinzip(parked_car_boxes,overlaps):117118#Forthisparkingspace,findthemaxamountitwascoveredbyany119#carthatwasdetectedinourimage(doesn'treallymatterwhichcar)120max_IoU_overlap=np.max(overlap_areas)121122#Getthetop-leftandbottom-rightcoordinatesoftheparkingarea123y1,x1,y2,x2=parking_area124125#Checkiftheparkingspaceisoccupiedbyseeingifanycaroverlaps126#itbymorethan0.15usingIoU127ifmax_IoU_overlap0.15:128????????????????#?Parking?space?not?occupied!?Draw?a?green?box?around?it129????????????????cv2.rectangle(frame,?(x1,?y1),?(x2,?y2),?(0,?255,?0),?3)130????????????????#?Flag?that?we?have?seen?at?least?one?open?space131????????????????free_space?=?True132????????????else:133????????????????#?Parking?space?is?still?occupied?-?draw?a?red?box?around?it134????????????????cv2.rectangle(frame,?(x1,?y1),?(x2,?y2),?(0,?0,?255),?1)135136????????????#?Write?the?IoU?measurement?inside?the?box137????????????font?=?cv2.FONT_HERSHEY_DUPLEX138????????????cv2.putText(frame,?f"{max_IoU_overlap:0.2}",?(x1?+?6,?y2?-?6),?font,?0.3,?(255,?255,?255))139140????????#?If?at?least?one?space?was?free,?start?counting?frames141????????#?This?is?so?we?don't?alert?based?on?one?frame?of?a?spot?being?open.142????????#?This?helps?prevent?the?script?triggered?on?one?bad?detection.143????????if?free_space:144????????????free_space_frames?+=?1145????????else:146????????????#?If?no?spots?are?free,?reset?the?count147????????????free_space_frames?=?0148149????????#?If?a?space?has?been?free?for?several?frames,?we?are?pretty?sure?it?is?really?free!150????????if?free_space_frames?>10:151#WriteSPACEAVAILABLE!!atthetopofthescreen152font=cv2.FONT_HERSHEY_DUPLEX153cv2.putText(frame,f"SPACEAVAILABLE!",(10,150),font,3.0,(0,255,0),2,cv2.FILLED)154155#Ifwehaven'tsentanSMSyet,sentit!156ifnotsms_sent:157print("SENDINGSMS!!!")158message=client.messages.create(159body="Parkingspaceopen-gogogo!",160from_=twilio_phone_number,161to=destination_phone_number162)163sms_sent=True164165#Showtheframeofvideoonthescreen166cv2.imshow('Video',frame)167168#Hit'q'toquit169ifcv2.waitKey(1)&0xFF==ord('q'):170break171172#Cleanupeverythingwhenfinished173video_capture.release()174cv2.destroyAllWindows()
這段代碼寫的比較簡(jiǎn)潔,實(shí)現(xiàn)了基本的功能。大家也可以試著修改代碼以適應(yīng)不同的場(chǎng)景。僅僅更改一下模型參數(shù),出現(xiàn)的效果就可能完全不同,在不同應(yīng)用中盡情發(fā)揮想象力!
-
機(jī)器學(xué)習(xí)
+關(guān)注
關(guān)注
66文章
8353瀏覽量
132315 -
python
+關(guān)注
關(guān)注
55文章
4768瀏覽量
84376 -
深度學(xué)習(xí)
+關(guān)注
關(guān)注
73文章
5466瀏覽量
120891
原文標(biāo)題:春節(jié)停車難?用Python找空車位
文章出處:【微信號(hào):rgznai100,微信公眾號(hào):rgznai100】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論