joao-dutra commited on
Commit
cb48d1c
·
verified ·
1 Parent(s): 30b2bda
Files changed (1) hide show
  1. app.py +3 -104
app.py CHANGED
@@ -58,24 +58,20 @@ app.add_middleware(
58
  # ==============================================================================
59
 
60
  def process_image_bytes(img_bytes: bytes):
61
- """Lógica de análise de imagem com OpenCV. Retorna um dict com métricas e a imagem de corrosão em numpy (RGB)."""
62
  nparr = np.frombuffer(img_bytes, np.uint8)
63
  img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
64
  if img is None:
65
  raise ValueError("Não foi possível decodificar a imagem.")
66
 
67
  hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
68
-
69
- # Segmentação do objeto principal (fundo escuro)
70
  lower_bg = np.array([0, 0, 0], dtype=np.uint8)
71
  upper_bg = np.array([180, 255, 50], dtype=np.uint8)
72
  mask_bg = cv2.inRange(hsv, lower_bg, upper_bg)
73
  mask_obj = cv2.bitwise_not(mask_bg)
74
-
75
  kernel = np.ones((5, 5), np.uint8)
76
  mask_obj = cv2.morphologyEx(mask_obj, cv2.MORPH_OPEN, kernel)
77
  mask_obj = cv2.morphologyEx(mask_obj, cv2.MORPH_CLOSE, kernel)
78
-
79
  contours, _ = cv2.findContours(mask_obj, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
80
  if not contours:
81
  raise ValueError("Nenhum objeto principal detectado na imagem.")
@@ -83,11 +79,8 @@ def process_image_bytes(img_bytes: bytes):
83
  largest = max(contours, key=cv2.contourArea)
84
  mask_clean = np.zeros_like(mask_obj)
85
  cv2.drawContours(mask_clean, [largest], -1, 255, cv2.FILLED)
86
-
87
  isolated = cv2.bitwise_and(img, img, mask=mask_clean)
88
  hsv_iso = cv2.cvtColor(isolated, cv2.COLOR_BGR2HSV)
89
-
90
- # Corrosão branca (faixa de brancos)
91
  lower_white = np.array([0, 0, 180], dtype=np.uint8)
92
  upper_white = np.array([180, 60, 255], dtype=np.uint8)
93
  mask_white = cv2.inRange(hsv_iso, lower_white, upper_white)
@@ -103,8 +96,7 @@ def process_image_bytes(img_bytes: bytes):
103
  def to_data_uri(img_arr_rgb):
104
  bgr = cv2.cvtColor(img_arr_rgb, cv2.COLOR_RGB2BGR)
105
  ok, buf = cv2.imencode(".png", bgr)
106
- if not ok:
107
- return None
108
  b64 = base64.b64encode(buf.tobytes()).decode("ascii")
109
  return f"data:image/png;base64,{b64}"
110
 
@@ -115,101 +107,8 @@ def process_image_bytes(img_bytes: bytes):
115
  "isolated_image": to_data_uri(isolated_rgb),
116
  "corrosion_image": to_data_uri(corrosion_vis_rgb),
117
  }
118
-
119
- return analysis_results, corrosion_vis_rgb
120
-
121
 
122
- def analyze_and_persist(img_bytes: bytes, logical_name: str):
123
- """
124
- Processa a imagem em memória (process_image_bytes), faz upload no S3 (original & resultado)
125
- e insere na tabela 'amostras'. Retorna o dict da análise + chaves S3 + database_id.
126
- """
127
- # 1) Processa
128
- analysis_results, corrosion_image_np = process_image_bytes(img_bytes)
129
-
130
- # 2) Upload ORIGINAL
131
- content_type = mimetypes.guess_type(logical_name)[0] or "application/octet-stream"
132
- extensao = mimetypes.guess_extension(content_type) or ".jpg"
133
-
134
- s3_key_original = f"imagens_originais/{uuid.uuid4()}{extensao}"
135
- s3_client.put_object(
136
- Bucket=AWS_S3_BUCKET_NAME,
137
- Key=s3_key_original,
138
- Body=img_bytes,
139
- ContentType=content_type
140
- )
141
-
142
- # 3) Upload RESULTADO (PNG)
143
- bgr_result = cv2.cvtColor(corrosion_image_np, cv2.COLOR_RGB2BGR)
144
- ok, buffer = cv2.imencode('.png', bgr_result)
145
- if not ok:
146
- raise ValueError("Falha ao codificar a imagem de resultado para PNG.")
147
- s3_key_resultado = f"imagens_resultados/{uuid.uuid4()}.png"
148
- s3_client.put_object(
149
- Bucket=AWS_S3_BUCKET_NAME,
150
- Key=s3_key_resultado,
151
- Body=buffer.tobytes(),
152
- ContentType='image/png'
153
- )
154
-
155
- # 4) Insert Supabase (na mesma tabela 'amostras')
156
- dados_para_inserir = {
157
- "imagem_original": s3_key_original,
158
- "imagem_resultado": s3_key_resultado,
159
- "resultado": analysis_results["percent"]
160
- }
161
- response = supabase_client.from_("amostra").insert(dados_para_inserir).execute()
162
- new_record_id = response.data[0]['id']
163
-
164
- # Retorno enriquecido
165
- out = {
166
- **analysis_results,
167
- "database_id": new_record_id,
168
- "s3_original": s3_key_original,
169
- "s3_resultado": s3_key_resultado
170
- }
171
- return out
172
-
173
- def segmentate(file_bytes: bytes):
174
- """
175
- Roda o YOLO, salva predição e crops, e retorna:
176
- - save_dir (Path): diretório raiz onde o Ultralytics salvou esta execução
177
- - crop_paths (list[Path]): lista com todos os arquivos de imagem dentro de /crops
178
- """
179
- modelo = YOLO('back-ciser/best.pt')
180
-
181
- # Passa a imagem como array (sem salvar a original só para inferir)
182
- img = Image.open(io.BytesIO(file_bytes)).convert("RGB")
183
- np_img = np.array(img)
184
- np_img_bgr = cv2.cvtColor(np_img, cv2.COLOR_RGB2BGR)
185
-
186
- resultados = modelo.predict(
187
- source=np_img,
188
- imgsz=1280,
189
- conf=0.7,
190
- iou=0.3,
191
- save=True,
192
- save_crop=True,
193
- project=LOCAL_RESULT,
194
- name="predict", # deixa previsível
195
- exist_ok=True,
196
- verbose=False
197
- )
198
-
199
- # Diretório real onde esta execução foi salva
200
- save_dir = Path(resultados[0].save_dir)
201
-
202
- crops_dir = save_dir / "crops"
203
- if not crops_dir.exists():
204
- return save_dir, []
205
-
206
- # Varre recursivamente (crops/<classe>/*.jpg|png|...)
207
- crop_paths = []
208
- for ext in ("*.jpg", "*.png", "*.jpeg", "*.bmp", "*.tif", "*.tiff"):
209
- crop_paths.extend(crops_dir.rglob(ext))
210
-
211
- crop_paths = sorted(crop_paths, key=lambda p: str(p).lower())
212
- return save_dir, crop_paths
213
 
214
  # ==============================================================================
215
  # 3. ENDPOINTS DA API
 
58
  # ==============================================================================
59
 
60
  def process_image_bytes(img_bytes: bytes):
61
+ """Lógica de análise de imagem com OpenCV. Retorna um dict com métricas e a imagem de corrosão em numpy."""
62
  nparr = np.frombuffer(img_bytes, np.uint8)
63
  img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
64
  if img is None:
65
  raise ValueError("Não foi possível decodificar a imagem.")
66
 
67
  hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
 
 
68
  lower_bg = np.array([0, 0, 0], dtype=np.uint8)
69
  upper_bg = np.array([180, 255, 50], dtype=np.uint8)
70
  mask_bg = cv2.inRange(hsv, lower_bg, upper_bg)
71
  mask_obj = cv2.bitwise_not(mask_bg)
 
72
  kernel = np.ones((5, 5), np.uint8)
73
  mask_obj = cv2.morphologyEx(mask_obj, cv2.MORPH_OPEN, kernel)
74
  mask_obj = cv2.morphologyEx(mask_obj, cv2.MORPH_CLOSE, kernel)
 
75
  contours, _ = cv2.findContours(mask_obj, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
76
  if not contours:
77
  raise ValueError("Nenhum objeto principal detectado na imagem.")
 
79
  largest = max(contours, key=cv2.contourArea)
80
  mask_clean = np.zeros_like(mask_obj)
81
  cv2.drawContours(mask_clean, [largest], -1, 255, cv2.FILLED)
 
82
  isolated = cv2.bitwise_and(img, img, mask=mask_clean)
83
  hsv_iso = cv2.cvtColor(isolated, cv2.COLOR_BGR2HSV)
 
 
84
  lower_white = np.array([0, 0, 180], dtype=np.uint8)
85
  upper_white = np.array([180, 60, 255], dtype=np.uint8)
86
  mask_white = cv2.inRange(hsv_iso, lower_white, upper_white)
 
96
  def to_data_uri(img_arr_rgb):
97
  bgr = cv2.cvtColor(img_arr_rgb, cv2.COLOR_RGB2BGR)
98
  ok, buf = cv2.imencode(".png", bgr)
99
+ if not ok: return None
 
100
  b64 = base64.b64encode(buf.tobytes()).decode("ascii")
101
  return f"data:image/png;base64,{b64}"
102
 
 
107
  "isolated_image": to_data_uri(isolated_rgb),
108
  "corrosion_image": to_data_uri(corrosion_vis_rgb),
109
  }
 
 
 
110
 
111
+ return analysis_results, corrosion_vis_rgb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
112
 
113
  # ==============================================================================
114
  # 3. ENDPOINTS DA API