输出 Window 总是在上传或保存文件时冻结(Open CV on python 运行 on a Raspberry Pi 3)
The Output Window always freezes during uploading or saving files (Open CV on python running on a Raspberry Pi 3)
我参考了几本书,然后添加了自己的代码,制作了一个完全基于软件的运动检测器。添加的代码将检测到的运动帧本地保存在 Raspberry Pi 上,并将其上传到我的 Google 驱动器。另一组代码向我的电子邮件地址发送一封电子邮件,通知我检测到的动作。
问题是在保存和上传文件时,Open CV 输出 window 冻结,直到上述过程完成。我在 python 上尝试了多处理和多线程,但没有帮助。有什么方法可以改进我的逻辑,使其不会冻结输出 window?
编辑:通过从两个进程中删除 join() ,问题在某种程度上得到了解决。有一个非常轻微的滞后,但我认为这已经足够了。感谢所有回复的人:)
from pydrive.drive import GoogleDrive
from pydrive.auth import GoogleAuth
import cv2
from multiprocessing import Process
import numpy as np
import datetime
import time
import smtplib
# make count 0
count = 0
def sf(t2):
cv2.imwrite("/home/pi/Desktop/StoredImages/frame%d.jpg" % count, t2)
# 'google drive authentication' stuff
gauth = GoogleAuth()
# try to load saved client credentials
gauth.LoadCredentialsFile("mycreds.txt")
if gauth.credentials is None:
# authenticate if not there
gauth.LocalWebserverAuth()
elif gauth.access_token_expired:
# Refresh them if expired
gauth.Refresh()
else:
# Initialize the saved creds
gauth.Authorize()
# Save the current credentials to a file
gauth.SaveCredentialsFile("mycreds.txt")
drive = GoogleDrive(gauth)
def upload_file():
file1 = drive.CreateFile({'parent':'/home/pi/Desktop/StoredImages/'})
file1.SetContentFile('/home/pi/Desktop/StoredImages/frame%d.jpg' % count)
file1.Upload()
# 'sending an email' stuff
server = smtplib.SMTP('smtp.gmail.com',587)
server.starttls()
server.login("Removed Intentionally","Removed Intentionally")
msg = "Motion Detected! For more details check your Drive."
# capture Video from the camera module
cap = cv2.VideoCapture(0)
# stores the present date and time
lastUploaded = datetime.datetime.now()
# kernel is created for the dilation process
k = np.ones((3,3),np.uint8) # creates a 3X3 Matrix filled with ones and
# has the data type uint8 (unsigned integer)
# which can contain values from 0 to 255
# first two subsequent frames captured
t0 = cap.read()[1]
t1 = cap.read()[1]
# initially motion detected 0 times
motionCounter = 0
while True:
# difference between two subsequent frames
d=cv2.absdiff(t1,t0)
# stores present date and time
timestamp = datetime.datetime.now()
# converting difference to grayscale
grey = cv2.cvtColor(d,cv2.COLOR_BGR2GRAY)
# grayscale converted to gaussian blur
blur = cv2.GaussianBlur(grey,(3,3),0)
# gaussian blur converted to binary image
ret, th = cv2.threshold(blur, 15, 155, cv2.THRESH_BINARY)
# dilating the image before using the contour function
dilated = cv2.dilate(th,k,iterations=2)
# contour function to find edges
_, contours, heierarchy = cv2.findContours(dilated,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
# copying the original frame to a temporary frame for display
t2 = t0
# drawing green edges around the area with movement
cv2.drawContours(t2, contours, -1, (0,255,0), 2)
# showing output in a new window
cv2.imshow('Output',t2)
# going through each and every contour in the image
for c in contours:
# if contour is lesser than a threshold size, ignore
if cv2.contourArea(c) < 5000:
continue
# if motion occurred after 2 secs
if (timestamp - lastUploaded).seconds >= 2.0:
motionCounter += 1
# if 8 motions occured in 2 secs
if motionCounter >= 8:
# write to a temporary file location using threads
new_process = Process(target=sf, args=(t2,))
new_process.start()
new_process.join()
# upload the temporary pic to Google drive using threads
new_process = Process(target=upload_file)
new_process.start()
new_process.join()
# sending a mail about motion detected
server.sendmail("Removed Intentionally","Removed Intentionally",msg)
# increasing count by 1 and resetting everything
count=count+1
lastUploaded = timestamp
motionCounter = 0
# making the next frame the previous and reading a new frame
t0 = t1
t1 = cap.read()[1]
# esc key breaks the entire loop
if cv2.waitKey(5) == 27:
break
# stops the video stream and exits the window
cap.release()
cv2.destroyAllWindows()
# stops the email server connection
server.quit()
我认为您以错误的方式使用了多处理。你的代码
# write to a temporary file location using threads
new_process = Process(target=sf, args=(t2,))
new_process.start()
new_process.join()
实际上会创建并启动一个进程,但随后它也会等待它 (new_process.join()
) 完成。所以基本上你想开始一个并行的 运行ning 进程,然后你等待它完成。
更好的做法是在程序开始时创建并启动进程,然后等待它们在程序结束时完成。
同时为每个进程创建一个队列(也在多处理模块中)。
每个进程都应该运行在无限循环中等待一个队列。在你的主线程中,你为每个进程的队列提供它应该做的事情(本地存储文件,远程存储文件)
在你的程序结束时,你应该向你的进程发送一个结束无限循环的最终指示,这样你在主线程中的 new_process.join()
语句就会发现进程已经结束的事实。
我参考了几本书,然后添加了自己的代码,制作了一个完全基于软件的运动检测器。添加的代码将检测到的运动帧本地保存在 Raspberry Pi 上,并将其上传到我的 Google 驱动器。另一组代码向我的电子邮件地址发送一封电子邮件,通知我检测到的动作。
问题是在保存和上传文件时,Open CV 输出 window 冻结,直到上述过程完成。我在 python 上尝试了多处理和多线程,但没有帮助。有什么方法可以改进我的逻辑,使其不会冻结输出 window?
编辑:通过从两个进程中删除 join() ,问题在某种程度上得到了解决。有一个非常轻微的滞后,但我认为这已经足够了。感谢所有回复的人:)
from pydrive.drive import GoogleDrive
from pydrive.auth import GoogleAuth
import cv2
from multiprocessing import Process
import numpy as np
import datetime
import time
import smtplib
# make count 0
count = 0
def sf(t2):
cv2.imwrite("/home/pi/Desktop/StoredImages/frame%d.jpg" % count, t2)
# 'google drive authentication' stuff
gauth = GoogleAuth()
# try to load saved client credentials
gauth.LoadCredentialsFile("mycreds.txt")
if gauth.credentials is None:
# authenticate if not there
gauth.LocalWebserverAuth()
elif gauth.access_token_expired:
# Refresh them if expired
gauth.Refresh()
else:
# Initialize the saved creds
gauth.Authorize()
# Save the current credentials to a file
gauth.SaveCredentialsFile("mycreds.txt")
drive = GoogleDrive(gauth)
def upload_file():
file1 = drive.CreateFile({'parent':'/home/pi/Desktop/StoredImages/'})
file1.SetContentFile('/home/pi/Desktop/StoredImages/frame%d.jpg' % count)
file1.Upload()
# 'sending an email' stuff
server = smtplib.SMTP('smtp.gmail.com',587)
server.starttls()
server.login("Removed Intentionally","Removed Intentionally")
msg = "Motion Detected! For more details check your Drive."
# capture Video from the camera module
cap = cv2.VideoCapture(0)
# stores the present date and time
lastUploaded = datetime.datetime.now()
# kernel is created for the dilation process
k = np.ones((3,3),np.uint8) # creates a 3X3 Matrix filled with ones and
# has the data type uint8 (unsigned integer)
# which can contain values from 0 to 255
# first two subsequent frames captured
t0 = cap.read()[1]
t1 = cap.read()[1]
# initially motion detected 0 times
motionCounter = 0
while True:
# difference between two subsequent frames
d=cv2.absdiff(t1,t0)
# stores present date and time
timestamp = datetime.datetime.now()
# converting difference to grayscale
grey = cv2.cvtColor(d,cv2.COLOR_BGR2GRAY)
# grayscale converted to gaussian blur
blur = cv2.GaussianBlur(grey,(3,3),0)
# gaussian blur converted to binary image
ret, th = cv2.threshold(blur, 15, 155, cv2.THRESH_BINARY)
# dilating the image before using the contour function
dilated = cv2.dilate(th,k,iterations=2)
# contour function to find edges
_, contours, heierarchy = cv2.findContours(dilated,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
# copying the original frame to a temporary frame for display
t2 = t0
# drawing green edges around the area with movement
cv2.drawContours(t2, contours, -1, (0,255,0), 2)
# showing output in a new window
cv2.imshow('Output',t2)
# going through each and every contour in the image
for c in contours:
# if contour is lesser than a threshold size, ignore
if cv2.contourArea(c) < 5000:
continue
# if motion occurred after 2 secs
if (timestamp - lastUploaded).seconds >= 2.0:
motionCounter += 1
# if 8 motions occured in 2 secs
if motionCounter >= 8:
# write to a temporary file location using threads
new_process = Process(target=sf, args=(t2,))
new_process.start()
new_process.join()
# upload the temporary pic to Google drive using threads
new_process = Process(target=upload_file)
new_process.start()
new_process.join()
# sending a mail about motion detected
server.sendmail("Removed Intentionally","Removed Intentionally",msg)
# increasing count by 1 and resetting everything
count=count+1
lastUploaded = timestamp
motionCounter = 0
# making the next frame the previous and reading a new frame
t0 = t1
t1 = cap.read()[1]
# esc key breaks the entire loop
if cv2.waitKey(5) == 27:
break
# stops the video stream and exits the window
cap.release()
cv2.destroyAllWindows()
# stops the email server connection
server.quit()
我认为您以错误的方式使用了多处理。你的代码
# write to a temporary file location using threads
new_process = Process(target=sf, args=(t2,))
new_process.start()
new_process.join()
实际上会创建并启动一个进程,但随后它也会等待它 (new_process.join()
) 完成。所以基本上你想开始一个并行的 运行ning 进程,然后你等待它完成。
更好的做法是在程序开始时创建并启动进程,然后等待它们在程序结束时完成。
同时为每个进程创建一个队列(也在多处理模块中)。
每个进程都应该运行在无限循环中等待一个队列。在你的主线程中,你为每个进程的队列提供它应该做的事情(本地存储文件,远程存储文件)
在你的程序结束时,你应该向你的进程发送一个结束无限循环的最终指示,这样你在主线程中的 new_process.join()
语句就会发现进程已经结束的事实。