Трассировка сварного шва в цифровой радиографии: почему слепая нарезка разрушает датасеты и как построить устойчивый слайсер
Автоматизация анализа радиографических снимков сварных соединений методами сверточных нейросетей (CNN) традиционно упирается в несоответствие размеров данных. Исходный снимок цифровой радиографии высокого разрешения имеет протяженность от 3000 до 10000 пикселей, тогда как стандартный вход классификационных и детекционных сетей составляет скромные 224×224 или 512×512 пикселей. Прямое сжатие всего снимка до входа сети недопустимо: при масштабировании тонкие трещины и мелкие поры размером в 2–4 пикселя полностью растворяются в процессе интерполяции.
Единственным рабочим решением остается нарезка снимка на локальные фрагменты (патчи). Однако способ формирования этой нарезки напрямую определяет жизнеспособность будущей модели. В этой статье разобран методологический тупик распространенных открытых бенчмарков, сформулировано строгое правило изоляции выборок и представлен устойчивый алгоритм слайсера, ориентирующегося по оси шва независимо от его формы, контраста и наличия сопутствующих артефактов.
1. Методологический тупик слепой нарезки: урок датасета RIAWELC
Показательным примером методологических ошибок при подготовке радиографических данных является открытый датасет RIAWELC, сформированный на базе рентгеновских снимков GDXray [1]. Подробный критический разбор структуры этого датасета и допущенных в нем нестыковок ранее уже публиковался на моем портале [2].
Создатели RIAWELC пошли по пути наименьшего сопротивления: они применили к снимкам слепое скользящее окно с колоссальным взаимным перекрытием (свыше 80%), а затем распределили полученные тайлы между обучающей (train) и тестовой (test) выборками случайным образом. Этот шаг порождает две системные проблемы:
Проблема 1. Фиктивная точность из-за утечки данных (Data Leakage)
Когда соседние окна сдвинуты относительно друг друга всего на 15–20 пикселей, один и тот же физический дефект (например, пора или шлаковое включение) попадает сразу в 5–8 соседних нарезанных квадратов. При случайном перемешивании (random split) четыре квадрата с этим дефектом уходят в обучение, а пятый — в тест.
В результате сверточная сеть в тестовой выборке не решает задачу обобщения. Она не учится находить абстрактную пору среди чистого металла: она видит абсолютно ту же самую пору, окруженную той же микротекстурой шума детектора, теми же градиентами оптической плотности и тем же микрорельефом валика, которые она только что оптимизировала в функции потерь. Метрики точности взлетают до 98–99%, создавая иллюзию идеальной работы алгоритма. Но при первом же запуске на снимке реального стыка, которого не было в выборке, точность обваливается, так как инвариантности к дефекту сеть не приобрела.
Проблема 2. Обрезка границ шва и околошовной зоны
В RIAWELC нарезку производили строго по внутренней части усиления шва. При этом тело трубы и переходная зона были полностью отрезаны. В реальном неразрушающем контроле такой подход лишен практического смысла: наиболее опасные дефекты концентрируются не только в центре шва, но и по линии сплавления, а также в зоне термического влияния (ЗТВ). Подрезы, несплавления по кромкам и околошовные трещины располагаются как раз на границе перехода от шва к основному металлу. Если датасет лишен переходных зон, сеть физически не способна распознавать эти дефекты.
Отсюда формулируется базовая аксиома подготовки радиографических датасетов:
Разбиение данных должно производиться строго на уровне целых исходных снимков: один физический снимок целиком отправляется в обучающую выборку (train), другой снимок целиком — в проверочную (val/test). Пересечение нарезанных слайсов между выборками категорически недопустимо.
2. Проблематика поиска шва в цифровой радиографии
В современной дефектоскопии пленочные технологии вытеснены цифровой радиографией: контроль ведется на плоскопанельных детекторах (Flat Panel Detectors, DDA) или многоразовых фосфорных пластинах (CR). Это дает 12–16-битный динамический диапазон, но создает собственные сложности. Основной шум здесь — это не зерно фотоэмульсии, а квантовый шум излучения, шум считывания электроники детектора и неравномерность чувствительности отдельных пикселей матрицы.
Автоматическое определение геометрии шва на таких кадрах наталкивается на два препятствия:
- Слабый градиент зачищенных швов: Если валик усиления механически зачищен заподлицо или высота шва минимальна (Рис. 2), перепад оптической плотности между швом и металлом трубы составляет всего несколько единиц яркости. Простые градиентные операторы (Собель, Канни) или глобальная бинаризация Оцу тонут в шуме детектора.
- Высококонтрастные маркеры как стресс-тест: В реальном контроле на автоматизированных линиях маркировочных знаков на теле шва быть не должно. Однако при проектировании алгоритма снимки с свинцовыми литерами и эталонами проволочного типа (Рис. 1) использовались осознанно. Это служило жестким стресс-тестом: алгоритм обязан стабильно выделять траекторию шва и игнорировать любые посторонние включения максимальной яркости, которые могут встретиться на теле трубы (технологические метки, прижимы, брызги металла).
3. Алгоритм сквозной трассировки и нарезки
3.1. Двухпроходное определение пространственной ориентации
Шов в кадре не обязан быть строго горизонтальным — встречаются снимки с вертикальной подачей стыка. Попытка угадать ориентацию эвристиками ненадежна, поэтому модуль выполняет два независимых цикла сканирования:
- Горизонтальный проход: Кадр сканируется по вертикальным полосам вдоль оси X. Вычисляется уверенность трассировки горизонтального шва $conf_H$.
- Вертикальный проход: Исходный кадр программно поворачивается на 90° по часовой стрелке и сканируется по аналогичной схеме с расчетом уверенности $conf_V$.
Если оба направления показывают уверенность ниже 0.5 — алгоритм переходит в сплошную нарезку регулярной сеткой. Если одна из величин превышает порог, выбирается доминирующее направление. В случае, когда побеждает вертикальный проход ($conf_V > conf_H$), изображение разворачивается, и дальнейшая работа ведется в стандартизированной горизонтальной плоскости.
3.2. Подавление шума детектора через 1D-интегрирование
Локальные шумы матрицы детектора подавляются интегральным методом. Изображение разбивается на полосы шириной 150 пикселей. Внутри каждой полосы вычисляется медианный профиль по строкам:
$$P(y) = \text{median}_{x \in [X_1, X_2]} I(x, y)$$Фиксация ширины полосы в 150 px гарантирует, что даже крупная свинцовая литера или проволока эталона займет не более 20–25% ширины окна. Медианный фильтр стирает локальные всплески маркировки, восстанавливая профиль шва в виде гладкого купола.
3.3. Робастная аппроксимация сплайна: как работает RANSAC
После локализации пиков валика в каждой полосе формируется массив координатных точек $(X_i, Y_i)$. На реальных снимках часть точек неизбежно оказывается ложной (выбросы из-за дефектов пленки кассеты, приварившихся брызг или краев оснастки). Обычный метод наименьших квадратов (МНК) здесь не применим: даже один грубый выброс с большим плечом кардинально искажает форму полинома.
Для построения центральной траектории шва применяется алгоритм RANSAC (Random Sample Consensus) [3], адаптированный под параболический сплайн 2-го порядка $Y = ax^2 + bx + c$:
- Итеративная выборка: Из общего пула точек случайно выбирается минимально необходимый набор для однозначного построения параболы — 3 точки. Для воспроизводимости результатов генератор псевдослучайных чисел инициализируется детерминированным сидом (
seed=42). - Формирование гипотезы: По выбранному триплету строится аналитическая кривая.
- Подсчет согласованного множества (Inliers): Для всех остальных точек массива вычисляется абсолютная невязка $|Y_{pred} - Y_i|$. Точки, отстоящие от кривой не далее динамического порога (5% от высоты кадра), зачисляются в группу согласующихся (inliers).
- Селекция лучшей модели: Процедура повторяется фиксированное число раз (150 итераций). Побеждает модель, собравшая наибольшее количество точек-инлаеров.
Итоговая уверенность алгоритма ($Confidence$) рассчитывается как произведение доли согласованных точек на штраф за чрезмерный изгиб:
$$Confidence = \frac{N_{inliers}}{N_{total}} \times \max\left(0.0, \, 1.0 - \frac{|a| \cdot W^2}{10 \cdot H}\right)$$Если точки легли на плавную траекторию оси трубы, уверенность стремится к 1.0. Если точки разбросаны хаотично, RANSAC бракует гипотезу, и значение уверенности обнуляется.
4. Продольные дефекты и седловидный профиль: решение через морфологию
В ходе тестирования алгоритма на снимках с глубоким непроваром корня и сквозными продольными трещинами вскрылся нестандартный краевой эффект: центральная линия на соседних полосах скакала то выше, то ниже дефекта на 30–50 пикселей.
Физическая причина: Продольная трещина создает полосу минимального ослабления рентгеновского излучения (на снимке она выглядит как черная расщелина). В результате унимодальный световой купол валика шва распадается на два раздельных холма, образуя М-образный седловидный профиль. Классический поиск максимума цеплялся то за верхний валик усиления над трещиной, то за нижний.
Математическое решение: Проблема была устранена внедрением одномерного серого морфологического замыкания (scipy.ndimage.grey_closing) с линейным структурным элементом размером ~5% от высоты кадра. Замыкание по вертикали эффективно «заливает» темный провал трещины значениями окружающей оптической плотности металла шва. Раздвоенный профиль восстанавливает монотонность, а истинный центр стыка рассчитывается как геометрическая середина по полувысоте валика (FWHM).
5. Программная реализация
Ниже представлен ключевой блок анализа профилей и сборки RANSAC-аппроксимации:
from typing import Any, Dict, List, Optional, Tuple
import cv2
import numpy as np
from scipy.ndimage import gaussian_filter1d, grey_closing
from scipy.signal import find_peaks
def analyze_direction(
gray_img: np.ndarray, stripe_width: int = 150
) -> Tuple[float, Optional[np.ndarray], float, List[Dict[str, Any]]]:
"""Анализ профилей с морфологическим замыканием трещин и RANSAC-сплайном."""
h, w = gray_img.shape
eff_w = min(stripe_width, w)
stripe_ranges = []
x = 0
while x + eff_w <= w:
stripe_ranges.append((x, x + eff_w))
x += eff_w
if not stripe_ranges or stripe_ranges[-1][0] < (w - eff_w):
stripe_ranges.append((w - eff_w, w))
global_row_med = np.median(gray_img, axis=1)
global_smooth = gaussian_filter1d(global_row_med, sigma=max(3, h // 30))
y_global_hint = int(np.argmax(global_smooth))
dyn_range = float(np.max(global_smooth) - np.min(global_smooth))
x_coords, y_coords, seam_widths = [], [], []
sigma_val = max(3.0, h / 35.0)
closing_size = max(15, int(h * 0.05))
for x1, x2 in stripe_ranges:
stripe_raw = gray_img[:, x1:x2]
prof = np.median(stripe_raw, axis=1)
# Морфологическое замыкание: "сшиваем" М-образные провалы от трещин
closed_prof = grey_closing(prof, size=closing_size)
smooth = gaussian_filter1d(closed_prof, sigma=sigma_val)
min_w = max(5, int(h * 0.05))
prominence = max(4.0, dyn_range * 0.15)
peaks, props = find_peaks(smooth, prominence=prominence, width=min_w)
if len(peaks) > 0:
best_idx = int(np.argmin(np.abs(peaks - y_global_hint)))
# Геометрический центр по FWHM исключает смещение к одному из валиков
left_ip = props["left_ips"][best_idx]
right_ip = props["right_ips"][best_idx]
chosen_y = float((left_ip + right_ip) / 2.0)
x_coords.append((x1 + x2) / 2.0)
y_coords.append(chosen_y)
seam_widths.append(float(props["widths"][best_idx]))
num_stripes = len(stripe_ranges)
if len(x_coords) < num_stripes * 0.3:
return 0.0, None, 0.0, []
# Детерминированный RANSAC (seed=42)
rng = np.random.default_rng(42)
xs, ys = np.array(x_coords), np.array(y_coords)
best_inliers, best_poly = 0, None
threshold = max(8.0, h * 0.05)
for _ in range(150):
if len(xs) < 3:
break
idx = rng.choice(len(xs), 3, replace=False)
try:
poly = np.polyfit(xs[idx], ys[idx], 2)
except np.linalg.LinAlgError:
continue
inliers = np.sum(np.abs(np.polyval(poly, xs) - ys) < threshold)
if inliers > best_inliers:
best_inliers = inliers
best_poly = poly
if best_poly is None:
return 0.0, None, 0.0, []
curv_penalty = max(0.0, 1.0 - abs(best_poly[0]) * (w**2) / (h * 10.0))
confidence = float(np.clip((best_inliers / float(num_stripes)) * curv_penalty, 0.0, 1.0))
median_width = float(np.median(seam_widths)) if seam_widths else float(h * 0.15)
return confidence, best_poly, median_width, []
6. Примеры результирующих раскладок патчей с гарантированным захватом шва и околошовной зоны
Выводы
Качество работы сверточной нейросети в радиографическом контроле закладывается на этапе формирования датасета. Попытки механически нарезать кадры плотным скользящим окном с последующим случайным разбиением приводят к фиктивной переобученности, скрытой утечке данных и неспособности модели находить реальные дефекты на новых стыках.
Предложенный подход на основе двунаправленного проекционного профилирования, одномерного морфологического замыкания и детерминированного сплайн-RANSAC обеспечивает устойчивую трассировку шва даже при выраженных продольных дефектах, зачищенном валике и наличии маркировочных знаков. Сформированные слайсы центрированы относительно реальной оси стыка и включают в себя как тело шва, так и околошовное пространство, что позволяет обучать модели детекции на физически корректных данных.
Ссылки и источники
-
GDXray: The Database of X-ray Images for Nondestructive Testing
Domingo Mery, Vladimir Riffo, Uwe Zscherpel, German Mondragón, Iván Lillo, Irene Zuccar, Hans Lobel, Miguel Carrasco
Journal of Nondestructive Evaluation, Vol. 34, No. 4, Art. 42, 2015. DOI: 10.1007/s10921-015-0315-7.
Репозиторий проекта: https://github.com/computervision-xray-testing/GDXray
📄 Скачать статью: 2015_GDXray.pdf -
Анатомия датасета RIAWELC. Полезный проект или псевдо-академическая стряпня?
Публикация: https://dps.com.ru/posts/ru/what_RIAWELC_really_is.html -
Random Sample Consensus: A Paradigm for Model Fitting with Applications to Image Analysis and Automated Cartography
Fischler M. A., Bolles R. C.
Communications of the ACM, Vol. 24, No. 6, 1981, pp. 381–395. DOI: 10.1145/358669.358692.
Дополнительные материалы
-
Пример отчета моей реализации слайсера:
📄 W0003_0020_report.html (Осторожно, файл большой ~7.7 MB)