Fahimeh Orvati Nia
commited on
Commit
·
2ff67cd
1
Parent(s):
69b6a19
sorghum_pipeline/output/manager.py
CHANGED
|
@@ -153,6 +153,14 @@ class OutputManager:
|
|
| 153 |
if isinstance(size_img, np.ndarray) and size_img.size > 0:
|
| 154 |
titled = self._add_title_banner(size_img, 'Morphology Size')
|
| 155 |
cv2.imwrite(str(results_dir / 'size.size_analysis.png'), titled)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 156 |
except Exception as e:
|
| 157 |
logger.error(f"Failed to save size analysis: {e}")
|
| 158 |
|
|
@@ -221,4 +229,52 @@ class OutputManager:
|
|
| 221 |
cv2.putText(composed, text, (x+1, y+1), font, font_scale, (0, 0, 0), thickness+1, cv2.LINE_AA)
|
| 222 |
cv2.putText(composed, text, (x, y), font, font_scale, (0, 80, 0), thickness+1, cv2.LINE_AA)
|
| 223 |
|
| 224 |
-
return composed
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 153 |
if isinstance(size_img, np.ndarray) and size_img.size > 0:
|
| 154 |
titled = self._add_title_banner(size_img, 'Morphology Size')
|
| 155 |
cv2.imwrite(str(results_dir / 'size.size_analysis.png'), titled)
|
| 156 |
+
else:
|
| 157 |
+
# Fallback: synthesize a simple size analysis from the mask if available
|
| 158 |
+
mask_for_size = plant_data.get('mask')
|
| 159 |
+
base_img_for_size = plant_data.get('composite')
|
| 160 |
+
if isinstance(mask_for_size, np.ndarray) and mask_for_size.size > 0:
|
| 161 |
+
synthesized = self._create_size_analysis_from_mask(mask_for_size, base_img_for_size)
|
| 162 |
+
titled = self._add_title_banner(synthesized, 'Morphology Size')
|
| 163 |
+
cv2.imwrite(str(results_dir / 'size.size_analysis.png'), titled)
|
| 164 |
except Exception as e:
|
| 165 |
logger.error(f"Failed to save size analysis: {e}")
|
| 166 |
|
|
|
|
| 229 |
cv2.putText(composed, text, (x+1, y+1), font, font_scale, (0, 0, 0), thickness+1, cv2.LINE_AA)
|
| 230 |
cv2.putText(composed, text, (x, y), font, font_scale, (0, 80, 0), thickness+1, cv2.LINE_AA)
|
| 231 |
|
| 232 |
+
return composed
|
| 233 |
+
|
| 234 |
+
def _create_size_analysis_from_mask(self, mask: np.ndarray, base_image: Any = None) -> np.ndarray:
|
| 235 |
+
"""Create a simple size analysis visualization from a binary mask.
|
| 236 |
+
Draws contours and prints pixel area. If base_image is provided, overlays on it; otherwise uses a white canvas.
|
| 237 |
+
"""
|
| 238 |
+
if mask is None or mask.size == 0:
|
| 239 |
+
return np.zeros((1, 1, 3), dtype=np.uint8)
|
| 240 |
+
|
| 241 |
+
# Prepare base image
|
| 242 |
+
if isinstance(base_image, np.ndarray) and base_image.size > 0:
|
| 243 |
+
img = base_image
|
| 244 |
+
if img.dtype != np.uint8:
|
| 245 |
+
img = self._normalize_to_uint8(img.astype(np.float64))
|
| 246 |
+
if img.ndim == 2:
|
| 247 |
+
base_bgr = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
|
| 248 |
+
elif img.ndim == 3 and img.shape[2] == 3:
|
| 249 |
+
base_bgr = img.copy()
|
| 250 |
+
elif img.ndim == 3 and img.shape[2] == 4:
|
| 251 |
+
base_bgr = cv2.cvtColor(img, cv2.COLOR_BGRA2BGR)
|
| 252 |
+
else:
|
| 253 |
+
norm = self._normalize_to_uint8(img.astype(np.float64))
|
| 254 |
+
base_bgr = cv2.cvtColor(norm, cv2.COLOR_GRAY2BGR)
|
| 255 |
+
else:
|
| 256 |
+
h, w = mask.shape[:2]
|
| 257 |
+
base_bgr = np.full((h, w, 3), 255, dtype=np.uint8)
|
| 258 |
+
|
| 259 |
+
# Ensure binary mask
|
| 260 |
+
if mask.ndim == 3 and mask.shape[2] == 3:
|
| 261 |
+
gray = cv2.cvtColor(mask, cv2.COLOR_BGR2GRAY)
|
| 262 |
+
else:
|
| 263 |
+
gray = mask.astype(np.uint8)
|
| 264 |
+
_, bin_mask = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY)
|
| 265 |
+
|
| 266 |
+
# Contours and area
|
| 267 |
+
contours, _ = cv2.findContours(bin_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
|
| 268 |
+
cv2.drawContours(base_bgr, contours, -1, (0, 0, 255), 1)
|
| 269 |
+
area_px = int(cv2.countNonZero(bin_mask))
|
| 270 |
+
|
| 271 |
+
# Bounding box for the largest contour
|
| 272 |
+
if contours:
|
| 273 |
+
largest = max(contours, key=cv2.contourArea)
|
| 274 |
+
x, y, w, h = cv2.boundingRect(largest)
|
| 275 |
+
cv2.rectangle(base_bgr, (x, y), (x + w, y + h), (255, 0, 0), 1)
|
| 276 |
+
|
| 277 |
+
# Put area text
|
| 278 |
+
cv2.putText(base_bgr, f"Area: {area_px} px", (10, 24), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2, cv2.LINE_AA)
|
| 279 |
+
|
| 280 |
+
return base_bgr
|