[Поделиться]  |  [Печать]

Трассировка сварного шва в цифровой радиографии: почему слепая нарезка разрушает датасеты и как построить устойчивый слайсер

Автоматизация анализа радиографических снимков сварных соединений методами сверточных нейросетей (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-битный динамический диапазон, но создает собственные сложности. Основной шум здесь — это не зерно фотоэмульсии, а квантовый шум излучения, шум считывания электроники детектора и неравномерность чувствительности отдельных пикселей матрицы.

Автоматическое определение геометрии шва на таких кадрах наталкивается на два препятствия:

Снимок сварного соединения из серии GDXray W0003
Рис. 1. Исходный снимок сварного соединения с маркировкой и эталоном [1]
Слабоконтрастный снимок с зачищенным усилением шва
Рис. 2. Снимок соединения с малой толщиной усиления, где шов почти не выделяется по яркости [1]

3. Алгоритм сквозной трассировки и нарезки

3.1. Двухпроходное определение пространственной ориентации

Шов в кадре не обязан быть строго горизонтальным — встречаются снимки с вертикальной подачей стыка. Попытка угадать ориентацию эвристиками ненадежна, поэтому модуль выполняет два независимых цикла сканирования:

  1. Горизонтальный проход: Кадр сканируется по вертикальным полосам вдоль оси X. Вычисляется уверенность трассировки горизонтального шва $conf_H$.
  2. Вертикальный проход: Исходный кадр программно поворачивается на 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. Диагностическая панорама вертикальных полос с фиксацией экстремумов валика
Трассировка центральной оси шва параболическим сплайном
Рис. 4. Построенная центральная ось шва поверх исходного снимка

3.3. Робастная аппроксимация сплайна: как работает RANSAC

После локализации пиков валика в каждой полосе формируется массив координатных точек $(X_i, Y_i)$. На реальных снимках часть точек неизбежно оказывается ложной (выбросы из-за дефектов пленки кассеты, приварившихся брызг или краев оснастки). Обычный метод наименьших квадратов (МНК) здесь не применим: даже один грубый выброс с большим плечом кардинально искажает форму полинома.

Для построения центральной траектории шва применяется алгоритм RANSAC (Random Sample Consensus) [3], адаптированный под параболический сплайн 2-го порядка $Y = ax^2 + bx + c$:

Итоговая уверенность алгоритма ($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 пикселей.

Ступенчатый скачок центров из-за продольной трещины
Рис. 5. Проблема раздвоения профиля валика при наличии глубокой продольной несплошности по центру шва
После применения одномерного серого морфологического замыкания
Рис. 6. Корректное определение экстремума после применения одномерного серого морфологического замыкания

Физическая причина: Продольная трещина создает полосу минимального ослабления рентгеновского излучения (на снимке она выглядит как черная расщелина). В результате унимодальный световой купол валика шва распадается на два раздельных холма, образуя М-образный седловидный профиль. Классический поиск максимума цеплялся то за верхний валик усиления над трещиной, то за нижний.

Математическое решение: Проблема была устранена внедрением одномерного серого морфологического замыкания (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. Примеры результирующих раскладок патчей с гарантированным захватом шва и околошовной зоны

Итоговая раскладка слайсов вдоль контура шва
Рис. 7. Корректный результат на сложном сценарии (довольно низкий контраст шва относительно тела трубы)
Итоговая раскладка слайсов вдоль контура шва
Рис. 8. Любые эталоны и надписи с высокой яркостью игнорируются
Итоговая раскладка слайсов вдоль контура шва
Рис. 9. Шов дугой — не проблема
Итоговая раскладка слайсов вдоль контура шва
Рис. 10. Здесь не вполне хороший результат, хотя и близко. Есть над чем поработать.

Выводы

Качество работы сверточной нейросети в радиографическом контроле закладывается на этапе формирования датасета. Попытки механически нарезать кадры плотным скользящим окном с последующим случайным разбиением приводят к фиктивной переобученности, скрытой утечке данных и неспособности модели находить реальные дефекты на новых стыках.

Предложенный подход на основе двунаправленного проекционного профилирования, одномерного морфологического замыкания и детерминированного сплайн-RANSAC обеспечивает устойчивую трассировку шва даже при выраженных продольных дефектах, зачищенном валике и наличии маркировочных знаков. Сформированные слайсы центрированы относительно реальной оси стыка и включают в себя как тело шва, так и околошовное пространство, что позволяет обучать модели детекции на физически корректных данных.

Ссылки и источники

  1. 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

  2. Анатомия датасета RIAWELC. Полезный проект или псевдо-академическая стряпня?
    Публикация: https://dps.com.ru/posts/ru/what_RIAWELC_really_is.html

  3. 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.

Дополнительные материалы

  1. Пример отчета моей реализации слайсера:
    📄 W0003_0020_report.html (Осторожно, файл большой ~7.7 MB)