nmariotto commited on
Commit
a81bd48
·
verified ·
1 Parent(s): 0b4eabd

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +95 -74
app.py CHANGED
@@ -16,9 +16,9 @@ from googleapiclient.http import MediaIoBaseUpload
16
  import gspread
17
  import time
18
 
19
- # 🔥 Inicializar Roboflow
20
  API_KEY = st.secrets["roboflow_api_key"]
21
- rf = roboflow.Roboflow(api_key=API_KEY)
22
  project = rf.workspace(st.secrets["roboflow_workspace"]).project(st.secrets["roboflow_project"])
23
  model = project.version(st.secrets["roboflow_version"]).model
24
  model.confidence = 80
@@ -28,15 +28,15 @@ dpi_value = 300
28
  with st.expander("⚙️ Advanced Settings", expanded=True):
29
  model.confidence = st.slider("Model Confidence (%)", 20, 100, 80)
30
 
31
- # 📁 Setup Google Drive e Sheets
32
  scope = ["https://www.googleapis.com/auth/drive", "https://www.googleapis.com/auth/spreadsheets"]
33
- credentials_dict = json.loads(st.secrets["gcp_service_account"])
34
  credentials = service_account.Credentials.from_service_account_info(credentials_dict, scopes=scope)
35
  drive_service = build("drive", "v3", credentials=credentials)
36
  sheets_client = gspread.authorize(credentials)
37
  sheet = sheets_client.open_by_url(st.secrets["feedback_sheet_url"]).sheet1
38
 
39
- # 📌 Funções auxiliares
40
  def calculate_polygon_area(points):
41
  polygon = Polygon([(p['x'], p['y']) for p in points])
42
  return polygon.area
@@ -45,7 +45,7 @@ def safe_predict(image_path):
45
  for attempt in range(3):
46
  try:
47
  return model.predict(image_path)
48
- except:
49
  time.sleep(1)
50
  return None
51
 
@@ -93,18 +93,18 @@ def process_image(uploaded_file):
93
  prediction = safe_predict(temp_file.name)
94
  if not prediction:
95
  return {
96
- "Imagem": safe_name,
97
- "SemSegmentacao": True,
98
- "Exibir": image,
99
  "Original": get_image_bytes(image)
100
  }
101
  prediction_data = prediction.json()
102
 
103
  if not prediction_data["predictions"]:
104
  return {
105
- "Imagem": safe_name,
106
- "SemSegmentacao": True,
107
- "Exibir": image,
108
  "Original": get_image_bytes(image)
109
  }
110
 
@@ -126,25 +126,25 @@ def process_image(uploaded_file):
126
  fig2, ax2 = plt.subplots(figsize=(6, 6), dpi=dpi_value)
127
  ax2.plot(x, y, 'r-', linewidth=2)
128
  ax2.scatter(x, y, color='red', s=5)
129
- ax2.set_title("Contorno do Polígono")
130
  ax2.grid()
131
  plt.savefig(polygon_buffer, format="png", bbox_inches='tight')
132
  plt.close()
133
 
134
  return {
135
- "Imagem": safe_name,
136
- "Área Segmentada (px²)": area,
137
  "Original": original_buffer,
138
- "Segmentada": segmented_buffer,
139
- "Poligono": polygon_buffer,
140
- "Exibir": image,
141
- "SemSegmentacao": False
142
  }
143
 
144
- except:
145
  return None
146
 
147
- # 🗂️ Interface principal
148
  st.title("IA Model Segmentation")
149
  upload_option = st.radio("Choose upload type:", ["Single image", "Image folder"])
150
  results = []
@@ -155,16 +155,16 @@ if upload_option == "Single image":
155
  result = process_image(uploaded_file)
156
  if result:
157
  results.append(result)
158
- st.image(result["Exibir"], caption=f"Original Image - {result['Imagem']}", use_container_width=True)
159
- if not result["SemSegmentacao"]:
160
- st.image(result["Segmentada"], caption="Segmentation", use_container_width=True)
161
- st.image(result["Poligono"], caption="Polygon", use_container_width=True)
162
- st.write(f"📏 **Segmented Area:** {result['Área Segmentada (px²)']:.2f} pixels²")
163
 
164
  st.download_button(
165
  label="📥 Download Segmented Image",
166
- data=result["Segmentada"],
167
- file_name="imagem_segmentada.png",
168
  mime="image/png"
169
  )
170
  else:
@@ -176,28 +176,28 @@ elif upload_option == "Image folder":
176
  with ThreadPoolExecutor(max_workers=4) as executor:
177
  processed = list(executor.map(process_image, uploaded_files))
178
 
179
- falhas = [f.name for f, r in zip(uploaded_files, processed) if r and r.get("SemSegmentacao")]
180
- if falhas:
181
- st.warning(f"⚠️ {len(falhas)} image(s) with no segmentation detected:\n\n- " + "\n- ".join(falhas))
182
 
183
  zip_images_buffer = BytesIO()
184
  with zipfile.ZipFile(zip_images_buffer, "w") as zip_file:
185
  for result in processed:
186
  if result:
187
  results.append(result)
188
- st.image(result["Exibir"], caption=f"Original Image - {result['Imagem']}", use_container_width=True)
189
- if not result["SemSegmentacao"]:
190
- st.image(result["Segmentada"], caption="Segmentation", use_container_width=True)
191
- st.image(result["Poligono"], caption="Polygon", use_container_width=True)
192
- st.write(f"📏 **Segmented Area:** {result['Área Segmentada (px²)']:.2f} pixels²")
193
- zip_file.writestr(f"segmentada_{result['Imagem']}.png", result["Segmentada"].getvalue())
194
- zip_file.writestr(f"poligono_{result['Imagem']}.png", result["Poligono"].getvalue())
195
 
196
  zip_images_buffer.seek(0)
197
 
198
  if results:
199
  df = pd.DataFrame([
200
- { "Imagem": r["Imagem"], "Área Segmentada (px²)": r["Área Segmentada (px²)"] if not r["SemSegmentacao"] else "Sem Segmentação" }
201
  for r in results
202
  ])
203
  st.markdown("### 📊 Results Table")
@@ -207,42 +207,63 @@ elif upload_option == "Image folder":
207
  df.to_excel(excel_buffer, index=False)
208
  excel_buffer.seek(0)
209
 
210
- st.download_button("📥 Download Table (Excel)", data=excel_buffer, file_name="resultados_segmentacao.xlsx", mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
211
- st.download_button("📥 Download Segmented Images", data=zip_images_buffer, file_name="imagens_segmentadas.zip", mime="application/zip")
212
 
213
  # 📝 Manual Feedback
214
  if results:
215
  st.markdown("## 📝 Feedback")
216
- imagem_escolhida = st.selectbox("Select an image to evaluate:", [r["Imagem"] for r in results])
217
- avaliacao = st.radio("How do you evaluate this segmentation?", ["Great", "Acceptable", "Bad", "No segmentation"], horizontal=True)
218
- observacao = st.text_area("Observations (optional):")
219
-
220
- if st.button("Save Feedback"):
221
- row = [imagem_escolhida, avaliacao, observacao]
222
- sheet.append_row(row)
223
-
224
- if avaliacao in ["Acceptable", "Bad", "No segmentation"]:
225
- sufixo = "aceitavel" if avaliacao == "Acceptable" else "ruim" if avaliacao == "Bad" else "sem_segmentacao"
226
- parent_folder = find_or_create_folder("Feedback Segmentacoes")
227
- subfolder = find_or_create_folder(imagem_escolhida.replace(".png", ""), parent_folder)
228
-
229
- for r in results:
230
- if r["Imagem"] == imagem_escolhida:
231
- resized_original = resize_image(r["Exibir"])
232
- buffer = BytesIO()
233
- resized_original.save(buffer, format="PNG")
234
- buffer.seek(0)
235
- upload_to_drive(buffer, f"original_{sufixo}.png", subfolder)
236
-
237
- if avaliacao != "No segmentation" and "Segmentada" in r and "Poligono" in r:
238
- resized_segmented = resize_image(Image.open(BytesIO(r["Segmentada"].getvalue())))
239
- resized_polygon = resize_image(Image.open(BytesIO(r["Poligono"].getvalue())))
240
-
241
- for img_obj, nome in zip([resized_segmented, resized_polygon], ["segmentada", "poligono"]):
242
- buffer = BytesIO()
243
- img_obj.save(buffer, format="PNG")
244
- buffer.seek(0)
245
- upload_to_drive(buffer, f"{nome}_{sufixo}.png", subfolder)
246
- break
247
-
248
- st.success("✅ Feedback saved successfully!")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
  import gspread
17
  import time
18
 
19
+ # 🔥 Initialize Roboflow
20
  API_KEY = st.secrets["roboflow_api_key"]
21
+ rf = roboflow.Roboflow(api_key=API_KEY )
22
  project = rf.workspace(st.secrets["roboflow_workspace"]).project(st.secrets["roboflow_project"])
23
  model = project.version(st.secrets["roboflow_version"]).model
24
  model.confidence = 80
 
28
  with st.expander("⚙️ Advanced Settings", expanded=True):
29
  model.confidence = st.slider("Model Confidence (%)", 20, 100, 80)
30
 
31
+ # 📁 Setup Google Drive and Sheets
32
  scope = ["https://www.googleapis.com/auth/drive", "https://www.googleapis.com/auth/spreadsheets"]
33
+ credentials_dict = json.loads(st.secrets["gcp_service_account"] )
34
  credentials = service_account.Credentials.from_service_account_info(credentials_dict, scopes=scope)
35
  drive_service = build("drive", "v3", credentials=credentials)
36
  sheets_client = gspread.authorize(credentials)
37
  sheet = sheets_client.open_by_url(st.secrets["feedback_sheet_url"]).sheet1
38
 
39
+ # 📌 Helper Functions
40
  def calculate_polygon_area(points):
41
  polygon = Polygon([(p['x'], p['y']) for p in points])
42
  return polygon.area
 
45
  for attempt in range(3):
46
  try:
47
  return model.predict(image_path)
48
+ except Exception:
49
  time.sleep(1)
50
  return None
51
 
 
93
  prediction = safe_predict(temp_file.name)
94
  if not prediction:
95
  return {
96
+ "Image": safe_name,
97
+ "NoSegmentation": True,
98
+ "Display": image,
99
  "Original": get_image_bytes(image)
100
  }
101
  prediction_data = prediction.json()
102
 
103
  if not prediction_data["predictions"]:
104
  return {
105
+ "Image": safe_name,
106
+ "NoSegmentation": True,
107
+ "Display": image,
108
  "Original": get_image_bytes(image)
109
  }
110
 
 
126
  fig2, ax2 = plt.subplots(figsize=(6, 6), dpi=dpi_value)
127
  ax2.plot(x, y, 'r-', linewidth=2)
128
  ax2.scatter(x, y, color='red', s=5)
129
+ ax2.set_title("Polygon Outline")
130
  ax2.grid()
131
  plt.savefig(polygon_buffer, format="png", bbox_inches='tight')
132
  plt.close()
133
 
134
  return {
135
+ "Image": safe_name,
136
+ "Segmented Area (px²)": area,
137
  "Original": original_buffer,
138
+ "Segmented": segmented_buffer,
139
+ "Polygon": polygon_buffer,
140
+ "Display": image,
141
+ "NoSegmentation": False
142
  }
143
 
144
+ except Exception:
145
  return None
146
 
147
+ # 🗂️ Main Interface
148
  st.title("IA Model Segmentation")
149
  upload_option = st.radio("Choose upload type:", ["Single image", "Image folder"])
150
  results = []
 
155
  result = process_image(uploaded_file)
156
  if result:
157
  results.append(result)
158
+ st.image(result["Display"], caption=f"Original Image - {result['Image']}", use_container_width=True)
159
+ if not result["NoSegmentation"]:
160
+ st.image(result["Segmented"], caption="Segmentation", use_container_width=True)
161
+ st.image(result["Polygon"], caption="Polygon", use_container_width=True)
162
+ st.write(f"📏 **Segmented Area:** {result['Segmented Area (px²)']:.2f} pixels²")
163
 
164
  st.download_button(
165
  label="📥 Download Segmented Image",
166
+ data=result["Segmented"],
167
+ file_name="segmented_image.png",
168
  mime="image/png"
169
  )
170
  else:
 
176
  with ThreadPoolExecutor(max_workers=4) as executor:
177
  processed = list(executor.map(process_image, uploaded_files))
178
 
179
+ failures = [f.name for f, r in zip(uploaded_files, processed) if r and r.get("NoSegmentation")]
180
+ if failures:
181
+ st.warning(f"⚠️ {len(failures)} image(s) with no segmentation detected:\n\n- " + "\n- ".join(failures))
182
 
183
  zip_images_buffer = BytesIO()
184
  with zipfile.ZipFile(zip_images_buffer, "w") as zip_file:
185
  for result in processed:
186
  if result:
187
  results.append(result)
188
+ st.image(result["Display"], caption=f"Original Image - {result['Image']}", use_container_width=True)
189
+ if not result["NoSegmentation"]:
190
+ st.image(result["Segmented"], caption="Segmentation", use_container_width=True)
191
+ st.image(result["Polygon"], caption="Polygon", use_container_width=True)
192
+ st.write(f"📏 **Segmented Area:** {result['Segmented Area (px²)']:.2f} pixels²")
193
+ zip_file.writestr(f"segmented_{result['Image']}.png", result["Segmented"].getvalue())
194
+ zip_file.writestr(f"polygon_{result['Image']}.png", result["Polygon"].getvalue())
195
 
196
  zip_images_buffer.seek(0)
197
 
198
  if results:
199
  df = pd.DataFrame([
200
+ { "Image": r["Image"], "Segmented Area (px²)": r["Segmented Area (px²)"] if not r["NoSegmentation"] else "No Segmentation" }
201
  for r in results
202
  ])
203
  st.markdown("### 📊 Results Table")
 
207
  df.to_excel(excel_buffer, index=False)
208
  excel_buffer.seek(0)
209
 
210
+ st.download_button("📥 Download Table (Excel)", data=excel_buffer, file_name="segmentation_results.xlsx", mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
211
+ st.download_button("📥 Download Segmented Images", data=zip_images_buffer, file_name="segmented_images.zip", mime="application/zip")
212
 
213
  # 📝 Manual Feedback
214
  if results:
215
  st.markdown("## 📝 Feedback")
216
+
217
+ available_images = [r["Image"] for r in results]
218
+ if not available_images:
219
+ st.warning("No images were processed to provide feedback.")
220
+ else:
221
+ chosen_image = st.selectbox("Select an image to evaluate:", available_images)
222
+ evaluation = st.radio("How do you rate this segmentation?", ["Great", "Acceptable", "Bad", "No segmentation"], horizontal=True)
223
+ observation = st.text_area("Observations (optional):")
224
+
225
+ if st.button("Save Feedback"):
226
+ # 1. Save feedback to the spreadsheet
227
+ row = [chosen_image, evaluation, observation]
228
+ sheet.append_row(row)
229
+ st.info("Feedback saved to spreadsheet...")
230
+
231
+ # 2. If the evaluation is not "Great", upload images to Google Drive
232
+ if evaluation in ["Acceptable", "Bad", "No segmentation"]:
233
+ st.info("Starting image upload to Google Drive...")
234
+ try:
235
+ suffix_map = {"Acceptable": "acceptable", "Bad": "bad", "No segmentation": "no_segmentation"}
236
+ suffix = suffix_map.get(evaluation, "feedback")
237
+
238
+ parent_folder = find_or_create_folder("Segmentation Feedback")
239
+ folder_name = os.path.splitext(chosen_image)[0]
240
+ subfolder = find_or_create_folder(folder_name, parent=parent_folder)
241
+
242
+ result_to_upload = next((r for r in results if r["Image"] == chosen_image), None)
243
+
244
+ if result_to_upload:
245
+ # Helper function to resize and upload
246
+ def upload_resized_image(image_obj, file_prefix, folder_id):
247
+ resized_pil_img = resize_image(image_obj)
248
+ buffer = get_image_bytes(resized_pil_img)
249
+ upload_to_drive(buffer, f"{file_prefix}_{suffix}.png", folder_id)
250
+ st.write(f" - Upload of {file_prefix}_{suffix}.png complete.")
251
+
252
+ # Upload original image
253
+ original_pil = result_to_upload["Display"]
254
+ upload_resized_image(original_pil, "original", subfolder)
255
+
256
+ # Upload segmented and polygon images, if applicable
257
+ if evaluation != "No segmentation" and not result_to_upload.get("NoSegmentation", True):
258
+ segmented_pil = Image.open(result_to_upload["Segmented"])
259
+ upload_resized_image(segmented_pil, "segmented", subfolder)
260
+
261
+ polygon_pil = Image.open(result_to_upload["Polygon"])
262
+ upload_resized_image(polygon_pil, "polygon", subfolder)
263
+
264
+ st.success("✅ Feedback and images saved successfully to Google Drive!")
265
+
266
+ except Exception as e:
267
+ st.error(f"An error occurred during the upload to Google Drive: {e}")
268
+ else:
269
+ st.success("✅ Feedback saved successfully!")