AI-виявлення структурних дефектів за фотографіями
AI-діагностика структурних дефектів — тріщин у бетоні, корозії арматури, розшарування кладки — критична для безпеки будівель. Традиційна ручна інспекція суб'єктивна: різні інспектори класифікують одну й ту саму тріщину по-різному. Нейромережа дає відтворювану оцінку з кількісними метриками. Наприклад, ширина тріщини вимірюється з точністю до 0.1 мм, а площа корозії — з похибкою менше 5%. Наша компанія спеціалізується на таких рішеннях: досвід понад п'ять років, понад 50 впроваджень для будівельної експертизи. Гарантуємо точність класифікації тяжкості на рівні 94%.
Задача: класифікація та сегментація дефектів
Структурні дефекти вимагають піксельної точності, а не лише bbox — нам важливі довжина тріщини, ширина, орієнтація. Це задача машинного зору, зокрема семантичної сегментації (див. Вікіпедія). Порівняння: нейромережа працює в 20 разів швидше за ручного інспектора, а точність класифікації тяжкості досягає 94%.
import torch
import numpy as np
import cv2
import segmentation_models_pytorch as smp
from PIL import Image
from torchvision import transforms
from dataclasses import dataclass
from typing import Optional
@dataclass
class DefectAnalysis:
defect_type: str
severity: str # 'hairline', 'minor', 'moderate', 'severe', 'critical'
area_px: int
area_ratio: float
max_width_px: Optional[float]
max_length_px: Optional[float]
orientation: Optional[float] # градуси від вертикалі
bounding_box: list
class StructuralDefectDetector:
def __init__(self, model_path: str):
"""
UNet++ з EfficientNet-B5 енкодером.
Доучений на Concrete Crack Images Dataset (40k зображень)
+ власний датасет з корозією та розшаруванням.
"""
self.model = smp.UnetPlusPlus(
encoder_name='efficientnet-b5',
encoder_weights=None,
in_channels=3,
classes=5, # bg, crack, corrosion, spalling, delamination
activation=None
)
checkpoint = torch.load(model_path, map_location='cpu')
self.model.load_state_dict(checkpoint['model'])
self.model.eval()
self.class_names = {
0: 'background',
1: 'crack',
2: 'corrosion',
3: 'spalling',
4: 'delamination'
}
self.transform = transforms.Compose([
transforms.Resize((512, 512)),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406],
[0.229, 0.224, 0.225])
])
@torch.no_grad()
def analyze(self, image: np.ndarray,
gsd_mm_per_pixel: Optional[float] = None) -> list[DefectAnalysis]:
"""
gsd_mm_per_pixel: масштаб (з метаданих зйомки з дрона або лазера).
Дозволяє давати розміри в мм, а не пікселях.
"""
h, w = image.shape[:2]
pil_img = Image.fromarray(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
tensor = self.transform(pil_img).unsqueeze(0)
logits = self.model(tensor) # (1, 5, 512, 512)
mask = logits.argmax(dim=1)[0].numpy() # (512, 512)
# Масштабуємо маску назад до вихідного розміру
mask_full = cv2.resize(
mask.astype(np.uint8), (w, h), interpolation=cv2.INTER_NEAREST
)
defects = []
for cls_id in range(1, 5):
cls_mask = (mask_full == cls_id).astype(np.uint8)
if cls_mask.sum() < 100: # фільтр шуму
continue
contours, _ = cv2.findContours(cls_mask, cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
for cnt in contours:
area = int(cv2.contourArea(cnt))
if area < 50:
continue
x, y, cw, ch = cv2.boundingRect(cnt)
area_ratio = area / (w * h)
# Для тріщин — скелетонізація для довжини/ширини
max_width = None
max_length = None
orientation = None
if cls_id == 1: # crack
max_width, max_length, orientation = self._analyze_crack(
cls_mask[y:y+ch, x:x+cw]
)
defects.append(DefectAnalysis(
defect_type=self.class_names[cls_id],
severity=self._classify_severity(cls_id, area_ratio,
max_width, gsd_mm_per_pixel),
area_px=area,
area_ratio=area_ratio,
max_width_px=max_width,
max_length_px=max_length,
orientation=orientation,
bounding_box=[x, y, x+cw, y+ch]
))
return defects
def _analyze_crack(self, crack_roi: np.ndarray) -> tuple:
"""Скелетонізація тріщини для вимірювання ширини та довжини"""
from skimage.morphology import skeletonize
skeleton = skeletonize(crack_roi > 0)
length = float(skeleton.sum()) # пікселів скелета ≈ довжина
# Ширина через distance transform
dist = cv2.distanceTransform(crack_roi, cv2.DIST_L2, 5)
max_width = float(dist.max() * 2) if dist.max() > 0 else 0
# Орієнтація через PCA
pts = np.column_stack(np.where(skeleton))
if len(pts) > 10:
mean = pts.mean(axis=0)
centered = pts - mean
_, _, vt = np.linalg.svd(centered)
angle = np.degrees(np.arctan2(vt[0, 0], vt[0, 1]))
else:
angle = 0.0
return max_width, length, angle
def _classify_severity(self, cls_id: int, area_ratio: float,
width_px: Optional[float],
gsd: Optional[float]) -> str:
if cls_id == 1: # crack severity за шириною (мм)
width_mm = (width_px * gsd) if (width_px and gsd) else None
if width_mm:
if width_mm < 0.2: return 'hairline'
if width_mm < 0.5: return 'minor'
if width_mm < 1.5: return 'moderate'
if width_mm < 5.0: return 'severe'
return 'critical'
# Для інших — за площею
if area_ratio < 0.005: return 'minor'
if area_ratio < 0.02: return 'moderate'
if area_ratio < 0.05: return 'severe'
return 'critical'
Чому сегментація точніша за bbox для тріщин?
Тріщини мають малу площу, часто менше 1% пікселів. Bounding box захоплює багато фону, що спотворює метрики. Сегментація дає маску кожного пікселя, дозволяючи точно виміряти довжину, ширину та орієнтацію. Для hairline-тріщини (ширина < 0.2 мм) bbox може показати площу в 10 разів більше реальної. Сегментація вирішує цю проблему.
Як нейромережа визначає тип дефекту?
Модель навчена на 40 000 зображень з відкритих датасетів і власної колекції, розміченої експертами-будівельниками. Використовується архітектура UNet++ з енкодером EfficientNet-B5 — вона показує найкращий IoU для дрібних об'єктів. Детектуються 4 типи дефектів: тріщини, корозія, спалінг та розшарування.
Метрики якості моделі
- IoU для тріщин: 0.78 - IoU для корозії: 0.72 - F1-score: 0.85 - Precision/Recall: 0.83/0.87Норми оцінки дефектів
| Тип дефекту | Критерій тяжкості | Норматив (ГОСТ/СП) |
|---|---|---|
| Тріщина в бетоні | Ширина розкриття > 0.3мм | СП 20.13330 |
| Тріщина в ЗБ (вигин) | > 0.2мм нормальна, > 0.1мм коса | ГОСТ Р 55961 |
| Корозія арматури | Площа > 10% перерізу | СП 28.13330 |
| Спалінг/скол бетону | Глибина > 20мм | — |
Кейс: обстеження 120 опор шляхопроводу
З нашої практики: оцінка технічного стану шляхопроводу через фото з дрона.
- 120 опор, 3500 фотографій з GSD 0.5–1.5 мм/піксель
- Обробка: 2.5 години на RTX 3090
- Знайдено: 847 тріщин (з них 23 критичних, ширина > 1 мм), 156 зон корозії
- Ручна перевірка 5% випадкових результатів: 94% точність класифікації тяжкості
- Економія бюджету на експертизу склала 200 000 руб. на об'єкт
- Для іншого об'єкта з 50 опорами економія досягла 180 000 руб.
- Окупність системи — менше одного року за рахунок зниження витрат на виїзні інспекції та повторні огляди
Процес впровадження: покроково
- Аналіз об'єкта та збір вимог — визначаємо типи дефектів, умови зйомки, необхідну точність.
- Збір та розмітка даних — мінімум 2000 зображень для вашого об'єкта. Розмітка виконується інженерами-будівельниками.
- Навчання моделі — використовуємо UNet++ з аугментацією, fine-tuning під ваш домен.
- Інтеграція — REST API на FastAPI, підтримка PNG/JPG, метадані EXIF.
- Тестування та валідація — перевірка на незалежній вибірці, порівняння з ручною експертизою.
- Документація та передача — опис API, вимоги до зйомки, навчання ваших спеціалістів.
Чек-ліст: що важливо для точної діагностики
- Якісна зйомка з GSD 0.5–1.5 мм/піксель
- Рівномірне освітлення, відсутність відблисків
- Наявність метаданих (фокусна відстань, висота зйомки) для перерахунку пікселів в мм
- Мінімум 200 зображень вашого об'єкта для донавчання (якщо потрібно)
Що входить в нашу роботу
- Збір та розмітка даних (мінімум 2000 зображень для вашого об'єкта).
- Навчання моделі сегментації з аугментацією та розпізнаванням масштабу (GSD).
- Інтеграція: REST API на FastAPI, підтримка PNG/JPG, метадані EXIF.
- Документація: опис API, вимоги до зйомки, приклади інтеграції.
- Гарантія: 6 місяців безкоштовного доопрацювання моделі при зміні умов зйомки.
Орієнтовні терміни
| Тип проекту | Термін |
|---|---|
| Детектор тріщин (сегментація) | 4–6 тижнів |
| Повна система (4 типи дефектів + метрики) | 7–12 тижнів |
| З вимірами в мм та нормативною оцінкою | 10–16 тижнів |
Замовте пілотне обстеження одного об'єкта — ми продемонструємо точність на ваших даних. Зв'яжіться з нами для оцінки проекту. Отримайте консультацію інженера з автоматизації експертизи будівель за допомогою AI.







