190 lines
7.1 KiB
Python
190 lines
7.1 KiB
Python
import depthai as dai
|
|
import cv2
|
|
import numpy as np
|
|
import time
|
|
import json
|
|
import sys
|
|
import threading
|
|
import paho.mqtt.client as mqtt
|
|
import uuid
|
|
from flask import Flask, Response, request
|
|
|
|
# 🔹 Configurações MQTT
|
|
mqtt_client = mqtt.Client(f"client_oak_d_lite_{uuid.uuid4()}")
|
|
mqtt_client.connect("localhost", port=1883)
|
|
|
|
# 🔹 Parâmetros de entrada
|
|
output_folder = 'Python/Output/'
|
|
mqtt_topic = sys.argv[1] # Tópico MQTT para envio dos dados de profundidade
|
|
porta = int(sys.argv[2]) # Porta do Flask
|
|
url = sys.argv[3] # URL do vídeo
|
|
max_readings = int(sys.argv[4])
|
|
|
|
# 🔹 Flask App
|
|
app = Flask(__name__)
|
|
|
|
# 🔹 Criando o pipeline
|
|
pipeline = dai.Pipeline()
|
|
|
|
width, height = 1280, 720
|
|
|
|
# 📷 Câmera RGB
|
|
cam_rgb = pipeline.create(dai.node.ColorCamera)
|
|
cam_rgb.setPreviewSize(width, height)
|
|
cam_rgb.setBoardSocket(dai.CameraBoardSocket.RGB)
|
|
cam_rgb.setInterleaved(False)
|
|
|
|
# Criar XLinkOut para saída RGB
|
|
xout_rgb = pipeline.create(dai.node.XLinkOut)
|
|
xout_rgb.setStreamName("rgb")
|
|
cam_rgb.preview.link(xout_rgb.input)
|
|
|
|
# 🔹 Câmera de Profundidade
|
|
mono_left = pipeline.create(dai.node.MonoCamera)
|
|
mono_right = pipeline.create(dai.node.MonoCamera)
|
|
stereo = pipeline.create(dai.node.StereoDepth)
|
|
|
|
mono_left.setResolution(dai.MonoCameraProperties.SensorResolution.THE_400_P)
|
|
mono_right.setResolution(dai.MonoCameraProperties.SensorResolution.THE_400_P)
|
|
|
|
mono_left.setBoardSocket(dai.CameraBoardSocket.LEFT)
|
|
mono_right.setBoardSocket(dai.CameraBoardSocket.RIGHT)
|
|
|
|
# Configuração do StereoDepth
|
|
stereo.setDefaultProfilePreset(dai.node.StereoDepth.PresetMode.HIGH_DENSITY)
|
|
stereo.setLeftRightCheck(True)
|
|
stereo.setSubpixel(True)
|
|
|
|
mono_left.out.link(stereo.left)
|
|
mono_right.out.link(stereo.right)
|
|
|
|
# Criar XLinkOut para profundidade
|
|
xout_depth = pipeline.create(dai.node.XLinkOut)
|
|
xout_depth.setStreamName("depth")
|
|
stereo.depth.link(xout_depth.input)
|
|
|
|
|
|
# 🔹 Função para enviar vídeo via Flask
|
|
def generate_video(camera_index):
|
|
# Listar todas as câmeras conectadas
|
|
devices = dai.Device.getAllAvailableDevices()
|
|
|
|
if len(devices) == 0:
|
|
print("Nenhuma câmera OAK conectada.")
|
|
return
|
|
|
|
if camera_index >= len(devices):
|
|
print(f"Índice da câmera ({camera_index}) inválido. Apenas {len(devices)} câmeras disponíveis.")
|
|
return
|
|
|
|
selected_device_info = devices[camera_index] # Seleciona a câmera correta pelo índice
|
|
print(f"Usando câmera: {selected_device_info.name} (ID: {selected_device_info.mxid})")
|
|
|
|
with dai.Device(pipeline, selected_device_info) as device: # 🔹 Agora usa a câmera correta
|
|
rgb_queue = device.getOutputQueue(name="rgb", maxSize=1, blocking=True)
|
|
depth_queue = device.getOutputQueue(name="depth", maxSize=1, blocking=True)
|
|
|
|
readings = []
|
|
rgb_frame = None
|
|
depth_frame = None
|
|
|
|
while True:
|
|
timestamp = time.time()
|
|
|
|
# Pega os dois frames ao mesmo tempo, para evitar desincronização
|
|
in_rgb = rgb_queue.tryGet()
|
|
in_depth = depth_queue.tryGet()
|
|
|
|
if in_rgb is not None and in_depth is not None:
|
|
rgb_frame = in_rgb.getCvFrame()
|
|
depth_frame = in_depth.getFrame()
|
|
|
|
# 🔹 Verifica se depth_frame está vazio antes de processar
|
|
if depth_frame is None or depth_frame.size == 0:
|
|
print("⚠️ Frame de profundidade inválido. Pulando esta iteração.")
|
|
continue
|
|
|
|
# Normaliza a profundidade para visualização (mapa de calor)
|
|
depth_visual = cv2.normalize(depth_frame, None, 0, 255, cv2.NORM_MINMAX, dtype=cv2.CV_8U)
|
|
depth_visual = cv2.applyColorMap(depth_visual, cv2.COLORMAP_JET)
|
|
|
|
# 📡 Enviar dados via MQTT (Apenas a matriz de profundidade reduzida)
|
|
depth_data = depth_frame.tolist() # Converte a matriz para lista JSON
|
|
depth_small = cv2.resize(depth_frame, (width // 2, height // 2)) # Reduz para metade
|
|
depth_data = depth_small.tolist()
|
|
|
|
try:
|
|
memory_usage = device.getDdrMemoryUsage()
|
|
memory_info = {
|
|
"remaining": memory_usage.remaining,
|
|
"total": memory_usage.total,
|
|
"used": memory_usage.used
|
|
}
|
|
except:
|
|
memory_info = None # Se houver erro, define como None
|
|
|
|
try:
|
|
temp = device.getChipTemperature()
|
|
temp_info = {
|
|
"css": temp.css,
|
|
"mss": temp.mss,
|
|
"upa": temp.upa,
|
|
"dss": temp.dss
|
|
}
|
|
except:
|
|
temp_info = None # Se houver erro, define como None
|
|
|
|
device_data = {
|
|
"id": selected_device_info.getMxId(), # ID do dispositivo
|
|
"name": selected_device_info.name, # Nome do dispositivo
|
|
"state": selected_device_info.state.name, # Estado do dispositivo
|
|
"usb_speed": str(device.getUsbSpeed().name) if hasattr(device, 'getUsbSpeed') else None, # Velocidade USB
|
|
"available_camera_sensors": [sensor.name for sensor in device.getConnectedCameras()], # Sensores de câmera disponíveis
|
|
"version": str(device.getDeviceInfo().protocol) if hasattr(device, 'getDeviceInfo') else None, # Versão do protocolo
|
|
"memory_usage": memory_info, # Uso de memória DDR
|
|
"temperature": temp_info, # Temperatura do chip
|
|
"bootloader_version": str(device.getBootloaderVersion()) if hasattr(device, 'getBootloaderVersion') else None, # Bootloader
|
|
"is_pipeline_running": device.isPipelineRunning() if hasattr(device, 'isPipelineRunning') else None # Pipeline rodando?
|
|
}
|
|
|
|
|
|
json_data = {
|
|
'timestamp': timestamp,
|
|
'device_data': device_data,
|
|
'x_max': width,
|
|
'y_max': height,
|
|
'depth_data': depth_data,
|
|
}
|
|
|
|
readings.append(json_data)
|
|
|
|
# Enviar apenas a cada max_readings capturas
|
|
if len(readings) >= max_readings:
|
|
mensagem_relevante = readings[-1]
|
|
mqtt_client.publish(mqtt_topic, json.dumps(mensagem_relevante).encode('utf-8'))
|
|
readings.clear()
|
|
|
|
|
|
frame = rgb_frame.getCvFrame()
|
|
ret, buffer = cv2.imencode('.jpg', frame, [cv2.IMWRITE_JPEG_QUALITY, 80]) # Reduz qualidade para 80%
|
|
frame = buffer.tobytes()
|
|
yield (b'--frame\r\n'
|
|
b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
|
|
|
|
|
|
|
|
def send_script_ready():
|
|
mqtt_client.publish(mqtt_topic, "OK")
|
|
|
|
def run_flask_server():
|
|
app.run(host='0.0.0.0', port=porta, threaded=True, debug=False)
|
|
|
|
@app.route('/' + url, methods=['GET'])
|
|
def video_feed():
|
|
camera_index = int(request.args.get('camera_index'))
|
|
return Response(generate_video(camera_index), mimetype='multipart/x-mixed-replace; boundary=frame')
|
|
|
|
if __name__ == '__main__':
|
|
mqtt_thread = threading.Thread(target=send_script_ready)
|
|
mqtt_thread.start()
|
|
run_flask_server() |