2

我有以下代码:

#!/usr/bin/python
import StringIO
import subprocess
import os
import time
from datetime import datetime
from PIL import Image

# Original code written by brainflakes and modified to exit
# image scanning for loop as soon as the sensitivity value is exceeded.
# this can speed taking of larger photo if motion detected early in scan

# Motion detection settings:
# need future changes to read values dynamically via command line parameter or xml file
# --------------------------
# Threshold      - (how much a pixel has to change by to be marked as "changed")
# Sensitivity    - (how many changed pixels before capturing an image) needs to be higher if noisy view
# ForceCapture   - (whether to force an image to be captured every forceCaptureTime seconds)
# filepath       - location of folder to save photos
# filenamePrefix - string that prefixes the file name for easier identification of files.
threshold = 10
sensitivity = 180
forceCapture = True
forceCaptureTime = 60 * 60 # Once an hour
filepath = "/home/pi/camera"
filenamePrefix = "capture"
# File photo size settings
saveWidth = 1280
saveHeight = 960
diskSpaceToReserve = 40 * 1024 * 1024 # Keep 40 mb free on disk

# Capture a small test image (for motion detection)
def captureTestImage():
    command = "raspistill -w %s -h %s -t 500 -e bmp -o -" % (100, 75)
    imageData = StringIO.StringIO()
    imageData.write(subprocess.check_output(command, shell=True))
    imageData.seek(0)
    im = Image.open(imageData)
    buffer = im.load()
    imageData.close()
    return im, buffer

# Save a full size image to disk
def saveImage(width, height, diskSpaceToReserve):
    keepDiskSpaceFree(diskSpaceToReserve)
    time = datetime.now()
    filename = filepath + "/" + filenamePrefix + "-%04d%02d%02d-%02d%02d%02d.jpg" % ( time.year, time.month, time.day, time.hour, time.minute, time.second)
    subprocess.call("raspistill -w 1296 -h 972 -t 1000 -e jpg -q 15 -o %s" % filename, shell=True)
    print "Captured %s" % filename

# Keep free space above given level
def keepDiskSpaceFree(bytesToReserve):
    if (getFreeSpace() < bytesToReserve):
        for filename in sorted(os.listdir(filepath + "/")):
            if filename.startswith(filenamePrefix) and filename.endswith(".jpg"):
                os.remove(filepath + "/" + filename)
                print "Deleted %s to avoid filling disk" % filename
                if (getFreeSpace() > bytesToReserve):
                    return

# Get available disk space
def getFreeSpace():
    st = os.statvfs(".")
    du = st.f_bavail * st.f_frsize
    return du

# Get first image
image1, buffer1 = captureTestImage()

# Reset last capture time
lastCapture = time.time()

# added this to give visual feedback of camera motion capture activity.  Can be removed as required
os.system('clear')
print "            Motion Detection Started"
print "            ------------------------"
print "Pixel Threshold (How much)   = " + str(threshold)
print "Sensitivity (changed Pixels) = " + str(sensitivity)
print "File Path for Image Save     = " + filepath
print "---------- Motion Capture File Activity --------------"

while (True):

    # Get comparison image
    image2, buffer2 = captureTestImage()

    # Count changed pixels
    changedPixels = 0
    for x in xrange(0, 100):
        # Scan one line of image then check sensitivity for movement
        for y in xrange(0, 75):
            # Just check green channel as it's the highest quality channel
            pixdiff = abs(buffer1[x,y][1] - buffer2[x,y][1])
            if pixdiff > threshold:
                changedPixels += 1

        # Changed logic - If movement sensitivity exceeded then
        # Save image and Exit before full image scan complete
        if changedPixels > sensitivity:   
            lastCapture = time.time()
            saveImage(saveWidth, saveHeight, diskSpaceToReserve)
            break
        continue

    # Check force capture
    if forceCapture:
        if time.time() - lastCapture > forceCaptureTime:
            changedPixels = sensitivity + 1

    # Swap comparison buffers
    image1  = image2
    buffer1 = buffer2

一旦检测到移动,此代码就会拍照,并一直这样做,直到我手动停止它。(我应该提一下,该代码用于 Raspberry Pi 计算机)

我在 Stackoverflow 上也有以下由 Nathan Jhaveri 提供的代码:

import SocketServer
from BaseHTTPServer import BaseHTTPRequestHandler

def some_function():
    print "some_function got called"

class MyHandler(BaseHTTPRequestHandler):
    def do_GET(self):
        if self.path == '/captureImage':
            saveImage(saveWidth, saveHeight, diskSpaceToReserve)

        self.send_response(200)

httpd = SocketServer.TCPServer(("", 8080), MyHandler)
httpd.serve_forever()

此代码运行一个简单的服务器,该服务器将执行

saveImage(saveWidth, saveHeight, diskSpaceToReserve)

在服务器上访问 url /captureImage 时的函数。我遇到了这个问题。由于这两段代码都是无限循环,所以它们不能并排运行。我会假设我需要做某种多线程,但这是我以前从未在 Python 中尝试过的东西。如果有人能帮助我重回正轨,我将不胜感激。

4

3 回答 3

0

尝试使用网络服务器,并在后台线程上运行它,这样调用“serve_forever()”就不会阻塞主线程的“while True:”循环。将现有的对 httpd.serve_forever() 的调用替换为:

import threading
class WebThread(threading.Thread):
    def run(self):
        httpd = SocketServer.TCPServer(("", 8080), MyHandler)
        httpd.serve_forever()

WebThread().start()

确保代码块在“while (True):”循环之前运行,并且您应该同时运行 webserver 循环和主线程循环。

请记住,拥有多个线程可能会变得复杂。当两个线程同时访问同一个资源时会发生什么?正如 Velox 在另一个答案中提到的那样,了解更多关于线程的信息是值得的。

于 2013-10-20T01:17:11.510 回答
0

这不是一个小问题。最好的办法是学习一些 Python 线程教程,例如:http ://www.tutorialspoint.com/python/python_multithreading.htm (通过 google 找到)

于 2013-10-19T16:38:52.140 回答
0

我可以用多线程来说明一个简单的例子。

from http.server import BaseHTTPRequestHandler, HTTPServer
import concurrent.futures
import logging
import time

hostName = "localhost"
serverPort = 5001

class MyServer(BaseHTTPRequestHandler):
    def do_GET(self):
        self.send_response(200)
        self.send_header("Content-type", "text/html")
        self.end_headers()
        self.wfile.write(bytes("<html><head><title>python3 http server</title><body>", "utf-8"))  

def serverThread():
    webServer = HTTPServer((hostName, serverPort), MyServer)
    logging.info("Server started http://%s:%s" % (hostName, serverPort))

    try:
        webServer.serve_forever()
    except :
        pass

    webServer.server_close()
    logging.info("Server stopped.")
  
def logThread():
    while True:
        time.sleep(2.0)
        logging.info('hi from log thread')

if __name__ == "__main__":        

    logging.basicConfig(level=logging.INFO)
       
    with concurrent.futures.ThreadPoolExecutor(max_workers=2) as executor:
        # Run Server
        executor.submit(serverThread)
        # Run A Parallel Thread
        executor.submit(logThread)

这里我们有两个线程:一个服务器另一个并行线程,每 2 秒记录一行。

您必须在单独的函数中定义每个线程对应的代码,并将其提交到concurrent.futures线程池。

顺便说一句,我还没有研究过以这种方式运行服务器的效率。

于 2021-01-08T14:03:22.353 回答