Systems Library / Industry Applications / How to Build an AI Listing Photo Enhancement System
Industry Applications real estate

How to Build an AI Listing Photo Enhancement System

Enhance property photos automatically with AI editing and virtual staging.

Jay Banlasan

Jay Banlasan

The AI Systems Guy

AI listing photo enhancement for real estate turns phone photos into professional-looking listing images. I built this pipeline for agents who can't afford a photographer for every listing. It handles brightness correction, sky replacement, decluttering descriptions for virtual staging prompts, and batch processing entire property photo sets.

What You Need Before Starting

Step 1: Build the Image Analysis Module

import anthropic
import base64
from dotenv import load_dotenv
load_dotenv()

def analyze_listing_photo(image_path):
    client = anthropic.Anthropic()
    
    with open(image_path, "rb") as f:
        image_data = base64.standard_b64encode(f.read()).decode()
    
    response = client.messages.create(
        model="claude-sonnet-4-20250514",
        max_tokens=512,
        messages=[{
            "role": "user",
            "content": [
                {"type": "image", "source": {"type": "base64", "media_type": "image/jpeg", "data": image_data}},
                {"type": "text", "text": """Analyze this real estate photo. Return JSON with:
- room_type: kitchen, bedroom, bathroom, living_room, exterior, yard, etc.
- quality_score: 1-10
- issues: list of problems (dark, cluttered, poor angle, etc.)
- enhancement_suggestions: what would improve this photo
- virtual_staging_needed: true/false"""}
            ]
        }]
    )
    
    import json
    try:
        return json.loads(response.content[0].text)
    except json.JSONDecodeError:
        return {"room_type": "unknown", "quality_score": 5, "issues": [], "enhancement_suggestions": []}

Step 2: Apply Basic Enhancements with Pillow

from PIL import Image, ImageEnhance, ImageFilter

def enhance_photo(image_path, output_path, analysis):
    img = Image.open(image_path)
    
    quality = analysis.get("quality_score", 5)
    issues = analysis.get("issues", [])
    
    if "dark" in str(issues).lower() or quality < 6:
        enhancer = ImageEnhance.Brightness(img)
        img = enhancer.enhance(1.2)
    
    enhancer = ImageEnhance.Contrast(img)
    img = enhancer.enhance(1.1)
    
    enhancer = ImageEnhance.Color(img)
    img = enhancer.enhance(1.05)
    
    enhancer = ImageEnhance.Sharpness(img)
    img = enhancer.enhance(1.15)
    
    img.save(output_path, quality=95)
    return output_path

Step 3: Generate Virtual Staging Prompts

def generate_staging_prompt(analysis, room_type):
    staging_styles = {
        "living_room": "modern minimalist living room with a gray sectional sofa, white coffee table, and warm lighting",
        "bedroom": "cozy master bedroom with a king bed, neutral bedding, nightstands with lamps",
        "kitchen": "clean modern kitchen with stainless steel appliances, white countertops, and fresh fruit bowl",
        "dining_room": "elegant dining room with a wood table set for four, simple centerpiece",
        "bathroom": "spa-like bathroom with rolled white towels, small plant, clean countertop",
        "exterior": "well-maintained exterior with green lawn, trimmed bushes, clear sky"
    }
    
    base_prompt = staging_styles.get(room_type, "tastefully furnished room with modern decor")
    
    return f"Real estate listing photo of a {base_prompt}. Professional photography, well-lit, magazine quality. No people. No text overlays."

Step 4: Batch Process Property Photos

import os

def process_property_photos(photo_dir, output_dir):
    os.makedirs(output_dir, exist_ok=True)
    os.makedirs(os.path.join(output_dir, "enhanced"), exist_ok=True)
    
    results = []
    photos = [f for f in os.listdir(photo_dir) if f.lower().endswith((".jpg", ".jpeg", ".png"))]
    
    for photo in sorted(photos):
        input_path = os.path.join(photo_dir, photo)
        print(f"Analyzing {photo}...")
        
        analysis = analyze_listing_photo(input_path)
        print(f"  Room: {analysis['room_type']}, Quality: {analysis['quality_score']}/10")
        
        enhanced_path = os.path.join(output_dir, "enhanced", photo)
        enhance_photo(input_path, enhanced_path, analysis)
        
        results.append({
            "file": photo,
            "analysis": analysis,
            "enhanced": enhanced_path,
            "staging_prompt": generate_staging_prompt(analysis, analysis["room_type"]) if analysis.get("virtual_staging_needed") else None
        })
    
    return results

Step 5: Generate the Enhancement Report

def write_enhancement_report(results, output_dir):
    report_path = os.path.join(output_dir, "enhancement_report.txt")
    
    with open(report_path, "w") as f:
        f.write("Property Photo Enhancement Report\n")
        f.write("=" * 40 + "\n\n")
        
        for r in results:
            f.write(f"File: {r['file']}\n")
            f.write(f"  Room: {r['analysis']['room_type']}\n")
            f.write(f"  Quality: {r['analysis']['quality_score']}/10\n")
            if r['analysis'].get('issues'):
                f.write(f"  Issues: {', '.join(r['analysis']['issues'])}\n")
            if r.get('staging_prompt'):
                f.write(f"  Staging needed: Yes\n")
                f.write(f"  Prompt: {r['staging_prompt']}\n")
            f.write("\n")
    
    print(f"Report saved to {report_path}")

if __name__ == "__main__":
    results = process_property_photos("photos/123-oak-st/", "output/123-oak-st/")
    write_enhancement_report(results, "output/123-oak-st/")

What to Build Next

Integrate with a virtual staging API to actually generate staged versions of empty rooms. Present the agent with before/after comparisons for approval before publishing.

Related Reading

Want this system built for your business?

Get a free assessment. We will map every system your business needs and show you the ROI.

Get Your Free Assessment

Related Systems