Skip to main content

Architectural Styles

Classification and analysis of French architectural styles using LiDAR data.

Overview​

The IGN LiDAR HD dataset enables detailed analysis of architectural styles across French territories, supporting:

  • Heritage preservation - Document historical buildings
  • Urban planning - Understand architectural patterns
  • Cultural mapping - Identify regional variations
  • Building classification - Automated style recognition

Style Classification​

Traditional French Styles​

Haussmann (1853-1870)​

Characteristic of central Paris, uniform height and faΓ§ade organization.

from ign_lidar.styles import HaussmannDetector

detector = HaussmannDetector()
buildings = detector.classify(lidar_data, criteria={
'height_uniformity': 0.9, # Very uniform heights
'facade_alignment': 0.95, # Aligned street facades
'courtyard_ratio': 0.3, # Inner courtyards
'roof_type': 'mansard' # Characteristic roofs
})

Detection Features:

  • Consistent building heights (6-7 stories)
  • Aligned street frontages
  • Internal courtyards
  • Mansard roofs with dormers
  • Continuous urban fabric

Art Nouveau (1890-1910)​

Organic forms, decorative elements, innovative materials.

detector = ArtNouveauDetector()
buildings = detector.classify(lidar_data, criteria={
'facade_complexity': 'high',
'decorative_elements': True,
'asymmetric_composition': True,
'material_diversity': 'iron_glass_stone'
})

Detection Features:

  • Irregular rooflines
  • Curved architectural elements
  • Glass and iron integration
  • Asymmetrical compositions
  • Ornamental details

Regional Vernacular​

Traditional styles specific to French regions.

# Alsatian timber-framed houses
alsatian_config = {
'timber_framing': True,
'steep_roofs': 45, # degrees
'gable_orientation': 'street_facing',
'materials': ['timber', 'stone', 'render']
}

# Norman colombage
norman_config = {
'half_timbered': True,
'thatched_roofs': True,
'irregular_plan': True,
'courtyard_farms': True
}

# ProvenΓ§al mas
provencal_config = {
'stone_construction': True,
'low_pitch_roofs': 30, # degrees
'tile_covering': 'terracotta',
'thick_walls': True
}

Modern Styles​

Art Deco (1920-1939)​

Geometric patterns, vertical emphasis, luxury materials.

detector = ArtDecoDetector()
buildings = detector.classify(lidar_data, criteria={
'geometric_patterns': True,
'vertical_emphasis': 'strong',
'setback_terraces': True,
'decorative_cornices': True
})

Modernist/Bauhaus (1920-1960)​

Functional design, flat roofs, geometric forms.

detector = ModernistDetector()
buildings = detector.classify(lidar_data, criteria={
'flat_roofs': 0.8, # Mostly flat roofs
'geometric_forms': True,
'minimal_decoration': True,
'large_windows': True,
'white_facades': 0.6 # Often white/light colored
})

Brutalist (1950-1980)​

Massive concrete structures, geometric forms.

detector = BrutalistDetector()
buildings = detector.classify(lidar_data, criteria={
'concrete_construction': True,
'massive_forms': True,
'minimal_windows': True,
'geometric_complexity': 'high',
'monumental_scale': True
})

Implementation​

Style Detection Pipeline​

from ign_lidar import Processor, StyleClassifier

class ArchitecturalAnalyzer:
def __init__(self):
self.processor = Processor()
self.classifier = StyleClassifier()

def analyze_buildings(self, tile_path):
"""Analyze architectural styles in a LiDAR tile."""

# Extract buildings
buildings = self.processor.extract_buildings(tile_path)

# Classify styles
styles = {}
for building_id, building in buildings.items():
style = self.classifier.predict_style(building)
styles[building_id] = style

return styles

def generate_style_map(self, tiles):
"""Generate architectural style map."""

style_map = {}
for tile in tiles:
tile_styles = self.analyze_buildings(tile)
style_map.update(tile_styles)

return self.create_visualization(style_map)

Feature Extraction​

def extract_architectural_features(building_points):
"""Extract features relevant to architectural style."""

features = {
# Geometric features
'height': calculate_height(building_points),
'footprint_area': calculate_area(building_points),
'perimeter': calculate_perimeter(building_points),
'compactness': calculate_compactness(building_points),

# Roof features
'roof_type': classify_roof_type(building_points),
'roof_pitch': calculate_roof_pitch(building_points),
'roof_complexity': measure_roof_complexity(building_points),

# Facade features
'facade_complexity': analyze_facade(building_points),
'window_patterns': detect_openings(building_points),
'setbacks': detect_setbacks(building_points),

# Context features
'urban_context': analyze_context(building_points),
'alignment': check_street_alignment(building_points),
'density': calculate_local_density(building_points)
}

return features

Machine Learning Classification​

from sklearn.ensemble import RandomForestClassifier
import numpy as np

class StyleClassifier:
def __init__(self):
self.model = RandomForestClassifier(
n_estimators=100,
random_state=42
)
self.feature_names = [
'height', 'area', 'compactness', 'roof_pitch',
'facade_complexity', 'window_regularity', 'setback_count'
]

def train(self, training_data):
"""Train the style classifier."""

features = []
labels = []

for building, style in training_data:
feature_vector = self.extract_features(building)
features.append(feature_vector)
labels.append(style)

X = np.array(features)
y = np.array(labels)

self.model.fit(X, y)

def predict_style(self, building):
"""Predict architectural style."""

features = self.extract_features(building)
style = self.model.predict([features])[0]
confidence = self.model.predict_proba([features]).max()

return {
'style': style,
'confidence': confidence,
'features': features
}

Regional Variations​

Northern France​

northern_styles = {
'flemish_baroque': {
'gabled_facades': True,
'brick_construction': True,
'ornate_details': True
},
'picard_traditional': {
'timber_framing': True,
'brick_infill': True,
'steep_roofs': True
}
}

Central France​

central_styles = {
'loire_renaissance': {
'stone_construction': True,
'decorative_turrets': True,
'formal_gardens': True
},
'berry_vernacular': {
'limestone_walls': True,
'slate_roofs': True,
'agricultural_buildings': True
}
}

Southern France​

southern_styles = {
'mediterranean': {
'flat_roofs': True,
'tile_roofs': True,
'stone_construction': True,
'courtyards': True
},
'basque': {
'timber_framing': True,
'white_walls': True,
'red_tile_roofs': True,
'mountain_adaptation': True
}
}

Validation and Quality Control​

Ground Truth Comparison​

def validate_classification(predictions, ground_truth):
"""Validate architectural style predictions."""

accuracy_metrics = {
'overall_accuracy': calculate_accuracy(predictions, ground_truth),
'style_precision': calculate_precision_by_style(predictions, ground_truth),
'style_recall': calculate_recall_by_style(predictions, ground_truth),
'confusion_matrix': create_confusion_matrix(predictions, ground_truth)
}

return accuracy_metrics

Expert Validation​

def expert_review_pipeline(classified_buildings):
"""Submit classifications for expert review."""

# Prioritize uncertain classifications
uncertain = filter_by_confidence(classified_buildings, threshold=0.7)

# Generate review materials
review_package = {
'building_images': generate_building_views(uncertain),
'feature_summaries': create_feature_summaries(uncertain),
'context_maps': create_context_visualizations(uncertain)
}

return review_package

Applications​

Heritage Documentation​

def heritage_survey(region_tiles):
"""Survey heritage buildings in region."""

analyzer = ArchitecturalAnalyzer()
heritage_buildings = []

for tile in region_tiles:
styles = analyzer.analyze_buildings(tile)

# Identify heritage styles
heritage = {
building_id: style
for building_id, style in styles.items()
if style['style'] in HERITAGE_STYLES and
style['confidence'] > 0.8
}

heritage_buildings.extend(heritage)

return create_heritage_database(heritage_buildings)

Urban Evolution Analysis​

def analyze_urban_evolution(historical_tiles):
"""Analyze architectural evolution over time."""

evolution_data = {}

for year, tiles in historical_tiles.items():
styles = analyze_architectural_styles(tiles)
evolution_data[year] = aggregate_style_statistics(styles)

trends = {
'style_progression': track_style_changes(evolution_data),
'densification_patterns': analyze_density_changes(evolution_data),
'preservation_status': assess_heritage_preservation(evolution_data)
}

return trends

Planning Support​

def architectural_planning_analysis(planning_zone):
"""Support urban planning with architectural analysis."""

current_styles = analyze_existing_architecture(planning_zone)

recommendations = {
'compatible_styles': suggest_compatible_styles(current_styles),
'height_guidelines': recommend_height_limits(current_styles),
'density_limits': calculate_appropriate_density(current_styles),
'preservation_priorities': identify_preservation_candidates(current_styles)
}

return recommendations

Integration with Other Systems​

QGIS Integration​

def export_to_qgis(style_classifications):
"""Export style data to QGIS."""

# Create styled layer
layer = create_vector_layer(style_classifications)

# Apply style-based symbology
apply_architectural_styling(layer)

# Add attribute data
add_style_attributes(layer, style_classifications)

return layer

Database Integration​

def store_architectural_data(classifications, database_connection):
"""Store classifications in heritage database."""

for building_id, classification in classifications.items():
record = {
'building_id': building_id,
'architectural_style': classification['style'],
'confidence': classification['confidence'],
'period': classification.get('period'),
'regional_variant': classification.get('variant'),
'conservation_status': assess_conservation_status(classification)
}

database_connection.insert_architectural_record(record)

Best Practices​

Classification Guidelines​

  1. Multi-scale Analysis: Consider building, block, and neighborhood scales
  2. Temporal Context: Account for construction periods and modifications
  3. Regional Adaptation: Adjust criteria for regional variations
  4. Expert Validation: Incorporate architectural expert knowledge
  5. Continuous Learning: Update models with new training data

Quality Assurance​

  1. Cross-validation: Test on independent datasets
  2. Confidence Thresholds: Set appropriate confidence levels
  3. Manual Review: Review uncertain classifications
  4. Documentation: Maintain detailed classification rationale
  5. Version Control: Track model and criteria versions