Ищем соринку в глазу: контроль качества с помощью компьютерного зрения

от автора

Введение

Привет, Хабр. На связи Аеза и сегодня мы хотели бы рассказать о том, как используется искусственный интеллект для контроля качества различных изделий.

Здесь мы сразу оговоримся, что мы будем говорить именно о компьютерном зрении, как области  искусственного интеллекта, которая позволяет машинам интерпретировать и анализировать визуальные данные почти так же, как это делает человек.

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

В нашей статье мы тоже будем говорить о том, как можно на практике использовать компьютерное зрение, анализируя поступающие в систему изображения. Но мы не просто рассмотрим общие вопросы, связанные с использованием компьютерного зрения, а посмотрим, как на практике, с помощью Python можно реализовать простейшую систему контроля качества.

Зачем это нужно?

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

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

В этом примере мы фактически заменяем человеческий труд, автоматизируя процесс анализа изображений.

Другой, более технологичный пример. В транспортной индустрии для обеспечения безопасности перевозок необходимо регулярно проводить анализ состояния железнодорожного полотна. Наличие физических повреждений рельсов может привести к катастрофе. В прежние времена для дефектоскопии железнодорожных путей делали снимки, которые далее проверялись специалистами вручную. Теперь же, с помощью компьютерного зрения мы можем сразу анализировать изображения и выявлять аномалии в автоматическом режиме.

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

На рисунке ниже мы видим, как система распознала товар нормального качества и несколько видов брака.

Ну что ж, думаю теперь тебе понятно, зачем на практике нужно компьютерное зрение и мы можем перейти к построению такой системы.

О пользе глубокого обучения

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

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

Компьютерное зрение в трех этапах

Итак, из каких основных шагов состоит процесс работы системы компьютерного зрения? Прежде всего это конечно сбор данных.

Здесь, как бы банально это не звучало, самым важным является качество получаемых изображений. Нам необходимо обеспечить достаточный уровень качества изображений, но при этом нельзя допустить задержек при их записи. Так, если мы обрабатываем видео поток, то он не должен притормаживать, но при этом он должен быть приемлемого качества.

Камера для съема изображений должна размещаться таким образом, чтобы система могла однозначно идентифицировать содержимое изображения.

После сбора визуальных данных система обрабатывает их с помощью алгоритмов искусственного интеллекта. На этом этапе нейронная сеть анализирует изображения для выявления таких особенностей, как края, узоры и текстуры. Этот анализ позволяет системе обнаружить несоответствия или аномалии, такие как трещины, царапины или смещения. Такие методы, как обнаружение объектов, помогают найти конкретные компоненты, а сегментация изображения делит его на области для более детального осмотра.

В результате анализа собранной информации система принимает решение о качестве продукта. Например, она может классифицировать изделия как «прошедшие» или «не прошедшие» проверку, отмечать дефекты для дальнейшего рассмотрения или подавать сигнал тревоги, если изделие не соответствует требуемым стандартам. Эти решения часто интегрируются в автоматизированные рабочие процессы, что позволяет вносить коррективы в производственную линию в режиме реального времени.

Короткий путь

Отступление, для тех, кто недолюбливает ИИ, но почему-то дочитал до этого места. При анализе качества товаров мы можем не использовать глубокое обучение, а поступить проще: подготовить эталонное изображение нашего изделия и сравнивать все последующие изображения с ним.

Для практической реализации нам потребуется Python, и библиотеки OpenCV и TensorFlow. Для того, чтобы минимизировать количество ложных срабатываний нам необходимо предварительно обработать изображения. Мы выполним преобразование в градации серого для того, чтобы упростить изображение, сводя его к одному цветовому каналу. Далее, мы уменьшим шум с помощью гауссово размытие.

И наконец, с помощью метода Оцу выполним бинаризацию изображений, что позволит легче отличить продукт от фона.

import cv2  # Load image image = cv2.imread('product.jpg')  # Convert to grayscale gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)  # Apply Gaussian blur blurred = cv2.GaussianBlur(gray, (5, 5), 0)  # Apply Otsu's thresholding _, thresh = cv2.threshold(blurred, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)

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

# Edge detection edges = cv2.Canny(thresh, 100, 200)  # Find contours contours, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

И в завершении собственно процесс обнаружения дефектов. Мы будем сопоставлять текущее изображение с заданным шаблоном. В переменной template мы указываем файл шаблона, в result результаты сравнения, а в threshold коэффициент совпадения. В примере ниже изображения должны совпадать на 80 процентов.

# Example of template matching template = cv2.imread('template.jpg', 0) result = cv2.matchTemplate(gray, template, cv2.TM_CCOEFF_NORMED) threshold = 0.8 loc = np.where(result >= threshold)

Да, здесь мы обходимся без ИИ, ограничиваясь только тем функционалом, который нам предоставляет библиотека cv. Но такой подход будет эффективно работать только в тех случаях, где изображения действительно имеют полное графическое сходство, в противном случае мы получим большое количество ложных срабатываний.

Ну и совсем такой подход непригоден при динамическом анализе видео, когда к примеру, нам нужно обнаружить выбоины на дороге. Здесь нам точно потребуется глубокое обучение, о которым мы поговорим далее.

Обучаем систему

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

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

В качестве практического примера можно рассмотреть представленный ниже скрипт, который извлекает кадры из видео, формируя набор файлов в формате JPG.

import os import cv2  def extract_frames(video_path, output_folder, final_size, offset):     # Открываем видео     video = cv2.VideoCapture(video_path)     success, frame = video.read()     count = 0      # в цикле извлекаем изображения     while success:         min_dim = min(frame.shape[0], frame.shape[1])         center_x, center_y = frame.shape[1] // 2, frame.shape[0] // 2         half_dim = min_dim // 2         cropped_frame = frame[center_y - half_dim - offset:center_y + half_dim - offset, center_x - half_dim:center_x + half_dim]          # изменяем размер перед завершением обработки         resized_frame = cv2.resize(cropped_frame, (final_size, final_size))          frame_path = f"{output_folder}/frame_{count}.jpg"         cv2.imwrite(frame_path, resized_frame)  # Save the frame         success, frame = video.read()  # read the next frame         count += 1      video.release()     cv2.destroyAllWindows()     return count

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

Для того, чтобы начать обучение модели нам необходимо установить библиотеку Anomalib, предназначенную для обнаружения аномалий в изображениях.

$ pipenv shell $ pip install anomalib

Далее, нам необходимо разделить собранные данные на обучающее, тестовое и проверочное подмножества, для того, чтобы наша модель могла обучиться на этих данных.

from anomalib.data.image.folder import Folder from anomalib import TaskType from anomalib.data.utils import ValSplitMode  dataset_root = "/путь_к_папке_с_изображениями"  # Создаем модуль данных datamodule = Folder(     name="подпапка_с набором_в_корневой_папке",     root=dataset_root,     normal_dir="путь_к_папке_с_нормальными_образцами",     abnormal_dir=" путь_к_папке_с_ненормальными_образцами",     task=TaskType.CLASSIFICATION,     seed=42,     normal_split_ratio=0.2, # default value     val_split_mode=ValSplitMode.FROM_TEST, # default value     val_split_ratio=0.5, # default value     train_batch_size=32, # default value     eval_batch_size=32, # default value )  # Инициализируем модуль данных datamodule.setup()

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

В конце каждой эпохи обучения мы проверяем значение метрики AUROC, для того, чтобы понять насколько правильно модель распознает изображения и не требуется ли завершить обучение. Если она больше не растет за определенное количество эпох, равное граничному значению, то обучение завершается.

В сценарии, приведенном ниже мы также активно используем функции из библиотеки Anomalib.

from anomalib.models import ReverseDistillation from anomalib import TaskType from anomalib.data.image.folder import Folder from anomalib.loggers import AnomalibWandbLogger from anomalib.engine import Engine     from anomalib.deploy import ExportType from lightning.pytorch.callbacks import EarlyStopping, ModelCheckpoint      model = ReverseDistillation()  callbacks = [     ModelCheckpoint(         mode="max",         monitor="image_AUROC",         save_last=True,         verbose=True,         auto_insert_metric_name=True,         every_n_epochs=1,     ),     EarlyStopping(         monitor="image_AUROC",         mode="max",         patience=patience,     ), ]  wandb_logger = AnomalibWandbLogger(project="image_anomaly_detection",                                    name=name_wandb_experiment)  engine = Engine(     max_epochs=max_epochs,     callbacks=callbacks,     pixel_metrics="AUROC",     accelerator="auto",  # \<"cpu", "gpu", "tpu", "ipu", "hpu", "auto">,     devices=1,     logger=wandb_logger,     task=TaskType.CLASSIFICATION, )  print("Fit...") engine.fit(datamodule=datamodule, model=model)  print("Test...") engine.test(datamodule=datamodule, model=model)  print("Export weights...") path_export_weights = engine.export(export_type=ExportType.TORCH,                                     model=model)  print("path_export_weights: ", path_export_weights)

Скрипт автоматически сохраняет результаты тестового набора в папке «/results/ReverseDistillation/one_up/v0/images», где v0 остается для первого запуска. Если мы снова запустим фазу обучения, движок создаст новую папку v1 и так далее. В папке images есть две подпапки normal и abnormal, каждая из которых содержит изображения нормального и ненормального классов тестового набора.

Отмечаем дефекты

Отлично! Мы можем отделять изображения с дефектами от нормальных. Но хорошо было бы еще помечать проблемные области непосредственно на рисунках, для того, чтобы можно было понимать, где дефект.

Для того, чтобы выявить область в которой находится аномалия, мы будем использовать тепловую карту. Таким образом, анализируя аномальные изображения мы будем выделять часть изображения, в котором находится дефект. Здесь вместо ИИ будут использоваться средства работы с графикой из состава библиотеки OpenCV.

В скрипте ниже модель сначала делает предсказание относительно того, содержит ли исходное изображение аномалии. Затем нам необходимо обозначить проблемные области с помощью прямоугольников.

import sys from PIL import Image from anomalib.deploy import TorchInferencer import numpy as np import cv2 from torch import as_tensor from torchvision.transforms.v2.functional import to_dtype, to_image import torch from utils import show_image_list  inferencer = TorchInferencer(path=path_torch_model,                              device="cpu")  image = Image.open(path_image).convert("RGB") image = image.resize((256, 256)) image = to_dtype(to_image(image), torch.float32, scale=True) if as_tensor else np.array(image) / 255.0   result = inferencer.predict(image=image)  if result.pred_label == 0:     normal_score = 1 - result.pred_score     print("Normal - pred_score: {:.4f}".format(normal_score)) else:     print("Abnormal - pred_score: {:.4f}".format(result.pred_score))  # определяем границы прямоугольника image_bbox = result.image.copy() # определяем контуры contours, _ = cv2.findContours(result.pred_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # Рисуем прямоугольник for contour in contours:     x, y, w, h = cv2.boundingRect(contour)     cv2.rectangle(image_bbox, (x, y), (x+w, y+h), (255, 0, 0), 2)  mask = cv2.merge((result.pred_mask,result.pred_mask,result.pred_mask))  show_image_list(list_images=[result.image, image_bbox],                 list_titles=['image', 'image_bbox'],                 num_cols=3,                 figsize=(20, 10),                 grid=False,                 title_fontsize=20,                 path_image=path_result)

В результате работы скрипта мы получим исходные изображения и изображения с найденными аномалиями. Найденные области аномалий будут иметь примерно следующий вид:

Заключение

Упоминания искусственного интеллекта сейчас можно встретить практически везде: от высоких технологий до производства пищевых продуктов. Однако при этом мало кто понимает, как же ИИ можно использовать на практике.

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


ссылка на оригинал статьи https://habr.com/ru/articles/892280/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *