SmartHeal commited on
Commit
1f90f18
Β·
verified Β·
1 Parent(s): 014af55

Update src/ui_components_original.py

Browse files
Files changed (1) hide show
  1. src/ui_components_original.py +156 -10
src/ui_components_original.py CHANGED
@@ -11,6 +11,7 @@ import html
11
  from typing import Optional, Dict, Any
12
  import numpy as np
13
  import cv2
 
14
 
15
  # ---- Safe imports for local vs package execution ----
16
  try:
@@ -719,6 +720,7 @@ button.gr-button:hover, button.gr-button-primary:hover {
719
  with gr.Row():
720
  accept_segmentation_btn = gr.Button("βœ… Accept & Generate Full Report", variant="primary")
721
  manual_edit_btn = gr.Button("✏️ Manual Edit", variant="secondary")
 
722
 
723
  # Manual editing section (initially hidden)
724
  with gr.Group(visible=False) as manual_edit_group:
@@ -743,7 +745,9 @@ button.gr-button:hover, button.gr-button-primary:hover {
743
  interactive=True
744
  )
745
 
746
- process_manual_btn = gr.Button("πŸ”¬ Generate Report with Manual Mask", variant="primary")
 
 
747
 
748
  analysis_output = gr.HTML("")
749
 
@@ -954,25 +958,35 @@ button.gr-button:hover, button.gr-button-primary:hover {
954
  return {
955
  manual_edit_group: gr.update(visible=True),
956
  manual_mask_input: img_path, # Load the original image for manual editing
957
- analysis_output: "<div class='status-warning'>⚠️ Use the drawing tool to manually mark the wound area, then click 'Generate Report with Manual Mask'.</div>"
958
  }
959
 
960
  def process_manual_mask(mask_data):
961
  """Process the manual mask from ImageMask component"""
962
  if not mask_data:
963
- return "<div class='status-error'>❌ No manual mask provided.</div>"
964
 
965
  try:
966
  # Extract the mask from the ImageMask component
967
  # The mask_data contains both the background image and the drawn mask
968
- if isinstance(mask_data, dict) and "layers" in mask_data:
969
- # Get the alpha channel from the first layer (the drawn mask)
970
- alpha_channel = mask_data["layers"][0][:, :, 3]
971
- # Convert to binary mask
972
- mask = np.where(alpha_channel == 0, 0, 255).astype(np.uint8)
 
 
 
 
 
 
 
 
 
 
 
973
 
974
  # Save the mask temporarily
975
- import tempfile
976
  with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as tmp:
977
  cv2.imwrite(tmp.name, mask)
978
  manual_mask_path = tmp.name
@@ -985,6 +999,87 @@ button.gr-button:hover, button.gr-button-primary:hover {
985
  logging.error(f"Manual mask processing error: {e}")
986
  return None
987
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
988
  def run_full_analysis_with_manual_mask(
989
  mode, existing_label, np_name, np_age, np_gender,
990
  w_loc, w_dur, pain, moist, infect, diabetic,
@@ -1023,6 +1118,42 @@ button.gr-button:hover, button.gr-button-primary:hover {
1023
  analysis_output: f"<div class='status-error'>❌ Analysis failed: {html.escape(str(e))}</div>"
1024
  }
1025
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1026
  def run_full_analysis_accept_segmentation(
1027
  mode, existing_label, np_name, np_age, np_gender,
1028
  w_loc, w_dur, pain, moist, infect, diabetic,
@@ -1156,6 +1287,13 @@ button.gr-button:hover, button.gr-button-primary:hover {
1156
  [analysis_output, segmentation_preview_group, manual_edit_group]
1157
  )
1158
 
 
 
 
 
 
 
 
1159
  # Show manual edit interface
1160
  manual_edit_btn.click(
1161
  show_manual_edit_interface,
@@ -1172,6 +1310,13 @@ button.gr-button:hover, button.gr-button-primary:hover {
1172
  [analysis_output, segmentation_preview_group, manual_edit_group]
1173
  )
1174
 
 
 
 
 
 
 
 
1175
  history_btn.click(load_patient_history, [], [patient_history_output])
1176
  search_patient_btn.click(search_patient_by_name, [search_patient_name], [specific_patient_output])
1177
  view_details_btn.click(view_patient_details, [view_details_dd], [view_details_output])
@@ -1498,4 +1643,5 @@ button.gr-button:hover, button.gr-button-primary:hover {
1498
  'risk_score': 0,
1499
  'risk_level': 'Unknown',
1500
  'risk_factors': ['Unable to assess risk due to data processing error']
1501
- }
 
 
11
  from typing import Optional, Dict, Any
12
  import numpy as np
13
  import cv2
14
+ import tempfile
15
 
16
  # ---- Safe imports for local vs package execution ----
17
  try:
 
720
  with gr.Row():
721
  accept_segmentation_btn = gr.Button("βœ… Accept & Generate Full Report", variant="primary")
722
  manual_edit_btn = gr.Button("✏️ Manual Edit", variant="secondary")
723
+ segmentation_only_btn = gr.Button("🎯 Get Segmentation Only", variant="secondary")
724
 
725
  # Manual editing section (initially hidden)
726
  with gr.Group(visible=False) as manual_edit_group:
 
745
  interactive=True
746
  )
747
 
748
+ with gr.Row():
749
+ process_manual_btn = gr.Button("πŸ”¬ Generate Report with Manual Mask", variant="primary")
750
+ manual_segmentation_only_btn = gr.Button("🎯 Get Manual Segmentation Only", variant="secondary")
751
 
752
  analysis_output = gr.HTML("")
753
 
 
958
  return {
959
  manual_edit_group: gr.update(visible=True),
960
  manual_mask_input: img_path, # Load the original image for manual editing
961
+ analysis_output: "<div class='status-warning'>⚠️ Use the drawing tool to manually mark the wound area, then click your desired action.</div>"
962
  }
963
 
964
  def process_manual_mask(mask_data):
965
  """Process the manual mask from ImageMask component"""
966
  if not mask_data:
967
+ return None
968
 
969
  try:
970
  # Extract the mask from the ImageMask component
971
  # The mask_data contains both the background image and the drawn mask
972
+ if isinstance(mask_data, dict):
973
+ # Check if composite exists (newer format)
974
+ if "composite" in mask_data:
975
+ composite_img = mask_data["composite"]
976
+ # Convert to grayscale and extract the drawn areas
977
+ gray = cv2.cvtColor(composite_img, cv2.COLOR_RGB2GRAY)
978
+ # Create mask where drawn areas are white (255) and background is black (0)
979
+ _, mask = cv2.threshold(gray, 1, 255, cv2.THRESH_BINARY)
980
+ # Check if layers exist (older format)
981
+ elif "layers" in mask_data and len(mask_data["layers"]) > 0:
982
+ # Get the alpha channel from the first layer (the drawn mask)
983
+ alpha_channel = mask_data["layers"][0][:, :, 3]
984
+ # Convert to binary mask - drawn areas have alpha > 0
985
+ mask = np.where(alpha_channel > 0, 255, 0).astype(np.uint8)
986
+ else:
987
+ return None
988
 
989
  # Save the mask temporarily
 
990
  with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as tmp:
991
  cv2.imwrite(tmp.name, mask)
992
  manual_mask_path = tmp.name
 
999
  logging.error(f"Manual mask processing error: {e}")
1000
  return None
1001
 
1002
+ def get_segmentation_only(img_path, manual_mask_path=None):
1003
+ """Get only the segmentation mask without full analysis"""
1004
+ try:
1005
+ if not img_path:
1006
+ return "<div class='status-error'>❌ No image provided.</div>"
1007
+
1008
+ # Run visual analysis to get segmentation
1009
+ image_pil = Image.open(img_path)
1010
+
1011
+ if manual_mask_path:
1012
+ # Use manual mask
1013
+ visual_results = self.wound_analyzer.analyze_wound(
1014
+ img_path, {}, seg_adjust=0.0, manual_mask_path=manual_mask_path
1015
+ )
1016
+ mask_type = "Manual"
1017
+ else:
1018
+ # Use automatic segmentation
1019
+ visual_results = self.wound_analyzer.perform_visual_analysis(image_pil)
1020
+ mask_type = "Automatic"
1021
+
1022
+ if not visual_results:
1023
+ return "<div class='status-error'>❌ Failed to generate segmentation.</div>"
1024
+
1025
+ # Get the segmentation mask path
1026
+ roi_mask_path = visual_results.get("roi_mask_path")
1027
+ seg_path = visual_results.get("segmentation_image_path")
1028
+
1029
+ if not roi_mask_path or not os.path.exists(roi_mask_path):
1030
+ return "<div class='status-error'>❌ Segmentation mask not found.</div>"
1031
+
1032
+ # Convert mask to base64 for display
1033
+ mask_b64 = self.image_to_base64(roi_mask_path)
1034
+ seg_b64 = self.image_to_base64(seg_path) if seg_path and os.path.exists(seg_path) else None
1035
+
1036
+ html_output = f"""
1037
+ <div style="max-width: 800px; margin: 0 auto; background: white; border-radius: 16px; box-shadow: 0 8px 32px rgba(0,0,0,0.1); overflow: hidden;">
1038
+ <div style="background: linear-gradient(135deg, #3182ce 0%, #2c5aa0 100%); color: white; padding: 30px; text-align: center;">
1039
+ <h1 style="margin: 0; font-size: 28px; font-weight: 700;">🎯 {mask_type} Wound Segmentation</h1>
1040
+ <p style="margin: 10px 0 0 0; opacity: 0.9; font-size: 16px;">Binary mask showing wound boundaries</p>
1041
+ </div>
1042
+
1043
+ <div style="padding: 30px;">
1044
+ <div class="status-success" style="margin-bottom: 20px;">
1045
+ <strong>βœ… Segmentation Status:</strong> {mask_type} segmentation completed successfully
1046
+ </div>
1047
+
1048
+ <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 20px; margin: 20px 0;">
1049
+ <div style="background: #f8f9fa; padding: 20px; border-radius: 12px; text-align: center;">
1050
+ <h3 style="color: #2d3748; margin-top: 0;">Binary Mask</h3>
1051
+ {f'<img src="{mask_b64}" style="width: 100%; border-radius: 8px;" alt="Segmentation Mask">' if mask_b64 else '<p>Mask not available</p>'}
1052
+ <p style="color: #4a5568; margin: 10px 0 0 0; font-size: 14px;">White = Wound, Black = Background</p>
1053
+ </div>
1054
+
1055
+ <div style="background: #f8f9fa; padding: 20px; border-radius: 12px; text-align: center;">
1056
+ <h3 style="color: #2d3748; margin-top: 0;">Overlay Visualization</h3>
1057
+ {f'<img src="{seg_b64}" style="width: 100%; border-radius: 8px;" alt="Segmentation Overlay">' if seg_b64 else '<p>Overlay not available</p>'}
1058
+ <p style="color: #4a5568; margin: 10px 0 0 0; font-size: 14px;">Red overlay shows detected wound area</p>
1059
+ </div>
1060
+ </div>
1061
+
1062
+ <div style="background: #fff5f5; border: 2px solid #feb2b2; padding: 20px; border-radius: 12px; margin: 20px 0;">
1063
+ <h3 style="color: #c53030; margin-top: 0;">πŸ“₯ Download Instructions</h3>
1064
+ <p style="color: #742a2a; margin: 0;">Right-click on the binary mask image above and select "Save image as..." to download the segmentation mask for your use.</p>
1065
+ </div>
1066
+ </div>
1067
+ </div>
1068
+ """
1069
+
1070
+ # Clean up temporary file if it exists
1071
+ if manual_mask_path and os.path.exists(manual_mask_path):
1072
+ try:
1073
+ os.unlink(manual_mask_path)
1074
+ except:
1075
+ pass
1076
+
1077
+ return html_output
1078
+
1079
+ except Exception as e:
1080
+ logging.error(f"Segmentation only error: {e}")
1081
+ return f"<div class='status-error'>❌ Error: {html.escape(str(e))}</div>"
1082
+
1083
  def run_full_analysis_with_manual_mask(
1084
  mode, existing_label, np_name, np_age, np_gender,
1085
  w_loc, w_dur, pain, moist, infect, diabetic,
 
1118
  analysis_output: f"<div class='status-error'>❌ Analysis failed: {html.escape(str(e))}</div>"
1119
  }
1120
 
1121
+ def get_manual_segmentation_only(mask_data, img_path):
1122
+ """Get only the manual segmentation mask"""
1123
+ try:
1124
+ manual_mask_path = process_manual_mask(mask_data)
1125
+ if not manual_mask_path:
1126
+ return "<div class='status-error'>❌ Failed to process manual mask.</div>"
1127
+
1128
+ result = get_segmentation_only(img_path, manual_mask_path)
1129
+ return {
1130
+ analysis_output: result,
1131
+ segmentation_preview_group: gr.update(visible=False),
1132
+ manual_edit_group: gr.update(visible=False)
1133
+ }
1134
+
1135
+ except Exception as e:
1136
+ logging.error(f"Manual segmentation only error: {e}")
1137
+ return {
1138
+ analysis_output: f"<div class='status-error'>❌ Error: {html.escape(str(e))}</div>"
1139
+ }
1140
+
1141
+ def get_auto_segmentation_only(img_path):
1142
+ """Get only the automatic segmentation mask"""
1143
+ try:
1144
+ result = get_segmentation_only(img_path, None)
1145
+ return {
1146
+ analysis_output: result,
1147
+ segmentation_preview_group: gr.update(visible=False),
1148
+ manual_edit_group: gr.update(visible=False)
1149
+ }
1150
+
1151
+ except Exception as e:
1152
+ logging.error(f"Auto segmentation only error: {e}")
1153
+ return {
1154
+ analysis_output: f"<div class='status-error'>❌ Error: {html.escape(str(e))}</div>"
1155
+ }
1156
+
1157
  def run_full_analysis_accept_segmentation(
1158
  mode, existing_label, np_name, np_age, np_gender,
1159
  w_loc, w_dur, pain, moist, infect, diabetic,
 
1287
  [analysis_output, segmentation_preview_group, manual_edit_group]
1288
  )
1289
 
1290
+ # Get segmentation only (automatic)
1291
+ segmentation_only_btn.click(
1292
+ get_auto_segmentation_only,
1293
+ [wound_image],
1294
+ [analysis_output, segmentation_preview_group, manual_edit_group]
1295
+ )
1296
+
1297
  # Show manual edit interface
1298
  manual_edit_btn.click(
1299
  show_manual_edit_interface,
 
1310
  [analysis_output, segmentation_preview_group, manual_edit_group]
1311
  )
1312
 
1313
+ # Get manual segmentation only
1314
+ manual_segmentation_only_btn.click(
1315
+ get_manual_segmentation_only,
1316
+ [manual_mask_input, wound_image],
1317
+ [analysis_output, segmentation_preview_group, manual_edit_group]
1318
+ )
1319
+
1320
  history_btn.click(load_patient_history, [], [patient_history_output])
1321
  search_patient_btn.click(search_patient_by_name, [search_patient_name], [specific_patient_output])
1322
  view_details_btn.click(view_patient_details, [view_details_dd], [view_details_output])
 
1643
  'risk_score': 0,
1644
  'risk_level': 'Unknown',
1645
  'risk_factors': ['Unable to assess risk due to data processing error']
1646
+ }
1647
+