.引言
閱讀本文前,一定要閱讀這篇文章,<<手把手搭建流媒體服務器詳細步驟>>,能夠幫助你,快速搭建Srs流媒體服務器,可以用作后期的學習。
Srs4.0流媒體支持的技術。
Srs官網:https://github.com/ossrs/srs
推流端支持
(1)RTMP
(2)HLS
(3)WebRTC
(4)SRT
(5)GB28181
拉流端支持
(1)RTMP
(2)HLS
(3)WebRTC
(4)SRT
(5)GB28181
注意:不管推流端推上來何種格式,Srs流媒體服務器都是可以經過協議轉換,拉流端都可以拉取到不同協議。如推流端,推RTMP流,那拉流端,可以拉取HTTP流。另外SRS流媒體服務器是支持集群方案。
這里補充下這篇文章在搭建方面沒有的知識點,《手把手搭建流媒體服務器詳細步驟 》。如下幾點:
(1)安全退出正在運行的流媒體服務器
sudo kill -SIGQUIT srs_pid。
(2)srs流媒體服務器默認是后臺啟動方式,如果是要方便GDB調試,則要修改配置文件為前臺啟動。
listen 1935;
max_connections 1000;
#srs_log_tank file;
#srs_log_file ./objs/srs.log;
# 前臺運? 6 daemon off;
# 打印到終端控制臺
srs_log_tank console;
http_api {
enabled on;
listen 1985;
}
http_server {
enabled on;
listen 8081; # http監(jiān)聽端?
dir ./objs/nginx/html;
}
stats {
network 0;
disk sda sdb xvda xvdb;
}
vhost __defaultVhost__ {
# hls darren
hls {
enabled on;
hls_path ./objs/nginx/html;
hls_fragment 10;
hls_window 60;
}
# http-flv darren
http_remux {
enabled on;
mount [vhost]/[app]/[stream].flv;
hstrs on;
}
}
同樣的執(zhí)行方法:
./objs/srs -c conf/srs.conf
經過上面配置,就可以前臺顯示,如下:
(3)SRS是協程方案
1.源碼目錄
srs主要目錄,有以下幾個:
(1)trunk?錄
如下界面:
(2)src下的源碼目錄
trunk目錄下的src目錄,其界面如下:
(3)src下的app目錄
srs_app_async_call.cpp和srs_app_async_call.hpp作用是:可以?來執(zhí)?異步任務,通過execute()函數 push任務,然后在cycle()執(zhí)?,在cycle里面,用的是協程的方案。如下圖所示:
srs_app_bandwidth.cpp和srs_app_bandwidth.hpp作用是:提供寬帶測試接口。
srs_app_caster_flv.cpp和srs_app_caster_flv.hpp作用是:?持POST?個flv流到服務器,類似相當于RTMP的publish。
srs_app_config.cpp和srs_app_config.hpp作用是:讀取配置文件,支持熱更新。
srs_app_conn.cpp和srs_app_conn.hpp作用是:srs的基本連接,每個連接對應?個協程(不能開很多個線程,但可以開很多個協程),所有的連接都被管理。
srs_app_dash.cpp和srs_app_dash.hpp作用是:SrsDash 流媒體DASH業(yè)務 The MPEG-DASH encoder,transmux RTMP to DASH。
srs_app_dvr.cpp和srs_app_dvr.hpp作用是:SrsDvr 錄制RTMP流的flv或者mp4?件。
srs_app_edge.cpp和srs_app_edge.hpp作用是:SrsEdgeRtmpUpstream 邊緣節(jié)點業(yè)務,?如從源站拉流到邊緣,邊緣回溯到源站。
srs_app_encoder.cpp和srs_app_encoder.hpp作用是:轉封裝,SrsEncoder 可以使?多個ffmpeg來轉換指定的流,最終調?SrsFFMPEG來轉流。
srs_app_ffmpeg.cpp和srs_app_ffmpeg.hpp作用是:SrsFFMPEG 使?ffmpeg來轉換流。
srs_app_forward.cpp和srs_app_forward.hpp作用是:SrsForwarder 將流轉發(fā)到其他服務器。
srs_app_fragment.hpp:SrsFragment 表示?個分?,如HLS分?、DVR分?或DASH分?。它是?個媒體?件,例如FLV或MP4,有持續(xù)時間。
srs_app_hds.cpp和srs_app_hds.hpp作用是:SrsHds 將RTMP轉成Adobe HDS流。
srs_app_heartbeat.cpp和srs_app_heartbeat.hpp作用是:發(fā)送SrsHttpHeartbeat HHTP?跳包。
srs_app_hls.cpp和srs_app_hls.hpp作用是:HLS相關業(yè)務。
srs_app_hourglass.cpp和srs_app_hourglass.hpp作用是:SrsHourGlass 滴答tick的處理程序。
srs_app_http_api.cpp和srs_app_http_api.hpp作用是:SrsHttpApi HTTP業(yè)務API。
srs_app_http_conn.cpp和srs_app_http_conn.hpp作用是:SrsHttpConn,HTTP連接,繼承于SrsConnection。
srs_app_http_hooks.cpp和srs_app_http_hooks.hpp作用是:SrsHttpHooks HTTP勾?,HTTP回調API。
srs_app_http_static.cpp和srs_app_http_static.hpp作用是:SrsHttpStaticServer HTTP靜態(tài)服務器實例,為HTTP靜態(tài)?件和FLV/MP4視頻點播服務。
srs_app_http_stream.cpp和─ srs_app_http_stream.hpp作用是:SrsHttpStreamServer HTTP直播流服務,?持FLV/TS/MP3/AAC流。
srs_app_ingest.cpp和srs_app_ingest.hpp作用是:SrsIngester攝取?件/流/設備,?FFMPEG編碼(可選), 通過RTMP推送到SRS(或其他RTMP服務器)。
srs_app_listener.cpp和srs_app_listener.hpp作用是:TCP/UDP監(jiān)聽器。
srs_app_log.cpp和srs_app_log.hpp作用是:SrsFastLog ?志。
srs_app_pithy_print.cpp和srs_app_pithy_print.hpp作用是:SrsPithyPrint 收集信息,然后打印。
srs_app_process.cpp和srs_app_process.hpp作用是:SrsProcess啟動和停?進程,當被終?時調?cycle重新啟動進程。
srs_app_recv_thread.cpp和srs_app_recv_thread.hpp作用是:SrsHttpRecvThread HTTP數據讀取,SrsPublishRecvThread推流數據讀取,SrsQueueRecvThread從隊列讀?。籗rsRecvThread封裝的協程。
srs_app_reload.cpp和srs_app_reload.hpp作用是:ISrsReloadHandler 重新讀取配置?件的處理。
srs_app_rtmp_conn.cpp和srs_app_rtmp_conn.hpp作用是:SrsRtmpConn RTMP連接。
srs_app_rtsp.cpp和srs_app_rtsp.hpp作用是:SrsRtpConn RTSP連接,SrsRtspCaster RTSP業(yè)務。
srs_app_security.cpp和srs_app_security.hpp作用是:SrsSecurity 安全限制,主要是限制url。
srs_app_server.cpp和srs_app_server.hpp作用是:SrsServer SRS服務,對應的rtmp、rtsp、http-flv等等業(yè)務在這?啟動。
srs_app_source.cpp和srs_app_source.hpp作用是:SrsSource 對應?個源,?持多個SrsConsumer來拉流,SrsSourceManager管理源, SrsMetaCache?于源緩存Meta數據,SrsConsumer源的消費者,SrsGopCache GOP緩存。
srs_app_statistic.cpp和srs_app_statistic.hpp作用是:SrsStatistic流統計。
srs_app_st.cpp和srs_app_st.hpp作用是:SrsSTCoroutine協程相關。
srs_app_thread.cpp和srs_app_thread.hpp作用是:SrsCoroutineManager協程管理。
srs_app_utility.cpp和srs_app_utility.hpp作用是:?具類:SrsPlatformInfo、SrsNetworkDevices、SrsMemInfo、SrsDiskStat等等。
(4)srs下的core目錄
core目錄下,有以下主要文件。
srs_core_autofree.cpp和srs_core_autofree.hpp作用是:通過棧上的?式構建?動釋放堆申請的對象,這個設計還是?常值得我們學習。
srs_core.cpp和srs_core.hpp作用是:版本相關的?些信息。
srs_core_mem_watch.cpp和srs_core_mem_watch.hpp作用是:內存監(jiān)測接?。
srs_core_performance.cpp和srs_core_performance.hpp作用是:性能測試相關。
srs_core_time.cpp和srs_core_time.hpp作用是:時間單位相關。
srs_core_version3.cpp和srs_core_version3.hpp作用是:版本信息。
(5)srs下的kernel目錄
srs_kernel_aac.cpp和srs_kernel_aac.hpp作用是:SrsAacTransmuxer 合成AAC?頻流,帶ADTS header。
srs_kernel_balance.cpp和srs_kernel_balance.hpp作用是:SrsLbRoundRobin負載均衡,?于邊緣節(jié)點拉流和其他多個服務器的功能。
srs_kernel_buffer.cpp和srs_kernel_buffer.hpp作用是:SrsBuffer讀取字節(jié)的實?類。
srs_kernel_codec.cpp和rs_kernel_codec.hpp作用是:編碼器相關,包括視頻和?頻,?常核?的?件;SrsFlvVideo?來檢測FLV的video tag對應內容;SrsFlvAudio?來檢測FLV的audio tag對應內容;SrsMaxNbSamples 256表示video最?的NALUS個數,audio最?的packet數量;SrsFrame存儲幀,SrsAudioFrame 存儲AAC幀,SrsVideoFrame存儲視頻幀;SrsFormat編碼器格式,包含了?個或者多個流,?如為RTMP format時,包含?個視頻和?個?頻幀。
srs_kernel_consts.cpp和srs_kernel_consts.hpp作用是:SRS的常量定義,?如播放的標記#defineSRS_CONSTS_LOG_PLAY "PLA",發(fā)布的標記#define SRS_CONSTS_LOG_CLIENT_PUBLISH"CPB",SRS_CONSTS_HTTP_XXX等HTTP響應碼,SRS_CONSTS_RTSP_XXX RTSP響應碼等等。
srs_kernel_error.cpp和srs_kernel_error.hpp作用是:返回值常量定義,ERROR_XXX;SrsCplxError 異常類。
srs_kernel_file.cpp和srs_kernel_file.hpp作用是:?件的讀寫,SrsFileWriter?件寫?器,SrsFileReader?件讀取器。
srs_kernel_flv.cpp和srs_kernel_flv.hpp作用是:FLV SrsFlvDecoder解析,SrsFlvTransmuxer將RTMP轉成FLV流。SrsSharedPtrMessage對應RTMP的消息。
srs_kernel_io.cpp和srs_kernel_io.hpp作用是:IO讀寫接?類。
srs_kernel_log.cpp和srs_kernel_log.hpp作用是:日志相關。
srs_kernel_mp3.cpp和srs_kernel_mp3.hpp作用是:SrsMp3Transmuxer將RTMP轉成MP3流。
srs_kernel_mp4.cpp和srs_kernel_mp4.hpp作用是:SrsMp4Encoder MP4復?器。
srs_kernel_stream.cpp和srs_kernel_stream.hpp作用是:SrsSimpleStream?vector實現的簡單的字節(jié)append類,主要在hls和http中使?,將來需要進?改進。
srs_kernel_ts.cpp和srs_kernel_ts.hpp作用是:SrsTsTransmuxer將RTMP流轉成http-ts流,該?件實現了ts格式相關的接?。
srs_kernel_utility.cpp和srs_kernel_utility.hpp作用是:?具函數,?如bool srs_string_ends_with(std::string str,std::string flag)。
(6)srs下的libs目錄
libs目錄包含如下一些文件:
srs_lib_bandwidth.cpp和srs_lib_bandwidth.hpp作用是:srs-librtmp 客戶端帶寬統計。
srs_librtmp.cpp和srs_librtmp.hpp作用是:srs提供的客戶端rtmp庫。
srs_lib_simple_socket.cpp和srs_lib_simple_socket.hpp作用是:SimpleSocketStream rtmp客戶端的socket封裝。
注意:這些庫,有可能是用到客戶端上去。
(6)srs下的main目錄
main目錄包含如下一些文件:
srs_main_ingest_hls.cpp作用是:拉取hls發(fā)布到rtmp流媒體服務器。
srs_main_mp4_parser.cpp作用是:MP4 box解析。
srs_main_server.cpp作用是:srs流媒體服務器主??。
(7)srs下的protocol目錄
流媒體相關的協議分析,protocol目錄包含如下一些文件:
srs_http_stack.cpp和srs_http_stack.hpp作用是:HTTP協議分析。
srs_protocol_amf0.cpp和srs_protocol_amf0.hpp作用是:Amf0解析。
srs_protocol_format.cpp和srs_protocol_format.hpp作用是:SrsRtmpFormat繼承了SrsFormat, 代表RTMP格式。
srs_protocol_io.cpp和srs_protocol_io.hpp作用是:協議數據讀取的IO封裝接?,?如ISrsProtocolReadWriter。
srs_protocol_json.cpp和srs_protocol_json.hpp作用是:json類。
srs_protocol_kbps.cpp和srs_protocol_kbps.hpp作用是:?特率統計相關。
srs_protocol_stream.cpp和srs_protocol_stream.hpp作用是:流讀取,從ISrsReader讀取數據到buffer??。
srs_protocol_utility.cpp和srs_protocol_utility.hpp作用是:協議?具函數。
srs_raw_avc.cpp和srs_raw_avc.hpp作用是:SrsRawH264Stream H264裸流解析,SrsRawAacStream AAC裸流解析。
srs_rtmp_handshake.cpp和srs_rtmp_handshake.hpp作用是:RTMP握?,包括SrsSimpleHandshake和SrsComplexHandshake。
srs_rtmp_msg_array.cpp和srs_rtmp_msg_array.hpp作用是:SrsMessageArray消息數組。
srs_rtmp_stack.cpp和srs_rtmp_stack.hpp作用是:RTMP協議棧。
(7)srs下的service目錄
srs_service_conn.cpp和srs_service_conn.hpp作用是:ISrsConnection HTTP/RTMP/RTSP等對象的連接接?。
srs_service_http_client.cpp和srs_service_http_client.hpp作用是:SrsHttpClient HTTP客戶端。
srs_service_http_conn.cpp和srs_service_http_conn.hpp作用是:HTTP連接 SrsHttpParser,SrsHttpMessage,SrsHttpResponseWriter,SrsHttpResponseReader。
srs_service_log.cpp和srs_service_log.hpp作用是:SrsConsoleLog?志相關。
srs_service_rtmp_conn.cpp和srs_service_rtmp_conn.hpp作用是:SrsBasicRtmpClient RTMP客戶端類。
srs_service_st.cpp和srs_service_st.hpp作用是:對st-thread協程的封裝。
srs_service_utility.cpp和srs_service_utility.hpp作用是:service組件的?具類。
(8)srs下的utest目錄
由于篇幅原因,這里僅僅列出一部分。
srs_utest_amf0.cpp和srs_utest_amf0.hpp。
srs_utest_app.cpp和srs_utest_app.hpp。
srs_utest_avc.cpp和srs_utest_avc.hpp。
srs_utest_config.cpp和srs_utest_config.hpp。
2.總結
本篇文章主要介紹了SRS流媒體服務器的目錄介紹以及具體文件是干什么的,大致能夠對SRS流媒體服務器有個了解。希望能夠幫助到想學習流媒體服務器的朋友。
歡迎關注,轉發(fā),點贊,收藏,分享,評論區(qū)討論。
后期關于項目的知識,會在微信公眾號上更新,如果想要學習項目,可以關注微信公眾號“記錄世界 from antonio”
本教程中,您將學習如何通過Flask和Python使用OpenCV將視頻從網絡攝像頭流式傳輸到網頁瀏覽器/HTML頁面。
您的車被偷過嗎?
我的車在周末就被偷了。讓我告訴您,我很生氣。
我不能透露太多的細節(jié),因為這個案件還在調查中,但以下是我可以告訴您的:
大約六個月前,我和妻子從康涅狄格州的諾沃克搬到了賓夕法尼亞州的費城。我有一輛車,我不經常開,但還是留著它以備不時之需。
我們小區(qū)很難找到停車的地方,所以我需要一個車庫。
我聽說有個車庫,就報名了,開始把車停在那里。
直到上個星期天。
我和妻子來到車庫取車。我們打算開車到馬里蘭去看望我的父母,吃一些螃蟹(馬里蘭的螃蟹很有名)。
我走到我的車旁,取下車衣。
我立馬就蒙圈了——這不是我的車。
我的車#$&@去哪里了?
幾分鐘后我就意識到一個現實——我的車被偷了。
在過去的一周中,我為即將出版的《樹莓派電腦視覺》一書正在做的工作被打斷了——我一直在與停車場的主人、費城警察局和我車上的GPS跟蹤服務打交道,想弄清楚到底發(fā)生了什么。
在事情解決之前,我不能公開透露任何細節(jié),但是讓我告訴您,我正埋頭處理警察報告、律師信件、還有保險索賠等一大堆的文件。
我希望下個月這個問題能得到解決——我討厭分心,尤其是讓我遠離我最喜歡做的事情——教計算機視覺和深度學習。
我成功地利用我的挫折啟發(fā)了一篇新的安全相關的計算機視覺博客帖子。
在這篇文章中,我們將學習如何使用Flask和OpenCV將視頻流式傳輸到網頁瀏覽器中。
您可以在不到5分鐘的時間內將此系統部署到樹莓派上:
沒什么比一個小視頻證據更能抓住小偷了。
當我繼續(xù)與警察、保險等處理文書工作時,您就可以開始用樹莓派相機武裝自己,無論您在哪里生活和工作,都可以抓住壞人。
要學習如何使用OpenCV和Flask將視頻流式傳輸到一個網頁瀏覽器的HTML頁面,請繼續(xù)閱讀!
在本教程中,我們將首先討論Flask,它是一個用于Python編程語言的微型web框架。
我們將學習運動檢測的基本知識,以便我們可以將它應用到我們的項目中。我們將通過一個背景減法器來實現運動檢測。
在此基礎上,我們將Flask與OpenCV結合,這樣我們就能夠:
此外,我們將涉及的代碼將能夠支持多個客戶端(即,不止一個人/網頁瀏覽器/標簽頁能同時訪問流媒體),這是您在網上看到的絕大多數例子都無法處理的。
把所有這些過程塊放在一起,我們就會得到一個能夠執(zhí)行運動檢測的家庭監(jiān)控系統,然后它會將視頻結果流式傳輸到您的網頁瀏覽器中。
讓我們開始吧!
圖1:Flask是Python的一個微型web框架(image source)。
在本節(jié)中,我們將簡要討論Flask web框架以及如何在您的系統中安裝它。
Flask是一個非常流行的用Python編程語言編寫的微型web框架。
與Django一樣,Flask是使用Python構建web應用程序時最常見的web框架之一。
但是,與Django不同的是,Flask非常輕量,這使得使用它構建基本的web應用程序非常容易。
正如我們將在本節(jié)中看到的,我們只需要一小部分代碼就可以使用Flask實現實時流式傳輸視頻——其余的代碼包括(1)OpenCV和訪問我們的視頻流,或者(2)確保我們的代碼是線程安全的,并且可以處理多個客戶端。
如果您需要在一個機器上安裝Flask,您只需要簡單地按以下命令進行操作:
安裝了它之后,您可以繼續(xù)安裝NumPy、OpenCV和imutils:
注意:如果您想要完整安裝包括“非免費”(專利)算法的OpenCV,那您一定要從源代碼來編譯OpenCV。
在我們繼續(xù)之前,讓我們看看我們項目的目錄結構:
為了執(zhí)行背景去除和運動檢測,我們將實現一個名為SingleMotionDetector的類——該類將位于singlemotiondetector.py文件中pyimagesearch的motion_detection子模塊中。
webstreaming.py文件將使用OpenCV訪問我們的網絡攝像頭,通過SingleMotionDetector執(zhí)行運動檢測,然后通過Flask web框架將輸出幀提供給我們的網絡瀏覽器。
為了讓我們網絡瀏覽器能有東西顯示,我們需要使用HTML填充index.html的內容來提供接收到的視頻。我們只需要插入一些基本的HTML標記——Flask將實際處理將視頻流發(fā)送到我們的瀏覽器的事情。
圖2:使用Raspberry Pi、OpenCV、Flask和網絡流媒體進行視頻監(jiān)控。
通過使用背景去除進行運動檢測,我們可以檢測到我在椅子上的運動。
我們的運動檢測算法將通過背景減除的形式來檢測運動。
大多數背景去除算法的工作原理是:
我們的運動檢測實現將位于SingleMotionDetector類中,該類可以在SingleMotionDetector .py中找到。
我們稱之為一個“單一運動檢測器”,因為其算法本身只對尋找單一的、最大的運動區(qū)域感興趣。
我們也可以很容易地擴展這個方法來處理多個運動區(qū)域。
讓我們來實現該運動檢測器。
打開singlemotiondetector.py文件,并插入以下代碼:
第2-4行處理所需的導入。
所有這些都是相當標準的,包括用于數字處理的NumPy、用于為我們提供方便函數的imutils和用于OpenCV綁定的cv2。
然后我們在第6行定義SingleMotionDetector類。這個類接受一個可選的參數accumWeight,它是用于累積加權平均值的因數。
accumWeight越大,在累積加權平均值時,背景(bg)被考慮的越少。
相反地,accumWeight越小,在計算平均值時考慮背景(bg)就會越多。
設置accumWeight=0.5會均勻地加權背景和前景——我經常建議使用這個設置作為起始值(然后您可以根據自己的實驗調整它)。
接下來,讓我們定義update方法,它將接受一個輸入幀并計算加權平均值:
為了防止我們的bg幀為None(這意味著update從未被調用),我們只需要存儲bg幀(第15-18行)。
否則,我們會計算輸入幀、現有背景bg和相應的accumWeight因子之間的加權平均值。
鑒于我們的背景bg,我們現在可以通過detect方法應用運動檢測:
detect方法需要一個參數和一個可選參數:
給定我們的輸入image,我們計算該image和bg之間的絕對誤差(第27行)。
任何差異>tVal的像素位置都被設置為255(白色;前景),否則設置為0(黑色;背景)(28行)。
通過一系列的腐蝕和膨脹來消除噪聲和小的局部運動區(qū)域,否則這些區(qū)域會被認為是假陽性的(可能是由于反射或光線的快速變化)。
下一步是應用輪廓檢測提取任何運動區(qū)域:
第37-39行對我們的thresh圖像執(zhí)行輪廓檢測。
然后,我們初始化兩組記賬變量,以跟蹤包含任何運動的位置(第40行和第41行)。這些變量將形成“邊界框”,它將告訴我們運動發(fā)生的位置。
最后一步是填充這些變量(假設運動存在于幀中,當然是這樣):
在43-45行中,我們檢查我們的輪廓列表是否為空。
如果是這種情況,那么在幀中就找不到運動,我們就可以放心地忽略它。
否則,在幀中確實存在運動,所以我們就需要開始在輪廓線上進行循環(huán)(第48行)。
對于每個輪廓,我們計算其邊界框,然后更新我們的記賬變量(第47-53行),找到所有運動發(fā)生的最小和最大(x, y)坐標。
最后,我們將邊界框位置返回給調用函數。
圖3:OpenCV和Flask (一個Python微型網絡框架)是涉及Raspberry Pi和類似硬件的網絡流媒體和視頻監(jiān)控項目的完美搭檔。
讓我們繼續(xù),將OpenCV和Flask結合起來,從一個視頻流(運行在樹莓派上)向一個網絡瀏覽器提供幀。
打開您項目結構中的webstreaming.py 文件,并插入如下代碼:
第2-12行處理我們需要的導入:
讓我們繼續(xù)執(zhí)行一些初始化:
首先,我們在第17行初始化我們的outputFrame——這將是將提供給客戶端的幀(投遞運動檢測)。
然后,我們在第18行創(chuàng)建一個lock,它將在更新ouputFrame時被用來確保線程安全行為(即確保某個幀在更新時不被任何線程嘗試讀?。?/p>
第21行初始化我們的Flask app本身,而第25-27行訪問我們的視頻流:
下一個函數index將會渲染我們的index.html模板并提供輸出視頻流:
這個函數非常簡單—它所做的就是在我們的HTML文件中調用Flask render_template。
我們將在下一章查看該index.html文件,因此,我們將推遲對此文件內容的進一步討論直到那個時候。
我們的下一個函數的功能是:
而且,這個函數必須以線程安全的方式來執(zhí)行所有這些操作,以確保支持并發(fā)。
現在讓我們看看這個函數:
我們的detection_motion函數接受單個參數frameCount,它是在SingleMotionDetector類中構建我們的背景bg所需的最小幀數:
第37行獲取對三個變量的全局引用:
第41行使用一個accumWeight=0.1值來初始化我們的SingleMotionDetector 類,這意味著在計算加權平均值時,bg值的權重會更高。
第42行初始化到目前為止讀取的幀的total數——我們需要確保已經讀取了足夠多的幀來構建我們的背景模型。
從那里,我們將能夠執(zhí)行背景去除。
這些初始化完成后,我們現在可以開始對來自相機的幀進行循環(huán):
第48行讀取來自我們相機的frame幀,而第49-51行執(zhí)行預處理操作,包括:
然后,我們獲取當前時間戳并將其繪制在frame上(第54-57行)。
在進行一次最終檢查之后,我們就可以執(zhí)行運動檢測:
在第62行中,我們確保我們至少讀取了frameCount幀來構建我們的背景去除模型。
如果是這樣,我們將應用我們運動檢測器的.detect運動,它將返回單個變量motion。
如果motion是None,那么我們就知道當前frame中沒有發(fā)生運動。否則,如果motion不是None(第67行),那么我們需要在frame上繪制運動區(qū)域的邊界框坐標。
第76行更新我們的運動檢測背景模型,而第77行增加了迄今為止從攝像機讀取的幀的total數。
最后,第81行獲得支持線程并發(fā)所需的lock,而第82行設置outputFrame。
我們需要獲取鎖,以確保我們在試圖更新outputFrame變量時客戶機不會意外讀取它。
我們的下一個函數,generate,是一個Python生成器,用于將我們的outputFrame編碼為JPEG數據——現在讓我們來看看它:
第86行獲取對outputFrame和lock的全局引用,類似于detect_motion函數。
然后generate在第89行啟動一個無限循環(huán),這個循環(huán)將一直持續(xù)到我們結束腳本。
在循環(huán)內部,我們:
在這么短的代碼中做了這么多工作,所以一定要檢查這個函數幾次,以確保您了解它是如何工作的。
下一個函數video_feed會調用我們的generate函數:
注意這個app.route函數簽名,就像上面的index函數一樣。
這個app.route簽名告訴Flask這個函數是一個URL端點,數據是從http://your_ip_address/video_feed提供的。
video_feed的輸出是實時運動檢測輸出,通過generate函數編碼為一個字節(jié)數組。您的網絡瀏覽器非常聰明,可以將這個字節(jié)數組作為一個實時輸出顯示在您的瀏覽器中。
我們最后的代碼塊處理解析命令行參數和啟動Flask應用程序的任務:
第118-125行處理解析命令行參數的任務。
這里我們需要三個參數,包括:
第128-131行啟動一個線程用于執(zhí)行運動檢測。
使用一個線程確保detect_motion函數可以安全地在后臺運行——它將不斷地運行和更新我們的outputFrame,以便我們可以為我們的客戶端提供任何運動檢測結果。
最后,第134和135行啟動Flask應用程序本身。
正如我們在webstreaming.py中看到的,我們正在渲染一個名為index.html的HTML模板。
該模板本身由Flask 網絡框架進行填充,然后提供給網絡瀏覽器。
然后,您的網絡瀏覽器將生成的HTML呈現到您的屏幕上。
讓我們檢查一下index.html文件的內容:
我們可以看到,這是一個超級基礎的網頁;但是,請密切注意第7行——注意我們如何指示Flask動態(tài)呈現我們video_feed路徑的URL。
由于video_feed函數負責提供來自我們網絡攝像頭的幀,所以圖像的src將會被自動填充上我們的輸出幀。
然后,我們的網絡瀏覽器足夠智能,可以正確渲染網頁并提供實時視頻流。
現在我們已經寫完了我們項目的代碼,讓我們對其進行測試。
打開一個終端,執(zhí)行以下命令:
正如您在視頻中看到的,我從多個瀏覽器打開了到Flask/OpenCV服務器的連接,每個瀏覽器都有多個選項卡。我甚至拿出我的iPhone,并打開了一些來自那里的連接。服務器沒有跳過一個幀,持續(xù)地使用Flask和OpenCV可靠地提供幀。
加入嵌入式計算機視覺和深度學習革命!
我第一次彈吉他是在20年前,那時我還在上中學。我不太擅長,幾年后我就放棄了?;仡欉^去,我堅信我沒有堅持下去的原因是因為我沒有以一種實際的、動手操作的方式來學習。
相反,我的音樂老師一直向我腦子里灌輸理論——但作為一個11歲的孩子,我只是想弄清楚我是否喜歡彈吉他,更不用說我是否想研究音樂背后的理論了。
大約一年半以前,我決定重新開始上吉他課。這一次,我特意找了一位能夠將理論與實踐相結合的老師,教我如何在學習理論技巧的同時演奏歌曲或即興重復樂段。
結果呢?我的手指速度比以往任何時候都快,我的節(jié)奏也很準,我可以不斷地惹惱我的妻子,在我的Les Paul上演奏Sweet Child of Mine。
我的觀點是,無論何時您在學習一項新技能時,無論是計算機視覺,還是使用樹莓派進行滲透,甚至是彈吉他,最快、最簡單的學習方法之一就是圍繞這項技能設計(小的)現實世界的項目,并嘗試解決它。
對于吉他來說,這意味著學習短的即興重復,這不僅教會了我真正的歌曲的一部分,也給了我一個寶貴的技巧(例如,掌握一種特定的五聲音階)。
在計算機視覺和圖像處理中,您的目標應該是思考一些小型項目,然后嘗試解決它們。不要太快就把事情復雜化,那是失敗的秘訣。
相反,您可以拿一本我寫的《樹莓派計算機視覺》書,讀一讀,把它作為您個人項目的一個啟動平臺。
當您讀完之后,回到那些最激勵您的章節(jié),看看您能如何以某種方式擴展它們(即使只是將相同的技術應用到一個不同的場景中)。
解決您思考的小項目不僅會讓您對這個主題感興趣(因為您自己想到了它們),而且它們還會教您實踐技能。
今天的教程——運動檢測和流式傳輸到網絡瀏覽器——就是這樣一個迷您項目的一個很好的起點。我希望既然您已經閱讀了本教程,您已經對如何將這個項目擴展到您自己的應用程序進行了思考。
但是,如果您有興趣學習更多……
我的新書《樹莓派計算機視覺》中有40多個與嵌入式計算機視覺+物聯網(IoT)相關的項目。您可以根據書中的項目進行構建來解決家里、公司甚至客戶的問題。每一個項目都有著重方向:
幾個精品項目包括:
本書還涵蓋了使用谷歌Coral和Intel Movidius NCS協作處理器(Hacker + Complete Bundles)的深度學習。當需要更多的深度學習能力時,我們還將引入NVIDIA Jetson Nano(Complete Bundle)。
如果您錯過了Kickstarter,您可以看看我的公告視頻:
您準備好和我一起學習計算機視覺和如何應用嵌入式設備(如樹莓派、Google Coral和NVIDIA Jetson Nano)了嗎?
如果是這樣,請使用下面的鏈接查看這本書!
在本教程中,您學習了如何將幀從一個服務器機器流式傳輸到一個客戶端網絡瀏覽器。使用這個網絡流式傳輸程序,我們能夠構建一個基本的安全應用程序來監(jiān)控我們房子里的一個房間的運動。
背景去除是計算機視覺中最常用的一種方法。通常,這些算法的計算效率很高,這使得它們適合于資源受限的設備,如樹梅派。
在實現了我們的背景去除器后,我們將其與Flask 網絡框架結合,這使得我們能夠:
此外,我們的實現支持多個客戶端、瀏覽器或選項卡——這在大多數其它實現中都找不到。
無論何時您需要將幀從一個設備流式傳輸到一個網絡瀏覽器時,一定要使用此代碼作為一個模板/起點。
英文原文:https://www.pyimagesearch.com/2019/09/02/opencv-stream-video-to-web-browser-html-page
譯者:Nothing
瀏覽器構建請求報文信息,構建好后,瀏覽器準備發(fā)起網絡
請求行
GET /index.html HTTP1.1
發(fā)送請求行,就是告訴服務器瀏覽器需要什么資源,最常用的請求方法是 Get。
請求體
如果使用 POST 方法,那么瀏覽器還要準備數據給服務器,這里準備的數據是通過請求體來發(fā)送。
請求頭
請求行之后,瀏覽器器以請求頭形式發(fā)送其他一些信息,把瀏覽器的一些基礎信息告訴服務器。比如包含了瀏覽器所使用的操作系統、瀏覽器內核等信息,以及當前請求的域名信息、瀏覽器端的 Cookie 信息,等等。
瀏覽器在發(fā)送請求之前先在瀏覽器緩存(是一種在本地保存資源副本,以供下次請求時直接使用的技術)中查詢是否有要請求的文件。 當瀏覽器發(fā)現請求的資源已經在瀏覽器緩存中存有副本,它會攔截請求,返回該資源的副本,并直接結束請求,而不會再去源服務器重新下載。 好處如下:
緩解服務器端壓力,提升性能(獲取資源的耗時更短了);
對于網站來說,緩存是實現快速資源加載的重要組成部分。 如果查找緩存失敗,則進入網絡請求過程。
IP 需要用到DNS來查找對應的IP地址
端口號 HTTP 協議默認是 80 端口,HTTPS協議是443端口。
不是說準備好了IP和端口號了就可以直接發(fā)送TCP連接的。 Chrome 有個機制,默認情況下同一個域名同時最多只能建立 6 個 TCP 連接,如果在同一個域名下同時有 10 個請求發(fā)生,那么其中 4 個請求會進入排隊等待Pending狀態(tài),直至進行中的請求完成。
一旦建立了 TCP 連接,瀏覽器就可以和服務器進行通信了。而 HTTP 中的數據正是在這個通信過程中傳輸的。
瀏覽器是如何發(fā)送請求信息給服務器的過程如下
在瀏覽器發(fā)送請求行命令之后,還要以請求頭形式發(fā)送其他一些信息,把瀏覽器的一些基礎信息告訴服務器。比如包含了瀏覽器所使用的操作系統、瀏覽器內核等信息,以及當前請求的域名信息、瀏覽器端的 Cookie 信息,等等。
你可以通過工具軟件 curl 來查看返回請求數據curl -i https://time.geekbang.org/注意這里加上了-i是為了返回響應行、響應頭和響應體的數據。
首先服務器會返回響應行,包括協議版本和狀態(tài)碼。但并不是所有的請求都可以被服務器處理的,那么一些無法處理或者處理出錯的信息,怎么辦呢?服務器會通過請求行的狀態(tài)碼來告訴瀏覽器它的處理結果
正如瀏覽器會隨同請求發(fā)送請求頭一樣,服務器也會隨同響應向瀏覽器發(fā)送響應頭。響應頭包含了服務器自身的一些信息,比如服務器生成返回數據的時間、返回的數據類型(JSON、HTML、流媒體等類型),以及服務器要在客戶端保存的 Cookie 等信息。發(fā)送完響應頭后,服務器就可以繼續(xù)發(fā)送響應體的數據,通常,響應體就包含了 HTML 的實際內容。
通常情況下,一旦服務器向客戶端返回了請求數據,它就要關閉 TCP 連接。不過如果瀏覽器或者服務器在其頭信息中加入了:Connection:Keep-Alive 那么 TCP 連接在發(fā)送后將仍然保持打開狀態(tài),這樣瀏覽器就可以繼續(xù)通過同一個 TCP 連接發(fā)送請求。保持 TCP 連接可以省去下次請求時需要建立連接的時間,提升資源加載速度。比如,一個 Web 頁面中內嵌的圖片就都來自同一個 Web 站點,如果初始化了一個持久連接,你就可以復用該連接,以請求其他資源,而不需要重新再建立新的 TCP 連接。
比如當你在瀏覽器中打開 geekbang.org 后,你會發(fā)現最終打開的頁面地址是 https://www.geekbang.org。curl -I geekbang.org
從圖中你可以看到,響應行返回的狀態(tài)碼是 301,狀態(tài) 301 就是告訴瀏覽器,我需要重定向到另外一個網址,而需要重定向的網址正是包含在響應頭的 Location 字段中,接下來,瀏覽器獲取 Location 字段中的地址,并使用該地址重新導航,這就是一個完整重定向的執(zhí)行流程。
Q: 為什么很多站點第二次打開速度會很快?
如果第二次頁面打開很快,主要原因是第一次加載頁面過程中,緩存了一些耗時的數據--DNS 緩存和頁面資源緩存 緩存處理過程如圖所示
從上圖的第一次請求可以看出,當服務器返回 HTTP 響應頭給瀏覽器時,瀏覽器是通過響應頭中的 Cache-Control 字段來設置是否緩存該資源。通常,我們還需要為這個資源設置一個緩存過期時長,而這個時長是通過 Cache-Control 中的 Max-age 參數來設置的,比如上圖設置的緩存過期時間是 2000 秒。
Cache-Control:Max-age=2000
這也就意味著,在該緩存資源還未過期的情況下, 如果再次請求該資源,會直接返回緩存中的資源給瀏覽器。 但如果緩存過期了,瀏覽器則會繼續(xù)發(fā)起網絡請求,并且在 HTTP 請求頭中帶上:
If-None-Match:"4f80f-13c-3a1xb12a"
服務器收到請求頭后,會根據 If-None-Match 的值來判斷請求的資源是否有更新。
如果沒有更新,就返回 304 狀態(tài)碼,相當于服務器告訴瀏覽器:“這個緩存可以繼續(xù)使用,這次就不重復發(fā)送數據給你了。”如果資源有更新,服務器就直接返回最新資源給瀏覽器。
簡要來說,很多網站第二次訪問能夠秒開,是因為這些網站把很多資源都緩存在了本地,瀏覽器緩存直接使用本地副本來回應請求,而不會產生真實的網絡請求,從而節(jié)省了時間。同時,DNS 數據也被瀏覽器緩存了,這又省去了 DNS 查詢環(huán)節(jié)。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。