212 lines
7.2 KiB
Python
212 lines
7.2 KiB
Python
import cv2
|
|
import numpy as np
|
|
import math
|
|
import json
|
|
import time
|
|
import socket
|
|
import threading
|
|
import sys
|
|
import os
|
|
from flask import Flask, Response, request
|
|
|
|
# Variável para mostrar as linhas (True = mostrar, False = não mostrar)
|
|
max_readings = int(sys.argv[1])
|
|
porta = sys.argv[2]
|
|
url = sys.argv[3]
|
|
arquivoSaida = sys.argv[4]
|
|
mostrar_linhas = sys.argv[5] == "1"
|
|
socket_porta = int(sys.argv[6])
|
|
|
|
app = Flask(__name__)
|
|
|
|
# Função para calcular o ângulo entre duas linhas
|
|
def calcular_angulo(linha1, linha2):
|
|
# Extraia os elementos individuais dos arrays NumPy
|
|
angulo1 = math.atan2(float(linha1[1]) - float(linha1[3]), float(linha1[0]) - float(linha1[2]))
|
|
angulo2 = math.atan2(float(linha2[1]) - float(linha2[3]), float(linha2[0]) - float(linha2[2]))
|
|
angulo = math.degrees(angulo1 - angulo2)
|
|
angulo = (angulo + 360) % 360
|
|
if angulo > 180:
|
|
angulo -= 360
|
|
return angulo
|
|
|
|
# Função para desenhar as linhas na imagem
|
|
def desenhar_linhas(frame, altura, largura, esquerda_x, direita_x, mostrar_linhas):
|
|
if mostrar_linhas:
|
|
meio = largura // 2
|
|
cv2.line(frame, (meio, 0), (meio, altura), (255, 0, 0), 2)
|
|
cv2.line(frame, (esquerda_x, 0), (direita_x, altura), (0, 255, 0), 2)
|
|
cv2.line(frame, (esquerda_x, 0), (esquerda_x, altura), (0, 255, 255), 2)
|
|
cv2.line(frame, (direita_x, 0), (direita_x, altura), (0, 255, 255), 2)
|
|
|
|
# Função para processar cada frame do vídeo e calcular as distâncias
|
|
def processar_frame(frame, largura, altura):
|
|
# Convertendo para escala de cinza
|
|
cinza = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
|
|
|
|
# Limiarização para criar uma imagem binária
|
|
_, binarizada = cv2.threshold(cinza, 128, 255, cv2.THRESH_BINARY_INV)
|
|
|
|
# Encontrar os contornos
|
|
contornos, _ = cv2.findContours(binarizada, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
|
|
|
|
# Se houver contornos, assumir que o maior é a linha preta
|
|
if contornos:
|
|
maior_contorno = max(contornos, key=cv2.contourArea)
|
|
|
|
# Ajustar uma linha ao maior contorno (linha preta)
|
|
[vx, vy, x0, y0] = cv2.fitLine(maior_contorno, cv2.DIST_L2, 0, 0.01, 0.01)
|
|
|
|
# Verificar se vy é zero para evitar divisão por zero
|
|
if vy == 0:
|
|
esquerda_x = x0
|
|
direita_x = x0
|
|
else:
|
|
# Determinar os pontos extremos da linha preta
|
|
esquerda_x = int(x0 + (-y0 * vx / vy))
|
|
direita_x = int(x0 + ((altura - y0) * vx / vy))
|
|
|
|
# Calcular distâncias das bordas
|
|
distancia_esquerda = max(0, esquerda_x)
|
|
distancia_direita = max(0, largura - direita_x)
|
|
|
|
# Calcular o ângulo entre a linha central e a linha ajustada
|
|
linha_central = [largura // 2, 0, largura // 2, altura]
|
|
linha_ajustada = [esquerda_x, 0, direita_x, altura]
|
|
angulo = calcular_angulo(linha_central, linha_ajustada)
|
|
|
|
# Desenhar linhas, se necessário
|
|
desenhar_linhas(frame, altura, largura, esquerda_x, direita_x, mostrar_linhas)
|
|
|
|
return (angulo, distancia_esquerda, distancia_direita, frame)
|
|
|
|
return (None, None, None, frame)
|
|
|
|
# Caminho do arquivo JSON para salvar os dados
|
|
output_folder = 'Python/Output/'
|
|
json_path = arquivoSaida
|
|
json_data = None
|
|
|
|
# Função para salvar os dados em formato JSON
|
|
def salvar_json(angulo, distancia_esquerda, distancia_direita, timestamp, json_path):
|
|
global json_data # Indica que queremos usar a variável global json_data
|
|
|
|
# Assegure-se que todos os dados são tipos primitivos antes de salvar em JSON
|
|
json_data = {
|
|
'timestamp': timestamp,
|
|
'angulo': angulo,
|
|
'distancia_esquerda': distancia_esquerda,
|
|
'distancia_direita': distancia_direita
|
|
}
|
|
|
|
if not os.path.exists(output_folder):
|
|
os.makedirs(output_folder)
|
|
|
|
try:
|
|
with open(output_folder + json_path, 'r') as file:
|
|
leituras = json.load(file)
|
|
except FileNotFoundError:
|
|
leituras = []
|
|
|
|
leituras.append(json_data)
|
|
leituras = leituras[-10:]
|
|
|
|
with open(output_folder + json_path, 'w') as file:
|
|
json.dump(leituras, file, indent=4)
|
|
|
|
def detect_lines(camera_index):
|
|
# Inicializando a captura de vídeo
|
|
cap = cv2.VideoCapture(camera_index)
|
|
if not cap.isOpened():
|
|
print("Erro: A câmera não pôde ser aberta.")
|
|
return
|
|
|
|
altura, largura = None, None
|
|
|
|
try:
|
|
while True:
|
|
ret, frame = cap.read()
|
|
if not ret:
|
|
print("Falha ao capturar imagem da câmera.")
|
|
break
|
|
|
|
if altura is None or largura is None:
|
|
altura, largura = frame.shape[:2]
|
|
|
|
# Processar o frame atual
|
|
angulo, distancia_esquerda, distancia_direita, frame_processado = processar_frame(frame, largura, altura)
|
|
|
|
if angulo is not None and distancia_esquerda is not None and distancia_direita is not None:
|
|
timestamp = int(time.time())
|
|
salvar_json(angulo, distancia_esquerda, distancia_direita, timestamp, json_path)
|
|
|
|
# Codificar o frame processado para JPEG
|
|
ret, buffer = cv2.imencode('.jpg', frame_processado)
|
|
if not ret:
|
|
continue
|
|
|
|
frame_bytes = buffer.tobytes()
|
|
yield (b'--frame\r\n'
|
|
b'Content-Type: image/jpeg\r\n\r\n' + frame_bytes + b'\r\n')
|
|
|
|
finally:
|
|
# Quando tudo estiver feito, liberar a captura
|
|
cap.release()
|
|
|
|
# Função para lidar com a conexão de cada cliente
|
|
def handle_client_connection(client_socket):
|
|
try:
|
|
while True:
|
|
# Enviar o dicionário serializado em JSON
|
|
client_socket.send(json.dumps(json_data).encode('utf-8'))
|
|
|
|
# Aguardar um pouco antes de enviar os próximos dados
|
|
time.sleep(0.1)
|
|
except socket.error:
|
|
print(f"Cliente desconectado.")
|
|
finally:
|
|
# Fechar a conexão do socket ao sair do loop
|
|
client_socket.close()
|
|
|
|
# Configuração inicial do servidor de socket
|
|
def start_server(address='localhost', port=socket_porta):
|
|
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
server.bind((address, port))
|
|
server.listen()
|
|
print(f"Servidor iniciado. Aguardando conexões em {address}:{port}...")
|
|
|
|
try:
|
|
while True:
|
|
client_sock, address = server.accept()
|
|
print(f"Aceitando conexão de {address[0]}:{address[1]}")
|
|
client_handler = threading.Thread(
|
|
target=handle_client_connection,
|
|
args=(client_sock,)
|
|
)
|
|
client_handler.start()
|
|
finally:
|
|
server.close()
|
|
|
|
|
|
# Esta função é para iniciar o servidor de socket em uma thread separada
|
|
def run_socket_server():
|
|
start_server()
|
|
|
|
# Iniciar o servidor Flask em uma thread separada
|
|
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(detect_lines(camera_index), mimetype='multipart/x-mixed-replace; boundary=frame')
|
|
|
|
|
|
# Iniciar o servidor
|
|
if __name__ == '__main__':
|
|
# Inicia o servidor de socket em uma thread separada
|
|
socket_server_thread = threading.Thread(target=run_socket_server)
|
|
socket_server_thread.start()
|
|
|
|
# Inicia o servidor Flask na thread principal
|
|
run_flask_server() |