team-8/image_extraction.py

201 lines
7.9 KiB
Python
Raw Normal View History

2025-08-02 13:46:28 +02:00
from plantcv import plantcv as pcv
import cv2, json, copy
def plantcv_to_json(obs, plant="vine"):
# Morfologia
area = obs["plant_1"]["area"]["value"]
solidity = obs["plant_1"]["solidity"]["value"]
ecc = obs["plant_1"]["ellipse_eccentricity"]["value"]
height = obs["plant_1"]["height"]["value"]
if area < 100000: area_cat = "small"
elif area < 300000: area_cat = "medium"
else: area_cat = "large"
if solidity > 0.8: solidity_cat = "compact"
elif solidity > 0.5: solidity_cat = "normal"
else: solidity_cat = "loose"
if ecc < 0.4: shape_cat = "round"
elif ecc < 0.7: shape_cat = "elliptical"
else: shape_cat = "elongated"
if height < 50: height_cat = "low"
elif height < 150: height_cat = "medium"
else: height_cat = "high"
# Colore
h_mean = obs["plant_1"]["hue_circular_mean"]["value"]
h_std = obs["plant_1"]["hue_circular_std"]["value"]
if h_mean < 30: leaf_color = "yellowish"
elif h_mean < 90: leaf_color = "green-yellowish"
elif h_mean < 150: leaf_color = "green"
else: leaf_color = "bluish-green"
uniformity = "uniform" if h_std < 5 else "moderate" if h_std < 15 else "variegated"
# Health
gm_freq = obs["plant_1"]["green-magenta_frequencies"]["value"]
if sum(gm_freq[len(gm_freq)//2:]) > sum(gm_freq[:len(gm_freq)//2]):
health = "stressed"
else:
health = "good"
# Leaf count (se passato)
contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
leaf_count = len(contours)
if leaf_count < 5: leaf_count_cat = "few"
elif leaf_count < 15: leaf_count_cat = "medium"
else: leaf_count_cat = "many"
result = {
"plant": plant,
"morphology": {
"area": area_cat,
"shape": shape_cat,
"solidity": solidity_cat,
"height": height_cat,
"leaf_count": leaf_count_cat
},
"color": {
"leaf_color": leaf_color,
"uniformity": uniformity
},
"health": {
"status": health
}
}
return result
def simplify_plantcv_results(filepath, plant_key="plant_1"):
"""
Carica un JSON generato da PlantCV e restituisce una versione semplificata
con i valori chiave (senza istogrammi lunghi).
"""
with open(filepath, "r") as f:
data = json.load(f)
obs = data.get("observations", {}).get(plant_key, {})
# Chiavi utili da conservare
keep_keys = [
"hue_circular_mean",
"hue_circular_std",
"hue_median",
"area",
"solidity",
"height",
"width",
"perimeter",
"longest_path",
"ellipse_major_axis",
"ellipse_minor_axis",
"ellipse_eccentricity",
"object_in_frame"
]
simplified = {}
for key in keep_keys:
if key in obs:
val = obs[key].get("value", None)
if isinstance(val, list) and len(val) == 1:
val = val[0]
simplified[key] = val
return simplified
def plantcv_to_hydroshoot(obs, base_config, scale_factor=0.025):
"""
Converte osservazioni PlantCV in parametri HydroShoot.
- obs: dizionario semplificato da PlantCV (hue, area, height, leaf_count, ecc.)
- base_config: JSON HydroShoot di partenza (dict caricato da file)
- scale_factor: conversione pixel cm
"""
with open("hydroshoot_example.json", "r") as f:
base_config = json.load(f)
config = copy.deepcopy(base_config)
# Conversioni px → cm / cm²
height_cm = obs.get("height", 0) * scale_factor
area_cm2 = obs.get("area", 0) * (scale_factor**2)
leaf_count = obs.get("leaf_count", 0)
mean_leaf_area = area_cm2 / leaf_count if leaf_count > 0 else 0
# Colore foglie → stato salute
h_mean = obs.get("hue_circular_mean", 0)
if h_mean < 30:
leaf_color = "yellow"
photo_eff = 0.5 # fotosintesi molto ridotta
elif h_mean < 90:
leaf_color = "yellow-green"
photo_eff = 0.7
else:
leaf_color = "green"
photo_eff = 1.0
# Stato salute generale
uniformity = obs.get("hue_circular_std", 0)
health_index = max(0.0, 1.0 - uniformity/30.0)
# Aggiornamenti HydroShoot
config["simulation"]["unit_scene_length"] = "cm"
config["planting"]["spacing_on_row"] = max(0.5, 1 - (leaf_count/1000)) # spacing ridotto con piante più fitte
config["exchange"]["par_photo"]["alpha"] *= photo_eff * health_index
config["exchange"]["par_gs"]["g0"] *= health_index
config["exchange"]["par_gs"]["m0"] *= health_index
config["soil"]["rhyzo_coeff"] = min(1.0, 0.25 + (area_cm2/10000.0)) # più area = più radici attive
# Salviamo anche un blocco fenotipico extra
config["plantcv_update"] = {
"plant_height_cm": round(height_cm, 1),
"total_leaf_area_cm2": round(area_cm2, 1),
"mean_leaf_area_cm2": round(mean_leaf_area, 1),
"leaf_count": int(leaf_count),
"leaf_color": leaf_color,
"health_index": round(health_index, 2)
}
return config
def main():
# Prende il nome del file dell'immagine base
filename = "baseImg.jpeg"
# Legge immagine con PlantCV
img, path, filename = pcv.readimage(filename, mode='rgb')
# FIX: se viene restituito un tuple, prendo solo la prima immagine (RGB)
if isinstance(img, tuple):
img = img[0]
print("Formato immagine:", img.shape) # dovrebbe stampare (H, W, 3)
# ==============================================================
# Segmentazione verde con custom_range (HSV) - serve a estrarre immagine della pianta da sfondo
# ==============================================================
# Converte in Hue
hsv_hue = pcv.rgb2gray_hsv(img, channel='h')
# Soglia Hue (verde ~2585)
mask_low = pcv.threshold.binary(hsv_hue, threshold=25, object_type='light')
mask_high = pcv.threshold.binary(hsv_hue, threshold=85, object_type='dark')
# Combina le due maschere → range verde
mask = pcv.logical_and(mask_low, mask_high)
# Riempi piccoli buchi nella maschera
mask = pcv.fill(bin_img=mask, size=200)
# ==============================================================
# Analisi colore e forma
# ==============================================================
pcv.analyze.color(img, mask, colorspaces="hsv", label="plant")
pcv.analyze.color(img, mask, colorspaces="lab", label="plant")
pcv.analyze.size(img, mask, label="plant")
# ==============================================================
# Output RAW da PlantCV
# ==============================================================
#print("Output RAW da PlantCV:\n")
obs=pcv.outputs.observations
#controlla le chiavi presenti nel dizionario
print(pcv.outputs.observations.keys())
#controlla le sottochiavi dentro a plant_1 (la chiave giusta sotto cui salva tutti i dati al momento, le altre che leggi nella print prima sono di test vecchi)
print(pcv.outputs.observations["plant_1"].keys())
result=pcv.outputs.save_results("output.json")
finalJson=simplify_plantcv_results("output.json")
print("\nJSON risultante per Stable Diffusion:\n")
print(json.dumps(finalJson, indent=2))
# ==============================================================
# Conversione a json compatibile con HydroShoot
# ==============================================================
with open(r".\hydroshoot\example\vsp_ws_grapevine\params.json", "r") as f:
base_config = json.load(f)
#backup
with open(r".\hydroshoot\example\vsp_ws_grapevine\params_backup.json", "w") as f:
json.dump(base_config, f, indent=2) # indent=2 per leggibilità
new_config = plantcv_to_hydroshoot(obs, base_config)
# Salva su file (sovrascrivi params.json)
with open(r".\hydroshoot\example\vsp_ws_grapevine\params.json", "w") as f:
json.dump(new_config, f, indent=2) # indent=2 per leggibilità
if __name__=='__main__':
main()