Python遠(yuǎn)程視頻監(jiān)控程序的實(shí)例代碼
老板由于事務(wù)繁忙無法經(jīng)常親臨教研室,于是讓我搞個(gè)監(jiān)控系統(tǒng),讓他在辦公室就能看到教研室來了多少人。o(>﹏<)o|||
最初我的想法是直接去網(wǎng)上下個(gè)軟件,可是找來找去不是有毒就是收費(fèi),無奈技術(shù)不到家無法破解,只得另尋他法。
正當(dāng)沒有辦法的時(shí)候,我看到一篇博文一個(gè)基于python的高速視頻傳輸程序 ,看完茅塞頓開,覺得完全可以自己寫一個(gè),在此感謝作者詹姆斯。
這個(gè)程序包括一個(gè)服務(wù)器和一個(gè)客戶端。需要的庫有 VideoCapture 和 pygame,一個(gè)用來得到攝像頭的視頻,一個(gè)用來顯示。Python庫可以點(diǎn)這里下載:Python Extension Packages。進(jìn)去后ctrl+F找到相應(yīng)的庫,然后選擇相應(yīng)的版本即可,這里還有很多其他的庫可提供下載。
我想到的解決方案是,在教研室開一臺(tái)電腦,接一個(gè)USB攝像頭,然后開啟一個(gè)服務(wù)器程序,等待著老板使用客戶端連接,由于是實(shí)時(shí)視頻傳輸,使用UDP協(xié)議。(主要傳輸部分采用詹姆斯的代碼)。
服務(wù)器端代碼如下:
# -*- coding: UTF-8 -*- import socket import time import traceback from VideoCapture import Device import threading # 全局變量 is_sending = False cli_address = ('', 0) # 主機(jī)地址和端口 host = '' port = 10218 # 初始化UDP socket ser_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) ser_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) ser_socket.bind((host, port)) # 接收線程類,用于接收客戶端發(fā)送的消息 class UdpReceiver(threading.Thread): def __init__(self): threading.Thread.__init__(self) self.thread_stop = False def run(self): while not self.thread_stop: # 聲明全局變量,接收消息后更改 global cli_address global is_sending try: message, address = ser_socket.recvfrom(2048) except: traceback.print_exc() continue # print message,cli_address cli_address = address if message == 'startCam': print 'start camera', is_sending = True ser_socket.sendto('startRcv', cli_address) if message == 'quitCam': is_sending = False print 'quit camera', def stop(self): self.thread_stop = True # 創(chuàng)建接收線程 receiveThread = UdpReceiver() receiveThread.setDaemon(True) # 該選項(xiàng)設(shè)置后使得主線程退出后子線程同時(shí)退出 receiveThread.start() # 初始化攝像頭 cam = Device() cam.setResolution(320,240) # 主線程循環(huán),發(fā)送視頻數(shù)據(jù) while 1: if is_sending: img = cam.getImage().resize((160,120)) data = img.tostring() ser_socket.sendto(data, cli_address) time.sleep(0.05) else: time.sleep(1) receiveThread.stop() ser_socket.close()
服務(wù)器啟動(dòng)一個(gè)子線程,來監(jiān)聽客戶端發(fā)送的消息。當(dāng)有消息時(shí),將is_sending改為True,則服務(wù)器向該客戶端發(fā)送視頻數(shù)據(jù)。具體信息可以看代碼注釋。
客戶端代碼如下:
# -*- coding: UTF-8 -*- import socket, time import pygame from pygame.locals import * from sys import exit # 服務(wù)器地址,初始化socket ser_address = ('localhost', 10218) cli_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # 設(shè)置超時(shí) cli_socket.settimeout(5) # 向服務(wù)器發(fā)送消息,并判斷接收時(shí)是否超時(shí),若超時(shí)則重發(fā) while 1: cli_socket.sendto('startCam', ser_address) try: message, address = cli_socket.recvfrom(2048) if message == 'startRcv': print message break except socket.timeout: continue # 此句無用。。防止窗口初始化后等待數(shù)據(jù) cli_socket.recvfrom(65536) # 初始化視頻窗口 pygame.init() screen = pygame.display.set_mode((640,480)) pygame.display.set_caption('Web Camera') pygame.display.flip() # 設(shè)置時(shí)間,可以用來控制幀率 clock = pygame.time.Clock() # 主循環(huán),顯示視頻信息 while 1: try: data, address = cli_socket.recvfrom(65536) except socket.timeout: continue camshot = pygame.image.frombuffer(data, (160,120), 'RGB') camshot = pygame.transform.scale(camshot, (640, 480)) for event in pygame.event.get(): if event.type == pygame.QUIT: cli_socket.sendto('quitCam', ser_address) cli_socket.close() pygame.quit() exit() screen.blit(camshot, (0,0)) pygame.display.update() clock.tick(20)
客戶端就是簡(jiǎn)單地向服務(wù)器發(fā)送啟動(dòng)消息,接收到回復(fù)后開始進(jìn)入主循環(huán)開始接收視頻數(shù)據(jù)并顯示。
由于UDP協(xié)議不保證信息是否成功到達(dá),因此前面設(shè)置了個(gè)重發(fā)機(jī)制,只有當(dāng)客戶端收到服務(wù)器的回復(fù)后,才停止發(fā)送開啟消息并進(jìn)入主循環(huán)。具體見注釋。
使用時(shí)將localhost改成服務(wù)器IP即可,目前測(cè)試僅適用于局域網(wǎng),校園網(wǎng)。外網(wǎng)暫未測(cè)試,熟悉網(wǎng)絡(luò)編程的同學(xué)可以自行實(shí)驗(yàn)。
經(jīng)驗(yàn)
調(diào)試的時(shí)候出現(xiàn)過服務(wù)器怎么都收不到客戶端消息,結(jié)果調(diào)試一下午都找不到原因。晚上回來把防火墻、安全軟件全關(guān)了,順利通過。
服務(wù)器開啟新線程后,由于Python奇怪的設(shè)定,主線程退出后子線程得完成后才會(huì)退出,而這里子線程又是一個(gè)死循環(huán),因此需要對(duì)子線程調(diào)用setDaemon(True),這樣主線程退出時(shí)子線程也會(huì)自動(dòng)退出。若沒有調(diào)用該方法,調(diào)試一次后第二次可能失敗,因?yàn)楹笈_(tái)還有個(gè)子線程在運(yùn)行。
- Python3遠(yuǎn)程監(jiān)控程序的實(shí)現(xiàn)方法
- 用Python的Flask框架結(jié)合MySQL寫一個(gè)內(nèi)存監(jiān)控程序
- Python實(shí)現(xiàn)監(jiān)控程序執(zhí)行時(shí)間并將其寫入日志的方法
- Python寫的服務(wù)監(jiān)控程序?qū)嵗?/a>
- Python監(jiān)控服務(wù)器實(shí)用工具psutil使用解析
- python psutil監(jiān)控進(jìn)程實(shí)例
- python實(shí)現(xiàn)監(jiān)控阿里云賬戶余額功能
- 使用 Supervisor 監(jiān)控 Python3 進(jìn)程方式
- python3.8 微信發(fā)送服務(wù)器監(jiān)控報(bào)警消息代碼實(shí)現(xiàn)
- 基于python3監(jiān)控服務(wù)器狀態(tài)進(jìn)行郵件報(bào)警
- 基于python監(jiān)控程序是否關(guān)閉
相關(guān)文章
解決Tensorflow 使用時(shí)cpu編譯不支持警告的問題
今天小編就為大家分享一篇解決Tensorflow 使用時(shí)cpu編譯不支持警告的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-02-02Python3中對(duì)json格式數(shù)據(jù)的分析處理
這篇文章主要介紹了Python3中對(duì)json格式數(shù)據(jù)的分析處理,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-01-01Python json模塊與jsonpath模塊區(qū)別詳解
這篇文章主要介紹了Python json模塊與jsonpath模塊區(qū)別詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-03-03PyQT中QTableWidget如何根據(jù)單元格內(nèi)容設(shè)置自動(dòng)寬度
這篇文章主要介紹了PyQT中QTableWidget如何根據(jù)單元格內(nèi)容設(shè)置自動(dòng)寬度問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-05-05Async?IO在Python中的異步編程工作實(shí)例解析
這篇文章主要為大家介紹了Async?IO在Python中的異步編程工作實(shí)例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-12-12Pygame實(shí)戰(zhàn)之迷宮游戲的實(shí)現(xiàn)
玩迷宮游戲長大的我們,欣慰地看到,下一代仍熱愛著這個(gè)經(jīng)典游戲。本文將通過Python中的Pygame庫制作這一經(jīng)典的游戲,需要的可以參考一下2022-02-02pytorch tensor int型除法出現(xiàn)的問題
這篇文章主要介紹了pytorch tensor int型除法出現(xiàn)的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2021-04-04