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)







