Florence-2: Microsoft's Multi-Task Vision Foundation Model

# Florence-2: Model Vision Multi-Task dari Microsoft ## Daftar Isi 1. [Pendahuluan](#pendahuluan) 2. [Prasyarat](#prasyarat) 3. [Instalasi](#instalasi) 4. [Memuat Model Florence-2](#memuat-model-flo...

By Ruby Abdullah · · tutorial
Florence-2Computer VisionMicrosoftObject DetectionPython

Florence-2: Microsoft's Multi-Task Vision Foundation Model

Table of Contents

  • Introduction
  • Prerequisites
  • Installation
  • Loading Florence-2 Models
  • Understanding Task Prompts
  • Image Captioning
  • Object Detection
  • OCR (Optical Character Recognition)
  • Region Proposal and Segmentation
  • Visual Grounding and Referring Expression
  • Batch Processing
  • Fine-tuning on Custom Dataset
  • Integration with Supervision for Visualization
  • Practical Project: Document Analysis Pipeline
  • Best Practices
  • Conclusion
  • Introduction

    Florence-2 is a vision foundation model from Microsoft designed to handle a wide variety of computer vision tasks with a single unified model. Unlike traditional models trained for one specific task, Florence-2 uses a sequence-to-sequence approach that enables captioning, object detection, OCR, segmentation, visual grounding, and more simply by changing the text prompt.

    Key advantages of Florence-2:

    • Multi-task in one model: A single model for captioning, detection, OCR, segmentation, and more
    • Prompt-based: Simply change the text prompt to switch between tasks
    • Lightweight and efficient: Available in base (232M parameters) and large (771M parameters) variants
    • Zero-shot capability: Can be used directly without fine-tuning for many tasks
    • Fine-tunable: Can be fine-tuned on custom datasets for improved performance

    In this tutorial, you will learn to use Florence-2 for various vision tasks, perform batch processing, fine-tune on custom datasets, and build a practical document analysis pipeline.

    Prerequisites

    • Python 3.9 or higher
    • GPU with at least 8GB VRAM (for base model) or 16GB VRAM (for large model)
    • Basic understanding of PyTorch and Hugging Face Transformers
    • Familiarity with basic computer vision concepts (bounding boxes, segmentation, etc.)

    Installation

    # Install main dependencies
    

    pip install torch torchvision torchaudio

    Install transformers and Florence-2 dependencies

    pip install transformers einops timm flashattn

    Install additional libraries for image processing

    pip install Pillow opencv-python matplotlib

    Install supervision for visualization

    pip install supervision

    Install libraries for fine-tuning

    pip install datasets peft accelerate

    Verify the installation:

    import torch
    

    import transformers

    print(f"PyTorch version: {torch.version}")

    print(f"Transformers version: {transformers.version}")

    print(f"CUDA available: {torch.cuda.isavailable()}")

    if torch.cuda.isavailable():

    print(f"GPU: {torch.cuda.getdevicename(0)}")

    print(f"VRAM: {torch.cuda.getdeviceproperties(0).totalmem / 1e9:.1f} GB")

    Loading Florence-2 Models

    Florence-2 comes in two size variants. Choose based on your needs and hardware capacity.

    Florence-2-base

    from transformers import AutoProcessor, AutoModelForCausalLM
    

    import torch

    Load base model (232M parameters)

    modelid = "microsoft/Florence-2-base"

    processor = AutoProcessor.frompretrained(modelid, trustremotecode=True)

    model = AutoModelForCausalLM.frompretrained(

    modelid,

    torchdtype=torch.float16,

    trustremotecode=True

    ).to("cuda")

    print("Florence-2-base loaded successfully!")

    Florence-2-large

    # Load large model (771M parameters) for higher accuracy
    

    modelid = "microsoft/Florence-2-large"

    processor = AutoProcessor.frompretrained(modelid, trustremotecode=True)

    model = AutoModelForCausalLM.frompretrained(

    modelid,

    torchdtype=torch.float16,

    trustremotecode=True

    ).to("cuda")

    print("Florence-2-large loaded successfully!")

    Utility Function for Inference

    from PIL import Image
    

    import requests

    from io import BytesIO

    def loadimage(imagepathorurl):

    """Load an image from a local path or URL."""

    if imagepathorurl.startswith("http"):

    response = requests.get(imagepathorurl)

    image = Image.open(BytesIO(response.content)).convert("RGB")

    else:

    image = Image.open(imagepathorurl).convert("RGB")

    return image

    def runflorence(image, taskprompt, textinput=None):

    """Run Florence-2 inference with a specific task prompt."""

    if textinput:

    prompt = taskprompt + textinput

    else:

    prompt = taskprompt

    inputs = processor(

    text=prompt,

    images=image,

    returntensors="pt"

    ).to("cuda", torch.float16)

    generatedids = model.generate(

    inputids=inputs["inputids"],

    pixelvalues=inputs["pixelvalues"],

    maxnewtokens=1024,

    numbeams=3

    )

    generatedtext = processor.batchdecode(

    generatedids, skipspecialtokens=False

    )[0]

    result = processor.postprocessgeneration(

    generatedtext,

    task=taskprompt,

    imagesize=(image.width, image.height)

    )

    return result

    Load a sample image

    image = loadimage("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/tasks/car.jpg")

    Understanding Task Prompts

    Florence-2 uses special task prompts to determine which task to perform. Here is a complete list of supported task prompts:

    # Complete list of Florence-2 task prompts
    

    TASKPROMPTS = {

    # Captioning

    "": "Brief caption",

    "CAPTION>": "Detailed caption",

    "DETAILEDCAPTION>": "Very detailed caption",

    # Object Detection

    "": "Object detection",

    "REGIONCAPTION>": "Caption for each detected region",

    # OCR

    "": "Text extraction (OCR)",

    "WITHREGION>": "OCR with text region locations",

    # Region Proposal

    "PROPOSAL>": "Object region proposals",

    # Segmentation

    "EXPRESSIONSEGMENTATION>": "Segmentation based on text expression",

    # Visual Grounding

    "TOPHRASEGROUNDING>": "Phrase grounding from caption",

    "VOCABULARYDETECTION>": "Open-vocabulary object detection",

    # Referring Expression

    "TODESCRIPTION>": "Description from region",

    "TOCATEGORY>": "Category from region",

    "TOSEGMENTATION>": "Segmentation from region",

    }

    Print all task prompts

    for prompt, description in TASKPROMPTS.items():

    print(f"{prompt:45s} -> {description}")

    Image Captioning

    Florence-2 supports three levels of captioning detail.

    Brief Caption

    # Brief caption
    

    result = runflorence(image, "")

    print("Caption:", result[""])

    Output: "A green car parked in front of a yellow building."

    Detailed Caption

    # Detailed caption
    

    result = runflorence(image, "CAPTION>")

    print("Detailed Caption:", result["CAPTION>"])

    More Detailed Caption

    # Very detailed caption
    

    result = runflorence(image, "DETAILEDCAPTION>")

    print("Very Detailed Caption:", result["DETAILEDCAPTION>"])

    Comparing Detail Levels

    # Compare all three captioning levels
    

    for task in ["", "CAPTION>", "DETAILEDCAPTION>"]:

    result = runflorence(image, task)

    print(f"\n{task}:")

    print(f" {result[task]}")

    Object Detection

    Florence-2 can detect objects in images and produce bounding boxes along with their labels.

    Standard Object Detection

    # Object detection
    

    result = runflorence(image, "")

    detection = result[""]

    print(f"Objects detected: {len(detection['bboxes'])}")

    for bbox, label in zip(detection["bboxes"], detection["labels"]):

    x1, y1, x2, y2 = bbox

    print(f" {label}: [{x1:.0f}, {y1:.0f}, {x2:.0f}, {y2:.0f}]")

    Dense Region Caption

    # Caption for each detected region
    

    result = runflorence(image, "REGIONCAPTION>")

    regions = result["REGIONCAPTION>"]

    for bbox, label in zip(regions["bboxes"], regions["labels"]):

    print(f" Region: {label}")

    print(f" BBox: {bbox}")

    Open-Vocabulary Detection

    # Open-vocabulary object detection
    

    result = runflorence(image, "VOCABULARYDETECTION>", textinput="car. building. wheel.")

    detections = result["VOCABULARYDETECTION>"]

    for bbox, label in zip(detections["bboxes"], detections["labels"]):

    print(f" {label}: {bbox}")

    Visualizing Detection Results with Matplotlib

    import matplotlib.pyplot as plt
    

    import matplotlib.patches as patches

    def visualizedetection(image, result, taskkey):

    """Visualize object detection results."""

    fig, ax = plt.subplots(1, figsize=(12, 8))

    ax.imshow(image)

    colors = plt.cm.Set3(range(len(result[taskkey]["bboxes"])))

    for idx, (bbox, label) in enumerate(

    zip(result[taskkey]["bboxes"], result[taskkey]["labels"])

    ):

    x1, y1, x2, y2 = bbox

    width = x2 - x1

    height = y2 - y1

    rect = patches.Rectangle(

    (x1, y1), width, height,

    linewidth=2, edgecolor=colors[idx], facecolor="none"

    )

    ax.addpatch(rect)

    ax.text(

    x1, y1 - 5, label,

    fontsize=10, color="white",

    bbox=dict(boxstyle="round", facecolor=colors[idx], alpha=0.8)

    )

    ax.axis("off")

    plt.tightlayout()

    plt.savefig("detectionresult.png", dpi=150, bboxinches="tight")

    plt.show()

    Use the visualization function

    result = runflorence(image, "")

    visualizedetection(image, result, "")

    OCR (Optical Character Recognition)

    Florence-2 can extract text from images, both plain text and with location information.

    Basic Text Extraction

    # Basic OCR
    

    result = runflorence(image, "")

    print("Detected text:", result[""])

    OCR with Region Information

    # OCR with region locations
    

    result = runflorence(image, "WITHREGION>")

    ocrresult = result["WITHREGION>"]

    for bbox, text in zip(ocrresult["quadboxes"], ocrresult["labels"]):

    print(f" Text: '{text}'")

    print(f" Location: {bbox}")

    print()

    Visualizing OCR Results

    def visualizeocr(image, result):
    

    """Visualize OCR results with bounding boxes."""

    fig, ax = plt.subplots(1, figsize=(14, 10))

    ax.imshow(image)

    ocrdata = result["WITHREGION>"]

    for quad, label in zip(ocrdata["quadboxes"], ocrdata["labels"]):

    # quadboxes contain [x1,y1, x2,y2, x3,y3, x4,y4]

    xcoords = [quad[i] for i in range(0, 8, 2)]

    ycoords = [quad[i] for i in range(1, 8, 2)]

    polygon = patches.Polygon(

    list(zip(xcoords, ycoords)),

    closed=True, fill=False,

    edgecolor="red", linewidth=1.5

    )

    ax.addpatch(polygon)

    ax.text(

    min(xcoords), min(ycoords) - 3, label,

    fontsize=7, color="white",

    bbox=dict(boxstyle="round", facecolor="red", alpha=0.7)

    )

    ax.axis("off")

    plt.title("Florence-2 OCR Results")

    plt.tightlayout()

    plt.savefig("ocrresult.png", dpi=150, bboxinches="tight")

    plt.show()

    result = runflorence(image, "WITHREGION>")

    visualizeocr(image, result)

    Region Proposal and Segmentation

    Region Proposal

    # Generate region proposals
    

    result = runflorence(image, "PROPOSAL>")

    proposals = result["PROPOSAL>"]

    print(f"Proposed regions: {len(proposals['bboxes'])}")

    for i, (bbox, label) in enumerate(zip(proposals["bboxes"], proposals["labels"])):

    print(f" Region {i+1}: {bbox} - {label}")

    Region Description

    # Get description for a specific region
    

    Region format: x1>y1>x2>y2> (normalized coordinates 0-999)

    result = runflorence(image, "TODESCRIPTION>", textinput="100>100>500>500>")

    print("Region description:", result["TODESCRIPTION>"])

    Region Category

    # Get category for a specific region
    

    result = runflorence(image, "TOCATEGORY>", textinput="100>100>500>500>")

    print("Region category:", result["TOCATEGORY>"])

    Region Segmentation

    # Segmentation from a specific region
    

    result = runflorence(image, "TOSEGMENTATION>", textinput="100>100>500>500>")

    print("Region segmentation:", result["TOSEGMENTATION>"])

    Visual Grounding and Referring Expression

    Caption to Phrase Grounding

    # Phrase grounding from a caption
    

    caption = "A green car parked in front of a yellow building"

    result = runflorence(image, "TOPHRASEGROUNDING>", textinput=caption)

    grounding = result["TOPHRASEGROUNDING>"]

    for bbox, label in zip(grounding["bboxes"], grounding["labels"]):

    print(f" Phrase: '{label}'")

    print(f" Location: {bbox}")

    Referring Expression Segmentation

    # Segmentation based on text expression
    

    result = runflorence(

    image,

    "EXPRESSIONSEGMENTATION>",

    textinput="the green car"

    )

    segmentation = result["EXPRESSIONSEGMENTATION>"]

    print("Segmentation polygons:", segmentation)

    Visualizing Grounding Results

    def visualizegrounding(image, result):
    

    """Visualize phrase grounding results."""

    fig, ax = plt.subplots(1, figsize=(12, 8))

    ax.imshow(image)

    grounding = result["TOPHRASEGROUNDING>"]

    colors = ["#FF6B6B", "#4ECDC4", "#45B7D1", "#96CEB4", "#FFEAA7"]

    for idx, (bbox, label) in enumerate(

    zip(grounding["bboxes"], grounding["labels"])

    ):

    color = colors[idx % len(colors)]

    x1, y1, x2, y2 = bbox

    rect = patches.Rectangle(

    (x1, y1), x2 - x1, y2 - y1,

    linewidth=2, edgecolor=color, facecolor="none"

    )

    ax.addpatch(rect)

    ax.text(

    x1, y1 - 5, label,

    fontsize=11, color="white",

    bbox=dict(boxstyle="round", facecolor=color, alpha=0.8)

    )

    ax.axis("off")

    plt.title("Phrase Grounding Result")

    plt.tightlayout()

    plt.savefig("groundingresult.png", dpi=150, bboxinches="tight")

    plt.show()

    caption = "A green car parked in front of a yellow building"

    result = runflorence(image, "TOPHRASEGROUNDING>", textinput=caption)

    visualizegrounding(image, result)

    Batch Processing

    For efficient processing of many images, use batch processing.

    import os
    

    from pathlib import Path

    def batchprocess(imagepaths, taskprompt, textinput=None, batchsize=4):

    """Batch process images with Florence-2."""

    allresults = []

    for i in range(0, len(imagepaths), batchsize):

    batchpaths = imagepaths[i:i + batchsize]

    batchimages = [loadimage(p) for p in batchpaths]

    if textinput:

    prompts = [taskprompt + textinput] len(batchimages)

    else:

    prompts = [taskprompt] len(batchimages)

    inputs = processor(

    text=prompts,

    images=batchimages,

    returntensors="pt",

    padding=True

    ).to("cuda", torch.float16)

    generatedids = model.generate(

    inputids=inputs["inputids"],

    pixelvalues=inputs["pixelvalues"],

    maxnewtokens=1024,

    numbeams=3

    )

    generatedtexts = processor.batchdecode(

    generatedids, skipspecialtokens=False

    )

    for j, (text, img) in enumerate(zip(generatedtexts, batchimages)):

    result = processor.postprocessgeneration(

    text,

    task=taskprompt,

    imagesize=(img.width, img.height)

    )

    allresults.append({

    "imagepath": batchpaths[j],

    "result": result

    })

    print(f"Batch {i // batchsize + 1} completed ({len(batchpaths)} images)")

    return allresults

    Example batch processing usage

    imagedir = "path/to/images"

    imagepaths = list(Path(imagedir).glob(".jpg"))

    Batch captioning

    results = batchprocess(imagepaths, "", batchsize=4)

    for r in results:

    print(f"{r['imagepath']}: {r['result']['']}")

    Multi-Task Batch Processing

    def multitaskprocess(imagepath, tasks):
    

    """Run multiple tasks on a single image."""

    image = loadimage(imagepath)

    results = {}

    for taskprompt in tasks:

    result = runflorence(image, taskprompt)

    results[taskprompt] = result[taskprompt]

    return results

    Run multiple tasks on one image

    tasks = ["", "", ""]

    results = multitaskprocess("example.jpg", tasks)

    for task, result in results.items():

    print(f"\n{task}: {result}")

    Fine-tuning on Custom Dataset

    Fine-tuning Florence-2 allows you to improve performance on specific domains.

    Dataset Preparation

    from datasets import Dataset
    

    from PIL import Image

    import json

    def preparedataset(annotationsfile, imagesdir):

    """Prepare dataset for Florence-2 fine-tuning."""

    with open(annotationsfile, "r") as f:

    annotations = json.load(f)

    data = {

    "image": [],

    "prefix": [],

    "suffix": [],

    }

    for ann in annotations:

    imagepath = os.path.join(imagesdir, ann["imagefilename"])

    image = Image.open(imagepath).convert("RGB")

    # For object detection task

    if "objects" in ann:

    prefix = ""

    # Output format: label1x1>y1>x2>y2>label2...

    suffixparts = []

    for obj in ann["objects"]:

    bbox = obj["bbox"] # [x1, y1, x2, y2] normalized

    label = obj["label"]

    x1 = int(bbox[0] 999)

    y1 = int(bbox[1] 999)

    x2 = int(bbox[2] 999)

    y2 = int(bbox[3] 999)

    suffixparts.append(

    f"{label}{x1}>{y1}>{x2}>{y2}>"

    )

    suffix = "".join(suffixparts)

    # For captioning task

    elif "caption" in ann:

    prefix = ""

    suffix = ann["caption"]

    data["image"].append(image)

    data["prefix"].append(prefix)

    data["suffix"].append(suffix)

    return Dataset.fromdict(data)

    Prepare datasets

    traindataset = preparedataset("trainannotations.json", "trainimages/")

    valdataset = preparedataset("valannotations.json", "valimages/")

    print(f"Training dataset: {len(traindataset)} samples")

    print(f"Validation dataset: {len(valdataset)} samples")

    Configuration and Training

    from transformers import TrainingArguments, Trainer
    

    import torch

    class Florence2Dataset(torch.utils.data.Dataset):

    """Custom dataset for Florence-2 fine-tuning."""

    def init(self, dataset, processor, maxlength=1024):

    self.dataset = dataset

    self.processor = processor

    self.maxlength = maxlength

    def len(self):

    return len(self.dataset)

    def getitem(self, idx):

    item = self.dataset[idx]

    image = item["image"]

    prefix = item["prefix"]

    suffix = item["suffix"]

    inputs = self.processor(

    text=prefix,

    images=image,

    returntensors="pt",

    maxlength=self.maxlength,

    padding="maxlength",

    truncation=True

    )

    labels = self.processor.tokenizer(

    suffix,

    returntensors="pt",

    maxlength=self.maxlength,

    padding="maxlength",

    truncation=True

    )

    return {

    "inputids": inputs["inputids"].squeeze(),

    "pixelvalues": inputs["pixelvalues"].squeeze(),

    "labels": labels["inputids"].squeeze(),

    }

    Create dataset loaders

    traintorchdataset = Florence2Dataset(traindataset, processor)

    valtorchdataset = Florence2Dataset(valdataset, processor)

    Training configuration

    trainingargs = TrainingArguments(

    outputdir="./florence2-finetuned",

    numtrainepochs=10,

    perdevicetrainbatchsize=4,

    perdeviceevalbatchsize=4,

    gradientaccumulationsteps=4,

    learningrate=1e-5,

    weightdecay=0.01,

    warmupratio=0.1,

    lrschedulertype="cosine",

    loggingsteps=50,

    evalstrategy="steps",

    evalsteps=200,

    savestrategy="steps",

    savesteps=200,

    savetotallimit=3,

    loadbestmodelatend=True,

    metricforbestmodel="evalloss",

    fp16=True,

    dataloadernumworkers=4,

    removeunusedcolumns=False,

    reportto="tensorboard",

    )

    Initialize Trainer

    trainer = Trainer(

    model=model,

    args=trainingargs,

    traindataset=traintorchdataset,

    evaldataset=valtorchdataset,

    )

    Start training

    trainer.train()

    Save the model

    trainer.savemodel("./florence2-finetuned-final")

    processor.savepretrained("./florence2-finetuned-final")

    print("Model saved successfully!")

    Fine-tuning with LoRA (Memory Efficient)

    from peft import LoraConfig, getpeftmodel
    
    

    LoRA configuration

    loraconfig = LoraConfig(

    r=16,

    loraalpha=32,

    targetmodules=["qproj", "vproj", "kproj", "oproj"],

    loradropout=0.05,

    bias="none",

    tasktype="CAUSALLM",

    )

    Apply LoRA to the model

    peftmodel = getpeftmodel(model, loraconfig)

    peftmodel.printtrainableparameters()

    Output: trainable params: 2,359,296 || all params: 234,567,890 || trainable%: 1.01%

    Use peftmodel instead of model in Trainer

    trainer = Trainer(

    model=peftmodel,

    args=trainingargs,

    traindataset=traintorchdataset,

    evaldataset=valtorchdataset,

    )

    trainer.train()

    peftmodel.savepretrained("./florence2-lora-finetuned")

    Integration with Supervision for Visualization

    The Supervision library from Roboflow provides powerful visualization utilities for Florence-2 detection results.

    import supervision as sv
    

    import numpy as np

    def florencetosupervision(result, taskkey, imagesize):

    """Convert Florence-2 results to Supervision format."""

    detectionsdata = result[taskkey]

    if "bboxes" not in detectionsdata or len(detectionsdata["bboxes"]) == 0:

    return sv.Detections.empty()

    bboxes = np.array(detectionsdata["bboxes"])

    labels = detectionsdata["labels"]

    # Create unique label to classid mapping

    uniquelabels = list(set(labels))

    classids = np.array([uniquelabels.index(l) for l in labels])

    detections = sv.Detections(

    xyxy=bboxes,

    classid=classids,

    data={"classname": np.array(labels)}

    )

    return detections, uniquelabels

    Object Detection Visualization

    def visualizewithsupervision(image, result, taskkey=""):
    

    """Visualize detections using Supervision."""

    imagenp = np.array(image)

    detections, labels = florencetosupervision(

    result, taskkey, (image.width, image.height)

    )

    # Bounding box annotator

    boxannotator = sv.BoxAnnotator(

    thickness=2,

    color=sv.ColorPalette.fromhex(

    ["#FF6B6B", "#4ECDC4", "#45B7D1", "#96CEB4", "#FFEAA7"]

    )

    )

    # Label annotator

    labelannotator = sv.LabelAnnotator(

    textscale=0.5,

    textthickness=1,

    textpadding=5,

    color=sv.ColorPalette.fromhex(

    ["#FF6B6B", "#4ECDC4", "#45B7D1", "#96CEB4", "#FFEAA7"]

    )

    )

    # Apply annotations

    annotated = boxannotator.annotate(

    scene=imagenp.copy(),

    detections=detections

    )

    annotated = labelannotator.annotate(

    scene=annotated,

    detections=detections,

    labels=list(detections.data["classname"])

    )

    # Save result

    resultimage = Image.fromarray(annotated)

    resultimage.save("supervisiondetection.png")

    print("Result saved to supervisiondetection.png")

    return annotated

    Run detection and visualize

    result = runflorence(image, "")

    annotated = visualizewithsupervision(image, result)

    Heatmap Visualization

    def visualizeheatmap(image, result, taskkey=""):
    

    """Create a heatmap from object detections."""

    imagenp = np.array(image)

    detections, = florencetosupervision(

    result, taskkey, (image.width, image.height)

    )

    heatmapannotator = sv.HeatMapAnnotator(

    radius=40,

    kernelsize=25,

    )

    heatmap = heatmapannotator.annotate(

    scene=imagenp.copy(),

    detections=detections

    )

    resultimage = Image.fromarray(heatmap)

    resultimage.save("detectionheatmap.png")

    return heatmap

    result = runflorence(image, "")

    heatmap = visualizeheatmap(image, result)

    Practical Project: Document Analysis Pipeline

    Here is a complete example of building a document analysis pipeline that combines OCR, captioning, and object detection.

    import json
    

    from datetime import datetime

    from pathlib import Path

    class DocumentAnalysisPipeline:

    """Document analysis pipeline using Florence-2."""

    def init(self, modelid="microsoft/Florence-2-large"):

    self.processor = AutoProcessor.frompretrained(

    modelid, trustremotecode=True

    )

    self.model = AutoModelForCausalLM.frompretrained(

    modelid,

    torchdtype=torch.float16,

    trustremotecode=True

    ).to("cuda")

    self.model.eval()

    print(f"Pipeline loaded with model: {modelid}")

    def runtask(self, image, taskprompt, textinput=None):

    """Run a single Florence-2 task."""

    prompt = taskprompt + textinput if textinput else taskprompt

    inputs = self.processor(

    text=prompt, images=image,

    returntensors="pt"

    ).to("cuda", torch.float16)

    with torch.nograd():

    generatedids = self.model.generate(

    inputids=inputs["inputids"],

    pixelvalues=inputs["pixelvalues"],

    maxnewtokens=1024,

    numbeams=3

    )

    generatedtext = self.processor.batchdecode(

    generatedids, skipspecialtokens=False

    )[0]

    return self.processor.postprocessgeneration(

    generatedtext,

    task=taskprompt,

    imagesize=(image.width, image.height)

    )

    def extracttext(self, image):

    """Extract text from a document."""

    result = self.runtask(image, "WITHREGION>")

    ocrdata = result["WITHREGION>"]

    textblocks = []

    for quad, text in zip(ocrdata["quadboxes"], ocrdata["labels"]):

    textblocks.append({

    "text": text,

    "position": {

    "x1": quad[0], "y1": quad[1],

    "x2": quad[2], "y2": quad[3],

    "x3": quad[4], "y3": quad[5],

    "x4": quad[6], "y4": quad[7],

    }

    })

    # Sort top-to-bottom, left-to-right

    textblocks.sort(key=lambda b: (b["position"]["y1"], b["position"]["x1"]))

    fulltext = " ".join([b["text"] for b in textblocks])

    return {"fulltext": fulltext, "textblocks": textblocks}

    def generatedescription(self, image):

    """Generate a detailed description of the document."""

    result = self.runtask(image, "DETAILEDCAPTION>")

    return result["DETAILEDCAPTION>"]

    def detectelements(self, image):

    """Detect elements in the document."""

    result = self.runtask(image, "")

    detection = result[""]

    elements = []

    for bbox, label in zip(detection["bboxes"], detection["labels"]):

    elements.append({

    "type": label,

    "bbox": {

    "x1": bbox[0], "y1": bbox[1],

    "x2": bbox[2], "y2": bbox[3]

    },

    "area": (bbox[2] - bbox[0]) (bbox[3] - bbox[1])

    })

    return elements

    def detectspecificelements(self, image, elementtypes):

    """Detect specific elements using open-vocabulary detection."""

    textinput = ". ".join(elementtypes) + "."

    result = self.runtask(

    image, "VOCABULARYDETECTION>", textinput=textinput

    )

    return result["VOCABULARYDETECTION>"]

    def analyzedocument(self, imagepath, outputdir="analysisoutput"):

    """Run complete analysis on a single document."""

    os.makedirs(outputdir, existok=True)

    image = loadimage(imagepath)

    print(f"Analyzing: {imagepath}")

    print(f"Image size: {image.width}x{image.height}")

    results = {}

    # Step 1: Extract text

    print("\n[1/4] Extracting text...")

    textresult = self.extracttext(image)

    results["text"] = textresult

    print(f" Text found: {len(textresult['textblocks'])} blocks")

    print(f" Preview: {textresult['fulltext'][:200]}...")

    # Step 2: Document description

    print("\n[2/4] Generating description...")

    description = self.generatedescription(image)

    results["description"] = description

    print(f" Description: {description[:200]}...")

    # Step 3: Element detection

    print("\n[3/4] Detecting elements...")

    elements = self.detectelements(image)

    results["elements"] = elements

    print(f" Elements detected: {len(elements)}")

    for elem in elements:

    print(f" - {elem['type']} (area: {elem['area']:.0f}px)")

    # Step 4: Specific document element detection

    print("\n[4/4] Detecting specific document elements...")

    docelements = self.detectspecificelements(

    image,

    ["table", "chart", "logo", "signature", "header", "paragraph"]

    )

    results["documentelements"] = docelements

    # Save results

    timestamp = datetime.now().strftime("%Y%m%d%H%M%S")

    outputfile = os.path.join(outputdir, f"analysis{timestamp}.json")

    with open(outputfile, "w", encoding="utf-8") as f:

    json.dump(results, f, indent=2, ensureascii=False)

    print(f"\nResults saved to: {outputfile}")

    # Create visualization

    Related Articles