File size: 3,552 Bytes
c792c63
 
fddf7b4
 
 
 
 
76396cf
fddf7b4
c792c63
fddf7b4
76396cf
fddf7b4
 
6801165
fddf7b4
 
 
 
 
c792c63
76396cf
fddf7b4
76396cf
688d726
76396cf
 
 
c792c63
76396cf
 
c792c63
 
 
76396cf
 
c792c63
fbad683
76396cf
c792c63
 
 
fbad683
76396cf
c792c63
 
76396cf
6801165
c792c63
 
 
aaac6d6
76396cf
c792c63
fbad683
76396cf
c792c63
 
 
 
 
 
76396cf
c792c63
 
 
 
76396cf
 
c792c63
 
 
76396cf
 
 
 
 
 
 
 
 
 
 
 
fddf7b4
c792c63
 
 
76396cf
 
fddf7b4
 
 
c792c63
76396cf
fddf7b4
c792c63
 
76396cf
 
b70cb7b
 
 
76396cf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# app.py
from fastapi import FastAPI, File, UploadFile, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
import numpy as np
import cv2
import base64
import io

app = FastAPI(title="Detector de Corrosão Branca")

# PARA PROTOTIPO: permitir todas origens. Em produção restrinja ao domínio do frontend.
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

def process_image_bytes(img_bytes: bytes):
    # lê bytes em numpy + OpenCV
    nparr = np.frombuffer(img_bytes, np.uint8)
    img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
    if img is None:
        raise ValueError("Não foi possível decodificar a imagem.")

    # 1) Converter para HSV
    hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

    # 2) máscara do fundo preto (V baixo)
    lower_bg = np.array([0, 0, 0], dtype=np.uint8)
    upper_bg = np.array([180, 255, 50], dtype=np.uint8)
    mask_bg = cv2.inRange(hsv, lower_bg, upper_bg)

    # 3) objeto = invertendo máscara do fundo
    mask_obj = cv2.bitwise_not(mask_bg)

    # 4) limpar máscara (morfologia)
    kernel = np.ones((5, 5), np.uint8)
    mask_obj = cv2.morphologyEx(mask_obj, cv2.MORPH_OPEN, kernel)
    mask_obj = cv2.morphologyEx(mask_obj, cv2.MORPH_CLOSE, kernel)

    # 5) maior contorno (supõe um parafuso)
    contours, _ = cv2.findContours(mask_obj, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    if not contours:
        return {"error": "Nenhum objeto detectado"}

    largest = max(contours, key=cv2.contourArea)
    mask_clean = np.zeros_like(mask_obj)
    cv2.drawContours(mask_clean, [largest], -1, 255, cv2.FILLED)

    # 6) isolar objeto
    isolated = cv2.bitwise_and(img, img, mask=mask_clean)

    # 7) detectar corrosão BRANCA (S baixa, V alta)
    hsv_iso = cv2.cvtColor(isolated, cv2.COLOR_BGR2HSV)
    lower_white = np.array([0, 0, 180], dtype=np.uint8)
    upper_white = np.array([180, 60, 255], dtype=np.uint8)
    mask_white = cv2.inRange(hsv_iso, lower_white, upper_white)
    mask_white = cv2.bitwise_and(mask_white, mask_white, mask=mask_clean)

    # 8) métricas
    total_pixels = int(np.count_nonzero(mask_clean))
    corrosion_pixels = int(np.count_nonzero(mask_white))
    percent = (corrosion_pixels / max(1, total_pixels)) * 100.0

    # 9) preparar imagens para frontend (PNG base64)
    # isolado em RGB para visualização
    isolated_rgb = cv2.cvtColor(isolated, cv2.COLOR_BGR2RGB)
    corrosion_vis = cv2.bitwise_and(isolated_rgb, isolated_rgb, mask=mask_white)

    def to_data_uri(img_arr):
        # img_arr: RGB uint8
        bgr = cv2.cvtColor(img_arr, cv2.COLOR_RGB2BGR)
        ok, buf = cv2.imencode(".png", bgr)
        if not ok:
            return None
        b64 = base64.b64encode(buf.tobytes()).decode("ascii")
        return f"data:image/png;base64,{b64}"

    isolated_b64 = to_data_uri(isolated_rgb)
    corrosion_b64 = to_data_uri(corrosion_vis)

    return {
        "percent": round(percent, 4),
        "total_pixels": total_pixels,
        "corrosion_pixels": corrosion_pixels,
        "isolated_image": isolated_b64,
        "corrosion_image": corrosion_b64,
    }

@app.post("/analyze")
async def analyze(file: UploadFile = File(...)):
    content = await file.read()
    try:
        result = process_image_bytes(content)
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    return JSONResponse(result)

@app.get("/")
def read_root():
    return {"status": "ok"}