用python通過(guò)opencv模塊來(lái)做實(shí)時(shí)監(jiān)控這件事情很早就想做了污淋,但是因?yàn)楸救说耐涎影Y一直被擱置直到最近強(qiáng)迫自己才通過(guò)網(wǎng)上的現(xiàn)有資料進(jìn)行進(jìn)行更改姻檀,完成了這個(gè)基本能正常工作的版本,我們暫且叫他1.0
首先是服務(wù)器端代碼什湘,主要功能其實(shí)就是通過(guò)opencv模塊進(jìn)行攝像頭數(shù)據(jù)的采集暑脆,然后將每一幀數(shù)據(jù),也就是圖像涣澡,通過(guò)cv2.imencode()函數(shù)轉(zhuǎn)換成jpg格式,這個(gè)步驟主要是為了將數(shù)據(jù)進(jìn)行壓縮丧诺,不然傳輸?shù)臄?shù)據(jù)量太大入桂,我們通常外網(wǎng)訪問(wèn)基本沒(méi)法承受。(假設(shè)我們不去進(jìn)行任何數(shù)據(jù)壓縮處理驳阎,那一個(gè)380240的圖片實(shí)際上是3804203(這個(gè)3是因?yàn)槭荝GB圖)個(gè)字節(jié)抗愁,也就是470kb,一秒就算只有10幀呵晚,那也至少需要4.7MB每秒的傳輸速度蜘腌。那顯然不靠譜。)壓縮完之后饵隙,然后通過(guò)socket模塊使用tcp協(xié)議將數(shù)據(jù)發(fā)送出去撮珠,服務(wù)器端程序基本面功能也就完成了。
服務(wù)器端代碼:
客戶端代碼金矛,主要使用socket模塊通過(guò)tcp協(xié)議將服務(wù)器發(fā)來(lái)的數(shù)據(jù)進(jìn)行解碼芯急,然后顯示在自己的電腦上,由于本人極端厭惡做人機(jī)交互界面驶俊,所以這里通過(guò)配置文件的形式來(lái)改變整個(gè)監(jiān)控的參數(shù)娶耍,比如每秒幾幀,圖像分辨率饼酿,圖像質(zhì)量榕酒,還有服務(wù)器ip胚膊。首次運(yùn)行,系統(tǒng)會(huì)自動(dòng)創(chuàng)建配置文件想鹰,txt格式澜掩,然后將配置文件里的數(shù)據(jù)改成你需要的數(shù)據(jù)再保存,再次運(yùn)行程序杖挣,程序會(huì)自動(dòng)讀取你最新配置的配置參數(shù)肩榕。
客戶端代碼:
import socket;
import threading;
import struct;
import cv2
import time
import os
import numpy
class webCamera:
def __init__(self, resolution = (640, 480), host = ("", 7999)):
self.resolution = resolution;
self.host = host;
self.setSocket(self.host);
self.img_quality = 15
def setImageResolution(self, resolution):
self.resolution = resolution;
def setHost(self, host):
self.host = host;
def setSocket(self, host):
self.socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM);
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR,1);
self.socket.bind(self.host);
self.socket.listen(5);
print("Server running on port:%d" % host[1]);
def recv_config(self,client):
info = struct.unpack("lhh",client.recv(8));
if info[0]>911: #print(info[0])
self.img_quality=int(info[0])-911
self.resolution=list(self.resolution)
self.resolution[0]=info[1]
self.resolution[1]=info[2]
self.resolution=tuple(self.resolution)
return 1
else :
return 0
def _processConnection(self, client,addr):
if(self.recv_config(client)==0):
return
camera = cv2.VideoCapture(0)
encode_param=[int(cv2.IMWRITE_JPEG_QUALITY),self.img_quality]
f = open("video_info.txt", 'a+')
print("Got connection from %s:%d" % (addr[0], addr[1]),file=f);
print("像素為:%d * %d"%(self.resolution[0],self.resolution[1]),file=f)
print ("打開(kāi)攝像頭成功",file=f)
print("連接開(kāi)始時(shí)間:%s"%time.strftime("%Y-%m-%d %H:%M:%S",
time.localtime(time.time())),file=f)
f.close()
while(1):
time.sleep(0.13)
(grabbed, self.img) = camera.read()
self.img = cv2.resize(self.img,self.resolution)
result, imgencode = cv2.imencode('.jpg',self.img,encode_param)
img_code = numpy.array(imgencode)
self.imgdata = img_code.tostring()
try:
client.send(struct.pack("lhh",len(self.imgdata),
self.resolution[0],self.resolution[1])+self.imgdata); #發(fā)送圖片信息(圖片
長(zhǎng)度,分辨率,圖片內(nèi)容)
except:
f = open("video_info.txt", 'a+')
print("%s:%d disconnected!" % (addr[0], addr[1]),file=f);
print("連接結(jié)束時(shí)間:%s"%time.strftime("%Y-%m-%d %H:%M:%S",
time.localtime(time.time())),file=f)
print("****************************************",file=f)
camera.release()
f.close()
return;
def run(self):
while(1):
client,addr = self.socket.accept();
clientThread = threading.Thread(target = self._processConnection,
args = (client, addr, )); #有客戶端連接時(shí)產(chǎn)生新的線程進(jìn)行處理
clientThread.start();
def main():
cam = webCamera();
cam.run();
if __name__ == "__main__":
main();
客戶端代碼,主要使用socket模塊通過(guò)tcp協(xié)議將服務(wù)器發(fā)來(lái)的數(shù)據(jù)進(jìn)行解碼惩妇,然后顯示在自己的電腦上株汉,由于本人極端厭惡做人機(jī)交互界面,所以這里通過(guò)配置文件的形式來(lái)改變整個(gè)監(jiān)控的參數(shù)歌殃,比如每秒幾幀乔妈,圖像分辨率,圖像質(zhì)量氓皱,還有服務(wù)器ip路召。首次運(yùn)行,系統(tǒng)會(huì)自動(dòng)創(chuàng)建配置文件波材,txt格式股淡,然后將配置文件里的數(shù)據(jù)改成你需要的數(shù)據(jù)再保存,再次運(yùn)行程序廷区,程序會(huì)自動(dòng)讀取你最新配置的配置參數(shù)唯灵。
客戶端代碼:
import socket;
import threading;
import struct; import os;
import time; import sys;
import numpy
import cv2import re
class webCamConnect:
def __init__(self, resolution = [640,480], remoteAddress = ("115.216.215.130",
7999), windowName = "video"):
self.remoteAddress = remoteAddress;
self.resolution = resolution;
self.name = windowName;
self.mutex = threading.Lock();
self.src=911+15
self.interval=0
self.path=os.getcwd()
self.img_quality = 15
def _setSocket(self):
self.socket=socket.socket(socket.AF_INET, socket.SOCK_STREAM);
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1);
def connect(self):
self._setSocket();
self.socket.connect(self.remoteAddress);
def _processImage(self):
self.socket.send(struct.pack("lhh",self.src,self.resolution[0],self.resolution[1]));
while(1):
info = struct.unpack("lhh",self.socket.recv(8));
bufSize = info[0];
if bufSize:
try:
self.mutex.acquire();
self.buf=b''
tempBuf=self.buf;
while(bufSize): #循環(huán)讀取到一張圖片的長(zhǎng)度
tempBuf = self.socket.recv(bufSize);
bufSize -= len(tempBuf);
self.buf += tempBuf;
data = numpy.fromstring(self.buf,dtype='uint8')
self.image=cv2.imdecode(data,1)
cv2.imshow(self.name,self.image)
except:
print("接收失敗")
pass;
finally:
self.mutex.release();
if cv2.waitKey(10) == 27:
self.socket.close()
cv2.destroyAllWindows()
print("放棄連接")
break
def getData(self, interval):
showThread=threading.Thread(target=self._processImage);
showThread.start();
if interval != 0: # 非0則啟動(dòng)保存截圖到本地的功能
saveThread=threading.Thread(target=self._savePicToLocal,args = (interval,
));
saveThread.setDaemon(1);
saveThread.start();
def setWindowName(self, name):
self.name = name;
def setRemoteAddress(remoteAddress):
self.remoteAddress = remoteAddress;
def _savePicToLocal(self, interval):
while(1):
try:
self.mutex.acquire();
path=os.getcwd() + "\\" + "savePic";
if not os.path.exists(path):
os.mkdir(path);
cv2.imwrite(path + "\\" + time.strftime("%Y%m%d-%H%M%S",
time.localtime(time.time())) + ".jpg",self.image)
except:
pass;
finally:
self.mutex.release();
time.sleep(interval);
def check_config(self):
path=os.getcwd()
print(path)
if os.path.isfile(r'%s\video_config.txt'%path) is False:
f = open("video_config.txt", 'w+')
print("w = %d,h = %d" %(self.resolution[0],self.resolution[1]),file=f)
print("IP is %s:%d" %(self.remoteAddress[0],self.remoteAddress[1]),file=f)
print("Save pic flag:%d" %(self.interval),file=f)
print("image's quality is:%d,range(0~95)"%(self.img_quality),file=f)
f.close()
print("初始化配置");
else:
f = open("video_config.txt", 'r+')
tmp_data=f.readline(50)#1 resolution
num_list=re.findall(r"\d+",tmp_data)
self.resolution[0]=int(num_list[0])
self.resolution[1]=int(num_list[1])
tmp_data=f.readline(50)#2 ip,port
num_list=re.findall(r"\d+",tmp_data)
str_tmp="%d.%d.%d.%d"
%(int(num_list[0]),int(num_list[1]),int(num_list[2]),int(num_list[3]))
self.remoteAddress=(str_tmp,int(num_list[4]))
tmp_data=f.readline(50)#3 savedata_flag
self.interval=int(re.findall(r"\d",tmp_data)[0])
tmp_data=f.readline(50)#3 savedata_flag
#print(tmp_data)
self.img_quality=int(re.findall(r"\d+",tmp_data)[0])
#print(self.img_quality)
self.src=911+self.img_quality
f.close()
print("讀取配置")
def main():
print("創(chuàng)建連接...")
cam = webCamConnect();
cam.check_config()
print("像素為:%d * %d"%(cam.resolution[0],cam.resolution[1]))
print("目標(biāo)ip為%s:%d"%(cam.remoteAddress[0],cam.remoteAddress[1]))
cam.connect();
cam.getData(cam.interval);
if __name__ == "__main__":
main();