IA y Visión ArtificialIngeniero

Contador de personas privado para la puerta de una tienda

Cuenta visitantes que entran y salen con una cámara cenital que guarda solo números: nunca se guarda ninguna imagen.

NivelIngeniero
Tiempo2.5 h
Costo est.~$157
Pasos5

Las tiendas pequeñas quieren saber sus horas pico. Una cámara gran angular montada sobre la puerta mira hacia abajo, OpenCV encuentra figuras en movimiento y el Pi cuenta cuando cruzan una línea virtual. Los cuadros se procesan en memoria y se descartan, así que solo se guardan totales por hora.

⚠ SEGURIDAD
Cuenta personas solo en un local que sea tuyo o que administres, nunca grabes ni transmitas el video y sigue las reglas locales de avisos y privacidad para contar clientes.

Pasos de la misión

  1. Móntala arriba

    Pon la cámara en el techo sobre la puerta mirando derecho hacia abajo; la vista desde arriba muestra formas, no caras.

  2. Instala los paquetes

    Corre sudo apt install python3-picamera2 python3-opencv.

  3. Ajusta la línea

    Cambia LINE_Y para que la línea virtual cruce la puerta y MIN_AREA para que una persona forme una sola mancha.

  4. Cuenta y registra

    El script empareja cada mancha con la más cercana del cuadro anterior y cuenta los cruces de la línea en cada dirección.

  5. Sé transparente

    Pon un letrero que diga que los visitantes se cuentan de forma anónima y que no se graba video.

Código

import cv2, time, csv, datetime as dt
from picamera2 import Picamera2

cam = Picamera2()
cam.configure(cam.create_video_configuration(main={'size': (640, 480), 'format': 'RGB888'}))
cam.start()
bg = cv2.createBackgroundSubtractorMOG2(history=500, detectShadows=False)
LINE_Y, MIN_AREA, MAX_JUMP = 240, 5000, 120
prev, ins, outs, hour = [], 0, 0, dt.datetime.now().hour

while True:
    gray = cv2.GaussianBlur(cv2.cvtColor(cam.capture_array(), cv2.COLOR_BGR2GRAY), (21, 21), 0)
    mask = cv2.threshold(bg.apply(gray), 200, 255, cv2.THRESH_BINARY)[1]
    contours, _ = cv2.findContours(cv2.dilate(mask, None, iterations=2), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    now = [(x + w // 2, y + h // 2) for x, y, w, h in
           (cv2.boundingRect(c) for c in contours if cv2.contourArea(c) > MIN_AREA)]
    for cx, cy in now:
        if not prev: break
        px, py = min(prev, key=lambda p: (p[0] - cx) ** 2 + (p[1] - cy) ** 2)
        if abs(py - cy) > MAX_JUMP: continue
        if py < LINE_Y <= cy: ins += 1
        elif py >= LINE_Y > cy: outs += 1
    prev = now                                   # frame is discarded here
    if dt.datetime.now().hour != hour:
        with open('visits.csv', 'a', newline='') as f:
            csv.writer(f).writerow([dt.datetime.now().strftime('%Y-%m-%d %H:00'), ins, outs])
        ins = outs = 0; hour = dt.datetime.now().hour

Code comments are in English, like most libraries and docs — a good habit for makers.

Preguntas

Dos personas caminando juntas cuentan como una.

El conteo simple de manchas une figuras cercanas. Monta la cámara más alto, baja MIN_AREA con cuidado o pasa a un modelo de detección de personas en el AI HAT+.