{"id":86,"date":"2026-06-25T22:00:00","date_gmt":"2026-06-25T22:00:00","guid":{"rendered":"https:\/\/rpi.temporiti.net\/wordpress\/?p=86"},"modified":"2026-05-30T14:06:28","modified_gmt":"2026-05-30T12:06:28","slug":"florence-2-image-caption","status":"publish","type":"post","link":"https:\/\/rpi.temporiti.net\/wordpress\/?p=86","title":{"rendered":"Caption automatici di immagini con Florence-2 base"},"content":{"rendered":"<p>Negli anni la mia knowledge base tech personale si \u00e8 riempita di screenshot: dashboard Grafana di esperimenti, terminal con output di comandi che voglio ricordare, snippet di interfacce di tool che ho provato, diagrammi presi al volo durante una call. Quando li riprendo in mano mesi dopo, riconoscere a colpo d&#8217;occhio cosa contiene ciascuno di trecento screenshot \u00e8 impossibile, e cercarli per nome file non aiuta perch\u00e9 il nome \u00e8 quasi sempre <code>Screenshot_2026-04-12_at_15-32-08.png<\/code>. Da qualche settimana mi sto appoggiando a Florence-2 base, il modello vision-language compatto di Microsoft, per fare un primo giro di caption automatici da rifinire poi a mano e usare come metadato di ricerca.<\/p>\n<p>Il modello pesa intorno ai 270 MB, gira su CPU senza farsi notare e produce caption brevi in inglese che mi servono come bozza. La traduzione in italiano me la faccio dopo nello stesso script, ma \u00e8 un dettaglio successivo.<\/p>\n<h2>Setup con Transformers e Florence-2<\/h2>\n<p>Florence-2 si carica con la libreria <code>transformers<\/code> di Hugging Face, e l&#8217;API \u00e8 quella standard <code>AutoModelForCausalLM<\/code> + <code>AutoProcessor<\/code> con <code>trust_remote_code=True<\/code> (perch\u00e9 il modello porta con s\u00e9 del codice di pre-processing custom).<\/p>\n<pre><code class=\"language-bash\">\nsudo apt install -y python3-venv\npython3 -m venv ~\/.venvs\/florence\nsource ~\/.venvs\/florence\/bin\/activate\npip install --upgrade pip\npip install transformers torch pillow einops timm\n<\/code><\/pre>\n<p>Lo script che uso lavora su una cartella di immagini e per ognuna chiede a Florence-2 una caption nel formato <code><MORE_DETAILED_CAPTION><\/code>, che \u00e8 quello che mi d\u00e0 la descrizione pi\u00f9 ricca senza scivolare nel prolisso.<\/p>\n<pre><code class=\"language-python\">\nfrom pathlib import Path\nfrom PIL import Image\nimport torch\nfrom transformers import AutoModelForCausalLM, AutoProcessor\n\nMODEL_ID = \"microsoft\/Florence-2-base\"\n\nprocessor = AutoProcessor.from_pretrained(MODEL_ID, trust_remote_code=True)\nmodel = AutoModelForCausalLM.from_pretrained(\n    MODEL_ID,\n    trust_remote_code=True,\n    torch_dtype=torch.float32,\n)\nmodel.eval()\n\ndef caption(image_path: Path, task: str = \"&lt;MORE_DETAILED_CAPTION&gt;\") -&gt; str:\n    image = Image.open(image_path).convert(\"RGB\")\n    inputs = processor(text=task, images=image, return_tensors=\"pt\")\n    with torch.no_grad():\n        out = model.generate(\n            input_ids=inputs[\"input_ids\"],\n            pixel_values=inputs[\"pixel_values\"],\n            max_new_tokens=256,\n            num_beams=3,\n            do_sample=False,\n        )\n    text = processor.batch_decode(out, skip_special_tokens=False)[0]\n    parsed = processor.post_process_generation(\n        text, task=task, image_size=(image.width, image.height)\n    )\n    return parsed[task]\n\nscreenshots = Path.home() \/ \"Screenshots\"\nfor img in sorted(screenshots.glob(\"*.png\")):\n    print(f\"{img.name}: {caption(img)}\")\n<\/code><\/pre>\n<p>Il primo run scarica i pesi del modello in <code>~\/.cache\/huggingface\/hub\/models--microsoft--Florence-2-base\/<\/code>, sono circa 270 MB. Da l\u00ec in poi il modello viene caricato dalla cache e parte in pochi secondi.<\/p>\n<p>Per gli screenshot lavoro in batch: il loop attraversa la cartella, scrive le caption in un file JSON di indice, e quando voglio cercare uno screenshot di una dashboard specifica leggo il JSON con <code>jq<\/code> o lo passo allo script di ricerca semantica che ho gi\u00e0 montato sopra MiniLM.<\/p>\n<h2>Un esempio reale<\/h2>\n<p>Ho passato un pomeriggio a riorganizzare la cartella <code>~\/Screenshots\/<\/code> che si era riempita di circa 480 immagini accumulate negli ultimi sei mesi. Tra dashboard Grafana di test di carico, terminal con output di <code>kubectl describe pod<\/code>, configurazioni Caddy aperte nell&#8217;editor, qualche grafico Prometheus, qualche pagina di documentazione di tool open source che avevo voluto archiviare. Per ricostruirne il senso dovevo aprirle una per una.<\/p>\n<p>Ho lanciato lo script Florence-2 su tutte e quattrocentottanta, lasciato il portatile in idle con il modello che girava su CPU a 8 thread. Ci ha messo circa due ore e mezza. Il risultato: ogni immagine aveva accanto una stringa tipo &#8220;a screenshot of a terminal with kubectl output showing several pods in pending state&#8221;, oppure &#8220;a Grafana dashboard with multiple time series panels displaying CPU and memory metrics over the last 24 hours&#8221;. Da l\u00ec ho buttato il JSON nello script di ricerca semantica con MiniLM, e in trenta secondi avevo un indice navigabile: query &#8220;grafana dashboard cpu&#8221; mi tirava fuori i sette screenshot rilevanti, query &#8220;kubectl pod pending&#8221; altri quattro. Non perfetto, ma utilissimo, e soprattutto fatto in modo automatico su un materiale che altrimenti avrei abbandonato a s\u00e9 stesso.<\/p>\n<h2>Cosa fa bene<\/h2>\n<p>Descrizione di scene comuni: dashboard, terminal, pagine web, codice in un editor, diagrammi semplici. Riconosce bene la tipologia di interfaccia (terminal, browser, dashboard di monitoring, editor) e i pattern visivi forti (un grafico a barre, un grafico time series, una tabella). Sui colori e sulle disposizioni spaziali (&#8220;in alto a sinistra&#8221;, &#8220;tre colonne&#8221;) tiene bene.<\/p>\n<h2>Cosa fa meno bene<\/h2>\n<p>Non legge il testo dentro le immagini in modo affidabile: per OCR vero serve altro (Tesseract o Florence-2 nel task <code>OCR<\/code> specifico, che \u00e8 un&#8217;altra modalit\u00e0). Su screenshot molto densi di informazione produce caption generiche tipo &#8220;a screenshot of a complex dashboard with multiple panels&#8221;, che non aiutano a distinguere fra trenta dashboard simili. Sui contenuti molto specifici di settore (un grafico di latenza percentile P99 vs P95) la descrizione \u00e8 troppo generica per essere utile da sola.<\/p>\n<h2>Privacy &#8211; vantaggio del modello locale<\/h2>\n<p>Gli screenshot tech che ho da catalogare sono pieni di dettagli che non posso permettermi di caricare su servizi terzi: hostname interni di clienti, IP di sistemi di produzione, output di comandi che mostrano configurazioni sensibili, snippet di documentazione interna. Florence-2 in locale processa tutto sull&#8217;host: il modello vede le immagini, sputa la caption, nulla esce dalla macchina. Su API di vision remote ogni immagine andrebbe uploadata e processata sui server del provider, con tutte le policy di retention del caso; qui questo problema non si pone.<\/p>\n<p>I pesi del modello stanno in <code>~\/.cache\/huggingface\/hub\/models--microsoft--Florence-2-base\/<\/code> e si liberano con <code>rm -rf<\/code>. Niente telemetria, niente chiamate di rete dopo il download iniziale. Confronto con servizi cloud: l&#8217;API di Vision di Google, Azure Computer Vision, Amazon Rekognition richiedono tutte upload e hanno policy di retention specifiche; qui niente upload, niente policy esterna.<\/p>\n<p>Licenza: Florence-2 \u00e8 rilasciato sotto MIT da Microsoft. La libreria <code>transformers<\/code> \u00e8 Apache 2.0 (Hugging Face). Stack interamente permissivo, integrabile in tooling interno senza vincoli copyleft.<\/p>\n<h2>In pratica<\/h2>\n<p>Per la mia knowledge base tech personale Florence-2 base \u00e8 diventato il primo passaggio di triage: appena una cartella di screenshot supera le cento immagini, lancio lo script di caption e poi indicizzo con MiniLM. Il risultato non \u00e8 una catalogazione perfetta, ma \u00e8 un livello di metadato di ricerca che prima semplicemente non esisteva. Per la documentazione visiva di tool e dashboard che voglio ricordare di aver visto, mi \u00e8 cambiato il modo di tenere ordinato l&#8217;archivio.<\/p>\n<hr>\n<blockquote>\n<p>Immagine generata con ComfyUI Mac M1 \/ RealVisXL V5 Lightning.<\/p>\n<\/blockquote>\n","protected":false},"excerpt":{"rendered":"<p>Negli anni la mia knowledge base tech personale si \u00e8 riempita di screenshot: dashboard Grafana di esperimenti, terminal con output di comandi che voglio ricordare, snippet di interfacce di tool che ho provato, diagrammi presi al volo durante una call. Quando li riprendo in mano mesi dopo, riconoscere a colpo d&#8217;occhio cosa contiene ciascuno di [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":87,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[6],"tags":[],"class_list":["post-86","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-ai-locale"],"_links":{"self":[{"href":"https:\/\/rpi.temporiti.net\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/86","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/rpi.temporiti.net\/wordpress\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/rpi.temporiti.net\/wordpress\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/rpi.temporiti.net\/wordpress\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/rpi.temporiti.net\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=86"}],"version-history":[{"count":5,"href":"https:\/\/rpi.temporiti.net\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/86\/revisions"}],"predecessor-version":[{"id":379,"href":"https:\/\/rpi.temporiti.net\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/86\/revisions\/379"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/rpi.temporiti.net\/wordpress\/index.php?rest_route=\/wp\/v2\/media\/87"}],"wp:attachment":[{"href":"https:\/\/rpi.temporiti.net\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=86"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/rpi.temporiti.net\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=86"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/rpi.temporiti.net\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=86"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}