输出 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() 语句就会发现进程已经结束的事实。