ai-analyze / app.py
sksameermujahid's picture
Upload 4 files
8b75d06 verified
raw
history blame
79.3 kB
import os
import io
import base64
import json
import requests
from PIL import Image
import numpy as np
from flask import Flask, render_template, request, jsonify, send_from_directory
from flask_cors import CORS
import torch
from transformers import (
AutoImageProcessor,
AutoModelForImageClassification,
BlipProcessor,
BlipForConditionalGeneration,
pipeline
)
import cv2
from skimage import measure
import logging
import threading
import time
import socket
import subprocess
import sys
from datetime import datetime
import psutil
from transformers import CLIPProcessor, CLIPModel
# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
def convert_numpy_types(obj):
"""Convert numpy types to Python native types for JSON serialization"""
if isinstance(obj, np.integer):
return int(obj)
elif isinstance(obj, np.floating):
return float(obj)
elif isinstance(obj, np.ndarray):
return obj.tolist()
elif isinstance(obj, dict):
return {key: convert_numpy_types(value) for key, value in obj.items()}
elif isinstance(obj, list):
return [convert_numpy_types(item) for item in obj]
else:
return obj
def find_free_port(start_port=7860, max_attempts=10):
"""Find a free port starting from start_port"""
for port in range(start_port, start_port + max_attempts):
try:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind(('localhost', port))
return port
except OSError:
continue
return start_port # Return default port if no free port found
def kill_process_on_port(port):
"""Kill process running on a specific port"""
try:
if sys.platform.startswith('win'):
# Windows
cmd = f'netstat -ano | findstr :{port}'
result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
if result.stdout:
lines = result.stdout.strip().split('\n')
for line in lines:
if f':{port}' in line:
parts = line.split()
if len(parts) >= 5:
pid = parts[-1]
subprocess.run(f'taskkill /PID {pid} /F', shell=True)
logger.info(f"Killed process {pid} on port {port}")
else:
# Linux/Mac
cmd = f'lsof -ti:{port}'
result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
if result.stdout.strip():
pids = result.stdout.strip().split('\n')
for pid in pids:
if pid:
subprocess.run(f'kill -9 {pid}', shell=True)
logger.info(f"Killed process {pid} on port {port}")
except Exception as e:
logger.warning(f"Could not kill process on port {port}: {e}")
# Initialize Flask app with correct template folder
app = Flask(__name__, template_folder='templates')
app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024 # 16MB max file size
CORS(app)
# Global variables for models
room_classifier = None
image_captioner = None
quality_analyzer = None
yolo_model = None
clip_processor = None
clip_model = None
def load_models():
"""Load advanced AI models for comprehensive analysis"""
global room_classifier, image_captioner, object_detector, clip_processor, clip_model
try:
logger.info("Loading advanced AI models...")
# 1. Room Classification Model
room_classifier = pipeline(
"image-classification",
model="andupets/real-estate-image-classification",
device=0 if torch.cuda.is_available() else -1
)
logger.info("βœ“ Room classification model loaded")
# 2. Advanced Image Captioning Model
image_captioner = pipeline(
"image-to-text",
model="Salesforce/blip-image-captioning-base",
device=0 if torch.cuda.is_available() else -1
)
logger.info("βœ“ Image captioning model loaded")
# 3. Advanced Object Detection Model
object_detector = pipeline(
"object-detection",
model="facebook/detr-resnet-50",
device=0 if torch.cuda.is_available() else -1
)
logger.info("βœ“ Object detection model loaded")
# 4. CLIP Model for Advanced Scene Understanding
try:
clip_processor = CLIPProcessor.from_pretrained("openai/clip-vit-base-patch32")
clip_model = CLIPModel.from_pretrained("openai/clip-vit-base-patch32")
if torch.cuda.is_available():
clip_model = clip_model.to('cuda')
logger.info("βœ“ CLIP model loaded for scene understanding")
except Exception as e:
logger.warning(f"CLIP model loading failed: {e}")
clip_processor = None
clip_model = None
# 5. Advanced Image Quality Assessment Model
try:
from transformers import AutoImageProcessor, AutoModelForImageClassification
quality_processor = AutoImageProcessor.from_pretrained("microsoft/resnet-50")
quality_model = AutoModelForImageClassification.from_pretrained("microsoft/resnet-50")
if torch.cuda.is_available():
quality_model = quality_model.to('cuda')
logger.info("βœ“ Advanced quality assessment model loaded")
except Exception as e:
logger.warning(f"Quality model loading failed: {e}")
quality_processor = None
quality_model = None
# 6. YOLO Model for Additional Object Detection
try:
from ultralytics import YOLO
yolo_model = YOLO('yolov8n.pt')
logger.info("βœ“ YOLO model loaded for enhanced object detection")
except Exception as e:
logger.warning(f"YOLO model loading failed: {e}")
yolo_model = None
logger.info("All advanced AI models loaded successfully!")
return True
except Exception as e:
logger.error(f"Error loading models: {str(e)}")
return False
def detect_objects_advanced(image):
"""Advanced AI-powered object detection using multiple models"""
try:
# Convert PIL image to numpy array
img_array = np.array(image)
# Ensure we have a valid image
if img_array.size == 0:
raise ValueError("Empty image array")
# Multiple AI models for comprehensive object detection
detected_objects = []
object_analysis = {}
# 1. DETR (DEtection TRansformer) - Primary detection
try:
from transformers import DetrImageProcessor, DetrForObjectDetection
import torch
processor = DetrImageProcessor.from_pretrained("facebook/detr-resnet-50")
model = DetrForObjectDetection.from_pretrained("facebook/detr-resnet-50")
# Prepare image for DETR
inputs = processor(images=image, return_tensors="pt")
with torch.no_grad():
outputs = model(**inputs)
# Post-process outputs
target_sizes = torch.tensor([image.size[::-1]])
results = processor.post_process_object_detection(outputs, target_sizes=target_sizes, threshold=0.5)[0]
for score, label, box in zip(results["scores"], results["labels"], results["boxes"]):
detected_objects.append({
"label": model.config.id2label[label.item()],
"confidence": float(score.item()), # Convert to Python float
"bbox": [float(x) for x in box.tolist()] # Convert to Python floats
})
except Exception as e:
logger.warning(f"DETR detection failed: {str(e)}")
# 2. YOLO v8 (if available) for additional detection
try:
from ultralytics import YOLO
# Load YOLO model
yolo_model = YOLO('yolov8n.pt')
# Run inference
results = yolo_model(image)
for result in results:
boxes = result.boxes
if boxes is not None:
for box in boxes:
# Get box coordinates
x1, y1, x2, y2 = box.xyxy[0].cpu().numpy()
confidence = float(box.conf[0].cpu().numpy()) # Convert to Python float
class_id = int(box.cls[0].cpu().numpy())
class_name = yolo_model.names[class_id]
# Add if not already detected by DETR
if not any(obj["label"].lower() == class_name.lower() for obj in detected_objects):
detected_objects.append({
"label": class_name,
"confidence": confidence,
"bbox": [float(x1), float(y1), float(x2), float(y2)] # Convert to Python floats
})
except Exception as e:
logger.warning(f"YOLO detection failed: {str(e)}")
# 3. Scene understanding with CLIP
try:
from transformers import CLIPProcessor, CLIPModel
clip_processor = CLIPProcessor.from_pretrained("openai/clip-vit-base-patch32")
clip_model = CLIPModel.from_pretrained("openai/clip-vit-base-patch32")
# Define real estate specific text prompts
real_estate_concepts = [
"modern furniture", "luxury interior", "kitchen appliances", "bathroom fixtures",
"bedroom furniture", "living room setup", "dining area", "home office",
"outdoor space", "balcony", "garden", "parking space", "storage area",
"lighting fixtures", "flooring", "wall decor", "window treatments",
"architectural features", "high ceilings", "open floor plan"
]
# Process image and text
inputs = clip_processor(images=image, text=real_estate_concepts, return_tensors="pt", padding=True)
with torch.no_grad():
outputs = clip_model(**inputs)
logits_per_image = outputs.logits_per_image
probs = logits_per_image.softmax(dim=-1)
# Get top matches
top_concepts = []
for i, prob in enumerate(probs[0]):
if prob > 0.3: # Threshold for relevance
top_concepts.append({
"concept": real_estate_concepts[i],
"confidence": float(prob.item()) # Convert to Python float
})
object_analysis["scene_concepts"] = sorted(top_concepts, key=lambda x: x["confidence"], reverse=True)[:5]
except Exception as e:
logger.warning(f"CLIP analysis failed: {str(e)}")
object_analysis["scene_concepts"] = []
# 4. Advanced object categorization and analysis
if detected_objects:
# Categorize objects by type
furniture_objects = [obj for obj in detected_objects if any(keyword in obj["label"].lower()
for keyword in ["chair", "table", "bed", "sofa", "desk", "cabinet", "shelf"])]
appliance_objects = [obj for obj in detected_objects if any(keyword in obj["label"].lower()
for keyword in ["refrigerator", "oven", "microwave", "dishwasher", "washer", "dryer"])]
fixture_objects = [obj for obj in detected_objects if any(keyword in obj["label"].lower()
for keyword in ["sink", "toilet", "bathtub", "shower", "faucet", "light", "lamp"])]
# Calculate object density and distribution
img_area = img_array.shape[0] * img_array.shape[1]
object_density = float(len(detected_objects) / (img_area / 10000)) # Convert to Python float
# Analyze object positioning
center_x, center_y = img_array.shape[1] / 2, img_array.shape[0] / 2
centered_objects = 0
for obj in detected_objects:
bbox = obj["bbox"]
obj_center_x = (bbox[0] + bbox[2]) / 2
obj_center_y = (bbox[1] + bbox[3]) / 2
# Check if object is in center region
if (abs(obj_center_x - center_x) < center_x * 0.3 and
abs(obj_center_y - center_y) < center_y * 0.3):
centered_objects += 1
object_analysis.update({
"total_objects": len(detected_objects),
"furniture_count": len(furniture_objects),
"appliance_count": len(appliance_objects),
"fixture_count": len(fixture_objects),
"object_density": object_density,
"centered_objects": centered_objects,
"composition_balance": float(centered_objects / len(detected_objects)) if detected_objects else 0.0, # Convert to Python float
"object_categories": {
"furniture": [obj["label"] for obj in furniture_objects],
"appliances": [obj["label"] for obj in appliance_objects],
"fixtures": [obj["label"] for obj in fixture_objects],
"other": [obj["label"] for obj in detected_objects
if obj not in furniture_objects + appliance_objects + fixture_objects]
}
})
else:
# Fallback analysis when no objects detected
object_analysis.update({
"total_objects": 0,
"furniture_count": 0,
"appliance_count": 0,
"fixture_count": 0,
"object_density": 0.0,
"centered_objects": 0,
"composition_balance": 0.0,
"object_categories": {"furniture": [], "appliances": [], "fixtures": [], "other": []}
})
# 5. Dynamic room type inference from objects
room_type_confidence = {}
# Kitchen indicators
kitchen_indicators = ["refrigerator", "oven", "microwave", "dishwasher", "sink", "stove"]
kitchen_score = sum(1 for obj in detected_objects
if any(indicator in obj["label"].lower() for indicator in kitchen_indicators))
room_type_confidence["kitchen"] = min(1.0, kitchen_score / 3)
# Bathroom indicators
bathroom_indicators = ["toilet", "bathtub", "shower", "sink", "mirror"]
bathroom_score = sum(1 for obj in detected_objects
if any(indicator in obj["label"].lower() for indicator in bathroom_indicators))
room_type_confidence["bathroom"] = min(1.0, bathroom_score / 2)
# Bedroom indicators
bedroom_indicators = ["bed", "nightstand", "dresser", "wardrobe"]
bedroom_score = sum(1 for obj in detected_objects
if any(indicator in obj["label"].lower() for indicator in bedroom_indicators))
room_type_confidence["bedroom"] = min(1.0, bedroom_score / 2)
# Living room indicators
living_indicators = ["sofa", "tv", "coffee table", "armchair", "fireplace"]
living_score = sum(1 for obj in detected_objects
if any(indicator in obj["label"].lower() for indicator in living_indicators))
room_type_confidence["living room"] = min(1.0, living_score / 2)
object_analysis["room_type_inference"] = room_type_confidence
return {
"objects": detected_objects,
"analysis": object_analysis
}
except Exception as e:
logger.error(f"Error in object detection: {str(e)}")
return {
"objects": [],
"analysis": {
"total_objects": 0,
"furniture_count": 0,
"appliance_count": 0,
"fixture_count": 0,
"object_density": 0.0,
"centered_objects": 0,
"composition_balance": 0.0,
"object_categories": {"furniture": [], "appliances": [], "fixtures": [], "other": []},
"room_type_inference": {},
"scene_concepts": []
}
}
def analyze_image_quality(image):
"""Advanced AI-powered image quality analysis using multiple models"""
try:
# Convert PIL image to numpy array
img_array = np.array(image)
# Ensure we have a valid image
if img_array.size == 0:
raise ValueError("Empty image array")
# Convert to grayscale for analysis
if len(img_array.shape) == 3:
gray = cv2.cvtColor(img_array, cv2.COLOR_RGB2GRAY)
else:
gray = img_array
# Ensure we have valid dimensions
if gray.shape[0] < 10 or gray.shape[1] < 10:
raise ValueError("Image too small for analysis")
# Advanced AI-based quality metrics
quality_metrics = {}
# 1. BRISQUE (Blind/Referenceless Image Spatial Quality Evaluator)
try:
from skimage.metrics import structural_similarity as ssim
from skimage.filters import sobel
# Calculate BRISQUE-like features
sobel_img = sobel(gray)
quality_metrics['sharpness'] = float(np.std(sobel_img))
# Local binary pattern for texture analysis
from skimage.feature import local_binary_pattern
lbp = local_binary_pattern(gray, P=8, R=1, method='uniform')
quality_metrics['texture_quality'] = float(np.std(lbp))
except:
quality_metrics['sharpness'] = float(cv2.Laplacian(gray, cv2.CV_64F).var())
quality_metrics['texture_quality'] = 50.0
# 2. Advanced brightness analysis with histogram
hist = cv2.calcHist([gray], [0], None, [256], [0, 256])
hist_norm = hist.ravel() / hist.sum()
# Calculate multiple brightness metrics
quality_metrics['brightness_mean'] = float(np.mean(gray))
quality_metrics['brightness_std'] = float(np.std(gray))
quality_metrics['brightness_skew'] = float(np.mean(((gray - np.mean(gray)) / np.std(gray)) ** 3))
quality_metrics['brightness_kurtosis'] = float(np.mean(((gray - np.mean(gray)) / np.std(gray)) ** 4))
# 3. Advanced contrast analysis
quality_metrics['contrast'] = float(np.std(gray))
quality_metrics['contrast_ratio'] = float(np.max(gray) / (np.min(gray) + 1e-8))
# 4. Noise analysis using multiple methods
try:
# Structural similarity for noise
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
quality_metrics['noise_level'] = 1 - ssim(gray, blurred)
# Wavelet-based noise estimation
import pywt
coeffs = pywt.wavedec2(gray, 'db1', level=1)
detail_coeffs = coeffs[1]
quality_metrics['wavelet_noise'] = float(np.std(detail_coeffs[0]))
except:
quality_metrics['noise_level'] = 0.05
quality_metrics['wavelet_noise'] = 10.0
# 5. Resolution and composition analysis
height, width = gray.shape
quality_metrics['resolution'] = f"{width}x{height}"
quality_metrics['aspect_ratio'] = width / height
quality_metrics['pixel_density'] = (width * height) / 10000
# 6. Composition analysis using rule of thirds
thirds_h = height // 3
thirds_w = width // 3
# Check intersection points of rule of thirds
intersection_points = [
gray[thirds_h, thirds_w],
gray[thirds_h, 2*thirds_w],
gray[2*thirds_h, thirds_w],
gray[2*thirds_h, 2*thirds_w]
]
quality_metrics['composition_score'] = float(np.std(intersection_points))
# 7. Color analysis (if color image)
if len(img_array.shape) == 3:
# Convert to different color spaces
hsv = cv2.cvtColor(img_array, cv2.COLOR_RGB2HSV)
lab = cv2.cvtColor(img_array, cv2.COLOR_RGB2LAB)
quality_metrics['color_saturation'] = float(np.mean(hsv[:, :, 1]))
quality_metrics['color_variance'] = float(np.std(lab))
quality_metrics['color_balance'] = float(np.std([np.mean(img_array[:, :, i]) for i in range(3)]))
else:
quality_metrics['color_saturation'] = 0.0
quality_metrics['color_variance'] = 0.0
quality_metrics['color_balance'] = 0.0
# AI-based quality scoring using weighted combination
quality_score = 0
quality_issues = []
# Dynamic scoring based on image characteristics
# Brightness scoring (0-20 points)
brightness_score = 0
if quality_metrics['brightness_mean'] < 30:
quality_issues.append("Image is extremely dark")
brightness_score = 2
elif quality_metrics['brightness_mean'] < 50:
quality_issues.append("Image is too dark")
brightness_score = 8
elif quality_metrics['brightness_mean'] > 220:
quality_issues.append("Image is overexposed")
brightness_score = 5
elif quality_metrics['brightness_mean'] > 180:
quality_issues.append("Image is somewhat overexposed")
brightness_score = 12
else:
brightness_score = 20
# Contrast scoring (0-20 points)
contrast_score = 0
if quality_metrics['contrast'] < 15:
quality_issues.append("Very low contrast")
contrast_score = 2
elif quality_metrics['contrast'] < 30:
quality_issues.append("Low contrast")
contrast_score = 8
else:
contrast_score = 20
# Sharpness scoring (0-20 points)
sharpness_score = 0
if quality_metrics['sharpness'] < 30:
quality_issues.append("Image is very blurry")
sharpness_score = 2
elif quality_metrics['sharpness'] < 60:
quality_issues.append("Image appears blurry")
sharpness_score = 8
else:
sharpness_score = 20
# Noise scoring (0-20 points)
noise_score = 0
if quality_metrics['noise_level'] > 0.2:
quality_issues.append("High noise level")
noise_score = 5
elif quality_metrics['noise_level'] > 0.1:
quality_issues.append("Moderate noise level")
noise_score = 12
else:
noise_score = 20
# Resolution scoring (0-10 points)
resolution_score = 0
if quality_metrics['pixel_density'] < 20:
quality_issues.append("Very low resolution")
resolution_score = 2
elif quality_metrics['pixel_density'] < 50:
quality_issues.append("Low resolution")
resolution_score = 5
else:
resolution_score = 10
# Composition scoring (0-10 points)
composition_score = min(10, quality_metrics['composition_score'] / 10)
if composition_score < 3:
quality_issues.append("Poor composition")
# Calculate total score
quality_score = brightness_score + contrast_score + sharpness_score + noise_score + resolution_score + composition_score
quality_score = min(100, quality_score)
# Dynamic quality level determination
if quality_score >= 90:
quality_level = "Exceptional Quality"
elif quality_score >= 80:
quality_level = "High Quality"
elif quality_score >= 70:
quality_level = "Good Quality"
elif quality_score >= 50:
quality_level = "Medium Quality"
else:
quality_level = "Low Quality"
return {
"quality_level": quality_level,
"quality_score": quality_score,
"issues": quality_issues,
"metrics": quality_metrics
}
except Exception as e:
logger.error(f"Error in quality analysis: {str(e)}")
return {
"quality_level": "Analysis Failed",
"quality_score": 0,
"issues": ["Unable to analyze image quality"],
"metrics": {}
}
def get_room_type_description(room_type):
"""Get detailed description for room types"""
descriptions = {
"bathroom": "A bathroom with toilet, sink, and shower/bathtub facilities",
"bedroom": "A sleeping area with bed and bedroom furniture",
"dining room": "A formal dining area with table and chairs for meals",
"house facade": "The exterior front view of a house or building",
"kitchen": "A cooking area with appliances, countertops, and storage",
"living room": "A main living area with seating and entertainment space",
"sao paulo apartment facade": "Exterior view of an apartment building"
}
return descriptions.get(room_type, f"A {room_type} area")
@app.route('/')
def index():
"""Main page for the image analyzer"""
return render_template('index.html')
@app.route('/analyze', methods=['POST'])
def analyze_image():
"""Advanced AI-powered property image analysis with comprehensive insights"""
try:
if 'image' not in request.files:
return jsonify({'error': 'No image uploaded'}), 400
file = request.files['image']
if file.filename == '':
return jsonify({'error': 'No image selected'}), 400
# Load and validate image
try:
image = Image.open(file.stream).convert('RGB')
# Resize if too large for processing
max_size = 1024
if max(image.size) > max_size:
image.thumbnail((max_size, max_size), Image.Resampling.LANCZOS)
except Exception as e:
return jsonify({'error': f'Invalid image format: {str(e)}'}), 400
logger.info(f"Starting advanced analysis for image: {file.filename}")
# 1. Advanced Room Classification with Confidence Analysis
try:
room_results = room_classifier(image)
room_classification = {
'room_type': room_results[0]['label'].lower(),
'confidence': round(room_results[0]['score'] * 100, 2),
'all_predictions': [
{'room_type': result['label'].lower(), 'confidence': round(result['score'] * 100, 2)}
for result in room_results[:3]
]
}
logger.info(f"Room classification: {room_classification['room_type']} ({room_classification['confidence']}%)")
except Exception as e:
logger.error(f"Room classification failed: {e}")
room_classification = {'room_type': 'unknown', 'confidence': 0, 'all_predictions': []}
# 2. Advanced Image Captioning with Enhanced Descriptions
try:
caption_results = image_captioner(image, max_new_tokens=50)
image_caption = {
'caption': caption_results[0]['generated_text'],
'confidence': 0.85, # BLIP confidence
'enhanced_description': f"A {room_classification['room_type']} featuring {caption_results[0]['generated_text']}"
}
logger.info(f"Image caption: {image_caption['caption']}")
except Exception as e:
logger.error(f"Image captioning failed: {e}")
image_caption = {'caption': 'Unable to generate caption', 'confidence': 0, 'enhanced_description': ''}
# 3. Advanced Object Detection with Multiple Models
try:
object_detection = detect_objects_advanced(image)
logger.info(f"Object detection: {len(object_detection.get('objects', []))} objects detected")
except Exception as e:
logger.error(f"Object detection failed: {e}")
object_detection = {'objects': [], 'analysis': {}}
# 4. Advanced Image Quality Analysis with Multiple Metrics
try:
quality_analysis = analyze_image_quality(image)
logger.info(f"Quality analysis: {quality_analysis['quality_level']} ({quality_analysis['quality_score']}/100)")
except Exception as e:
logger.error(f"Quality analysis failed: {e}")
quality_analysis = {'quality_level': 'Analysis Failed', 'quality_score': 0, 'issues': [], 'metrics': {}}
# 5. Advanced Room Size Estimation
try:
room_size = estimate_room_size(image, room_classification['room_type'])
logger.info(f"Room size estimation: {room_size['estimated_size']}")
except Exception as e:
logger.error(f"Room size estimation failed: {e}")
room_size = {'estimated_size': 'Unable to estimate', 'confidence': 'Low'}
# 6. Advanced Property Assessment with AI Insights
try:
property_assessment = assess_property_image_quality(
room_classification, quality_analysis, object_detection, image_caption
)
logger.info(f"Property assessment: {property_assessment['overall_score']}/100")
except Exception as e:
logger.error(f"Property assessment failed: {e}")
property_assessment = {'overall_score': 0, 'strengths': [], 'weaknesses': [], 'recommendations': []}
# 7. Advanced Property Insights with Market Analysis
try:
property_insights = generate_property_insights(
room_classification, quality_analysis, object_detection, image_caption
)
logger.info("Property insights generated successfully")
except Exception as e:
logger.error(f"Property insights generation failed: {e}")
property_insights = {'marketing_tips': [], 'target_audience': [], 'pricing_considerations': []}
# 8. Advanced Scene Understanding with CLIP
try:
if clip_processor and clip_model:
scene_analysis = analyze_scene_with_clip(image, room_classification['room_type'])
logger.info("CLIP scene analysis completed")
else:
scene_analysis = {'scene_concepts': [], 'style_analysis': {}}
except Exception as e:
logger.error(f"Scene analysis failed: {e}")
scene_analysis = {'scene_concepts': [], 'style_analysis': {}}
# 9. Advanced Market Positioning Analysis
try:
market_analysis = analyze_market_positioning(
room_classification, quality_analysis, object_detection, property_assessment
)
logger.info("Market positioning analysis completed")
except Exception as e:
logger.error(f"Market positioning analysis failed: {e}")
market_analysis = {'market_tier': 'Unknown', 'competitive_position': 'Unknown'}
# 10. Generate Comprehensive Report
comprehensive_report = {
'analysis_summary': {
'room_type': room_classification['room_type'],
'room_confidence': room_classification['confidence'],
'quality_score': quality_analysis['quality_score'],
'object_count': len(object_detection.get('objects', [])),
'overall_assessment_score': property_assessment['overall_score'],
'professional_grade': property_assessment.get('professional_grade', False)
},
'room_classification': room_classification,
'image_caption': image_caption,
'object_detection': object_detection,
'quality_analysis': quality_analysis,
'room_size_estimation': room_size,
'property_assessment': property_assessment,
'property_insights': property_insights,
'scene_analysis': scene_analysis,
'market_analysis': market_analysis,
'technical_metadata': {
'image_dimensions': image.size,
'analysis_timestamp': datetime.now().isoformat(),
'models_used': ['Room Classification', 'BLIP Captioning', 'DETR Detection', 'Quality Analysis', 'CLIP Scene Understanding'],
'processing_time': 'Real-time'
}
}
# Convert numpy types to Python native types for JSON serialization
comprehensive_report = convert_numpy_types(comprehensive_report)
logger.info("Advanced analysis completed successfully")
return jsonify(comprehensive_report)
except Exception as e:
logger.error(f"Analysis failed: {str(e)}")
return jsonify({'error': f'Analysis failed: {str(e)}'}), 500
@app.route('/health')
def health_check():
"""Health check endpoint"""
return jsonify({
'status': 'healthy',
'models_loaded': {
'room_classifier': room_classifier is not None,
'image_captioner': image_captioner is not None,
'yolo_model': yolo_model is not None
}
})
@app.route('/static/<path:filename>')
def static_files(filename):
"""Serve static files"""
return send_from_directory('static', filename)
def assess_property_image_quality(room_classification, quality_analysis, object_detection, image_caption):
"""Advanced AI-powered property image assessment using dynamic analysis"""
try:
# Initialize assessment components
assessment = {
"overall_score": 0,
"strengths": [],
"weaknesses": [],
"recommendations": [],
"market_appeal": {},
"technical_analysis": {},
"composition_analysis": {},
"professional_grade": False
}
# 1. Dynamic Room Classification Analysis (0-25 points)
room_score = 0
room_confidence = room_classification.get('confidence', 0)
room_type = room_classification.get('room_type', 'unknown')
# AI-based room type validation
if room_confidence > 0.8:
room_score = 25
assessment["strengths"].append(f"Clear {room_type} identification with high confidence")
elif room_confidence > 0.6:
room_score = 20
assessment["strengths"].append(f"Good {room_type} identification")
elif room_confidence > 0.4:
room_score = 15
assessment["weaknesses"].append(f"Uncertain room type identification")
else:
room_score = 5
assessment["weaknesses"].append("Poor room type identification")
# Cross-validate with object detection
object_room_inference = object_detection.get('analysis', {}).get('room_type_inference', {})
if room_type in object_room_inference:
object_confidence = object_room_inference[room_type]
if object_confidence > 0.5:
room_score += 5 # Bonus for consistency
assessment["strengths"].append("Object detection confirms room type")
else:
room_score -= 5 # Penalty for inconsistency
assessment["weaknesses"].append("Object detection contradicts room type")
# 2. Advanced Quality Analysis (0-30 points)
quality_score = 0
quality_metrics = quality_analysis.get('metrics', {})
quality_level = quality_analysis.get('quality_level', 'Unknown')
quality_issues = quality_analysis.get('issues', [])
# Dynamic quality scoring based on multiple factors
base_quality = quality_analysis.get('quality_score', 0)
# Technical quality factors
brightness_score = 0
brightness_mean = quality_metrics.get('brightness_mean', 128)
if 60 <= brightness_mean <= 180:
brightness_score = 8
elif 40 <= brightness_mean <= 200:
brightness_score = 5
else:
brightness_score = 2
contrast_score = 0
contrast = quality_metrics.get('contrast', 0)
if contrast > 40:
contrast_score = 8
elif contrast > 25:
contrast_score = 5
else:
contrast_score = 2
sharpness_score = 0
sharpness = quality_metrics.get('sharpness', 0)
if sharpness > 80:
sharpness_score = 8
elif sharpness > 50:
sharpness_score = 5
else:
sharpness_score = 2
noise_score = 0
noise_level = quality_metrics.get('noise_level', 0)
if noise_level < 0.05:
noise_score = 6
elif noise_level < 0.1:
noise_score = 4
else:
noise_score = 1
quality_score = brightness_score + contrast_score + sharpness_score + noise_score
# Add quality issues to weaknesses
for issue in quality_issues:
assessment["weaknesses"].append(f"Quality: {issue}")
# 3. Advanced Object Detection Analysis (0-25 points)
object_score = 0
object_analysis = object_detection.get('analysis', {})
detected_objects = object_detection.get('objects', [])
# Object richness scoring
total_objects = object_analysis.get('total_objects', 0)
if total_objects >= 8:
object_score += 10
assessment["strengths"].append("Rich object content enhances property appeal")
elif total_objects >= 5:
object_score += 7
assessment["strengths"].append("Good object variety")
elif total_objects >= 3:
object_score += 4
else:
object_score += 1
assessment["weaknesses"].append("Limited object content")
# Object relevance scoring
furniture_count = object_analysis.get('furniture_count', 0)
appliance_count = object_analysis.get('appliance_count', 0)
fixture_count = object_analysis.get('fixture_count', 0)
if furniture_count > 0:
object_score += 5
if appliance_count > 0:
object_score += 5
if fixture_count > 0:
object_score += 5
# Composition balance
composition_balance = object_analysis.get('composition_balance', 0)
if composition_balance > 0.6:
object_score += 5
assessment["strengths"].append("Well-balanced object composition")
elif composition_balance < 0.3:
object_score -= 3
assessment["weaknesses"].append("Poor object distribution")
# 4. Dynamic Caption Quality Analysis (0-20 points)
caption_score = 0
caption = image_caption.get('caption', '')
if caption:
# Analyze caption length and content
caption_length = len(caption.split())
# Check for real estate keywords
real_estate_keywords = ['room', 'kitchen', 'bathroom', 'bedroom', 'living', 'dining',
'modern', 'luxury', 'spacious', 'bright', 'clean', 'furnished']
keyword_count = sum(1 for keyword in real_estate_keywords if keyword.lower() in caption.lower())
if caption_length >= 10 and keyword_count >= 3:
caption_score = 20
assessment["strengths"].append("Comprehensive and relevant caption")
elif caption_length >= 8 and keyword_count >= 2:
caption_score = 15
assessment["strengths"].append("Good descriptive caption")
elif caption_length >= 5:
caption_score = 10
else:
caption_score = 5
assessment["weaknesses"].append("Limited caption description")
else:
assessment["weaknesses"].append("No caption generated")
# 5. Calculate Overall Score with Dynamic Weighting
overall_score = room_score + quality_score + object_score + caption_score
# Normalize to 100-point scale
overall_score = min(100, overall_score)
# 6. Advanced Market Appeal Analysis
market_appeal = {}
# Professional grade determination
if overall_score >= 85:
assessment["professional_grade"] = True
market_appeal["level"] = "Premium"
market_appeal["description"] = "Professional-grade image suitable for luxury listings"
elif overall_score >= 75:
assessment["professional_grade"] = True
market_appeal["level"] = "Professional"
market_appeal["description"] = "High-quality image for professional listings"
elif overall_score >= 60:
market_appeal["level"] = "Standard"
market_appeal["description"] = "Acceptable quality for standard listings"
else:
market_appeal["level"] = "Needs Improvement"
market_appeal["description"] = "Image requires enhancement before listing"
# Target audience analysis
if room_type in ['kitchen', 'bathroom'] and quality_score > 20:
market_appeal["target_audience"] = "Home buyers, Investors"
elif room_type in ['bedroom', 'living room'] and object_score > 15:
market_appeal["target_audience"] = "Families, Young professionals"
else:
market_appeal["target_audience"] = "General buyers"
# 7. Dynamic Recommendations Generation
recommendations = []
# Quality-based recommendations
if brightness_mean < 50:
recommendations.append("Increase lighting or use HDR techniques")
elif brightness_mean > 200:
recommendations.append("Reduce exposure to avoid overexposure")
if contrast < 25:
recommendations.append("Enhance contrast in post-processing")
if sharpness < 50:
recommendations.append("Use tripod or image stabilization for sharper photos")
if noise_level > 0.1:
recommendations.append("Use noise reduction software")
# Object-based recommendations
if total_objects < 3:
recommendations.append("Include more furniture or decorative elements")
if composition_balance < 0.4:
recommendations.append("Reposition camera for better object distribution")
# Room-specific recommendations
if room_type == 'kitchen' and appliance_count < 2:
recommendations.append("Highlight kitchen appliances and features")
elif room_type == 'bathroom' and fixture_count < 2:
recommendations.append("Showcase bathroom fixtures and amenities")
# Technical recommendations
if not assessment["professional_grade"]:
recommendations.append("Consider professional photography services")
assessment["recommendations"] = recommendations
assessment["overall_score"] = overall_score
assessment["market_appeal"] = market_appeal
# 8. Technical Analysis Summary
assessment["technical_analysis"] = {
"room_classification_score": room_score,
"quality_analysis_score": quality_score,
"object_detection_score": object_score,
"caption_quality_score": caption_score,
"composition_balance": composition_balance,
"object_density": object_analysis.get('object_density', 0),
"quality_metrics_summary": {
"brightness": round(brightness_mean, 1),
"contrast": round(contrast, 1),
"sharpness": round(sharpness, 1),
"noise_level": round(noise_level, 3)
}
}
return assessment
except Exception as e:
logger.error(f"Error in property assessment: {str(e)}")
return {
"overall_score": 0,
"strengths": [],
"weaknesses": ["Assessment failed due to technical error"],
"recommendations": ["Please try again with a different image"],
"market_appeal": {"level": "Unknown", "description": "Unable to assess"},
"professional_grade": False,
"technical_analysis": {}
}
def estimate_room_size(image, room_type='unknown'):
"""Advanced AI-powered room size estimation using multiple analysis methods"""
try:
# Convert PIL image to numpy array
img_array = np.array(image)
# Get image dimensions
height, width = img_array.shape[:2]
image_area = height * width
# 1. Object-based size estimation
object_analysis = detect_objects_advanced(image)
detected_objects = object_analysis.get('objects', [])
object_analysis_data = object_analysis.get('analysis', {})
# Categorize objects by typical sizes
large_furniture = [obj for obj in detected_objects
if obj['label'].lower() in ['bed', 'sofa', 'couch', 'dining table', 'kitchen island']]
medium_furniture = [obj for obj in detected_objects
if obj['label'].lower() in ['chair', 'desk', 'cabinet', 'dresser', 'nightstand']]
small_furniture = [obj for obj in detected_objects
if obj['label'].lower() in ['lamp', 'plant', 'vase', 'picture frame']]
# 2. Object density analysis
total_objects = len(detected_objects)
object_density = object_analysis_data.get('object_density', 0)
# 3. Perspective and depth analysis
# Analyze object positioning for depth perception
if detected_objects:
# Calculate object distribution across image
x_positions = []
y_positions = []
object_sizes = []
for obj in detected_objects:
bbox = obj['bbox']
x_center = (bbox[0] + bbox[2]) / 2
y_center = (bbox[1] + bbox[3]) / 2
obj_width = bbox[2] - bbox[0]
obj_height = bbox[3] - bbox[1]
obj_area = obj_width * obj_height
x_positions.append(x_center)
y_positions.append(y_center)
object_sizes.append(obj_area)
# Calculate spatial distribution
x_variance = float(np.var(x_positions)) if len(x_positions) > 1 else 0.0
y_variance = float(np.var(y_positions)) if len(y_positions) > 1 else 0.0
avg_object_size = float(np.mean(object_sizes)) if object_sizes else 0.0
# Depth perception indicators
size_variance = float(np.var(object_sizes)) if len(object_sizes) > 1 else 0.0
depth_indicator = float(size_variance / (avg_object_size + 1e-8))
else:
x_variance = y_variance = avg_object_size = depth_indicator = 0.0
# 4. Advanced size estimation algorithm
size_score = 0
size_factors = {}
# Object count factor (0-30 points)
if total_objects >= 10:
size_score += 30
size_factors["object_count"] = "Very High"
elif total_objects >= 7:
size_score += 25
size_factors["object_count"] = "High"
elif total_objects >= 5:
size_score += 20
size_factors["object_count"] = "Medium-High"
elif total_objects >= 3:
size_score += 15
size_factors["object_count"] = "Medium"
elif total_objects >= 1:
size_score += 10
size_factors["object_count"] = "Low"
else:
size_factors["object_count"] = "Very Low"
# Furniture type factor (0-25 points)
furniture_score = 0
if len(large_furniture) >= 3:
furniture_score = 25
size_factors["furniture_type"] = "Multiple large pieces"
elif len(large_furniture) >= 2:
furniture_score = 20
size_factors["furniture_type"] = "Several large pieces"
elif len(large_furniture) >= 1:
furniture_score = 15
size_factors["furniture_type"] = "Some large pieces"
elif len(medium_furniture) >= 3:
furniture_score = 12
size_factors["furniture_type"] = "Multiple medium pieces"
elif len(medium_furniture) >= 1:
furniture_score = 8
size_factors["furniture_type"] = "Some medium pieces"
else:
furniture_score = 5
size_factors["furniture_type"] = "Small pieces only"
size_score += furniture_score
# Object density factor (0-20 points)
if object_density > 15:
size_score += 20
size_factors["object_density"] = "Very High"
elif object_density > 10:
size_score += 15
size_factors["object_density"] = "High"
elif object_density > 5:
size_score += 10
size_factors["object_density"] = "Medium"
elif object_density > 2:
size_score += 5
size_factors["object_density"] = "Low"
else:
size_factors["object_density"] = "Very Low"
# Spatial distribution factor (0-15 points)
spatial_score = 0
if x_variance > 10000 and y_variance > 10000:
spatial_score = 15
size_factors["spatial_distribution"] = "Wide spread"
elif x_variance > 5000 or y_variance > 5000:
spatial_score = 10
size_factors["spatial_distribution"] = "Moderate spread"
elif x_variance > 1000 or y_variance > 1000:
spatial_score = 5
size_factors["spatial_distribution"] = "Limited spread"
else:
size_factors["spatial_distribution"] = "Concentrated"
size_score += spatial_score
# Depth perception factor (0-10 points)
if depth_indicator > 0.5:
size_score += 10
size_factors["depth_perception"] = "Strong depth"
elif depth_indicator > 0.2:
size_score += 7
size_factors["depth_perception"] = "Moderate depth"
elif depth_indicator > 0.1:
size_score += 4
size_factors["depth_perception"] = "Limited depth"
else:
size_factors["depth_perception"] = "Flat perspective"
# 5. Dynamic size classification
if size_score >= 80:
estimated_size = "Very Large (300+ sq ft)"
size_category = "XL"
confidence = "High"
elif size_score >= 65:
estimated_size = "Large (200-300 sq ft)"
size_category = "L"
confidence = "High"
elif size_score >= 50:
estimated_size = "Medium-Large (150-200 sq ft)"
size_category = "ML"
confidence = "Medium"
elif size_score >= 35:
estimated_size = "Medium (100-150 sq ft)"
size_category = "M"
confidence = "Medium"
elif size_score >= 20:
estimated_size = "Small-Medium (80-100 sq ft)"
size_category = "SM"
confidence = "Medium"
elif size_score >= 10:
estimated_size = "Small (50-80 sq ft)"
size_category = "S"
confidence = "Low"
else:
estimated_size = "Very Small (<50 sq ft)"
size_category = "XS"
confidence = "Low"
# 6. Room type specific adjustments
# Use the room_type parameter passed to the function
# Adjust size based on room type expectations
if room_type == 'kitchen':
if size_category in ['XS', 'S']:
estimated_size = "Compact Kitchen (50-80 sq ft)"
elif size_category in ['M', 'ML']:
estimated_size = "Standard Kitchen (100-150 sq ft)"
else:
estimated_size = "Large Kitchen (150+ sq ft)"
elif room_type == 'bathroom':
if size_category in ['XS', 'S']:
estimated_size = "Standard Bathroom (40-60 sq ft)"
elif size_category in ['M', 'ML']:
estimated_size = "Large Bathroom (60-100 sq ft)"
else:
estimated_size = "Luxury Bathroom (100+ sq ft)"
elif room_type == 'bedroom':
if size_category in ['XS', 'S']:
estimated_size = "Small Bedroom (80-120 sq ft)"
elif size_category in ['M', 'ML']:
estimated_size = "Standard Bedroom (120-180 sq ft)"
else:
estimated_size = "Large Bedroom (180+ sq ft)"
# 7. Confidence calculation
confidence_factors = []
if total_objects >= 5:
confidence_factors.append("Multiple objects detected")
if len(large_furniture) >= 1:
confidence_factors.append("Large furniture present")
if object_density > 5:
confidence_factors.append("Good object density")
if x_variance > 5000 and y_variance > 5000:
confidence_factors.append("Good spatial distribution")
if len(confidence_factors) >= 3:
confidence = "High"
elif len(confidence_factors) >= 2:
confidence = "Medium"
else:
confidence = "Low"
return {
"estimated_size": estimated_size,
"size_category": size_category,
"confidence": confidence,
"confidence_factors": confidence_factors,
"size_score": int(size_score), # Convert to Python int
"size_factors": size_factors,
"object_analysis": {
"total_objects": int(total_objects), # Convert to Python int
"large_furniture": int(len(large_furniture)), # Convert to Python int
"medium_furniture": int(len(medium_furniture)), # Convert to Python int
"small_furniture": int(len(small_furniture)), # Convert to Python int
"object_density": float(round(object_density, 2)), # Convert to Python float
"spatial_variance": {
"x_variance": float(round(x_variance, 2)), # Convert to Python float
"y_variance": float(round(y_variance, 2)) # Convert to Python float
},
"depth_indicator": float(round(depth_indicator, 3)) # Convert to Python float
}
}
except Exception as e:
logger.error(f"Error in room size estimation: {str(e)}")
return {
"estimated_size": "Unable to estimate",
"size_category": "Unknown",
"confidence": "Low",
"confidence_factors": ["Estimation failed"],
"size_score": 0,
"size_factors": {},
"object_analysis": {
"total_objects": 0,
"large_furniture": 0,
"medium_furniture": 0,
"small_furniture": 0,
"object_density": 0.0,
"spatial_variance": {"x_variance": 0.0, "y_variance": 0.0},
"depth_indicator": 0.0
}
}
def generate_property_insights(room_classification, quality_analysis, object_detection, image_caption):
"""Advanced AI-powered property insights generation using dynamic analysis"""
try:
insights = {
"marketing_tips": [],
"target_audience": [],
"pricing_considerations": [],
"improvement_suggestions": [],
"market_positioning": {},
"competitive_analysis": {},
"investment_potential": {},
"staging_recommendations": []
}
# Extract key data
room_type = room_classification.get('room_type', 'unknown')
room_confidence = room_classification.get('confidence', 0)
quality_score = quality_analysis.get('quality_score', 0)
quality_level = quality_analysis.get('quality_level', 'Unknown')
object_analysis = object_detection.get('analysis', {})
detected_objects = object_detection.get('objects', [])
caption = image_caption.get('caption', '')
# 1. Dynamic Marketing Tips Generation
marketing_tips = []
# Quality-based marketing tips
if quality_score >= 80:
marketing_tips.append("Highlight the professional photography quality in listings")
marketing_tips.append("Use this image as a primary showcase photo")
elif quality_score >= 60:
marketing_tips.append("Consider this image for secondary photo positions")
else:
marketing_tips.append("Use this image sparingly or improve before listing")
# Room-specific marketing tips
if room_type == 'kitchen':
marketing_tips.append("Emphasize modern kitchen features and appliances")
marketing_tips.append("Highlight the kitchen as the heart of the home")
if object_analysis.get('appliance_count', 0) >= 3:
marketing_tips.append("Showcase the fully equipped kitchen")
elif room_type == 'bathroom':
marketing_tips.append("Focus on cleanliness and modern fixtures")
marketing_tips.append("Highlight bathroom luxury and comfort")
elif room_type == 'bedroom':
marketing_tips.append("Emphasize comfort and relaxation potential")
marketing_tips.append("Highlight bedroom size and natural light")
elif room_type == 'living room':
marketing_tips.append("Showcase entertainment and family gathering spaces")
marketing_tips.append("Highlight living room versatility and flow")
# Object-based marketing tips
furniture_count = object_analysis.get('furniture_count', 0)
if furniture_count >= 5:
marketing_tips.append("Emphasize the fully furnished and move-in ready aspect")
elif furniture_count >= 3:
marketing_tips.append("Highlight the well-appointed space")
# 2. Advanced Target Audience Analysis
target_audience = []
# Room type based targeting
if room_type == 'kitchen':
target_audience.extend(["Home chefs", "Families", "Entertainment enthusiasts"])
elif room_type == 'bathroom':
target_audience.extend(["Luxury seekers", "Families", "Young professionals"])
elif room_type == 'bedroom':
target_audience.extend(["Families", "Young professionals", "Students"])
elif room_type == 'living room':
target_audience.extend(["Families", "Entertainment lovers", "Social people"])
# Quality-based targeting
if quality_score >= 85:
target_audience.append("Luxury buyers")
elif quality_score >= 70:
target_audience.append("Professional buyers")
else:
target_audience.append("Budget-conscious buyers")
# Object-based targeting
if object_analysis.get('appliance_count', 0) >= 3:
target_audience.append("Modern lifestyle seekers")
if object_analysis.get('fixture_count', 0) >= 3:
target_audience.append("Quality-conscious buyers")
# 3. Dynamic Pricing Considerations
pricing_considerations = []
# Quality impact on pricing
if quality_score >= 80:
pricing_considerations.append("High-quality images can support premium pricing")
elif quality_score >= 60:
pricing_considerations.append("Standard image quality supports market-rate pricing")
else:
pricing_considerations.append("Image quality may limit pricing potential")
# Room type pricing impact
if room_type == 'kitchen':
pricing_considerations.append("Kitchen quality significantly impacts property value")
if object_analysis.get('appliance_count', 0) >= 3:
pricing_considerations.append("Modern appliances justify higher pricing")
elif room_type == 'bathroom':
pricing_considerations.append("Bathroom luxury can command premium pricing")
elif room_type == 'bedroom':
pricing_considerations.append("Bedroom appeal affects family buyer pricing")
# Object density pricing impact
object_density = object_analysis.get('object_density', 0)
if object_density > 10:
pricing_considerations.append("Rich content suggests well-appointed property")
elif object_density < 3:
pricing_considerations.append("Sparse content may suggest staging needed")
# 4. AI-Powered Improvement Suggestions
improvement_suggestions = []
# Technical improvements
if quality_score < 70:
improvement_suggestions.append("Improve lighting and exposure for better image quality")
improvement_suggestions.append("Use professional photography equipment")
# Composition improvements
composition_balance = object_analysis.get('composition_balance', 0)
if composition_balance < 0.4:
improvement_suggestions.append("Reposition camera for better composition")
improvement_suggestions.append("Follow rule of thirds for better framing")
# Content improvements
total_objects = object_analysis.get('total_objects', 0)
if total_objects < 3:
improvement_suggestions.append("Add more furniture or decorative elements")
improvement_suggestions.append("Consider professional staging")
# Room-specific improvements
if room_type == 'kitchen' and object_analysis.get('appliance_count', 0) < 2:
improvement_suggestions.append("Highlight kitchen appliances and features")
elif room_type == 'bathroom' and object_analysis.get('fixture_count', 0) < 2:
improvement_suggestions.append("Showcase bathroom fixtures and amenities")
# 5. Advanced Market Positioning Analysis
market_positioning = {}
# Quality positioning
if quality_score >= 85:
market_positioning["quality_tier"] = "Premium"
market_positioning["positioning_statement"] = "Luxury property with professional presentation"
elif quality_score >= 70:
market_positioning["quality_tier"] = "Professional"
market_positioning["positioning_statement"] = "Well-presented property suitable for discerning buyers"
elif quality_score >= 50:
market_positioning["quality_tier"] = "Standard"
market_positioning["positioning_statement"] = "Standard property presentation"
else:
market_positioning["quality_tier"] = "Needs Improvement"
market_positioning["positioning_statement"] = "Property requires better presentation"
# Room type positioning
if room_type in ['kitchen', 'bathroom']:
market_positioning["focus_area"] = "High-value rooms"
market_positioning["key_message"] = f"Showcase {room_type} quality and features"
else:
market_positioning["focus_area"] = "Living spaces"
market_positioning["key_message"] = f"Highlight {room_type} comfort and functionality"
# 6. Competitive Analysis
competitive_analysis = {}
# Quality comparison
if quality_score >= 80:
competitive_analysis["quality_advantage"] = "Above average"
competitive_analysis["differentiation"] = "Professional presentation sets property apart"
elif quality_score >= 60:
competitive_analysis["quality_advantage"] = "Competitive"
competitive_analysis["differentiation"] = "Standard presentation meets market expectations"
else:
competitive_analysis["quality_advantage"] = "Below average"
competitive_analysis["differentiation"] = "Needs improvement to compete effectively"
# Content comparison
if object_analysis.get('total_objects', 0) >= 8:
competitive_analysis["content_advantage"] = "Rich content"
competitive_analysis["content_message"] = "Well-appointed space with many features"
elif object_analysis.get('total_objects', 0) >= 5:
competitive_analysis["content_advantage"] = "Good content"
competitive_analysis["content_message"] = "Adequate feature representation"
else:
competitive_analysis["content_advantage"] = "Limited content"
competitive_analysis["content_message"] = "Consider adding more features"
# 7. Investment Potential Analysis
investment_potential = {}
# Quality impact on investment
if quality_score >= 80:
investment_potential["presentation_value"] = "High"
investment_potential["roi_potential"] = "Excellent - professional presentation supports premium pricing"
elif quality_score >= 60:
investment_potential["presentation_value"] = "Medium"
investment_potential["roi_potential"] = "Good - standard presentation supports market pricing"
else:
investment_potential["presentation_value"] = "Low"
investment_potential["roi_potential"] = "Limited - poor presentation may reduce pricing potential"
# Room type investment impact
if room_type in ['kitchen', 'bathroom']:
investment_potential["room_value"] = "High-impact rooms"
investment_potential["investment_priority"] = "Focus on these rooms for maximum ROI"
else:
investment_potential["room_value"] = "Standard rooms"
investment_potential["investment_priority"] = "Ensure adequate presentation quality"
# 8. Dynamic Staging Recommendations
staging_recommendations = []
# Object-based staging
if object_analysis.get('furniture_count', 0) < 2:
staging_recommendations.append("Add key furniture pieces to define the space")
if object_analysis.get('appliance_count', 0) < 2 and room_type == 'kitchen':
staging_recommendations.append("Highlight kitchen appliances and modern features")
if object_analysis.get('fixture_count', 0) < 2 and room_type == 'bathroom':
staging_recommendations.append("Showcase bathroom fixtures and luxury amenities")
# Quality-based staging
if quality_score < 60:
staging_recommendations.append("Improve lighting and staging for better presentation")
# Room-specific staging
if room_type == 'bedroom':
staging_recommendations.append("Create a welcoming and comfortable bedroom atmosphere")
elif room_type == 'living room':
staging_recommendations.append("Stage for entertainment and family gatherings")
# Update insights dictionary
insights.update({
"marketing_tips": marketing_tips,
"target_audience": list(set(target_audience)), # Remove duplicates
"pricing_considerations": pricing_considerations,
"improvement_suggestions": improvement_suggestions,
"market_positioning": market_positioning,
"competitive_analysis": competitive_analysis,
"investment_potential": investment_potential,
"staging_recommendations": staging_recommendations
})
return insights
except Exception as e:
logger.error(f"Error in generating property insights: {str(e)}")
return {
"marketing_tips": ["Unable to generate marketing tips"],
"target_audience": ["General buyers"],
"pricing_considerations": ["Standard market pricing"],
"improvement_suggestions": ["Improve image quality and content"],
"market_positioning": {"quality_tier": "Unknown"},
"competitive_analysis": {"quality_advantage": "Unknown"},
"investment_potential": {"presentation_value": "Unknown"},
"staging_recommendations": ["Consider professional staging"]
}
def analyze_scene_with_clip(image, room_type):
"""Advanced scene understanding using CLIP model"""
try:
if not clip_processor or not clip_model:
return {'scene_concepts': [], 'style_analysis': {}}
# Define comprehensive real estate concepts
real_estate_concepts = [
# Style concepts
"modern design", "traditional style", "contemporary", "luxury", "minimalist", "rustic", "industrial",
"scandinavian", "mediterranean", "asian fusion", "art deco", "mid-century modern",
# Quality indicators
"high-end finishes", "premium materials", "custom details", "architectural features",
"natural light", "open floor plan", "high ceilings", "hardwood floors", "granite countertops",
# Functionality
"functional layout", "efficient design", "storage solutions", "entertainment space",
"home office", "flexible space", "outdoor living", "smart home features",
# Room-specific concepts
"gourmet kitchen", "spa-like bathroom", "master suite", "entertainment room",
"dining area", "living space", "bedroom retreat", "home gym", "wine cellar"
]
# Process image and text
inputs = clip_processor(images=image, text=real_estate_concepts, return_tensors="pt", padding=True)
with torch.no_grad():
outputs = clip_model(**inputs)
logits_per_image = outputs.logits_per_image
probs = logits_per_image.softmax(dim=-1)
# Get top matches
top_concepts = []
for i, prob in enumerate(probs[0]):
if prob > 0.2: # Lower threshold for more concepts
top_concepts.append({
"concept": real_estate_concepts[i],
"confidence": float(prob)
})
# Analyze style patterns
style_keywords = ["modern", "traditional", "contemporary", "luxury", "minimalist", "rustic", "industrial"]
style_scores = {}
for style in style_keywords:
style_score = sum(concept["confidence"] for concept in top_concepts if style in concept["concept"].lower())
if style_score > 0:
style_scores[style] = style_score
# Determine dominant style
dominant_style = max(style_scores.items(), key=lambda x: x[1]) if style_scores else ("unknown", 0)
return {
"scene_concepts": sorted(top_concepts, key=lambda x: x["confidence"], reverse=True)[:10],
"style_analysis": {
"dominant_style": dominant_style[0],
"style_confidence": dominant_style[1],
"all_style_scores": style_scores,
"quality_indicators": [concept for concept in top_concepts if "quality" in concept["concept"].lower() or "premium" in concept["concept"].lower()],
"functionality_indicators": [concept for concept in top_concepts if "functional" in concept["concept"].lower() or "efficient" in concept["concept"].lower()]
}
}
except Exception as e:
logger.error(f"CLIP scene analysis failed: {str(e)}")
return {'scene_concepts': [], 'style_analysis': {}}
def analyze_market_positioning(room_classification, quality_analysis, object_detection, property_assessment):
"""Advanced market positioning analysis"""
try:
market_analysis = {
"market_tier": "Unknown",
"competitive_position": "Unknown",
"price_positioning": "Unknown",
"target_market": "Unknown",
"differentiation_factors": [],
"market_opportunities": [],
"competitive_advantages": [],
"market_risks": []
}
# Extract key metrics
quality_score = quality_analysis.get('quality_score', 0)
overall_score = property_assessment.get('overall_score', 0)
room_type = room_classification.get('room_type', 'unknown')
room_confidence = room_classification.get('confidence', 0)
object_analysis = object_detection.get('analysis', {})
# 1. Market Tier Analysis
if overall_score >= 85:
market_analysis["market_tier"] = "Luxury"
market_analysis["price_positioning"] = "Premium"
market_analysis["target_market"] = "High-end buyers, investors"
elif overall_score >= 75:
market_analysis["market_tier"] = "Premium"
market_analysis["price_positioning"] = "Above market"
market_analysis["target_market"] = "Professional buyers, families"
elif overall_score >= 60:
market_analysis["market_tier"] = "Standard"
market_analysis["price_positioning"] = "Market rate"
market_analysis["target_market"] = "General buyers"
else:
market_analysis["market_tier"] = "Value"
market_analysis["price_positioning"] = "Below market"
market_analysis["target_market"] = "Budget-conscious buyers"
# 2. Competitive Position Analysis
if quality_score >= 80 and room_confidence >= 80:
market_analysis["competitive_position"] = "Strong"
market_analysis["competitive_advantages"].append("High-quality presentation")
market_analysis["competitive_advantages"].append("Clear room identification")
elif quality_score >= 60 and room_confidence >= 60:
market_analysis["competitive_position"] = "Competitive"
market_analysis["competitive_advantages"].append("Good presentation quality")
else:
market_analysis["competitive_position"] = "Needs improvement"
market_analysis["market_risks"].append("Poor presentation may limit appeal")
# 3. Room-specific positioning
if room_type in ['kitchen', 'bathroom']:
appliance_count = object_analysis.get('appliance_count', 0)
fixture_count = object_analysis.get('fixture_count', 0)
if room_type == 'kitchen' and appliance_count >= 3:
market_analysis["differentiation_factors"].append("Fully equipped kitchen")
market_analysis["competitive_advantages"].append("Modern kitchen appliances")
elif room_type == 'bathroom' and fixture_count >= 2:
market_analysis["differentiation_factors"].append("Well-appointed bathroom")
market_analysis["competitive_advantages"].append("Quality bathroom fixtures")
# 4. Object density analysis
object_density = object_analysis.get('object_density', 0)
if object_density > 10:
market_analysis["differentiation_factors"].append("Rich content and features")
market_analysis["competitive_advantages"].append("Well-appointed space")
elif object_density < 3:
market_analysis["market_risks"].append("Limited content may reduce appeal")
# 5. Market opportunities
if quality_score < 70:
market_analysis["market_opportunities"].append("Improve image quality for better positioning")
if room_confidence < 70:
market_analysis["market_opportunities"].append("Enhance room type clarity")
if object_density < 5:
market_analysis["market_opportunities"].append("Add more features and furniture")
# 6. Professional grade analysis
if property_assessment.get('professional_grade', False):
market_analysis["competitive_advantages"].append("Professional-grade presentation")
market_analysis["differentiation_factors"].append("High-quality photography")
else:
market_analysis["market_opportunities"].append("Consider professional photography")
return market_analysis
except Exception as e:
logger.error(f"Market positioning analysis failed: {str(e)}")
return {
"market_tier": "Unknown",
"competitive_position": "Unknown",
"price_positioning": "Unknown",
"target_market": "Unknown",
"differentiation_factors": [],
"market_opportunities": [],
"competitive_advantages": [],
"market_risks": []
}
def classify_room_type(image):
"""Classify room type using the loaded room classifier"""
try:
if room_classifier is None:
return {'room_type': 'unknown', 'confidence': 0}
results = room_classifier(image)
return {
'room_type': results[0]['label'].lower(),
'confidence': round(results[0]['score'] * 100, 2)
}
except Exception as e:
logger.error(f"Room classification failed: {str(e)}")
return {'room_type': 'unknown', 'confidence': 0}
if __name__ == '__main__':
# Load models on startup
logger.info("Starting Real Estate Image Analyzer...")
load_models()
# Get port from environment variable or use default
port = int(os.environ.get('PORT', 7860))
# For Hugging Face Spaces, use 0.0.0.0 to bind to all interfaces
host = '0.0.0.0'
logger.info(f"Starting Flask app on {host}:{port}")
logger.info(f"Access your application at: http://localhost:{port}")
# Start Flask app
app.run(port=port, debug=False, host=host)