Anwendung von „Pipes“ in Python

Pipes sind ein sehr praktisches Mittel, wenn man in Python mehrere unabhängige Prozesse (mit der multiprocessing-Bibliothek) miteinander kommunizieren lassen will.

Das Beispiel besteht aus einem Control-Process, der in Abhängigkeit von Sensordaten irgendwas regeln oder schalten soll. Die Sensordaten werden dabei von einem anderem Prozess (getSensorData) aquiriert. In unserem Fall werden Zufallszahlen im Bereich von 0..99 erzeugt, um Sensordaten zu simulieren. Dieser Prozess wird von dem Controlprozess gestartet, dabei wird auch der Name der Verbindung übergeben. Eine Pipe ist eine Verbindung in nur eine Richtung, sie hat einen Eingang (hier child_conn) und einen“Ausgang“, hier parent_conn. Sie kann nur 2 Prozesse verbinden. Sollen die Daten an mehrere Unterprozesse verteilt werden, muss man „Queue“, ebenfalls aus der bibliothek „multiprocessing“ verwenden.

In dem vorliegenden Beispiel werden die Daten verzögert abgefragt, dies soll die Pufferung der Daten durch die Pipe demonstrieren.

Hier kommt schon mal der lauffähige Quelltext (Python 3.6)

from multiprocessing import Process, Pipe, current_process

from datetime import datetime
import time, random

dta1 = 1

def getSensorData(conn,dta1):
    print("getsensorData gerufen")
    ctr = 0
    while ctr < 10:
        timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        #print("time: ",timestamp)
        time.sleep(1.5)
        dta_1 = random.randint(0,99)
        dta_2 = random.randint(0,99)
        dta_3 = random.randint(0,99)
        conn.send([timestamp, dta_1,dta_2, dta_3])
        ctr += 1

def Control_Proc():
    p = current_process()
    print('Starting:', p.name, p.pid)
    parent_conn, child_conn = Pipe()
    ptemp = Process(name="getSensorData", target=getSensorData,\
    args=(child_conn,dta1))
    ptemp.daemon = True
    ptemp.start()

    while(True):
        while parent_conn.poll():
            timestamp, data_01,data_02, data_03 \
            = parent_conn.recv()
            print(timestamp, " data01: ",data_01, "data_02: "\
            ,data_02, "data_03: ",data_03)
            time.sleep(5)


if __name__ == '__main__':
    Control_Proc()

so sieht das Ergebnis im Entwicklungssystem aus.

Diesen Code findet Ihr auch wieder auf Github:

https://github.com/Rellin-Entwicklung/Piping-Demos/blob/master/Piping_demo.py

Webcam – Bewegungserkennung mit Python und OpenCV

Wenn man mit einer Webcam eine Szenerie beobachtet, macht es oft Sinn, zu wissen, ob sich irgend etwas in dieser Szenerie tut, also bewegt. Man kann z.B. nach Detektion einer Bewegung ein Bild abspeichern, eine Nachricht absetzen oder weitere Bildanalysen starten. Die Webcam wird also durch ein paar Zeilen Python-Code zu einem Bewegungsmelder, der nach meinen Erfahrungen den Vergleich mit einem passiv-Infrarot – Detektor (Piri, herkömmlicher Bewegungsmelder) nicht scheuen braucht.

In diesem Beitrag will ich Euch ein Code-Snippet für eine lauffähige Lösung vorstellen, die nach Detektion einer Bewegung ein Bild abspeichert. Die Empfindlichkeit der Unterscheidung, ob eine Bewegung erfolgt ist, ist dabei frei wählbar

Das unter Python 3.6 /OpenCV 3.4 lauffähige Code-Snippet für Bewegungserkennung mittels Webcam:

import cv2
import datetime

def diffImg(t0, t1, t2):
    d1 = cv2.absdiff(t2, t1)
    d2 = cv2.absdiff(t1, t0)
    return cv2.bitwise_and(d1, d2)

folder="BV"
message_01 = "not yet"
message_02= "not yet"
cam = cv2.VideoCapture(0)
cam.set(3,1280)
cam.set(4,720)

winName = "Bewegungserkennung"

font = "FONT_HERSHEY_SIMPLEX"
#cv2.namedWindow(winName, cv2.CV_WINDOW_AUTOSIZE)
# Read three images first:

return_value, image = cam.read()
t_minus = cv2.cvtColor(cam.read()[1], cv2.COLOR_RGB2GRAY)

t = cv2.cvtColor(cam.read()[1], cv2.COLOR_RGB2GRAY)

t_plus = cv2.cvtColor(cam.read()[1], cv2.COLOR_RGB2GRAY)

Durchschnitt = 1
n=1


while True:

    t_minus = t

    t = t_plus

    t_plus = cv2.cvtColor(cam.read()[1], cv2.COLOR_RGB2GRAY)
    result_image = diffImg(t_minus, t, t_plus)
    cv2.putText(result_image, 'OpenCV', (100, 500), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), thickness=2)
    cv2.putText(result_image, message_01, (100, 550), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), thickness=2)
    cv2.putText(result_image, "Stop with <ESC> ",(100, 600), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), thickness=2)
    cv2.imshow(winName, result_image)

    print (cv2.countNonZero(diffImg(t_minus, t, t_plus)))

    if cv2.countNonZero(diffImg(t_minus, t, t_plus)) > 305000:
        return_value, image = cam.read()
        # cv2.imwrite("buero" + str(n) + ".png", image)
        cv2.imwrite("{0}/{1:%d%b%Y_%H_%M_%S.%f}.png".format(
            folder, datetime.datetime.utcnow()), image)
        message_01 = str(n) + "  pictures saved"
        n= n+1

    key = cv2.waitKey(10)

    if key == 27:
        cam.release
        cv2.destroyWindow(winName)
        break

Das Ergebnis: Differenzbild wird angezeigt, solange Bewegung stattfindet werden Fotos abgespeichert. Auch die Anzahl der gespeicherten Fotos wird mitgeteilt.

erlogreicher „Selbstversuch“ – bei Bewegung werden Bilder gespeichert.

Diese Lösung hat sich im praktischen Test (Bewegungsmelder im Büro) als recht robust erwiesen und kommt dank gleitender Hintergrund-Durchschnittsbildung auch mit wechselnden Lichtverhältnissen gut zurecht.

Der Lösungsansatz auf Basis Differenzbilder geht auf Matthias Stein (http://www.steinm.com/blog/motion-detection-webcam-python-opencv-differential-images/) zurück, ich habe einige Anpassungen und Erweiterungen bezüglich meiner Applikation vorgenommen.

Anm: Das Titelbild stammt von: https://pixabay.com/de/person-bewegung-beschleunigen-2146508/, vielen Dank an ATDSPHOTO