|
import gradio as gr |
|
import cv2 |
|
import numpy as np |
|
import tensorflow as tf |
|
from PIL import Image |
|
import torch |
|
import torch.nn as nn |
|
from torchvision import transforms |
|
from scipy import signal |
|
from skimage import feature |
|
import matplotlib.pyplot as plt |
|
import io |
|
from datetime import datetime |
|
import pandas as pd |
|
import json |
|
|
|
class GasAnalyzer: |
|
"""Classe principal para análise de gás e chama""" |
|
def __init__(self): |
|
self.analyzer = FlameAnalyzer() |
|
self.consumption_history = [] |
|
self.maintenance_records = [] |
|
|
|
def save_analysis(self, analysis_data): |
|
"""Salva histórico de análise""" |
|
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") |
|
analysis_data['timestamp'] = timestamp |
|
self.consumption_history.append(analysis_data) |
|
return json.dumps(analysis_data, indent=2) |
|
|
|
def calculate_efficiency(self, consumption_data): |
|
"""Calcula eficiência do consumo""" |
|
if not consumption_data: |
|
return 0 |
|
|
|
recent_usage = float(consumption_data['daily_usage']) |
|
baseline = 0.8 |
|
|
|
efficiency = (baseline / recent_usage) * 100 |
|
return min(100, efficiency) |
|
|
|
def predict_replacement(self, consumption_history): |
|
"""Prevê data de substituição do gás""" |
|
if not consumption_history: |
|
return None |
|
|
|
avg_consumption = np.mean([float(h['daily_usage']) for h in consumption_history]) |
|
remaining_days = 13 / avg_consumption |
|
|
|
replacement_date = datetime.now() + pd.Timedelta(days=remaining_days) |
|
return replacement_date.strftime("%Y-%m-%d") |
|
|
|
def generate_maintenance_report(self): |
|
"""Gera relatório de manutenção""" |
|
if not self.maintenance_records: |
|
return "Nenhum registro de manutenção encontrado." |
|
|
|
report = "📋 Histórico de Manutenção:\n\n" |
|
for record in self.maintenance_records: |
|
report += f"Data: {record['date']}\n" |
|
report += f"Tipo: {record['type']}\n" |
|
report += f"Observações: {record['notes']}\n" |
|
report += "───────────────────\n" |
|
return report |
|
|
|
class FlameAnalyzer: |
|
"""Classe para análise específica da chama""" |
|
def __init__(self): |
|
self.model = self._initialize_model() |
|
|
|
def _initialize_model(self): |
|
"""Inicializa o modelo de análise de chama""" |
|
model = tf.keras.Sequential([ |
|
tf.keras.layers.Conv2D(32, 3, activation='relu', input_shape=(64, 64, 3)), |
|
tf.keras.layers.MaxPooling2D(), |
|
tf.keras.layers.Conv2D(64, 3, activation='relu'), |
|
tf.keras.layers.MaxPooling2D(), |
|
tf.keras.layers.Conv2D(64, 3, activation='relu'), |
|
tf.keras.layers.Flatten(), |
|
tf.keras.layers.Dense(64, activation='relu'), |
|
tf.keras.layers.Dense(4, activation='softmax') |
|
]) |
|
return model |
|
|
|
def analyze_flame(self, image): |
|
"""Análise completa da chama""" |
|
img = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2BGR) |
|
features = self.extract_features(img) |
|
health_score = self.calculate_health_score(features) |
|
return features, health_score |
|
|
|
def extract_features(self, image): |
|
"""Extrai características da chama""" |
|
features = {} |
|
|
|
|
|
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) |
|
lab = cv2.cvtColor(image, cv2.COLOR_BGR2LAB) |
|
|
|
|
|
features['color'] = { |
|
'mean_hue': np.mean(hsv[:,:,0]), |
|
'mean_saturation': np.mean(hsv[:,:,1]), |
|
'mean_value': np.mean(hsv[:,:,2]), |
|
'brightness': np.mean(lab[:,:,0]), |
|
'color_a': np.mean(lab[:,:,1]), |
|
'color_b': np.mean(lab[:,:,2]) |
|
} |
|
|
|
|
|
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) |
|
_, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_OTSU) |
|
contours, _ = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) |
|
|
|
if contours: |
|
largest_contour = max(contours, key=cv2.contourArea) |
|
features['shape'] = { |
|
'area': cv2.contourArea(largest_contour), |
|
'perimeter': cv2.arcLength(largest_contour, True), |
|
'circularity': 4 * np.pi * cv2.contourArea(largest_contour) / |
|
(cv2.arcLength(largest_contour, True) ** 2) if cv2.arcLength(largest_contour, True) > 0 else 0 |
|
} |
|
|
|
|
|
glcm = feature.graycomatrix(gray, [1], [0], 256, symmetric=True, normed=True) |
|
features['texture'] = { |
|
'contrast': feature.graycoprops(glcm, 'contrast')[0][0], |
|
'homogeneity': feature.graycoprops(glcm, 'homogeneity')[0][0], |
|
'energy': feature.graycoprops(glcm, 'energy')[0][0], |
|
'correlation': feature.graycoprops(glcm, 'correlation')[0][0] |
|
} |
|
|
|
return features |
|
|
|
def calculate_health_score(self, features): |
|
"""Calcula score de saúde da chama com critérios refinados""" |
|
|
|
weights = { |
|
'color': 0.5, |
|
'shape': 0.3, |
|
'texture': 0.2 |
|
} |
|
|
|
|
|
color_score = 0 |
|
if 'color' in features: |
|
hue = features['color']['mean_hue'] |
|
sat = features['color']['mean_saturation'] |
|
val = features['color']['mean_value'] |
|
|
|
|
|
color_score = ( |
|
(0.5 if 200 <= hue <= 240 else 0.3 if 180 <= hue <= 260 else 0.1) + |
|
(0.3 if sat > 50 else 0.1) + |
|
(0.2 if val > 150 else 0.1) |
|
) |
|
|
|
|
|
shape_score = 0 |
|
if 'shape' in features: |
|
circularity = features['shape']['circularity'] |
|
area = features['shape']['area'] |
|
|
|
|
|
shape_score = ( |
|
(0.6 if 0.7 <= circularity <= 0.9 else 0.3) + |
|
(0.4 if area > 1000 else 0.2) |
|
) |
|
else: |
|
shape_score = 0.5 |
|
|
|
|
|
texture_score = 0 |
|
if 'texture' in features: |
|
homogeneity = features['texture']['homogeneity'] |
|
energy = features['texture']['energy'] |
|
correlation = features['texture']['correlation'] |
|
|
|
|
|
texture_score = ( |
|
(0.4 if homogeneity > 0.7 else 0.2) + |
|
(0.3 if 0.2 <= energy <= 0.8 else 0.1) + |
|
(0.3 if correlation > 0.8 else 0.1) |
|
) |
|
|
|
|
|
raw_score = ( |
|
color_score * weights['color'] + |
|
shape_score * weights['shape'] + |
|
texture_score * weights['texture'] |
|
) |
|
|
|
|
|
normalized_score = 1 / (1 + np.exp(-5 * (raw_score - 0.5))) |
|
|
|
|
|
if normalized_score > 0.8: |
|
|
|
if color_score > 0.7 and shape_score > 0.6: |
|
return normalized_score |
|
return 0.75 |
|
|
|
return normalized_score |
|
|
|
def create_visualization(image, features, health_score): |
|
"""Cria visualização da análise""" |
|
fig = plt.figure(figsize=(12, 8)) |
|
gs = plt.GridSpec(2, 3, figure=fig) |
|
|
|
|
|
ax1 = fig.add_subplot(gs[0, 0]) |
|
ax1.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB)) |
|
ax1.set_title('Imagem Original') |
|
ax1.axis('off') |
|
|
|
|
|
ax2 = fig.add_subplot(gs[0, 1]) |
|
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) |
|
ax2.imshow(hsv[:,:,0], cmap='hsv') |
|
ax2.set_title('Análise de Matiz (HSV)') |
|
ax2.axis('off') |
|
|
|
|
|
ax3 = fig.add_subplot(gs[0, 2]) |
|
edges = cv2.Canny(cv2.cvtColor(image, cv2.COLOR_BGR2GRAY), 100, 200) |
|
ax3.imshow(edges, cmap='gray') |
|
ax3.set_title('Detecção de Bordas') |
|
ax3.axis('off') |
|
|
|
|
|
ax4 = fig.add_subplot(gs[1, :]) |
|
metrics = { |
|
'Saúde da Chama': health_score, |
|
'Homogeneidade': features['texture']['homogeneity'], |
|
'Energia': features['texture']['energy'], |
|
'Correlação': features['texture']['correlation'] |
|
} |
|
|
|
bars = ax4.bar(metrics.keys(), metrics.values()) |
|
ax4.set_ylim(0, 1) |
|
ax4.set_title('Métricas da Análise') |
|
|
|
|
|
for bar in bars: |
|
if bar.get_height() > 0.7: |
|
bar.set_color('green') |
|
elif bar.get_height() > 0.4: |
|
bar.set_color('yellow') |
|
else: |
|
bar.set_color('red') |
|
|
|
plt.tight_layout() |
|
|
|
|
|
buf = io.BytesIO() |
|
plt.savefig(buf, format='png', dpi=300, bbox_inches='tight') |
|
buf.seek(0) |
|
plt.close() |
|
|
|
return Image.open(buf) |
|
|
|
def analyze_flame_tab(image): |
|
"""Função principal para aba de análise da chama""" |
|
analyzer = FlameAnalyzer() |
|
features, health_score = analyzer.analyze_flame(image) |
|
|
|
|
|
if health_score > 0.8: |
|
condition = "Ótima" |
|
recommendations = [ |
|
"✅ Continue o uso normal", |
|
"📅 Faça manutenção preventiva regular", |
|
"📊 Registre o consumo para melhor previsão" |
|
] |
|
elif health_score > 0.6: |
|
condition = "Boa" |
|
recommendations = [ |
|
"✅ Monitore semanalmente", |
|
"⚠️ Planeje verificação mensal", |
|
"🔍 Observe mudanças na cor" |
|
] |
|
elif health_score > 0.4: |
|
condition = "Regular" |
|
recommendations = [ |
|
"⚠️ Agende troca de gás", |
|
"⏰ Evite uso prolongado", |
|
"🔧 Verifique regulagem" |
|
] |
|
else: |
|
condition = "Preocupante" |
|
recommendations = [ |
|
"🚨 Troque o gás imediatamente", |
|
"⚠️ Use apenas se necessário", |
|
"📞 Chame um técnico" |
|
] |
|
|
|
|
|
report = f""" |
|
📊 Análise da Chama |
|
───────────────── |
|
|
|
🔥 Condição: {condition} |
|
💯 Índice de Saúde: {health_score:.2f} |
|
|
|
📈 Métricas Técnicas: |
|
• Homogeneidade: {features['texture']['homogeneity']:.3f} |
|
• Energia: {features['texture']['energy']:.3f} |
|
• Correlação: {features['texture']['correlation']:.3f} |
|
|
|
📋 Recomendações: |
|
""" + "\n".join(recommendations) |
|
|
|
|
|
viz = create_visualization(np.array(image), features, health_score) |
|
|
|
return report, viz |
|
|
|
def calculate_consumption(daily_usage, num_people, cooking_hours): |
|
"""Calcula consumo de gás""" |
|
base_consumption = float(daily_usage) * float(cooking_hours) |
|
per_person_factor = float(num_people) * 0.2 |
|
total_consumption = base_consumption * (1 + per_person_factor) |
|
|
|
efficiency = 100 - (total_consumption / (13 * 0.8) * 100) |
|
|
|
report = f""" |
|
📊 Análise de Consumo |
|
───────────────────── |
|
|
|
📈 Consumo Diário: {total_consumption:.2f}kg |
|
👥 Fator Pessoas: {per_person_factor:.2f} |
|
⚡ Eficiência: {efficiency:.1f}% |
|
|
|
💡 Recomendações: |
|
""" |
|
|
|
if efficiency < 60: |
|
report += """ |
|
• Verifique vazamentos |
|
• Otimize tempo de cozimento |
|
• Considere manutenção |
|
""" |
|
else: |
|
report += """ |
|
• Mantenha o padrão |
|
• Continue monitorando |
|
• Faça manutenção preventiva |
|
""" |
|
|
|
return report |
|
|
|
def safety_check(pressure, connection_age, last_inspection): |
|
"""Realiza verificação de segurança""" |
|
try: |
|
pressure = float(pressure) |
|
connection_age = int(connection_age) |
|
last_inspection = datetime.strptime(last_inspection, "%Y-%m-%d") |
|
|
|
risks = [] |
|
if pressure < 1.8 or pressure > 2.2: |
|
risks.append("⚠️ Pressão fora do ideal") |
|
|
|
if connection_age > 5: |
|
risks.append("⚠️ Conexões antigas") |
|
|
|
days_since_inspection = (datetime.now() - last_inspection).days |
|
if days_since_inspection > 180: |
|
risks.append("⚠️ Inspeção vencida") |
|
|
|
risk_level = len(risks) |
|
|
|
report = f""" |
|
🔒 Relatório de Segurança |
|
──────────────────────── |
|
|
|
📊 Nível de Risco: {"Alto" if risk_level > 2 else "Médio" if risk_level > 0 else "Baixo"} |
|
|
|
📝 Verificações: |
|
• Pressão: {pressure} kgf/cm² {"✅" if 1.8 <= pressure <= 2.2 else "❌"} |
|
• Conexões: {connection_age} anos {"✅" if connection_age <= 5 else "❌"} |
|
• Inspeção: {last_inspection.strftime("%d/%m/%Y")} {"✅" if days_since_inspection <= 180 else "❌"} |
|
|
|
⚠️ Pontos de Atenção: |
|
""" |
|
|
|
if risks: |
|
report += "\n".join(risks) |
|
else: |
|
report += "✅ Nenhum risco identificado" |
|
|
|
return report |
|
except ValueError: |
|
return "❌ Erro: Verifique os valores inseridos. Formato de data deve ser YYYY-MM-DD" |
|
except Exception as e: |
|
return f"❌ Erro inesperado: {str(e)}" |
|
|
|
def maintenance_schedule(installation_date, last_maintenance): |
|
"""Gera cronograma de manutenção""" |
|
try: |
|
install_date = datetime.strptime(installation_date, "%Y-%m-%d") |
|
last_maint = datetime.strptime(last_maintenance, "%Y-%m-%d") |
|
|
|
next_maintenance = last_maint + pd.Timedelta(days=180) |
|
system_age = (datetime.now() - install_date).days / 365 |
|
|
|
schedule = f""" |
|
🔧 Cronograma de Manutenção |
|
────────────────────────── |
|
|
|
📅 Instalação: {install_date.strftime("%d/%m/%Y")} |
|
🔄 Última Manutenção: {last_maint.strftime("%d/%m/%Y")} |
|
⏰ Próxima Manutenção: {next_maintenance.strftime("%d/%m/%Y")} |
|
|
|
📊 Status do Sistema: |
|
• Idade: {system_age:.1f} anos |
|
• Ciclos de Manutenção: {int((datetime.now() - install_date).days / 180)} |
|
|
|
📋 Verificações Necessárias: |
|
• Teste de vazamento |
|
• Limpeza dos queimadores |
|
• Verificação das conexões |
|
• Calibração da pressão |
|
|
|
⚡ Otimizações Recomendadas: |
|
""" |
|
|
|
if system_age > 5: |
|
schedule += """ |
|
• Considerar substituição |
|
• Avaliação completa |
|
• Upgrade de segurança |
|
""" |
|
else: |
|
schedule += """ |
|
• Limpeza preventiva |
|
• Ajustes de eficiência |
|
• Verificação de rotina |
|
""" |
|
|
|
return schedule |
|
except ValueError: |
|
return "❌ Erro: Formato de data inválido. Use YYYY-MM-DD" |
|
except Exception as e: |
|
return f"❌ Erro inesperado: {str(e)}" |
|
|
|
except ValueError: |
|
return "❌ Erro: Formato de data inválido (use YYYY-MM-DD)" |
|
|
|
def efficiency_history(): |
|
"""Gera gráfico de histórico de eficiência""" |
|
dates = pd.date_range(start='2024-01-01', periods=10, freq='D') |
|
efficiencies = np.random.normal(80, 10, size=10) |
|
|
|
plt.figure(figsize=(10, 6)) |
|
plt.plot(dates, efficiencies, marker='o') |
|
plt.title('Histórico de Eficiência') |
|
plt.xlabel('Data') |
|
plt.ylabel('Eficiência (%)') |
|
plt.grid(True) |
|
|
|
buf = io.BytesIO() |
|
plt.savefig(buf, format='png') |
|
buf.seek(0) |
|
plt.close() |
|
|
|
return Image.open(buf) |
|
|
|
|
|
with gr.Blocks(theme=gr.themes.Soft()) as iface: |
|
gr.Markdown(""" |
|
# 🔥 Sistema Completo de Análise de Gás e Chama |
|
|
|
Sistema avançado para análise, monitoramento e manutenção do seu sistema de gás. |
|
""") |
|
|
|
with gr.Tabs(): |
|
|
|
with gr.Tab("📸 Análise da Chama"): |
|
with gr.Row(): |
|
with gr.Column(): |
|
input_image = gr.Image(label="Upload da Foto", type="pil") |
|
analyze_btn = gr.Button("🔍 Analisar Chama", variant="primary") |
|
|
|
with gr.Column(): |
|
output_text = gr.Textbox(label="Relatório de Análise", lines=10) |
|
output_viz = gr.Image(label="Visualização Técnica") |
|
|
|
analyze_btn.click( |
|
fn=analyze_flame_tab, |
|
inputs=[input_image], |
|
outputs=[output_text, output_viz] |
|
) |
|
|
|
|
|
with gr.Tab("📊 Análise de Consumo"): |
|
with gr.Row(): |
|
with gr.Column(): |
|
daily_usage = gr.Number(label="Consumo Diário (kg)", value=0.5) |
|
num_people = gr.Number(label="Número de Pessoas", value=1) |
|
cooking_hours = gr.Number(label="Horas de Cozimento/Dia", value=2) |
|
calc_btn = gr.Button("📊 Calcular Consumo") |
|
|
|
with gr.Column(): |
|
consumption_output = gr.Textbox(label="Análise de Consumo", lines=10) |
|
|
|
calc_btn.click( |
|
fn=calculate_consumption, |
|
inputs=[daily_usage, num_people, cooking_hours], |
|
outputs=[consumption_output] |
|
) |
|
|
|
|
|
with gr.Tab("🔒 Verificação de Segurança"): |
|
with gr.Row(): |
|
with gr.Column(): |
|
pressure = gr.Number(label="Pressão (kgf/cm²)", value=2.0) |
|
connection_age = gr.Number(label="Idade das Conexões (anos)", value=1) |
|
last_inspection = gr.Textbox( |
|
label="Data Última Inspeção (YYYY-MM-DD)", |
|
value=datetime.now().strftime("%Y-%m-%d") |
|
) |
|
safety_btn = gr.Button("🔍 Verificar Segurança") |
|
|
|
with gr.Column(): |
|
safety_output = gr.Textbox(label="Relatório de Segurança", lines=15) |
|
|
|
safety_btn.click( |
|
fn=safety_check, |
|
inputs=[pressure, connection_age, last_inspection], |
|
outputs=[safety_output] |
|
) |
|
|
|
|
|
with gr.Tab("🔧 Cronograma de Manutenção"): |
|
with gr.Row(): |
|
with gr.Column(): |
|
installation_date = gr.Textbox( |
|
label="Data de Instalação (YYYY-MM-DD)", |
|
value="2023-01-01" |
|
) |
|
last_maintenance = gr.Textbox( |
|
label="Data Última Manutenção (YYYY-MM-DD)", |
|
value=datetime.now().strftime("%Y-%m-%d") |
|
) |
|
maint_btn = gr.Button("📅 Gerar Cronograma") |
|
|
|
with gr.Column(): |
|
maintenance_output = gr.Textbox(label="Cronograma de Manutenção", lines=15) |
|
|
|
maint_btn.click( |
|
fn=maintenance_schedule, |
|
inputs=[installation_date, last_maintenance], |
|
outputs=[maintenance_output] |
|
) |
|
|
|
|
|
with gr.Tab("📝 Histórico"): |
|
with gr.Row(): |
|
with gr.Column(): |
|
gr.DataFrame( |
|
value=[ |
|
["2024-01-01", "Ótima", 95.5, 25], |
|
["2024-01-15", "Boa", 85.2, 20], |
|
["2024-02-01", "Regular", 75.8, 15] |
|
], |
|
headers=["Data", "Condição", "Eficiência", "Dias Restantes"], |
|
datatype=["str", "str", "number", "number"], |
|
label="Histórico de Análises" |
|
) |
|
|
|
with gr.Column(): |
|
gr.Image(value=efficiency_history(), label="Gráfico de Eficiência") |
|
|
|
|
|
with gr.Tab("💡 Dicas e Informações"): |
|
gr.Markdown(""" |
|
### 📚 Guia Completo de Uso do Gás |
|
|
|
#### 🔥 Boas Práticas |
|
1. **Manutenção Regular** |
|
- Limpeza mensal dos queimadores |
|
- Verificação trimestral das conexões |
|
- Teste de vazamento a cada 6 meses |
|
|
|
2. **Economia de Gás** |
|
- Use panelas com fundo plano |
|
- Mantenha as panelas tampadas |
|
- Evite chama alta desnecessária |
|
|
|
3. **Segurança** |
|
- Mantenha área ventilada |
|
- Verifique conexões regularmente |
|
- Troque mangueiras a cada 5 anos |
|
|
|
#### ⚠️ Sinais de Alerta |
|
- Chama amarelada |
|
- Fuligem nas panelas |
|
- Cheiro de gás |
|
- Ruídos estranhos |
|
|
|
#### 📱 Contatos Úteis |
|
- Emergência: 193 |
|
- Companhia de Gás: 0800-XXX-XXXX |
|
- Assistência Técnica: (XX) XXXX-XXXX |
|
""") |
|
|
|
gr.Markdown(""" |
|
### 📌 Notas Importantes |
|
- Mantenha registro das análises |
|
- Siga as recomendações de segurança |
|
- Em caso de dúvida, consulte um técnico |
|
""") |
|
|
|
if __name__ == "__main__": |
|
iface.launch() |