Image Understanding Agent with GPT-4V
What is a Visual Agent?
Visual agents use multimodal LLMs (like GPT-4 Vision) to understand images, extract text via OCR, parse diagrams and charts, and answer questions about visual content. They bridge the gap between visual data and structured information.
The key capabilities are: image description and understanding, text extraction from images (OCR), chart and diagram interpretation, visual question answering, and structured data extraction from visual sources.
These agents transform unvisual data (screenshots, scans, diagrams) into actionable information for downstream processing.
Project Overview
We will build a visual agent that:
- Analyzes images using GPT-4 Vision
- Extracts text from images (OCR)
- Parses charts and diagrams into structured data
- Answers questions about image content
- Processes documents with embedded images
- Generates image-based reports
Expected outcome: An agent that understands and extracts information from any image.
Difficulty: Advanced (requires understanding of multimodal APIs, image processing, and prompt engineering)
Tools & Setup
| Tool | Version | Purpose |
|---|---|---|
| Python | 3.11+ | Core language |
| openai | 1.0+ | GPT-4 Vision API |
| Pillow | 10.0+ | Image processing |
| pytesseract | 0.3+ | OCR fallback |
| httpx | 0.27+ | Image fetching |
Step 1: Environment Setup
python -m venv venv
source venv/bin/activate
pip install openai Pillow pytesseract httpx
export OPENAI_API_KEY="sk-your-key"
Step 2: Project Structure
visual-agent/
βββ vision/
β βββ __init__.py
β βββ gpt4v.py
βββ ocr/
β βββ __init__.py
β βββ extractor.py
βββ analysis/
β βββ __init__.py
β βββ chart_parser.py
β βββ scene_analyzer.py
βββ agent.py
βββ main.py
Step 3: GPT-4 Vision Client
# vision/gpt4v.py
from openai import OpenAI
import base64
from pathlib import Path
from typing import Dict, List
class GPT4VisionClient:
def __init__(self, model: str = "gpt-4-vision-preview"):
self.client = OpenAI()
self.model = model
def analyze_image(
self,
image_path: str,
question: str = "Describe this image in detail.",
detail: str = "high",
) -> str:
base64_image = self._encode_image(image_path)
response = self.client.chat.completions.create(
model=self.model,
messages=[
{
"role": "user",
"content": [
{"type": "text", "text": question},
{
"type": "image_url",
"image_url": {
"url": f"data:image/jpeg;base64,{base64_image}",
"detail": detail,
},
},
],
}
],
max_tokens=1000,
)
return response.choices[0].message.content
def analyze_url(
self, image_url: str, question: str = "Describe this image."
) -> str:
response = self.client.chat.completions.create(
model=self.model,
messages=[
{
"role": "user",
"content": [
{"type": "text", "text": question},
{"type": "image_url", "image_url": {"url": image_url, "detail": "high"}},
],
}
],
max_tokens=1000,
)
return response.choices[0].message.content
def extract_structured_data(
self, image_path: str, schema: str
) -> Dict:
base64_image = self._encode_image(image_path)
response = self.client.chat.completions.create(
model=self.model,
messages=[
{
"role": "user",
"content": [
{
"type": "text",
"text": f"""Extract data from this image into the following JSON schema:
{schema}
Return ONLY valid JSON.""",
},
{
"type": "image_url",
"image_url": {
"url": f"data:image/jpeg;base64,{base64_image}",
"detail": "high",
},
},
],
}
],
max_tokens=2000,
)
import json
try:
return json.loads(response.choices[0].message.content)
except:
return {"raw": response.choices[0].message.content}
def _encode_image(self, image_path: str) -> str:
with open(image_path, "rb") as f:
return base64.b64encode(f.read()).decode("utf-8")
def batch_analyze(
self, image_paths: List[str], question: str
) -> List[Dict]:
results = []
for path in image_paths:
answer = self.analyze_image(path, question)
results.append({"path": path, "answer": answer})
return results
Step 4: OCR and Chart Parser
# ocr/extractor.py
import pytesseract
from PIL import Image
from typing import Dict, List
class OCRExtractor:
def extract_text(self, image_path: str) -> str:
image = Image.open(image_path)
text = pytesseract.image_to_string(image)
return text
def extract_with_boxes(self, image_path: str) -> List[Dict]:
image = Image.open(image_path)
data = pytesseract.image_to_data(image, output_type=pytesseract.Output.DICT)
results = []
for i in range(len(data["text"])):
if data["text"][i].strip():
results.append({
"text": data["text"][i],
"confidence": data["conf"][i],
"bbox": {
"x": data["left"][i],
"y": data["top"][i],
"w": data["width"][i],
"h": data["height"][i],
},
})
return results
def extract_tables(self, image_path: str) -> List[List[str]]:
import cv2
import numpy as np
image = cv2.imread(image_path)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
_, binary = cv2.threshold(gray, 128, 255, cv2.THRESH_BINARY)
text = pytesseract.image_to_string(binary)
rows = [row.split("\t") for row in text.strip().split("\n") if row.strip()]
return rows
# analysis/chart_parser.py
from openai import OpenAI
from typing import Dict
import json
class ChartParser:
def __init__(self, model: str = "gpt-4-vision-preview"):
self.client = OpenAI()
self.model = model
def parse_chart(self, image_path: str) -> Dict:
import base64
with open(image_path, "rb") as f:
base64_image = base64.b64encode(f.read()).decode("utf-8")
response = self.client.chat.completions.create(
model=self.model,
messages=[
{
"role": "user",
"content": [
{
"type": "text",
"text": """Analyze this chart/graph and extract:
1. Chart type (bar, line, pie, scatter, etc.)
2. Title
3. Axes labels
4. Data points (as many as visible)
5. Key insights/trends
Return as JSON.""",
},
{
"type": "image_url",
"image_url": {
"url": f"data:image/jpeg;base64,{base64_image}",
"detail": "high",
},
},
],
}
],
max_tokens=2000,
)
try:
return json.loads(response.choices[0].message.content)
except:
return {"chart_type": "unknown", "raw": response.choices[0].message.content}
Step 5: Complete Agent
# agent.py
from vision.gpt4v import GPT4VisionClient
from ocr.extractor import OCRExtractor
from analysis.chart_parser import ChartParser
from typing import Dict, List
class VisualAgent:
def __init__(self, model: str = "gpt-4-vision-preview"):
self.vision = GPT4VisionClient(model)
self.ocr = OCRExtractor()
self.chart_parser = ChartParser(model)
def analyze(self, image_path: str, task: str = "describe") -> Dict:
if task == "describe":
description = self.vision.analyze_image(image_path, "Describe this image in detail.")
return {"type": "description", "content": description}
elif task == "ocr":
text = self.ocr.extract_text(image_path)
return {"type": "ocr", "content": text}
elif task == "chart":
chart_data = self.chart_parser.parse_chart(image_path)
return {"type": "chart", "content": chart_data}
elif task == "extract":
schema = '{"text": [], "numbers": [], "labels": []}'
data = self.vision.extract_structured_data(image_path, schema)
return {"type": "extraction", "content": data}
else:
answer = self.vision.analyze_image(image_path, task)
return {"type": "qa", "content": answer}
def process_document_images(self, image_paths: List[str]) -> Dict:
all_text = []
all_descriptions = []
for path in image_paths:
text = self.ocr.extract_text(image_paths[0]) if image_paths else ""
all_text.append(text)
desc = self.vision.analyze_image(path, "Summarize this document page.")
all_descriptions.append(desc)
return {
"pages": len(image_paths),
"extracted_text": "\n\n".join(all_text),
"summaries": all_descriptions,
}
Mathematical Foundation
Image Quality Score:
Where each parameter means:
- β sharpness (Laplacian variance)
- β contrast (std deviation)
- β resolution score
Intuition: Higher quality images yield better OCR and analysis results.
OCR Confidence:
Intuition: Average confidence across all detected text regions.
Testing & Evaluation
import pytest
from vision.gpt4v import GPT4VisionClient
def test_analyze_image():
client = GPT4VisionClient()
result = client.analyze_image("test_image.jpg", "What is in this image?")
assert len(result) > 0
def test_ocr():
extractor = OCRExtractor()
text = extractor.extract_text("test_document.png")
assert len(text) > 0
Performance Metrics
| Metric | Value | Notes |
|---|---|---|
| Image Analysis | 3-8s | GPT-4V per image |
| OCR Extraction | 1-3s | Tesseract per image |
| Chart Parsing | 5-10s | GPT-4V analysis |
| Batch Processing | 20+ images/hr | Sequential processing |
| OCR Accuracy | 95%+ | Clear printed text |
Deployment
# main.py
from agent import VisualAgent
def main():
agent = VisualAgent()
image_path = input("Image path: ").strip()
task = input("Task (describe/ocr/chart/extract): ").strip()
result = agent.analyze(image_path, task)
print(f"\nResult ({result['type']}):\n{result['content']}")
if __name__ == "__main__":
main()
Real-World Use Cases
- Document Processing: Extract data from scanned forms and invoices
- Chart Analysis: Convert visualizations to structured data
- Quality Control: Inspect product images for defects
- Medical Imaging: Preliminary analysis of medical scans
- Accessibility: Describe images for visually impaired users
Common Pitfalls & Solutions
| Pitfall | Solution |
|---|---|
| Poor OCR accuracy | Pre-process images (contrast, noise reduction) |
| Vision API costs | Use detail="low" for simple tasks |
| Image format issues | Convert to JPEG before processing |
| Large image sizes | Resize before API calls |
| Hallucinated details | Verify with multiple analysis passes |
Summary with Key Takeaways
- GPT-4 Vision provides powerful image understanding capabilities
- OCR extraction converts image text to machine-readable format
- Chart parsing transforms visualizations into structured data
- Image preprocessing improves OCR and analysis accuracy
- Always validate vision model outputs for critical applications