Recently, an insurance company approached us: they needed to automatically assess body damage from smartphone photos. The main pain point was tiny scratches and dents that operators missed. We developed a model that detects defects as small as 0.5 mm and classifies them by severity. A localization error could cost millions, so we aim for recall >95% with controlled false positives. Over 5 years in the market, we have completed more than 50 computer vision projects, including defect detection for automotive and metallurgy industries. Manual labor savings reach 80%, and claims drop by 30%. Get a preliminary estimate — contact us for a consultation.
Types of Damage and Detection Specifics
Cracks — thin linear structures with a small width-to-length ratio. Standard detectors perform poorly: bounding boxes are large while the defect is small. Segmentation is preferable.
Dents — surface deformation without material rupture. Hard to detect in 2D; raking light and 3D reconstruction help.
Scratches — similar to cracks, linear structures. Depth affects severity.
How We Detect Fine Cracks and Scratches
We use a combination of YOLOv8 for instance segmentation and specialized preprocessing. Raking light at a shallow angle casts shadows from the tiniest irregularities, revealing defects only a few pixels wide. The pipeline includes top-hat transformations and contrast enhancement.
System Architecture
from ultralytics import YOLO
import numpy as np
import cv2
class DamageDetectionSystem:
def __init__(self, config: dict):
# Детектор повреждений (YOLOv8 instance segmentation)
self.detector = YOLO(config['detection_model'])
# Классификатор тяжести
self.severity_classifier = load_severity_model(config['severity_model'])
# Измеритель размеров (требует калибровки)
self.pixels_per_mm = config.get('pixels_per_mm')
def analyze(self, image: np.ndarray) -> dict:
# Детекция и сегментация повреждений
results = self.detector(image, conf=0.4, iou=0.5)
damages = []
for i, (box, mask) in enumerate(zip(
results[0].boxes,
results[0].masks.data if results[0].masks else []
)):
damage_type = self.detector.model.names[int(box.cls)]
bbox = box.xyxy[0].tolist()
area_px = int(mask.sum().item())
# Вырезаем регион для классификации тяжести
x1, y1, x2, y2 = map(int, bbox)
crop = image[y1:y2, x1:x2]
severity = self.severity_classifier.predict(crop)
# Реальные размеры если есть калибровка
size_info = {}
if self.pixels_per_mm:
size_info['area_mm2'] = round(area_px / self.pixels_per_mm**2, 2)
size_info['length_mm'] = self._estimate_length(mask)
damages.append({
'id': i,
'type': damage_type,
'severity': severity,
'bbox': bbox,
'area_pixels': area_px,
'confidence': float(box.conf),
**size_info
})
return {
'damages': damages,
'total_count': len(damages),
'has_critical': any(d['severity'] == 'critical' for d in damages),
'summary': self._generate_summary(damages)
} Why Raking Light Is Effective
For cracks and scratches, standard frontal lighting is insufficient. Raking light — a source at a shallow angle to the surface — casts shadows from the tiniest irregularities. We use top-hat transformation to extract fine details and histogram equalization to enhance contrast. This increases recall for small defects by 15-20%.
def process_raking_light_image(image_path: str) -> np.ndarray:
"""Normalized image with raking light"""
# При правильном освещении на стенде — дополнительная обработка:
img = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)
# Топ-hat трансформация для выделения мелких деталей
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (25, 25))
tophat = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernel)
# Усиление контраста
enhanced = cv2.equalizeHist(tophat)
return enhanced
How We Measure Defect Sizes
After detection, we need to estimate real dimensions — crack length or dent area. We calibrate the camera with a reference object. The parameter pixels_per_mm is stored in the system config. Then, using the defect mask, we compute physical sizes. For cracks, we skeletonize the mask for more accurate length.
def measure_crack_length(mask: np.ndarray, pixels_per_mm: float) -> float:
"""Measure crack length from mask skeleton"""
from skimage.morphology import skeletonize
skeleton = skeletonize(mask > 0)
length_px = skeleton.sum()
return round(length_px / pixels_per_mm, 2)For precise measurements, calibration using a reference is required. We use a chessboard with known spacing, determine the camera matrix, and derive the pixels_per_mm factor.
Datasets and Metrics
Public datasets:
- NEU Surface Defect — 6 classes of steel defects, 1800 images
- DAGM — texture defects, 10 categories
- AITEX Fabric — fabric defects
- Concrete Crack Images — cracks in concrete
# Example training on NEU Surface Defect
from ultralytics import YOLO
model = YOLO('yolov8m-seg.pt')
model.train(
data='neu_defect.yaml',
epochs=150,
imgsz=640,
batch=16,
workers=8,
optimizer='AdamW',
lr0=5e-4,
augment=True,
degrees=180, # дефекты могут быть в любой ориентации
fliplr=0.5,
flipud=0.5,
mosaic=1.0
) Metrics on Different Materials
| Material | [email protected] | Complexity |
|---|---|---|
| Metal (scratches, cracks) | 88–94% | Medium |
| Glass (cracks) | 82–89% | High |
| Plastic (dents) | 84–91% | High |
| Concrete (cracks) | 90–96% | Medium |
What's Included in the Work
- Requirements analysis and dataset collection (shoot defects on your equipment or use ready-made datasets)
- Development of detection and segmentation model, training with augmentation
- Integration into your IT infrastructure (REST API, Docker container)
- Camera calibration and lighting setup (raking light rig if needed)
- Documentation and operator training
- 3-month warranty support
The cost of developing such a system depends on complexity and data volume. We evaluate each project individually to define the scope. Get a preliminary estimate — contact us.
Implementation Timeline
| Task | Duration |
|---|---|
| 2–3 defect types, supervised | 3–5 weeks |
| Dimensional analysis + calibration | 5–8 weeks |
| Industrial system with lighting | 8–14 weeks |
Checklist: Production Readiness for AI Defect Detection
Before starting the project, check the following:
- Controlled lighting on the stand (raking or diffuse light).
- Stable camera mount with resolution at least 5 MP for defects from 0.5 mm.
- Historical image archive: at least 200–300 examples of each defect type.
- Clear acceptance criteria: maximum allowed false positive and miss rates.
- Readiness for data labeling (mask annotation) or a pre-labeled dataset.
- Defined SLA: acceptable inspection time per object.
We guarantee transparent support at all stages. Request an engineer consultation — discuss the details of your project. Get a solution that really works.
NEU Surface Defect dataset (Song et al., 2019)







