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 ~25–85) 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()