我有一個python腳本,用於通過家庭網絡從ip攝像頭抓取圖像並添加日期時間信息。在12小時的時間內,它可以拍攝大約200,000張照片。但是,當使用zoneminder(相機監控軟件)時,相機在7小時內管理250,000。如何從IP攝像機高效地讀取和保存視頻?
我在想,如果有人可以幫助我提高我的劇本效率我已經使用線程模塊來創建2個線程嘗試,但它並沒有幫助我不知道我是否已經實現了它是不是錯了。下面是代碼,我目前正在使用:
#!/usr/bin/env python
# My First python script to grab images from an ip camera
import requests
import time
import urllib2
import sys
import os
import PIL
from PIL import ImageFont
from PIL import Image
from PIL import ImageDraw
import datetime
from datetime import datetime
import threading
timecount = 43200
lock = threading.Lock()
wdir = "/workdir/"
y = len([f for f in os.listdir(wdir)
if f.startswith('Cam1') and os.path.isfile(os.path.join(wdir, f))])
def looper(timeCount):
global y
start = time.time()
keepLooping = True
while keepLooping:
with lock:
y += 1
now = datetime.now()
dte = str(now.day) + ":" + str(now.month) + ":" + str(now.year)
dte1 = str(now.hour) + ":" + str(now.minute) + ":" + str(now.second) + "." + str(now.microsecond)
cname = "Cam1:"
dnow = """Date: %s """ % (dte)
dnow1 = """Time: %s""" % (dte1)
buffer = urllib2.urlopen('http://(ip address)/snapshot.cgi?user=uname&pwd=password').read()
img = str(wdir) + "Cam1-" + str('%010d' % y) + ".jpg"
f = open(img, 'wb')
f.write(buffer)
f.close()
if time.time()-start > timeCount:
keepLooping = False
font = ImageFont.truetype("/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf",10)
img=Image.open(img)
draw = ImageDraw.Draw(img)
draw.text((0, 0),cname,fill="white",font=font)
draw.text((0, 10),dnow,fill="white",font=font)
draw.text((0, 20),dnow1,fill="white",font=font)
draw = ImageDraw.Draw(img)
draw = ImageDraw.Draw(img)
img.save(str(wdir) + "Cam1-" + str('%010d' % y) + ".jpg")
for i in range(2):
thread = threading.Thread(target=looper,args=(timecount,))
thread.start()
thread.join()
我怎麼能改善這個腳本或者我如何從相機中打開一個流,然後從流中搶圖像?那甚至會提高效率/捕獲率?
編輯:
由於kobejohn的幫助下,我已經提出了下面的實現。運行了12小時的時間,它已經從2臺獨立攝像機(同一臺計算機)上獲得了超過420,000張照片,每張照片在同一時間都在自己的線程上運行,相比之下,我的原始實現大約有200,000張。下面的代碼將運行在平行(或足以使其接近)2攝像頭的添加文字對他們說:
import base64
from datetime import datetime
import httplib
import io
import os
import time
from PIL import ImageFont
from PIL import Image
from PIL import ImageDraw
import multiprocessing
wdir = "/workdir/"
stream_urlA = '192.168.3.21'
stream_urlB = '192.168.3.23'
usernameA = ''
usernameB = ''
password = ''
y = sum(1 for f in os.listdir(wdir) if f.startswith('CamA') and os.path.isfile(os.path.join(wdir, f)))
x = sum(1 for f in os.listdir(wdir) if f.startswith('CamB') and os.path.isfile(os.path.join(wdir, f)))
def main():
time_count = 43200
# time_count = 1
procs = list()
for i in range(1):
p = multiprocessing.Process(target=CameraA, args=(time_count, y,))
q = multiprocessing.Process(target=CameraB, args=(time_count, x,))
procs.append(p)
procs.append(q)
p.start()
q.start()
for p in procs:
p.join()
def CameraA(time_count, y):
y = y
h = httplib.HTTP(stream_urlA)
h.putrequest('GET', '/videostream.cgi')
h.putheader('Authorization', 'Basic %s' % base64.encodestring('%s:%s' % (usernameA, password))[:-1])
h.endheaders()
errcode, errmsg, headers = h.getreply()
stream_file = h.getfile()
start = time.time()
end = start + time_count
while time.time() <= end:
y += 1
now = datetime.now()
dte = str(now.day) + "-" + str(now.month) + "-" + str(now.year)
dte1 = str(now.hour) + ":" + str(now.minute) + ":" + str(now.second) + "." + str(now.microsecond)
cname = "Cam#: CamA"
dnow = """Date: %s """ % dte
dnow1 = """Time: %s""" % dte1
# your camera may have a different streaming format
# but I think you can figure it out from the debug style below
source_name = stream_file.readline() # '--ipcamera'
content_type = stream_file.readline() # 'Content-Type: image/jpeg'
content_length = stream_file.readline() # 'Content-Length: 19565'
#print 'confirm/adjust content (source?): ' + source_name
#print 'confirm/adjust content (type?): ' + content_type
#print 'confirm/adjust content (length?): ' + content_length
# find the beginning of the jpeg data BEFORE pulling the jpeg framesize
# there must be a more efficient way, but hopefully this is not too bad
b1 = b2 = b''
while True:
b1 = stream_file.read(1)
while b1 != chr(0xff):
b1 = stream_file.read(1)
b2 = stream_file.read(1)
if b2 == chr(0xd8):
break
# pull the jpeg data
framesize = int(content_length[16:])
jpeg_stripped = b''.join((b1, b2, stream_file.read(framesize - 2)))
# throw away the remaining stream data. Sorry I have no idea what it is
junk_for_now = stream_file.readline()
# convert directly to an Image instead of saving/reopening
# thanks to SO: http://stackoverflow.com/a/12020860/377366
image_as_file = io.BytesIO(jpeg_stripped)
image_as_pil = Image.open(image_as_file)
draw = ImageDraw.Draw(image_as_pil)
draw.text((0, 0), cname, fill="white")
draw.text((0, 10), dnow, fill="white")
draw.text((0, 20), dnow1, fill="white")
img_name = "CamA-" + str('%010d' % y) + ".jpg"
img_path = os.path.join(wdir, img_name)
image_as_pil.save(img_path)
def CameraB(time_count, x):
x = x
h = httplib.HTTP(stream_urlB)
h.putrequest('GET', '/videostream.cgi')
h.putheader('Authorization', 'Basic %s' % base64.encodestring('%s:%s' % (usernameB, password))[:-1])
h.endheaders()
errcode, errmsg, headers = h.getreply()
stream_file = h.getfile()
start = time.time()
end = start + time_count
while time.time() <= end:
x += 1
now = datetime.now()
dte = str(now.day) + "-" + str(now.month) + "-" + str(now.year)
dte1 = str(now.hour) + ":" + str(now.minute) + ":" + str(now.second) + "." + str(now.microsecond)
cname = "Cam#: CamB"
dnow = """Date: %s """ % dte
dnow1 = """Time: %s""" % dte1
# your camera may have a different streaming format
# but I think you can figure it out from the debug style below
source_name = stream_file.readline() # '--ipcamera'
content_type = stream_file.readline() # 'Content-Type: image/jpeg'
content_length = stream_file.readline() # 'Content-Length: 19565'
#print 'confirm/adjust content (source?): ' + source_name
#print 'confirm/adjust content (type?): ' + content_type
#print 'confirm/adjust content (length?): ' + content_length
# find the beginning of the jpeg data BEFORE pulling the jpeg framesize
# there must be a more efficient way, but hopefully this is not too bad
b1 = b2 = b''
while True:
b1 = stream_file.read(1)
while b1 != chr(0xff):
b1 = stream_file.read(1)
b2 = stream_file.read(1)
if b2 == chr(0xd8):
break
# pull the jpeg data
framesize = int(content_length[16:])
jpeg_stripped = b''.join((b1, b2, stream_file.read(framesize - 2)))
# throw away the remaining stream data. Sorry I have no idea what it is
junk_for_now = stream_file.readline()
# convert directly to an Image instead of saving/reopening
# thanks to SO: http://stackoverflow.com/a/12020860/377366
image_as_file = io.BytesIO(jpeg_stripped)
image_as_pil = Image.open(image_as_file)
draw = ImageDraw.Draw(image_as_pil)
draw.text((0, 0), cname, fill="white")
draw.text((0, 10), dnow, fill="white")
draw.text((0, 20), dnow1, fill="white")
img_name = "CamB-" + str('%010d' % x) + ".jpg"
img_path = os.path.join(wdir, img_name)
image_as_pil.save(img_path)
if __name__ == '__main__':
main()
EDIT(26/05/2014):
我已經花了更好的一部分2個月試圖更新這個腳本/程序來使用python 3,但已完全無法讓它做任何事情。任何人都可以指出我正確的方向嗎?
我已經試過了2to3的腳本,但它只是改變了一些條目,我仍然無法得到它的所有功能。
一個變化,或者可以是小改善使用genratar表達和總和(代替如果f.startswith('CamFront')和os.path.isfile(os.path.join(wdir,f)))''sum(1 for f in os.listdir(wdir))' –
那麼該部分只是爲了檢查工作目錄中是否存在圖像,以確定計數器是從1開始還是從另一個開始。它更多的是我試圖改善活套功能的捕獲速度。如果f.startswith('CamFront')? – ButtzyB
我也是新的Python學習者,我只是讀了一些在哪裏'sun(genrator表達式)'比'len([listcompresion])更好'當然這不是你的問題的答案,我希望我可以但在這個階段我無法提供:(:( –