如何让树莓派OpenCV人脸检测仅发送一次MQTT消息?
Hey there! I get it—your current script sends an MQTT message every single frame a face is detected, which leads to a flood of unwanted messages. Let's fix this with a simple state-tracking variable that ensures we only send one notification per face appearance, and reset the ability to send once the face is gone.
The Core Idea
We'll add a boolean variable (let's call it face_already_notified) that keeps track of whether we've already sent the MQTT message for the current detected face. Here's how it works:
- Initialize the variable as
False(we haven't notified anyone yet). - When a face is detected:
- If
face_already_notifiedisFalse, send the MQTT message and set the variable toTrue. - If it's already
True, do nothing (we've already notified for this face).
- If
- When no face is detected, reset
face_already_notifiedback toFalseso we can send a message again the next time a face appears.
Modified Code
Here's your updated script with the fix included (I've added comments to highlight key changes):
from picamera.array import PiRGBArray from picamera import PiCamera import paho.mqtt.client as mqtt import time import cv2 # MQTT setup host = '10.0.0.192' client = mqtt.Client("Security") client.connect(host) # Image processing parameters threshold = 60 # BINARY threshold blurValue = 41 # GaussianBlur parameter bgSubThreshold = 50 # NEW: State variable to track if we've already sent the notification face_already_notified = False # Camera initialization camera = PiCamera() camera.resolution = (640, 480) camera.framerate = 64 rawCapture = PiRGBArray(camera, size=(640, 480)) # Allow camera to warmup time.sleep(0.1) # IMPORTANT: Move cascade classifier initialization outside the loop! # Loading it every frame wastes resources and slows down your script face_cascade = cv2.CascadeClassifier('/home/pi/opencv-face-sentdex/faces.xml') # Capture frames from the camera for frame in camera.capture_continuous(rawCapture, format="bgr", use_video_port=True): image = frame.array gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY) blur = cv2.GaussianBlur(gray, (blurValue, blurValue), 0) faces = face_cascade.detectMultiScale(blur, 1.1, 5) # Check if faces are detected if len(faces) > 0: # Draw rectangle around each face for (x,y,w,h) in faces: cv2.rectangle(image,(x,y),(x+w,y+h),(255,255,0),2) # NEW: Only send MQTT message if we haven't already for this face if not face_already_notified: client.publish("/home/pi/snips-app","faceDetected")#publish face_already_notified = True print("Face detected - sent MQTT message") # Optional: for debugging else: # NEW: Reset the notification state when no face is detected if face_already_notified: face_already_notified = False print("Face lost - reset notification state") # Optional: for debugging # Show the frame cv2.imshow("Frame", image) key = cv2.waitKey(1) & 0xFF # Clear the stream for next frame rawCapture.truncate(0) # Exit on 'q' press if key == ord("q"): break # Cleanup resources cv2.destroyAllWindows() client.disconnect()
Key Improvements Beyond the Fix
I also added one critical optimization:
- Moved the
face_cascade = cv2.CascadeClassifier(...)line outside the loop. Loading the classifier every frame is unnecessary and wastes processing power—loading it once at the start makes your script run much smoother.
How It Works
- When a face first appears,
face_already_notifiedisFalse, so we send the message and flip the variable toTrue. - As long as the face stays in the frame,
face_already_notifiedremainsTrue, so no duplicate messages are sent. - When the face leaves the frame, we reset
face_already_notifiedtoFalse, so the next time a face is detected, we'll send a fresh notification.
This way, you get exactly one MQTT alert per face appearance, no matter how long the face stays in view.
内容的提问来源于stack exchange,提问作者Nick D

